1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2023 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
#if swift(>=5.8)
@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *)
extension BigString {
mutating func _append(contentsOf other: __owned Substring) {
if other.isEmpty { return }
if isEmpty {
self = Self(other)
return
}
var ingester = _ingester(forInserting: other, at: endIndex, allowForwardPeek: true)
let last = _rope.index(before: _rope.endIndex)
if let final = _rope[last].append(from: &ingester) {
precondition(!final.isUndersized)
_rope.append(final)
return
}
// Make a temp rope out of the rest of the chunks and then join the two trees together.
if !ingester.isAtEnd {
var builder = _Rope.Builder()
while let chunk = ingester.nextWellSizedChunk() {
precondition(!chunk.isUndersized)
builder.insertBeforeTip(chunk)
}
precondition(ingester.isAtEnd)
_rope = _Rope.join(_rope, builder.finalize())
}
}
}
@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *)
extension BigString {
var _firstUnicodeScalar: Unicode.Scalar {
assert(!isEmpty)
return _rope.root.firstItem.value.string.unicodeScalars.first!
}
mutating func _append(contentsOf other: __owned BigString) {
guard !other.isEmpty else { return }
guard !self.isEmpty else {
self = other
return
}
let hint = other._firstUnicodeScalar
var other = other._rope
var old = _CharacterRecognizer()
var new = self._breakState(upTo: endIndex, nextScalarHint: hint)
_ = other.resyncBreaks(old: &old, new: &new)
_append(other)
}
mutating func _append(contentsOf other: __owned BigString, in range: Range<Index>) {
guard !range._isEmptyUTF8 else { return }
guard !self.isEmpty else {
self = Self(_from: other, in: range)
return
}
var other = BigString(_from: other, in: range)
let hint = other._firstUnicodeScalar
var old = _CharacterRecognizer()
var new = self._breakState(upTo: endIndex, nextScalarHint: hint)
_ = other._rope.resyncBreaks(old: &old, new: &new)
_append(other._rope)
}
mutating func prepend(contentsOf other: __owned BigString) {
guard !other.isEmpty else { return }
guard !self.isEmpty else {
self = other
return
}
let hint = self._firstUnicodeScalar
var old = _CharacterRecognizer()
var new = other._breakState(upTo: other.endIndex, nextScalarHint: hint)
_ = self._rope.resyncBreaks(old: &old, new: &new)
_prepend(other._rope)
}
mutating func prepend(contentsOf other: __owned BigString, in range: Range<Index>) {
guard !range._isEmptyUTF8 else { return }
let extract = Self(_from: other, in: range)
guard !self.isEmpty else {
self = extract
return
}
let hint = self._firstUnicodeScalar
var old = _CharacterRecognizer()
var new = extract._breakState(upTo: extract.endIndex, nextScalarHint: hint)
_ = self._rope.resyncBreaks(old: &old, new: &new)
_prepend(extract._rope)
}
}
@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *)
extension BigString {
var isUndersized: Bool {
_utf8Count < _Chunk.minUTF8Count
}
}
@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *)
extension BigString {
/// Note: This assumes `other` already has the correct break positions.
mutating func _append(_ other: __owned _Chunk) {
assert(!other.isEmpty)
guard !self.isEmpty else {
self._rope.append(other)
return
}
guard self.isUndersized || other.isUndersized else {
self._rope.append(other)
return
}
var other = other
let last = self._rope.index(before: self._rope.endIndex)
if !self._rope[last].rebalance(nextNeighbor: &other) {
assert(!other.isUndersized)
self._rope.append(other)
}
}
/// Note: This assumes `self` and `other` already have the correct break positions.
mutating func _prepend(_ other: __owned _Chunk) {
assert(!other.isEmpty)
guard !self.isEmpty else {
self._rope.prepend(other)
return
}
guard self.isUndersized || other.isUndersized else {
self._rope.prepend(other)
return
}
var other = other
let first = self._rope.startIndex
if !self._rope[first].rebalance(prevNeighbor: &other) {
self._rope.prepend(other)
}
}
/// Note: This assumes `other` already has the correct break positions.
mutating func _append(_ other: __owned _Rope) {
guard !other.isEmpty else { return }
guard !self._rope.isEmpty else {
self._rope = other
return
}
if other.isSingleton {
self._append(other.first!)
return
}
if self.isUndersized {
assert(self._rope.isSingleton)
let chunk = self._rope.first!
self._rope = other
self._prepend(chunk)
return
}
self._rope = _Rope.join(self._rope, other)
}
/// Note: This assumes `self` and `other` already have the correct break positions.
mutating func _prepend(_ other: __owned _Rope) {
guard !other.isEmpty else { return }
guard !self.isEmpty else {
self._rope = other
return
}
if other.isSingleton {
self._prepend(other.first!)
return
}
if self.isUndersized {
assert(self._rope.isSingleton)
let chunk = self._rope.first!
self._rope = other
self._append(chunk)
return
}
self._rope = _Rope.join(other, self._rope)
}
}
#endif
|