Swift 里字符串(七)stringIndex
在 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的更多相关文章
- Swift 里字符串(十)修改字符串
以append操作为例 public mutating func append(_ other: String) { if self.isEmpty && !_guts.hasNati ...
- Swift里字符串(五)Native strings
Native strings have tail-allocated storage, which begins at an offset of nativeBias from the storage ...
- Swift 里字符串(三)small String
 small string, 只有两个 UInt64 的字,这里面存储了所有的信息. 内存布局如下:  第二个 UInt64 存储了标记位和长度信息,以及部分字符串的值 // Get an int ...
- Swift 里字符串(四)large sting
对于普通的字符串,对应的_StringObject 有两个存储属性: _countAndFlagsBits: UInt64 _object: Builtin.BridgeObject _countAn ...
- Swift 里字符串(一)概览
感受一下字符串相关的源文件个数  String 概览 是一个结构体 只有一个变量,类型是 _StringGuts  如上所示,String 真正的内容在__StringStorage或者__Sha ...
- Swift 里字符串(九)UTF16View
即以 UTF16 编码的格式来查看字符串. UTF16View 是一个结构体 @_fixed_layout public struct UTF16View { @usableFromInline in ...
- Swift 里字符串(八)UnicodeScalarView
即以 Unicode Scarlar 的方式来查看字符串. /// let flag = "
- Swift里字符串(六)Shared strings
Shared strings do not have tail-allocated storage, but can provide access upon query to contiguous U ...
- Swift 里字符串(十一)OC 字符串和 Swift 字符串的转换
 to OC func _bridgeToObjectiveCImpl() -> AnyObject { if _guts.isSmall { return _guts.asSmall.wit ...
随机推荐
- 16款值得一用的iPhone线框图模板 (PSD & Sketch)
在任何网站或移动应用设计的过程中,线框图作为设计元素和功能的图示,它有助于帮助定义和更好地传达信息层次结构,让参与设计和开发的人员更好的理解设计师的思路和设计的功能点. 即使线框图设计是一个比较耗时的 ...
- Response.Redirect原理图解
- linux信号量初识
以下程序使用信号量控制程序运行 "信号"量 "变"量 /*信号量(semaphore)是变量,是一种特殊的变量.它仅取正值. 对信息号量的操作只有2种:等待(w ...
- .NET中的Func委托用法
MSDN对于Func<T, TResult>)的官方解释: 封装一个具有一个参数并返回 TResult 参数指定的类型值的方法. 下面通过几个例子对比下,就容易知道其用法: 以下例子演示了 ...
- 流程控制 if while for 已及数字类型 进制转换
一:if 语句 语法一:ifif 条件: code1 code1 code1 语法二:if ...else ... if 条件: code1 code1 code1else: code1 code1 ...
- 《Delphi XE6 android 编程入门教程》推荐
近5.6年已经没有看见关于delphi的新技术的书出来了(看来在国内delphi的使用量确实很低了), 高勇同学最近出了一本<Delphi XE6 android 编程入门教程>,上周刚拿 ...
- hdu-1107(模拟题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1107 注意:1.路线是要反向的,走不通就反向: 2.输入输出全部是整形 3.攻击力不断变化 #incl ...
- Spring boot变量的初始化顺序
起因是Spring建议”总是在您的bean中使用构造函数建立依赖注入.总是使用断言强制依赖”,而且之前用@Autowired时idea总是给警告,于是全部改成了构造器注入,运行时发生了循环注入,于是找 ...
- Win7 SP1 提示ADO的问题
需要安装 Windows6.1-KB2640696-v3-x64.msu 这个Pack
- MEF程序设计指南
############################################################################################## ##### ...