String 里,用来索引 Character 的,不是整数,而是StringIndex

内部结构

extension String {
/// A position of a character or code unit in a string.
@_fixed_layout
public struct Index {
@usableFromInline
internal var _rawBits: UInt64 @inlinable @inline(__always)
init(_ raw: UInt64) {
self._rawBits = raw
self._invariantCheck()
}
}
}

其实就是一个UInt64的值,不过不同的bit有不同的含义。

String's Index has the following layout:

 ┌──────────┬───────────────────┬────────────────┬──────────┐
│ b63:b16 │ b15:b14 │ b13:b8 │ b7:b0 │
├──────────┼───────────────────┼────────────────┼──────────┤
│ position │ transcoded offset │ grapheme cache │ reserved │
└──────────┴───────────────────┴────────────────┴──────────┘ - grapheme cache: A 6-bit value remembering the distance to the next grapheme
boundary
- position aka `encodedOffset`: An offset into the string's code units
- transcoded offset: a sub-scalar offset, derived from transcoding
  • position,即当前字符的相对于起始位置的偏移,以 code unit 计算。在String里,默认是utf8编码,所以指代距离起始位置的字节数。
  • transcoded offset 和编码相关
  • grapheme cache 标记当前字符距离下一个字符的距离。

起始和结束位置的定义

// Index
extension _StringGuts {
@usableFromInline
internal typealias Index = String.Index @inlinable
internal var startIndex: String.Index {
@inline(__always) get { return Index(encodedOffset: 0) }
}
@inlinable
internal var endIndex: String.Index {
@inline(__always) get { return Index(encodedOffset: self.count) } //count 不是String 的count
}
}

即指向了内存地址的起始和结束。

计算字符串的长度

String 的长度,根据文档说,不可以在O(1)时间内获得,因为要遍历整个字符串。string遵守BidirectionalCollection,而不是RandomAccessCollection

  /// The number of characters in a string.
public var count: Int {
@inline(__always) get {
return distance(from: startIndex, to: endIndex)
}
}

从定义中可以看到,为了计算长度,需要计算两个Index 之间的距离。
最终是需要从startIndex 遍历到 endIndex的。

  @inlinable // protocol-only
internal func _distance(from start: Index, to end: Index) -> Int {
var start = start
var count = 0 if start < end {
while start != end {
count += 1
formIndex(after: &start)
}
}
else if start > end {
while start != end {
count -= 1
formIndex(before: &start)
}
} return count
}

每一次formIndex都会调用到下面的代码:

  public func index(after i: Index) -> Index {
_precondition(i < endIndex, "String index is out of bounds") // TODO: known-ASCII fast path, single-scalar-grapheme fast path, etc.
let stride = _characterStride(startingAt: i)
let nextOffset = i.encodedOffset &+ stride
let nextStride = _characterStride(
startingAt: Index(encodedOffset: nextOffset)) return Index(
encodedOffset: nextOffset, characterStride: nextStride)
}

可以看到,需要确定当前字符占用code unit 的个数,以及下一个字符占用code unit的个数。
这样子逐一遍历下去,不能在常数时间内完成也就可想而知了。

Swift 里字符串(七)stringIndex的更多相关文章

  1. Swift 里字符串(十)修改字符串

    以append操作为例 public mutating func append(_ other: String) { if self.isEmpty && !_guts.hasNati ...

  2. Swift里字符串(五)Native strings

    Native strings have tail-allocated storage, which begins at an offset of nativeBias from the storage ...

  3. Swift 里字符串(三)small String

     small string, 只有两个 UInt64 的字,这里面存储了所有的信息. 内存布局如下:  第二个 UInt64 存储了标记位和长度信息,以及部分字符串的值 // Get an int ...

  4. Swift 里字符串(四)large sting

    对于普通的字符串,对应的_StringObject 有两个存储属性: _countAndFlagsBits: UInt64 _object: Builtin.BridgeObject _countAn ...

  5. Swift 里字符串(一)概览

    感受一下字符串相关的源文件个数  String 概览 是一个结构体 只有一个变量,类型是 _StringGuts  如上所示,String 真正的内容在__StringStorage或者__Sha ...

  6. Swift 里字符串(九)UTF16View

    即以 UTF16 编码的格式来查看字符串. UTF16View 是一个结构体 @_fixed_layout public struct UTF16View { @usableFromInline in ...

  7. Swift 里字符串(八)UnicodeScalarView

    即以 Unicode Scarlar 的方式来查看字符串. /// let flag = "

  8. Swift里字符串(六)Shared strings

    Shared strings do not have tail-allocated storage, but can provide access upon query to contiguous U ...

  9. Swift 里字符串(十一)OC 字符串和 Swift 字符串的转换

     to OC func _bridgeToObjectiveCImpl() -> AnyObject { if _guts.isSmall { return _guts.asSmall.wit ...

随机推荐

  1. socket多文件发送(压缩,解压)

    .客户端代码 public static void FileMoveInVirtualMachineForCompressor() { var obj = new object(); string i ...

  2. c++ 博客资源

    /************************************************************** 技术博客 http://www.cnblogs.com/itdef/   ...

  3. 高性能 js -- 无阻塞加载脚本

    参考: <<高性能JavaScript>> Nicbolas C. Zakas 著 javascript代码的下载和执行过程会阻塞浏览器的其他进程, 比如页面的绘制, 遇到&l ...

  4. 557. Reverse Words in a String III

    static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...

  5. 2018.10.19 NOIP训练 桌子(快速幂优化dp)

    传送门 勉强算一道dp好题. 显然第kkk列和第k+nk+nk+n列放的棋子数是相同的. 因此只需要统计出前nnn列的选法数. 对于前mmm%nnn列,一共有(m−1)/n+1(m-1)/n+1(m− ...

  6. python入门前的准备

    为什么学习python? python是一种高级脚本解释性语言,若运行for循环等肯定不如c或fortran快,但是它是开源的,有很多特别有用的库,代码以空格强制控制格式,形式优美简洁,且特别容易实现 ...

  7. hdu2844

    题目 这道题,刚开始题没读懂,就是这句话:,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of ...

  8. Discoverer Table

    http://www.cnblogs.com/fandychen/p/3182826.html EUL4_BAS Table gives list of Business Areas EUL4_OBJ ...

  9. LeetCode141:Linked List Cycle

    题目: Given a linked list, determine if it has a cycle in it. Follow up: Can you solve it without usin ...

  10. HLSL-高级着色语言简介【转】

    HLSL-High Level Shader Language 优点 用来书写Vertex Shader和Pixel Shader程序的代码,语法类似于C/C++,在DirectX 8.x的时代,Sh ...