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. Spring官方文档翻译(1~6章)

    Spring官方文档翻译(1~6章) 转载至 http://blog.csdn.net/tangtong1/article/details/51326887 Spring官方文档.参考中文文档 一.S ...

  2. 慢工出细活,Facebook点赞按钮设计中的门道

    一年前,Facebook点赞按钮发布更新.一年后的今天,Facebook小小的点赞按钮因为Ted刚发布的一段演讲掀起波澜.设计一个像FB点赞按钮那么小的东西很难么?Ted中Margaret Gould ...

  3. struts2乱码问题

    简介:做了个功能,用的struts2,表单提交到后台,接收后打印出来的数据乱码.   解决步骤: 1. struts.xml中配置<constant name="struts.i18n ...

  4. PetaPoco与SQLite

    PetaPoco与SQLite. 对于精简版本的ORM,PetaPoco确实短小精悍,想做个WPF的Demo,然后将PetaPoco与SQLite集成一起使用,简单易用,是不错的选择. ()==数据库 ...

  5. 如何优化Mysql数据库

    1.添加主键ID 2.尽量避免使用select * form table 3.创建索引     对于查询占主要的应用来说,索引显得尤为重要.很多时候性能问题很简单的就是因为我们忘了添加索引而造成的,或 ...

  6. 关于调用Feign client超时得不到结果的问题

    需要在调用方的配置文件加入以下配置 hystrix.command.default.execution.timeout.enabled: false ribbon: ConnectTimeout: R ...

  7. 自学如何去学习jQuery

    学习JQ第一个demo: 制作一个轮播图,制作方法我前面写了一篇博客,传送门-->http://www.cnblogs.com/yewenxiang/p/6100206.html 需要的JQ知识 ...

  8. autolayout之后获取uiview的frame

    这个只要一行代码就搞定了.详细请看: In order to get the right frame/bounds of your UIImageView after resizing, you ne ...

  9. (线段树 区间查询)The Water Problem -- hdu -- 5443 (2015 ACM/ICPC Asia Regional Changchun Online)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=5443 The Water Problem Time Limit: 1500/1000 MS (Java/ ...

  10. 给ubuntu系统的root设置密码:

    首先输入:sudo passwd root 然后输入当前用户的密码,例如xiaomeige这个用户的密码为xiaomeige 然后输入希望给root账户设置的密码,例如密码也为root