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
@@ -300,23 +317,27 @@ extension _SmallString {
300
317
#endif
301
318
302
319
extension UInt64 {
303
- // Fetches the `i`th byte, from least-significant to most-significant
304
- //
305
- // TODO: endianess awareness day
320
+ // Fetches the `i`th byte, from left to right.
306
321
@inlinable @inline ( __always)
307
322
internal func _uncheckedGetByte( at i: Int ) -> UInt8 {
308
323
_internalInvariant ( i >= 0 && i < MemoryLayout< UInt64> . stride)
324
+ #if _endian(big)
325
+ let shift = ( 7 - UInt64( truncatingIfNeeded: i) ) &* 8
326
+ #else
309
327
let shift = UInt64 ( truncatingIfNeeded: i) &* 8
328
+ #endif
310
329
return UInt8 ( truncatingIfNeeded: ( self &>> shift) )
311
330
}
312
331
313
- // Sets the `i`th byte, from least-significant to most-significant
314
- //
315
- // TODO: endianess awareness day
332
+ // Sets the `i`th byte, from left to right.
316
333
@inlinable @inline ( __always)
317
334
internal mutating func _uncheckedSetByte( at i: Int , to value: UInt8 ) {
318
335
_internalInvariant ( i >= 0 && i < MemoryLayout< UInt64> . stride)
336
+ #if _endian(big)
337
+ let shift = ( 7 - UInt64( truncatingIfNeeded: i) ) &* 8
338
+ #else
319
339
let shift = UInt64 ( truncatingIfNeeded: i) &* 8
340
+ #endif
320
341
let valueMask : UInt64 = 0xFF &<< shift
321
342
self = ( self & ~ valueMask) | ( UInt64 ( truncatingIfNeeded: value) &<< shift)
322
343
}
@@ -336,5 +357,6 @@ internal func _bytesToUInt64(
336
357
r = r | ( UInt64 ( input [ idx] ) &<< shift)
337
358
shift = shift &+ 8
338
359
}
339
- return r
360
+ // Convert from little-endian to host byte order.
361
+ return r. littleEndian
340
362
}
0 commit comments