Skip to content

Commit bcfa805

Browse files
authored
Zero trailing bytes of SmallStrings more efficiently (#59823)
1 parent f4c26c3 commit bcfa805

File tree

2 files changed

+42
-12
lines changed

2 files changed

+42
-12
lines changed

stdlib/public/core/SmallString.swift

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -241,22 +241,29 @@ extension _SmallString {
241241
fileprivate mutating func withMutableCapacity(
242242
_ f: (UnsafeMutableRawBufferPointer) throws -> Int
243243
) rethrows {
244-
let len = try withUnsafeMutableBytes(of: &self._storage) {
245-
(rawBufPtr: UnsafeMutableRawBufferPointer) -> Int in
246-
let len = try f(rawBufPtr)
247-
UnsafeMutableRawBufferPointer(
248-
rebasing: rawBufPtr[len...]
249-
).initializeMemory(as: UInt8.self, repeating: 0)
250-
return len
251-
}
252-
if len == 0 {
244+
let len = try withUnsafeMutableBytes(of: &_storage, f)
245+
246+
if len <= 0 {
247+
_debugPrecondition(len == 0)
253248
self = _SmallString()
254249
return
255250
}
256-
_internalInvariant(len <= _SmallString.capacity)
251+
_SmallString.zeroTrailingBytes(of: &_storage, from: len)
252+
self = _SmallString(leading: _storage.0, trailing: _storage.1, count: len)
253+
}
257254

258-
let (leading, trailing) = self.zeroTerminatedRawCodeUnits
259-
self = _SmallString(leading: leading, trailing: trailing, count: len)
255+
@inlinable
256+
@_alwaysEmitIntoClient
257+
internal static func zeroTrailingBytes(
258+
of storage: inout RawBitPattern, from index: Int
259+
) {
260+
_internalInvariant(index > 0)
261+
_internalInvariant(index <= _SmallString.capacity)
262+
//FIXME: Verify this on big-endian architecture
263+
let mask0 = (UInt64(bitPattern: ~0) &>> (8 &* ( 8 &- Swift.min(index, 8))))
264+
let mask1 = (UInt64(bitPattern: ~0) &>> (8 &* (16 &- Swift.max(index, 8))))
265+
storage.0 &= (index <= 0) ? 0 : mask0.littleEndian
266+
storage.1 &= (index <= 8) ? 0 : mask1.littleEndian
260267
}
261268
}
262269

validation-test/stdlib/String.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,4 +2347,27 @@ if #available(SwiftStdlib 5.6, *) {
23472347
}
23482348
}
23492349

2350+
StringTests.test("SmallString.zeroTrailingBytes") {
2351+
if #available(SwiftStdlib 5.8, *) {
2352+
let full: _SmallString.RawBitPattern = (.max, .max)
2353+
withUnsafeBytes(of: full) {
2354+
expectTrue($0.allSatisfy({ $0 == 0xff }))
2355+
}
2356+
2357+
let testIndices = [1, 7, 8, _SmallString.capacity]
2358+
for i in testIndices {
2359+
// The internal invariants in `_zeroTrailingBytes(of:from:)`
2360+
expectTrue(0 < i && i <= _SmallString.capacity)
2361+
print(i)
2362+
var bits = full
2363+
_SmallString.zeroTrailingBytes(of: &bits, from: i)
2364+
withUnsafeBytes(of: bits) {
2365+
expectTrue($0[..<i].allSatisfy({ $0 == 0xff }))
2366+
expectTrue($0[i...].allSatisfy({ $0 == 0 }))
2367+
}
2368+
bits = (0, 0)
2369+
}
2370+
}
2371+
}
2372+
23502373
runAllTests()

0 commit comments

Comments
 (0)