@@ -42,11 +42,8 @@ extension _BTree {
4242 /// This property is what takes ownership of the tree during the lifetime of the cursor. Once the cursor
4343 /// is consumed, it is set to nil and it is invalid to use the cursor.
4444 @usableFromInline
45- internal var __root : Node . Storage ?
45+ internal var _root : Node . Storage ?
4646
47- @inlinable
48- @inline ( __always)
49- internal var root : Node . Storage { __root. unsafelyUnwrapped }
5047
5148 /// Position of each of the parent nodes in their parents, including the bottom-most node.
5249 ///
@@ -68,17 +65,6 @@ extension _BTree {
6865 internal var path : Path
6966
7067 /// 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 ] ) }
8268
8369 /// The depth at which the last instance of sequential unique nodes starting at the root was found.
8470 ///
@@ -106,60 +92,63 @@ extension _BTree {
10692 root: Node . Storage ,
10793 slots: FixedSizeArray < _BTree . Slot > ,
10894 path: Path ,
109- lastUniqueDepth: Int ,
110- // Debug-only properties
111- isConcrete: Bool
95+ lastUniqueDepth: Int
11296 ) {
11397 // Slots and path should be non-empty
11498 assert ( slots. depth >= 1 , " Invalid tree cursor. " )
11599 assert ( path. depth >= 1 , " Invalid tree cursor. " )
116100
117- self . __root = root
101+ self . _root = root
118102 self . slots = slots
119103 self . path = path
120104 self . lastUniqueDepth = lastUniqueDepth
121-
122- #if COLLECTIONS_INTERNAL_CHECKS
123- self . isConcrete = isConcrete
124- #endif
125105 }
126106
127107 // 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+ ///
134110 /// Every member that operates on the element of the cursor must start by calling this function.
135111 ///
136112 /// Note that this is a noop in release builds.
137113 @inlinable
138114 @inline ( __always)
139- internal func assertConcrete ( ) {
115+ internal func assertValid ( ) {
140116 #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. " )
143119 #endif
144120 }
145121
146- // MARK: Basic Cursor Operations
122+ // MARK: Core Cursor Operations
147123 /// Finishes operating on a cursor and restores a tree
148124 @inlinable
149125 @inline ( __always)
150126 internal mutating func apply( to tree: inout _BTree ) {
127+ assertValid ( )
151128 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)
153137 }
154138
155139 /// Operators on a handle of the node
156140 /// - Warning: Ensure this is never called on an endIndex.
157141 @inlinable
158142 @inline ( __always)
159143 internal func readCurrentNode< R> (
160- _ body: ( Node . UnsafeHandle ) throws -> R
144+ _ body: ( Node . UnsafeHandle , Int ) throws -> R
161145 ) 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+ }
163152 }
164153
165154 /// Updates the node at a given depth.
@@ -170,19 +159,26 @@ extension _BTree {
170159 at depth: Int8 ,
171160 _ body: ( Node . UnsafeHandle , Int ) throws -> R
172161 ) rethrows -> ( node: Node , result: R ) {
173- var node = Node ( path [ depth] . takeUnretainedValue ( ) )
162+ assertValid ( )
163+
174164 let slot = Int ( slots [ depth] )
175165 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+ }
178177 }
179- path [ depth] = . passUnretained( node. storage)
180- return ( node, result)
181178 }
182179
183180
184- // MARK: Mutating with the Cursor
185-
181+ // MARK: Mutations with the Cursor
186182 /// Operates on a handle of the node.
187183 ///
188184 /// This MUST be followed by an operation which consumes the cursor and returns the new tree, as
@@ -197,7 +193,8 @@ extension _BTree {
197193 internal mutating func updateCurrentNode< R> (
198194 _ body: ( Node . UnsafeHandle , Int ) throws -> R
199195 ) rethrows -> R {
200- defer { self . lastUniqueDepth = . max }
196+ assertValid ( )
197+ defer { self . _declareUnique ( ) }
201198
202199 // Update the bottom-most node
203200 var ( node, result) = try self . updateNode ( at: path. depth - 1 , body)
@@ -224,6 +221,8 @@ extension _BTree {
224221 _ = handle. exchangeChild ( atSlot: slot, with: child)
225222 }
226223 }
224+
225+ return result
227226 } else {
228227 // depth < lastUniqueDepth
229228
@@ -235,7 +234,7 @@ extension _BTree {
235234 depth -= 1
236235 }
237236
238- self . __root = node. storage
237+ self . _root = node. storage
239238 return result
240239 }
241240
@@ -254,7 +253,8 @@ extension _BTree {
254253 _ element: Node . Element ,
255254 capacity: Int
256255 ) {
257- defer { self . lastUniqueDepth = . max }
256+ assertValid ( )
257+ defer { self . _declareUnique ( ) }
258258
259259 // TODO: make this not invalidate the cursor by updating slots
260260
@@ -283,9 +283,9 @@ extension _BTree {
283283
284284 if let splinter = splinter {
285285 let newRoot = splinter. toNode ( leftChild: node, capacity: capacity)
286- self . __root = newRoot. storage
286+ self . _root = newRoot. storage
287287 } else {
288- self . __root = node. storage
288+ self . _root = node. storage
289289 }
290290 }
291291
@@ -295,7 +295,8 @@ extension _BTree {
295295 /// - Complexity: O(`log n`). Ascends the tree once.
296296 @inlinable
297297 internal mutating func removeElement( hasValueHole: Bool = false ) {
298- defer { self . lastUniqueDepth = . max }
298+ assertValid ( )
299+ defer { self . _declareUnique ( ) }
299300
300301 var ( node, _) = self . updateNode (
301302 at: path. depth - 1
@@ -337,6 +338,7 @@ extension _BTree {
337338 while depth >= 0 {
338339 var ( newNode, _) = self . updateNode ( at: depth) { ( handle, slot) in
339340 handle. exchangeChild ( atSlot: slot, with: node)
341+ handle. subtreeCount -= 1
340342 handle. balance ( atSlot: slot)
341343 }
342344
@@ -349,7 +351,7 @@ extension _BTree {
349351 depth -= 1
350352 }
351353
352- self . __root = node. storage
354+ self . _root = node. storage
353355 }
354356 }
355357
@@ -375,7 +377,6 @@ extension _BTree {
375377 var parents =
376378 UnsafeCursor . Path ( repeating: . passUnretained( self . root. storage) )
377379
378- // TODO: swap
379380 var ownedRoot : Node . Storage
380381 do {
381382 var tempRoot : Node . Storage ? = nil
@@ -423,7 +424,7 @@ extension _BTree {
423424 if shouldStop { break }
424425 }
425426
426- assert ( slot != - 1 && lastUniqueDepth != - 1 , " B-Tree sanity check fail. " )
427+ assert ( slot != - 1 , " B-Tree sanity check fail. " )
427428
428429 parents. append ( node)
429430 slots. append ( UInt16 ( slot) )
@@ -432,8 +433,7 @@ extension _BTree {
432433 root: ownedRoot,
433434 slots: slots,
434435 path: parents,
435- lastUniqueDepth: lastUniqueDepth,
436- isConcrete: found
436+ lastUniqueDepth: lastUniqueDepth
437437 )
438438
439439 return ( cursor, found)
0 commit comments