10
10
//
11
11
//===----------------------------------------------------------------------===//
12
12
13
- //
14
- // NOTE: This is a prototype, it does not have e.g. 32-bit support yet.
15
- //
16
-
17
13
@_fixed_layout @usableFromInline
18
14
internal struct _SmallString {
19
15
@usableFromInline
20
- internal typealias RawBitPattern = _StringObject . RawBitPattern
16
+ internal typealias RawBitPattern = ( UInt64 , UInt64 )
21
17
22
18
// Small strings are values; store them raw
23
19
@usableFromInline
@@ -29,13 +25,13 @@ internal struct _SmallString {
29
25
}
30
26
31
27
@inlinable
32
- internal var leadingRawBits : UInt {
28
+ internal var leadingRawBits : UInt64 {
33
29
@inline ( __always) get { return _storage. 0 }
34
30
@inline ( __always) set { _storage. 0 = newValue }
35
31
}
36
32
37
33
@inlinable
38
- internal var trailingRawBits : UInt {
34
+ internal var trailingRawBits : UInt64 {
39
35
@inline ( __always) get { return _storage. 1 }
40
36
@inline ( __always) set { _storage. 1 = newValue }
41
37
}
@@ -66,15 +62,41 @@ internal struct _SmallString {
66
62
// TODO
67
63
extension _SmallString {
68
64
@inlinable
69
- internal static var capacity : Int { @inline ( __always) get { return 15 } }
65
+ internal static var capacity : Int {
66
+ @inline ( __always) get {
67
+ #if arch(i386) || arch(arm)
68
+ return 10
69
+ #else
70
+ return 15
71
+ #endif
72
+ }
73
+ }
74
+
75
+ @inlinable
76
+ internal var discriminator : _StringObject . Discriminator {
77
+ @inline ( __always) get {
78
+ let value = _storage. 1 &>> _StringObject. Nibbles. discriminatorShift
79
+ return _StringObject. Discriminator ( UInt8 ( truncatingIfNeeded: value) )
80
+ }
81
+ @inline ( __always) set {
82
+ _storage. 1 &= _StringObject. Nibbles. largeAddressMask
83
+ _storage. 1 |= (
84
+ UInt64 ( truncatingIfNeeded: newValue. _value)
85
+ &<< _StringObject. Nibbles. discriminatorShift)
86
+ }
87
+ }
70
88
71
89
@inlinable
72
- internal var capacity : Int { @inline ( __always) get { return 15 } }
90
+ internal var capacity : Int {
91
+ @inline ( __always) get {
92
+ return _SmallString. capacity
93
+ }
94
+ }
73
95
74
96
@inlinable
75
97
internal var count : Int {
76
98
@inline ( __always) get {
77
- return _StringObject ( rawUncheckedValue : self . rawBits ) . smallCount
99
+ return discriminator . smallCount
78
100
}
79
101
}
80
102
@@ -86,7 +108,7 @@ extension _SmallString {
86
108
@inlinable
87
109
internal var isASCII : Bool {
88
110
@inline ( __always) get {
89
- return _StringObject ( rawUncheckedValue : self . rawBits ) . smallIsASCII
111
+ return discriminator . smallIsASCII
90
112
}
91
113
}
92
114
@@ -97,25 +119,17 @@ extension _SmallString {
97
119
@inline ( __always) get {
98
120
return (
99
121
self . _storage. 0 ,
100
- _StringObject (
101
- rawUncheckedValue: self . rawBits
102
- ) . undiscriminatedObjectRawBits
103
- )
122
+ self . _storage. 1 & _StringObject. Nibbles. largeAddressMask)
104
123
}
105
124
}
106
125
107
126
@inlinable
108
127
internal func computeIsASCII( ) -> Bool {
109
128
// TODO(UTF8 codegen): Either mask off discrim before, or don't set bit
110
129
// after
111
-
112
- #if arch(i386) || arch(arm)
113
- unimplemented_utf8_32bit ( )
114
- #else
115
- let asciiMask : UInt = 0x8080_8080_8080_8080
130
+ let asciiMask : UInt64 = 0x8080_8080_8080_8080
116
131
let raw = zeroTerminatedRawCodeUnits
117
- return raw. 0 & asciiMask == 0 && raw. 1 & asciiMask == 0
118
- #endif
132
+ return ( raw. 0 & asciiMask == 0 ) && ( raw. 1 & asciiMask == 0 )
119
133
}
120
134
}
121
135
@@ -135,7 +149,7 @@ extension _SmallString {
135
149
#if INTERNAL_CHECKS_ENABLED
136
150
print ( """
137
151
smallUTF8: count: \( self . count) , codeUnits: \(
138
- self . map { String ( $0, radix: 16 ) } . dropLast ( ) . joined ( )
152
+ self . map { String ( $0, radix: 16 ) } . joined ( )
139
153
)
140
154
""" )
141
155
#endif // INTERNAL_CHECKS_ENABLED
@@ -218,9 +232,7 @@ extension _SmallString {
218
232
}
219
233
220
234
_sanityCheck ( len <= _SmallString. capacity)
221
- var obj = _StringObject ( rawUncheckedValue: self . rawBits)
222
- obj. setSmallCount ( len, isASCII: self . computeIsASCII ( ) )
223
- self = _SmallString ( obj)
235
+ discriminator = . small( withCount: len, isASCII: self . computeIsASCII ( ) )
224
236
}
225
237
226
238
// Write to excess capacity. `f` should return the new count.
@@ -249,20 +261,15 @@ extension _SmallString {
249
261
250
262
// TODO(SIMD): The below can be replaced with just be a masked unaligned
251
263
// vector load
252
-
253
264
let ptr = input. baseAddress. _unsafelyUnwrappedUnchecked
254
-
255
- let low = _bytesToUInt ( ptr, Swift . min ( input. count, 8 ) )
256
- let high = count > 8 ? _bytesToUInt ( ptr + 8 , count &- 8 ) : 0
257
-
258
- let isASCII = ( low | high) & 0x8080_8080_8080_8080 == 0
259
- let smallDiscriminator = _StringObject. Nibbles. small (
260
- withCount: count, isASCII: isASCII)
261
-
262
- self . init ( _StringObject (
263
- discriminator: smallDiscriminator,
264
- valueLeading: low,
265
- valueTrailing: high) )
265
+ let leading = _bytesToUInt64 ( ptr, Swift . min ( input. count, 8 ) )
266
+ let trailing = count > 8 ? _bytesToUInt64 ( ptr + 8 , count &- 8 ) : 0
267
+
268
+ let isASCII = ( leading | trailing) & 0x8080_8080_8080_8080 == 0
269
+ let discriminator = _StringObject. Discriminator. small (
270
+ withCount: count,
271
+ isASCII: isASCII)
272
+ self . init ( raw: ( leading, trailing | discriminator. rawBits) )
266
273
}
267
274
268
275
@usableFromInline // @testable
@@ -281,18 +288,16 @@ extension _SmallString {
281
288
_sanityCheck ( writeIdx == totalCount)
282
289
283
290
let isASCII = base. isASCII && other. isASCII
284
- let smallDiscriminator = _StringObject. Nibbles. small (
285
- withCount: totalCount, isASCII: isASCII)
291
+ let discriminator = _StringObject. Discriminator. small (
292
+ withCount: totalCount,
293
+ isASCII: isASCII)
286
294
287
295
let ( leading, trailing) = result. zeroTerminatedRawCodeUnits
288
- self . init ( _StringObject (
289
- discriminator: smallDiscriminator,
290
- valueLeading: leading,
291
- valueTrailing: trailing) )
296
+ self . init ( raw: ( leading, trailing | discriminator. rawBits) )
292
297
}
293
298
}
294
299
295
- #if _runtime(_ObjC)
300
+ #if _runtime(_ObjC) && !(arch(i386) || arch(arm))
296
301
// Cocoa interop
297
302
extension _SmallString {
298
303
// Resiliently create from a tagged cocoa string
@@ -312,14 +317,14 @@ extension _SmallString {
312
317
}
313
318
#endif
314
319
315
- extension UInt {
320
+ extension UInt64 {
316
321
// Fetches the `i`th byte, from least-significant to most-significant
317
322
//
318
323
// TODO: endianess awareness day
319
324
@inlinable @inline ( __always)
320
325
internal func _uncheckedGetByte( at i: Int ) -> UInt8 {
321
- _sanityCheck ( i >= 0 && i < MemoryLayout< UInt > . stride)
322
- let shift = UInt ( bitPattern : i) &* 8
326
+ _sanityCheck ( i >= 0 && i < MemoryLayout< UInt64 > . stride)
327
+ let shift = UInt64 ( truncatingIfNeeded : i) &* 8
323
328
return UInt8 ( truncatingIfNeeded: ( self &>> shift) )
324
329
}
325
330
@@ -328,22 +333,26 @@ extension UInt {
328
333
// TODO: endianess awareness day
329
334
@inlinable @inline ( __always)
330
335
internal mutating func _uncheckedSetByte( at i: Int , to value: UInt8 ) {
331
- _sanityCheck ( i >= 0 && i < MemoryLayout< UInt > . stride)
332
- let shift = UInt ( bitPattern : i) &* 8
333
- let valueMask = 0xFF &<< shift
334
- self = ( self & ~ valueMask) | ( UInt ( truncatingIfNeeded: value) &<< shift)
336
+ _sanityCheck ( i >= 0 && i < MemoryLayout< UInt64 > . stride)
337
+ let shift = UInt64 ( truncatingIfNeeded : i) &* 8
338
+ let valueMask : UInt64 = 0xFF &<< shift
339
+ self = ( self & ~ valueMask) | ( UInt64 ( truncatingIfNeeded: value) &<< shift)
335
340
}
336
341
}
337
342
338
343
@inlinable @inline ( __always)
339
- internal func _bytesToUInt( _ input: UnsafePointer < UInt8 > , _ c: Int ) -> UInt {
340
- var r : UInt = 0
344
+ internal func _bytesToUInt64(
345
+ _ input: UnsafePointer < UInt8 > ,
346
+ _ c: Int
347
+ ) -> UInt64 {
348
+ // FIXME: This should be unified with _loadPartialUnalignedUInt64LE.
349
+ // Unfortunately that causes regressions in literal concatenation tests. (Some
350
+ // owned to guaranteed specializations don't get inlined.)
351
+ var r : UInt64 = 0
341
352
var shift : Int = 0
342
353
for idx in 0 ..< c {
343
- r = r | ( UInt ( input [ idx] ) &<< shift)
354
+ r = r | ( UInt64 ( input [ idx] ) &<< shift)
344
355
shift = shift &+ 8
345
356
}
346
357
return r
347
358
}
348
-
349
-
0 commit comments