struct StringBuilderIncrementally constructs one valid UTF-8 string in a unique growable buffer.
byte_count <= capacity; the initialized prefix is valid UTF-8 after every public append. Growth doubles capacity, so repeated appends are amortized linear in the total bytes. finish transfers the allocation without copying.
Methods
mut func reserve_capacity(_ capacity: Int) -> Void
Ensures room for at least the requested number of bytes.
View Source
pub mut func reserve_capacity(_ capacity: Int) -> Void {
if capacity <= self.capacity { return () }
let fresh: ByteStorage = _byte_storage(capacity: capacity)
_copy(from: self.storage.base, to: fresh.base, length: self.byte_count)
self.storage = fresh
self.capacity = capacity
}mut func append(string value: String) -> Void
Appends every UTF-8 byte in value.
View Source
pub mut func append(string value: String) -> Void {
self.append_view(value.as_substring())
}mut func append(substring value: Substring) -> Void
Appends the borrowed byte range in value.
View Source
pub mut func append(substring value: Substring) -> Void {
self.append_view(value)
}mut func append(character value: Character) -> Void
Appends the complete grapheme cluster represented by value.
View Source
pub mut func append(character value: Character) -> Void {
self.append_view(value.as_substring())
}mut func append_scalar(_ scalar: Int) -> Void
Encodes one Unicode scalar and appends its UTF-8 bytes.
Values outside the scalar range, including surrogate code points, are replaced with U+FFFD. This keeps the builder's valid-UTF-8 invariant even when low-level Unicode algorithms supply an invalid integer.
View Source
pub mut func append_scalar(_ scalar: Int) -> Void {
let valid: Int = if scalar < 0 || scalar > 1114111 || (scalar >= 55296 && scalar <= 57343) {
65533
} else {
scalar
}
let bytes: Int = if valid < 128 {
1
} else {
if valid < 2048 {
2
} else {
if valid < 65536 {
3
} else {
4
}
}
}
self.ensure_capacity(self.byte_count + bytes)
if bytes == 1 {
self.storage.set(index: self.byte_count, value: valid._toByte())
} else {
if bytes == 2 {
self.storage.set(index: self.byte_count, value: (192 + valid / 64)._toByte())
self.storage.set(
index: self.byte_count + 1,
value: (128 + valid - (valid / 64) * 64)._toByte()
)
} else {
if bytes == 3 {
self.storage.set(index: self.byte_count, value: (224 + valid / 4096)._toByte())
self.storage.set(
index: self.byte_count + 1,
value: (128 + (valid / 64) - (valid / 4096) * 64)._toByte()
)
self.storage.set(
index: self.byte_count + 2,
value: (128 + valid - (valid / 64) * 64)._toByte()
)
} else {
self.storage.set(
index: self.byte_count,
value: (240 + valid / 262144)._toByte()
)
self.storage.set(
index: self.byte_count + 1,
value: (128 + (valid / 4096) - (valid / 262144) * 64)._toByte()
)
self.storage.set(
index: self.byte_count + 2,
value: (128 + (valid / 64) - (valid / 4096) * 64)._toByte()
)
self.storage.set(
index: self.byte_count + 3,
value: (128 + valid - (valid / 64) * 64)._toByte()
)
}
}
}
self.byte_count = self.byte_count + bytes
}mut func append_line(_ string: String) -> Void
Appends string followed by a newline byte.
View Source
pub mut func append_line(_ string: String) -> Void {
self.append_view(string.as_substring())
self.append_view("\n".as_substring())
}mut func clear() -> Void
Removes the accumulated contents while retaining allocated capacity.
View Source
pub mut func clear() -> Void {
self.byte_count = 0
}func utf8_count() -> Int
Returns the number of UTF-8 bytes.
View Source
pub func utf8_count() -> Int {
self.byte_count
}consuming func finish() -> String
Transfers the initialized buffer into an immutable String without copying.
The consumed builder is cleared before return so its destructor cannot release the allocation now owned by the string.
View Source
pub consuming func finish() -> String {
let storage = self.storage
let byte_count = self.byte_count
let capacity = self.capacity
self.storage = _byte_storage(capacity: 0)
self.byte_count = 0
self.capacity = 0
String(base: storage, byte_count: byte_count, capacity: capacity)
}