@@ -42,11 +42,8 @@ extension _BTree {
42
42
/// This property is what takes ownership of the tree during the lifetime of the cursor. Once the cursor
43
43
/// is consumed, it is set to nil and it is invalid to use the cursor.
44
44
@usableFromInline
45
- internal var __root : Node . Storage ?
45
+ internal var _root : Node . Storage ?
46
46
47
- @inlinable
48
- @inline ( __always)
49
- internal var root : Node . Storage { __root. unsafelyUnwrapped }
50
47
51
48
/// Position of each of the parent nodes in their parents, including the bottom-most node.
52
49
///
@@ -68,17 +65,6 @@ extension _BTree {
68
65
internal var path : Path
69
66
70
67
/// Bottom most node that the index point to.
71
- // TODO: look at implementing _modify accessor.
72
- @usableFromInline
73
- internal var currentNode : Unmanaged < Node . Storage > {
74
- get { path [ path. depth - 1 ] }
75
- set { path [ path. depth - 1 ] = newValue }
76
- }
77
-
78
- /// Slot within the bottom most node which the index points to.
79
- @inlinable
80
- @inline ( __always)
81
- internal var slot : Int { Int ( slots [ slots. depth - 1 ] ) }
82
68
83
69
/// The depth at which the last instance of sequential unique nodes starting at the root was found.
84
70
///
@@ -106,60 +92,63 @@ extension _BTree {
106
92
root: Node . Storage ,
107
93
slots: FixedSizeArray < _BTree . Slot > ,
108
94
path: Path ,
109
- lastUniqueDepth: Int ,
110
- // Debug-only properties
111
- isConcrete: Bool
95
+ lastUniqueDepth: Int
112
96
) {
113
97
// Slots and path should be non-empty
114
98
assert ( slots. depth >= 1 , " Invalid tree cursor. " )
115
99
assert ( path. depth >= 1 , " Invalid tree cursor. " )
116
100
117
- self . __root = root
101
+ self . _root = root
118
102
self . slots = slots
119
103
self . path = path
120
104
self . lastUniqueDepth = lastUniqueDepth
121
-
122
- #if COLLECTIONS_INTERNAL_CHECKS
123
- self . isConcrete = isConcrete
124
- #endif
125
105
}
126
106
127
107
// MARK: Internal Checks
128
- #if COLLECTIONS_INTERNAL_CHECKS
129
- /// A concrete cursor is one that refers to a specific element, not just a generic position.
130
- @usableFromInline internal let isConcrete : Bool
131
- #endif
132
-
133
- /// Check that this cursor is concrete
108
+ /// Check that this cursor is still valid
109
+ ///
134
110
/// Every member that operates on the element of the cursor must start by calling this function.
135
111
///
136
112
/// Note that this is a noop in release builds.
137
113
@inlinable
138
114
@inline ( __always)
139
- internal func assertConcrete ( ) {
115
+ internal func assertValid ( ) {
140
116
#if COLLECTIONS_INTERNAL_CHECKS
141
- assert ( self . isConcrete ,
142
- " Attempt to operate on an element using a non-concrete cursor. " )
117
+ assert ( self . _root != nil ,
118
+ " Attempt to operate on an element using an invalid cursor. " )
143
119
#endif
144
120
}
145
121
146
- // MARK: Basic Cursor Operations
122
+ // MARK: Core Cursor Operations
147
123
/// Finishes operating on a cursor and restores a tree
148
124
@inlinable
149
125
@inline ( __always)
150
126
internal mutating func apply( to tree: inout _BTree ) {
127
+ assertValid ( )
151
128
assert ( tree. root. _storage == nil , " Must apply to same tree as original. " )
152
- swap ( & tree. root. _storage, & self . __root)
129
+ swap ( & tree. root. _storage, & self . _root)
130
+ }
131
+
132
+ /// Declares that the cursor is completely unique
133
+ @inlinable
134
+ @inline ( __always)
135
+ internal mutating func _declareUnique( ) {
136
+ self . lastUniqueDepth = Int ( path. depth)
153
137
}
154
138
155
139
/// Operators on a handle of the node
156
140
/// - Warning: Ensure this is never called on an endIndex.
157
141
@inlinable
158
142
@inline ( __always)
159
143
internal func readCurrentNode< R> (
160
- _ body: ( Node . UnsafeHandle ) throws -> R
144
+ _ body: ( Node . UnsafeHandle , Int ) throws -> R
161
145
) rethrows -> R {
162
- return try currentNode. _withUnsafeGuaranteedRef { try $0. read ( body) }
146
+ assertValid ( )
147
+
148
+ let slot = Int ( slots [ slots. depth - 1 ] )
149
+ return try path [ path. depth - 1 ] . _withUnsafeGuaranteedRef {
150
+ try $0. read ( { try body ( $0, slot) } )
151
+ }
163
152
}
164
153
165
154
/// Updates the node at a given depth.
@@ -170,19 +159,26 @@ extension _BTree {
170
159
at depth: Int8 ,
171
160
_ body: ( Node . UnsafeHandle , Int ) throws -> R
172
161
) rethrows -> ( node: Node , result: R ) {
173
- var node = Node ( path [ depth] . takeUnretainedValue ( ) )
162
+ assertValid ( )
163
+
174
164
let slot = Int ( slots [ depth] )
175
165
let isOnUniquePath = depth <= lastUniqueDepth
176
- let result = try node. update ( isUnique: isOnUniquePath) {
177
- try body ( $0, slot)
166
+
167
+ return try path [ depth] . _withUnsafeGuaranteedRef { storage in
168
+ if isOnUniquePath {
169
+ let result = try storage. updateGuaranteedUnique ( { try body ( $0, slot) } )
170
+ return ( Node ( storage) , result)
171
+ } else {
172
+ let storage = storage. copy ( )
173
+ path [ depth] = . passUnretained( storage)
174
+ let result = try storage. updateGuaranteedUnique ( { try body ( $0, slot) } )
175
+ return ( Node ( storage) , result)
176
+ }
178
177
}
179
- path [ depth] = . passUnretained( node. storage)
180
- return ( node, result)
181
178
}
182
179
183
180
184
- // MARK: Mutating with the Cursor
185
-
181
+ // MARK: Mutations with the Cursor
186
182
/// Operates on a handle of the node.
187
183
///
188
184
/// This MUST be followed by an operation which consumes the cursor and returns the new tree, as
@@ -197,7 +193,8 @@ extension _BTree {
197
193
internal mutating func updateCurrentNode< R> (
198
194
_ body: ( Node . UnsafeHandle , Int ) throws -> R
199
195
) rethrows -> R {
200
- defer { self . lastUniqueDepth = . max }
196
+ assertValid ( )
197
+ defer { self . _declareUnique ( ) }
201
198
202
199
// Update the bottom-most node
203
200
var ( node, result) = try self . updateNode ( at: path. depth - 1 , body)
@@ -224,6 +221,8 @@ extension _BTree {
224
221
_ = handle. exchangeChild ( atSlot: slot, with: child)
225
222
}
226
223
}
224
+
225
+ return result
227
226
} else {
228
227
// depth < lastUniqueDepth
229
228
@@ -235,7 +234,7 @@ extension _BTree {
235
234
depth -= 1
236
235
}
237
236
238
- self . __root = node. storage
237
+ self . _root = node. storage
239
238
return result
240
239
}
241
240
@@ -254,7 +253,8 @@ extension _BTree {
254
253
_ element: Node . Element ,
255
254
capacity: Int
256
255
) {
257
- defer { self . lastUniqueDepth = . max }
256
+ assertValid ( )
257
+ defer { self . _declareUnique ( ) }
258
258
259
259
// TODO: make this not invalidate the cursor by updating slots
260
260
@@ -283,9 +283,9 @@ extension _BTree {
283
283
284
284
if let splinter = splinter {
285
285
let newRoot = splinter. toNode ( leftChild: node, capacity: capacity)
286
- self . __root = newRoot. storage
286
+ self . _root = newRoot. storage
287
287
} else {
288
- self . __root = node. storage
288
+ self . _root = node. storage
289
289
}
290
290
}
291
291
@@ -295,7 +295,8 @@ extension _BTree {
295
295
/// - Complexity: O(`log n`). Ascends the tree once.
296
296
@inlinable
297
297
internal mutating func removeElement( hasValueHole: Bool = false ) {
298
- defer { self . lastUniqueDepth = . max }
298
+ assertValid ( )
299
+ defer { self . _declareUnique ( ) }
299
300
300
301
var ( node, _) = self . updateNode (
301
302
at: path. depth - 1
@@ -337,6 +338,7 @@ extension _BTree {
337
338
while depth >= 0 {
338
339
var ( newNode, _) = self . updateNode ( at: depth) { ( handle, slot) in
339
340
handle. exchangeChild ( atSlot: slot, with: node)
341
+ handle. subtreeCount -= 1
340
342
handle. balance ( atSlot: slot)
341
343
}
342
344
@@ -349,7 +351,7 @@ extension _BTree {
349
351
depth -= 1
350
352
}
351
353
352
- self . __root = node. storage
354
+ self . _root = node. storage
353
355
}
354
356
}
355
357
@@ -375,7 +377,6 @@ extension _BTree {
375
377
var parents =
376
378
UnsafeCursor . Path ( repeating: . passUnretained( self . root. storage) )
377
379
378
- // TODO: swap
379
380
var ownedRoot : Node . Storage
380
381
do {
381
382
var tempRoot : Node . Storage ? = nil
@@ -423,7 +424,7 @@ extension _BTree {
423
424
if shouldStop { break }
424
425
}
425
426
426
- assert ( slot != - 1 && lastUniqueDepth != - 1 , " B-Tree sanity check fail. " )
427
+ assert ( slot != - 1 , " B-Tree sanity check fail. " )
427
428
428
429
parents. append ( node)
429
430
slots. append ( UInt16 ( slot) )
@@ -432,8 +433,7 @@ extension _BTree {
432
433
root: ownedRoot,
433
434
slots: slots,
434
435
path: parents,
435
- lastUniqueDepth: lastUniqueDepth,
436
- isConcrete: found
436
+ lastUniqueDepth: lastUniqueDepth
437
437
)
438
438
439
439
return ( cursor, found)
0 commit comments