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. jsp札记

    日期格式化 <s:date name="creaetime" format="yyyy-MM-dd HH:mm:ss" /> <base hr ...

  2. jquery和js中走的弯路

    1.$.each的错误用法 $.each的return xx 不能结束外层的函数,但return true/false可以 所以一般的: var result; $.each(json,functio ...

  3. document.body和document.documentElement区别

    1.document.documentElement表示文档节点树的根节点,即<html> document.body是body节点 2. 页面具有 DTD,或者说指定了 DOCTYPE ...

  4. 乞丐版servlet容器第2篇

    2. 监听端口接收请求 上一步中我们已经定义好了Server接口,并进行了多次重构,但是实际上那个Server是没啥毛用的东西. 现在要为其添加真正有用的功能. 大师说了,饭要一口一口吃,衣服要一件一 ...

  5. 判定map中是否存在某元素

    判断某key是否存在可以使用map的count方法来间接判定 count接受一个参数key值,返回map中key值为给定值的元素总数 map<int, string> i_to_s_map ...

  6. 2018.09.27 bzoj2510: 弱题(概率dp+循环矩阵优化)

    传送门 简单概率dp. 显然每次转移的式子可以用一个矩阵表示出来: 这个是循环矩阵. 因此只用维护第一行快速幂一波就行了. 代码: #include<bits/stdc++.h> #def ...

  7. 2018.07.17 后缀自动机模板(SAM)

    洛谷传送门 这是一道后缀自动机的模板题,这道题让我切身体会到了后缀自动机的方便与好写. 代码如下: #include<bits/stdc++.h> #define N 2000005 #d ...

  8. Spring MVC之@RequestMapping 传递数组

    1.前台: var param = {titles:['col1','col2','col3']}; $.ajax({url:url, type:"post", data:para ...

  9. MyEclipse 过期

    package util; import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamRea ...

  10. springMVC学习(注解实现依赖注入)

    原文:http://blog.csdn.net/mockingbirds/article/details/45399691 上一篇博客,学习了spring的依赖注入,即利用spring容器来为类中的属 ...