@@ -13,54 +13,57 @@ extension String {
13
13
/// A position of a character or code unit in a string.
14
14
@_fixed_layout // FIXME(sil-serialize-all)
15
15
public struct Index {
16
+ internal typealias _UTF8Buffer = UTF8 . EncodedScalar
17
+
16
18
@usableFromInline // FIXME(sil-serialize-all)
17
- internal var _compoundOffset : UInt64
19
+ internal var _compoundOffset : UInt64
20
+
18
21
@usableFromInline
19
- internal var _cache : _Cache
22
+ internal var _utf8Buffer = _UTF8Buffer ( )
20
23
21
- internal typealias _UTF8Buffer = _ValidUTF8Buffer < UInt64 >
22
- @_frozen // FIXME(sil-serialize-all)
23
24
@usableFromInline
24
- internal enum _Cache {
25
- case utf16
26
- case utf8( buffer: _UTF8Buffer )
27
- case character( stride: UInt16 )
28
- case unicodeScalar( value: Unicode . Scalar )
29
- }
25
+ internal var _graphemeStrideCache : UInt16 = 0
30
26
}
31
27
}
32
28
33
29
/// Convenience accessors
34
- extension String . Index . _Cache {
35
- @inlinable // FIXME(sil-serialize-all)
36
- internal var utf16 : Void ? {
37
- if case . utf16 = self { return ( ) } else { return nil }
38
- }
30
+ extension String . Index {
39
31
@inlinable // FIXME(sil-serialize-all)
40
- internal var utf8 : String . Index . _UTF8Buffer ? {
41
- if case . utf8( let r) = self { return r } else { return nil }
32
+ internal var utf8Buffer : String . Index . _UTF8Buffer ? {
33
+ guard !_utf8Buffer. isEmpty else { return nil }
34
+ return _utf8Buffer
42
35
}
36
+
43
37
@inlinable // FIXME(sil-serialize-all)
44
- internal var character : UInt16 ? {
45
- if case . character( let r) = self { return r } else { return nil }
38
+ internal var characterStride : Int ? {
39
+ guard _graphemeStrideCache > 0 else { return nil }
40
+ return Int ( truncatingIfNeeded: _graphemeStrideCache)
46
41
}
42
+
43
+ // TODO: Probably worth carving a bit for, or maybe a isSubScalar bit...
47
44
@inlinable // FIXME(sil-serialize-all)
48
- internal var unicodeScalar : UnicodeScalar ? {
49
- if case . unicodeScalar ( let r ) = self { return r } else { return nil }
45
+ internal var isUTF8 : Bool {
46
+ return self . utf8Buffer != nil || self . transcodedOffset > 0
50
47
}
51
48
}
52
49
53
50
extension String . Index : Equatable {
51
+ // A combined code unit and transcoded offset, for comparison purposes
52
+ @inlinable // FIXME(sil-serialize-all)
53
+ internal var _orderingValue : UInt64 {
54
+ return _compoundOffset
55
+ }
56
+
54
57
@inlinable // FIXME(sil-serialize-all)
55
58
public static func == ( lhs: String . Index , rhs: String . Index ) -> Bool {
56
- return lhs. _compoundOffset == rhs. _compoundOffset
59
+ return lhs. _orderingValue == rhs. _orderingValue
57
60
}
58
61
}
59
62
60
63
extension String . Index : Comparable {
61
64
@inlinable // FIXME(sil-serialize-all)
62
65
public static func < ( lhs: String . Index , rhs: String . Index ) -> Bool {
63
- return lhs. _compoundOffset < rhs. _compoundOffset
66
+ return lhs. _orderingValue < rhs. _orderingValue
64
67
}
65
68
}
66
69
@@ -72,56 +75,67 @@ extension String.Index : Hashable {
72
75
/// of this instance.
73
76
@inlinable // FIXME(sil-serialize-all)
74
77
public func hash( into hasher: inout Hasher ) {
75
- hasher. combine ( _compoundOffset )
78
+ hasher. combine ( _orderingValue )
76
79
}
77
80
}
78
81
79
82
extension String . Index {
80
- internal typealias _Self = String . Index
81
-
83
+ @inline ( __always)
84
+ @inlinable
85
+ internal init ( encodedOffset: Int , transcodedOffset: Int ) {
86
+ let cuOffset = UInt64 ( truncatingIfNeeded: encodedOffset)
87
+ _sanityCheck (
88
+ cuOffset & 0xFFFF_0000_0000_0000 == 0 , " String length capped at 48bits " )
89
+ let transOffset = UInt64 ( truncatingIfNeeded: transcodedOffset)
90
+ _sanityCheck ( transOffset <= 4 , " UTF-8 max transcoding is 4 code units " )
91
+
92
+ self . _compoundOffset = cuOffset &<< 2 | transOffset
93
+ }
94
+
95
+ @inline ( __always)
96
+ @inlinable
97
+ internal init ( from other: String . Index , adjustingEncodedOffsetBy adj: Int ) {
98
+ self . init (
99
+ encodedOffset: other. encodedOffset &+ adj,
100
+ transcodedOffset: other. transcodedOffset)
101
+ self . _utf8Buffer = other. _utf8Buffer
102
+ self . _graphemeStrideCache = other. _graphemeStrideCache
103
+ }
104
+
82
105
/// Creates a new index at the specified UTF-16 offset.
83
106
///
84
107
/// - Parameter offset: An offset in UTF-16 code units.
85
108
@inlinable // FIXME(sil-serialize-all)
86
109
public init ( encodedOffset offset: Int ) {
87
- _compoundOffset = UInt64 ( offset << _Self. _strideBits)
88
- _cache = . utf16
110
+ self . init ( encodedOffset: offset, transcodedOffset: 0 )
89
111
}
90
112
91
113
@inlinable // FIXME(sil-serialize-all)
92
- internal init ( encodedOffset o: Int , transcodedOffset: Int = 0 , _ c: _Cache ) {
93
- _compoundOffset = UInt64 ( o << _Self. _strideBits | transcodedOffset)
94
- _cache = c
114
+ internal init (
115
+ encodedOffset offset: Int , transcodedOffset: Int , buffer: _UTF8Buffer
116
+ ) {
117
+ self . init ( encodedOffset: offset, transcodedOffset: transcodedOffset)
118
+ self . _utf8Buffer = buffer
95
119
}
96
-
97
- @inlinable // FIXME(sil-serialize-all)
98
- internal static var _strideBits : Int { return 2 }
99
- @inlinable // FIXME(sil-serialize-all)
100
- internal static var _mask : UInt64 { return ( 1 &<< _Self. _strideBits) &- 1 }
101
-
102
- @inlinable // FIXME(sil-serialize-all)
103
- internal mutating func _setEncodedOffset( _ x: Int ) {
104
- _compoundOffset = UInt64 ( x << _Self. _strideBits)
120
+
121
+ @inlinable
122
+ internal init ( encodedOffset: Int , characterStride: Int ) {
123
+ self . init ( encodedOffset: encodedOffset, transcodedOffset: 0 )
124
+ if characterStride < UInt16 . max {
125
+ self . _graphemeStrideCache = UInt16 ( truncatingIfNeeded: characterStride)
126
+ }
105
127
}
106
-
128
+
107
129
/// The offset into a string's UTF-16 encoding for this index.
108
130
@inlinable // FIXME(sil-serialize-all)
109
131
public var encodedOffset : Int {
110
- return Int ( _compoundOffset >> _Self . _strideBits )
132
+ return Int ( truncatingIfNeeded : _compoundOffset & >> 2 )
111
133
}
112
134
113
135
/// The offset of this index within whatever encoding this is being viewed as
114
136
@inlinable // FIXME(sil-serialize-all)
115
- internal var _transcodedOffset : Int {
116
- get {
117
- return Int ( _compoundOffset & _Self. _mask)
118
- }
119
- set {
120
- let extended = UInt64 ( newValue)
121
- _sanityCheck ( extended <= _Self. _mask)
122
- _compoundOffset &= ~ _Self. _mask
123
- _compoundOffset |= extended
124
- }
137
+ internal var transcodedOffset : Int {
138
+ return Int ( truncatingIfNeeded: _compoundOffset & 0x3 )
125
139
}
126
140
}
127
141
@@ -130,27 +144,27 @@ extension String.Index {
130
144
@inlinable // FIXME(sil-serialize-all)
131
145
@available ( swift, deprecated: 3.2 )
132
146
@available ( swift, obsoleted: 4.0 )
133
- public // SPI(Foundation)
147
+ public // SPI(Foundation)
134
148
init ( _position: Int ) {
135
149
self . init ( encodedOffset: _position)
136
150
}
137
-
151
+
138
152
@inlinable // FIXME(sil-serialize-all)
139
153
@available ( swift, deprecated: 3.2 )
140
154
@available ( swift, obsoleted: 4.0 )
141
- public // SPI(Foundation)
142
- init ( _offset : Int ) {
143
- self . init ( encodedOffset: _offset )
155
+ public // SPI(Foundation)
156
+ init ( _codeUnitOffset : Int ) {
157
+ self . init ( encodedOffset: _codeUnitOffset )
144
158
}
145
-
159
+
146
160
@inlinable // FIXME(sil-serialize-all)
147
161
@available ( swift, deprecated: 3.2 )
148
162
@available ( swift, obsoleted: 4.0 )
149
- public // SPI(Foundation)
163
+ public // SPI(Foundation)
150
164
init ( _base: String . Index , in c: String . CharacterView ) {
151
165
self = _base
152
166
}
153
-
167
+
154
168
/// The integer offset of this index in UTF-16 code units.
155
169
@inlinable // FIXME(sil-serialize-all)
156
170
@available ( swift, deprecated: 3.2 )
@@ -171,7 +185,7 @@ extension String.Index {
171
185
}
172
186
173
187
174
- // backward compatibility for index interchange.
188
+ // backward compatibility for index interchange.
175
189
extension Optional where Wrapped == String . Index {
176
190
@inlinable // FIXME(sil-serialize-all)
177
191
@available (
0 commit comments