10
10
//
11
11
//===----------------------------------------------------------------------===//
12
12
13
+ // The code units in _SmallString are always stored in memory in the same order
14
+ // that they would be stored in an array. This means that on big-endian
15
+ // platforms the order of the bytes in storage is reversed compared to
16
+ // _StringObject whereas on little-endian platforms the order is the same.
17
+ //
18
+ // Memory layout:
19
+ //
20
+ // |0 1 2 3 4 5 6 7 8 9 A B C D E F| ← hexadecimal offset in bytes
21
+ // | _storage.0 | _storage.1 | ← raw bits
22
+ // | code units | | ← encoded layout
23
+ // ↑ ↑
24
+ // first (leftmost) code unit discriminator (incl. count)
25
+ //
13
26
@_fixed_layout @usableFromInline
14
27
internal struct _SmallString {
15
28
@usableFromInline
@@ -50,16 +63,18 @@ internal struct _SmallString {
50
63
@inlinable @inline ( __always)
51
64
internal init ( _ object: _StringObject ) {
52
65
_internalInvariant ( object. isSmall)
53
- self . init ( raw: object. rawBits)
66
+ // On big-endian platforms the byte order is the reverse of _StringObject.
67
+ let leading = object. rawBits. 0 . littleEndian
68
+ let trailing = object. rawBits. 1 . littleEndian
69
+ self . init ( raw: ( leading, trailing) )
54
70
}
55
71
56
72
@inlinable @inline ( __always)
57
73
internal init ( ) {
58
- self . init ( raw : _StringObject ( empty: ( ) ) . rawBits )
74
+ self . init ( _StringObject ( empty: ( ) ) )
59
75
}
60
76
}
61
77
62
- // TODO
63
78
extension _SmallString {
64
79
@inlinable
65
80
internal static var capacity : Int {
@@ -74,7 +89,8 @@ extension _SmallString {
74
89
75
90
@inlinable @inline ( __always)
76
91
internal var rawDiscriminatedObject : UInt64 {
77
- return _storage. 1
92
+ // Discriminator is the most significant byte.
93
+ return _storage. 1 . littleEndian
78
94
}
79
95
80
96
@inlinable
@@ -107,7 +123,7 @@ extension _SmallString {
107
123
// usage: it always clears the discriminator and count (in case it's full)
108
124
@inlinable @inline ( __always)
109
125
internal var zeroTerminatedRawCodeUnits : RawBitPattern {
110
- let smallStringCodeUnitMask : UInt64 = 0x00FF_FFFF_FFFF_FFFF
126
+ let smallStringCodeUnitMask = ~ UInt64( 0xFF ) . bigEndian // zero last byte
111
127
return ( self . _storage. 0 , self . _storage. 1 & smallStringCodeUnitMask)
112
128
}
113
129
@@ -231,11 +247,12 @@ extension _SmallString {
231
247
_internalInvariant ( count <= _SmallString. capacity)
232
248
233
249
let isASCII = ( leading | trailing) & 0x8080_8080_8080_8080 == 0
234
- let countAndDiscriminator = UInt64 ( truncatingIfNeeded: count) &<< 56
235
- | _StringObject. Nibbles. small ( isASCII: isASCII)
236
- _internalInvariant ( trailing & countAndDiscriminator == 0 )
250
+ let discriminator = _StringObject. Nibbles
251
+ . small ( withCount: count, isASCII: isASCII)
252
+ . littleEndian // reversed byte order on big-endian platforms
253
+ _internalInvariant ( trailing & discriminator == 0 )
237
254
238
- self . init ( raw: ( leading, trailing | countAndDiscriminator ) )
255
+ self . init ( raw: ( leading, trailing | discriminator ) )
239
256
_internalInvariant ( self . count == count)
240
257
}
241
258
@@ -295,23 +312,27 @@ extension _SmallString {
295
312
#endif
296
313
297
314
extension UInt64 {
298
- // Fetches the `i`th byte, from least-significant to most-significant
299
- //
300
- // TODO: endianess awareness day
315
+ // Fetches the `i`th byte, from left to right.
301
316
@inlinable @inline ( __always)
302
317
internal func _uncheckedGetByte( at i: Int ) -> UInt8 {
303
318
_internalInvariant ( i >= 0 && i < MemoryLayout< UInt64> . stride)
319
+ #if _endian(big)
320
+ let shift = ( 7 - UInt64( truncatingIfNeeded: i) ) &* 8
321
+ #else
304
322
let shift = UInt64 ( truncatingIfNeeded: i) &* 8
323
+ #endif
305
324
return UInt8 ( truncatingIfNeeded: ( self &>> shift) )
306
325
}
307
326
308
- // Sets the `i`th byte, from least-significant to most-significant
309
- //
310
- // TODO: endianess awareness day
327
+ // Sets the `i`th byte, from left to right.
311
328
@inlinable @inline ( __always)
312
329
internal mutating func _uncheckedSetByte( at i: Int , to value: UInt8 ) {
313
330
_internalInvariant ( i >= 0 && i < MemoryLayout< UInt64> . stride)
331
+ #if _endian(big)
332
+ let shift = ( 7 - UInt64( truncatingIfNeeded: i) ) &* 8
333
+ #else
314
334
let shift = UInt64 ( truncatingIfNeeded: i) &* 8
335
+ #endif
315
336
let valueMask : UInt64 = 0xFF &<< shift
316
337
self = ( self & ~ valueMask) | ( UInt64 ( truncatingIfNeeded: value) &<< shift)
317
338
}
@@ -331,5 +352,6 @@ internal func _bytesToUInt64(
331
352
r = r | ( UInt64 ( input [ idx] ) &<< shift)
332
353
shift = shift &+ 8
333
354
}
334
- return r
355
+ // Convert from little-endian to host byte order.
356
+ return r. littleEndian
335
357
}
0 commit comments