here’s a weird bug:
var description:String
{
.init(unsafeUninitializedCapacity: self.rawValue.utf8.count)
{
for (i, codeunit):(Int, UInt8) in zip($0.indices, self.rawValue.utf8)
{
switch codeunit
{
case 0x09, 0x20: $0[i] = 0x2E // '.'
case let codeunit: $0[i] = codeunit
}
}
return $0.count
}
}
this produces an empty string if the rawValue has less than 16 UTF-8 bytes, because the buffer count ($0.count) is always at least 16.
the fix, as it turns out, is:
@inlinable public
var description:String
{
.init(unsafeUninitializedCapacity: self.rawValue.utf8.count)
{
var i:Int = $0.startIndex
for codeunit:UInt8 in self.rawValue.utf8
{
switch codeunit
{
case 0x09, 0x20: $0[i] = 0x2E // '.'
case let codeunit: $0[i] = codeunit
}
i = $0.index(after: i)
}
return i
}
}
why on earth does String.init(unsafeUninitializedCapacity:initializingUTF8With:) even pass a buffer with a count that doesn’t match the specified capacity?
1 Like
xwu
(Xiaodi Wu)
2
Small strings have in-line buffer storage with fixed capacity. I think the uninitialized buffer will always have at least the requested capacity, but it may well have more (as is the case for Array.reserveCapacity). I would code defensively: you have easy access to both the capacity requested and the capacity received here.
2 Likes
xwu
(Xiaodi Wu)
3
Incidentally, this is guaranteed to work but only because startIndex is guaranteed to be 0 and index(after:) increments by 1. The return value is supposed to be the count of initialized code units, so it’s a counting exercise semantically independent of the buffer’s indices.
1 Like
I reported this issue (circa Swift 5.5) as apple/swift#57911. The current implementation seems incorrect because _SmallString.capacity is only 10, 14, or 15 bytes.
UPDATE: This issue has been fixed (on the main branch only, for Swift 5.10+).
2 Likes