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. 【Linux】Memcached安装

    Memcached概念 Memcached是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载. MemCache的工作流程如下:先检查客户端的请求数据是否在memcached中, ...

  2. 2018.09.25 poj3070 Fibonacci(矩阵快速幂)

    传送门 矩阵快速幂板题,写一道来练练手. 这一次在poj做题总算没忘了改万能库. 代码: #include<iostream> #include<cstdio> #define ...

  3. SQL查询优化的一些建议

    使用批量查询,而不是N次循环查询! 重复的数据,不要重复获取: 根据需要,按需要获取表字段,而不是SELECT *: 针对频繁的搜索字段,建立必要的索引,以加快查询速度: 使用关联查询,而不是粗暴地类 ...

  4. Ubuntu 16.04安装MySQL及遇到的问题解决方案

    使用以下命令即可进行MySQL安装: sudo apt-get install mysql-server 上述命令会安装以下包: apparmor mysql-client-5.7 mysql-com ...

  5. HDU 2161 Primes (素数筛选法)

    题意:输入一个数判断是不是素数,并规定2不是素数. 析:一看就很简单吧,用素数筛选法,注意的是结束条件是n<0,一开始被坑了... 不说了,直接上代码: #include <iostrea ...

  6. BeautifulSoup基本步骤

    http://blog.csdn.net/kikaylee/article/details/56841789 ’BeautifulSoup是Python的一个库,最主要的功能就是从网页爬取我们需要的数 ...

  7. day03(接口,多态)

    接口:            概念:是功能的集合,可以当做引用数据类型的一种.比抽象类更加抽象. 接口的成员:               成员变量:必须使用final修饰 默认被 public &a ...

  8. (并查集)Is It A Tree? --POJ--1308

    链接: http://poj.org/problem?id=1308 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82830#probl ...

  9. C# Timer类

    C# 有三种不同的Timer类 1.Threading.Timer 2.Timer.Timer 3.Forms.Timer using System; using System.Collections ...

  10. Pywinauto 基于Win32 程序的自动化功能测试工具

    1.  前提条件 ü  Python2.6 下载地址:http://ishare.iask.sina.com.cn/f/8173206.html ü  Pywinauto-0.4.1 下载地址:htt ...