@@ -255,6 +255,10 @@ struct common_params {
255
255
static void move (Alloc *alloc, slot_type *src, slot_type *dest) {
256
256
slot_policy::move (alloc, src, dest);
257
257
}
258
+ static void move (Alloc *alloc, slot_type *first, slot_type *last,
259
+ slot_type *result) {
260
+ slot_policy::move (alloc, first, last, result);
261
+ }
258
262
};
259
263
260
264
// A parameters structure for holding the type parameters for a btree_map.
@@ -332,6 +336,13 @@ struct set_slot_policy {
332
336
static void move (Alloc * /* alloc*/ , slot_type *src, slot_type *dest) {
333
337
*dest = std::move (*src);
334
338
}
339
+
340
+ template <typename Alloc>
341
+ static void move (Alloc *alloc, slot_type *first, slot_type *last,
342
+ slot_type *result) {
343
+ for (slot_type *src = first, *dest = result; src != last; ++src, ++dest)
344
+ move (alloc, src, dest);
345
+ }
335
346
};
336
347
337
348
// A parameters structure for holding the type parameters for a btree_set.
@@ -748,10 +759,14 @@ class btree_node {
748
759
template <typename ... Args>
749
760
void emplace_value (size_type i, allocator_type *alloc, Args &&... args);
750
761
751
- // Removes the values at positions [i, i + to_erase), shifting all existing
752
- // values and children after that range to the left by to_erase. Clears all
753
- // children between [i, i + to_erase).
754
- void remove_values (field_type i, field_type to_erase, allocator_type *alloc);
762
+ // Removes the value at position i, shifting all existing values and children
763
+ // at positions > i to the left by 1.
764
+ void remove_value (int i, allocator_type *alloc);
765
+
766
+ // Removes the values at positions [i, i + to_erase), shifting all values
767
+ // after that range to the left by to_erase. Does not change children at all.
768
+ void remove_values_ignore_children (int i, int to_erase,
769
+ allocator_type *alloc);
755
770
756
771
// Rebalances a node with its right sibling.
757
772
void rebalance_right_to_left (int to_move, btree_node *right,
@@ -763,7 +778,7 @@ class btree_node {
763
778
void split (int insert_position, btree_node *dest, allocator_type *alloc);
764
779
765
780
// Merges a node with its right sibling, moving all of the values and the
766
- // delimiting key in the parent node onto itself, and deleting the src node .
781
+ // delimiting key in the parent node onto itself.
767
782
void merge (btree_node *src, allocator_type *alloc);
768
783
769
784
// Node allocation/deletion routines.
@@ -784,27 +799,9 @@ class btree_node {
784
799
absl::container_internal::SanitizerPoisonMemoryRegion (
785
800
&mutable_child (start ()), (kNodeValues + 1 ) * sizeof (btree_node *));
786
801
}
787
-
788
- // Deletes a node and all of its children.
789
- // TODO(ezb): don't use recursion here to avoid potential stack overflows.
790
- static void clear_and_delete (btree_node *node, allocator_type *alloc) {
791
- const field_type start = node->start ();
792
- const field_type finish = node->finish ();
793
- for (field_type i = start; i < finish; ++i) {
794
- node->value_destroy (i, alloc);
795
- }
796
- if (node->leaf ()) {
797
- absl::container_internal::Deallocate<Alignment ()>(
798
- alloc, node, LeafSize (node->max_count ()));
799
- } else {
800
- // If the node is empty, then there are no children so don't try clearing.
801
- if (start < finish) {
802
- for (field_type i = start; i <= finish; ++i) {
803
- clear_and_delete (node->child (i), alloc);
804
- }
805
- }
806
- absl::container_internal::Deallocate<Alignment ()>(alloc, node,
807
- InternalSize ());
802
+ void destroy (allocator_type *alloc) {
803
+ for (int i = start (); i < finish (); ++i) {
804
+ value_destroy (i, alloc);
808
805
}
809
806
}
810
807
@@ -1426,8 +1423,25 @@ class btree {
1426
1423
}
1427
1424
1428
1425
// Deletion helper routines.
1426
+ void erase_same_node (iterator begin, iterator end);
1427
+ iterator erase_from_leaf_node (iterator begin, size_type to_erase);
1429
1428
iterator rebalance_after_delete (iterator iter);
1430
1429
1430
+ // Deallocates a node of a certain size in bytes using the allocator.
1431
+ void deallocate (const size_type size, node_type *node) {
1432
+ absl::container_internal::Deallocate<node_type::Alignment ()>(
1433
+ mutable_allocator (), node, size);
1434
+ }
1435
+
1436
+ void delete_internal_node (node_type *node) {
1437
+ node->destroy (mutable_allocator ());
1438
+ deallocate (node_type::InternalSize (), node);
1439
+ }
1440
+ void delete_leaf_node (node_type *node) {
1441
+ node->destroy (mutable_allocator ());
1442
+ deallocate (node_type::LeafSize (node->max_count ()), node);
1443
+ }
1444
+
1431
1445
// Rebalances or splits the node iter points to.
1432
1446
void rebalance_or_split (iterator *iter);
1433
1447
@@ -1496,6 +1510,9 @@ class btree {
1496
1510
template <typename K>
1497
1511
iterator internal_find (const K &key) const ;
1498
1512
1513
+ // Deletes a node and all of its children.
1514
+ void internal_clear (node_type *node);
1515
+
1499
1516
// Verifies the tree structure of node.
1500
1517
int internal_verify (const node_type *node, const key_type *lo,
1501
1518
const key_type *hi) const ;
@@ -1563,29 +1580,26 @@ inline void btree_node<P>::emplace_value(const size_type i,
1563
1580
}
1564
1581
1565
1582
template <typename P>
1566
- inline void btree_node<P>::remove_values(const field_type i,
1567
- const field_type to_erase,
1568
- allocator_type *alloc) {
1569
- // Transfer values after the removed range into their new places.
1570
- const field_type orig_finish = finish ();
1571
- const field_type src_i = i + to_erase;
1572
- for (field_type j = i; j < src_i; ++j) {
1573
- value_destroy (j, alloc);
1583
+ inline void btree_node<P>::remove_value(const int i, allocator_type *alloc) {
1584
+ if (!leaf () && finish () > i + 1 ) {
1585
+ assert (child (i + 1 )->count () == 0 );
1586
+ for (size_type j = i + 1 ; j < finish (); ++j) {
1587
+ set_child (j, child (j + 1 ));
1588
+ }
1589
+ clear_child (finish ());
1574
1590
}
1575
- transfer_n (orig_finish - src_i, i, src_i, this , alloc);
1576
1591
1577
- if (!leaf ()) {
1578
- // Delete all children between begin and end.
1579
- for (field_type j = 0 ; j < to_erase; ++j) {
1580
- clear_and_delete (child (i + j + 1 ), alloc);
1581
- }
1582
- // Rotate children after end into new positions.
1583
- for (field_type j = i + to_erase + 1 ; j <= orig_finish; ++j) {
1584
- set_child (j - to_erase, child (j));
1585
- clear_child (j);
1586
- }
1592
+ remove_values_ignore_children (i, /* to_erase=*/ 1 , alloc);
1593
+ }
1594
+
1595
+ template <typename P>
1596
+ inline void btree_node<P>::remove_values_ignore_children(
1597
+ const int i, const int to_erase, allocator_type *alloc) {
1598
+ params_type::move (alloc, slot (i + to_erase), finish_slot (), slot (i));
1599
+ for (int j = finish () - to_erase; j < finish (); ++j) {
1600
+ value_destroy (j, alloc);
1587
1601
}
1588
- set_finish (orig_finish - to_erase);
1602
+ set_finish (finish () - to_erase);
1589
1603
}
1590
1604
1591
1605
template <typename P>
@@ -1737,8 +1751,8 @@ void btree_node<P>::merge(btree_node *src, allocator_type *alloc) {
1737
1751
set_finish (start () + 1 + count () + src->count ());
1738
1752
src->set_finish (src->start ());
1739
1753
1740
- // Remove the value on the parent node and delete the src node .
1741
- parent ()->remove_values (position (), /* to_erase= */ 1 , alloc);
1754
+ // Remove the value on the parent node.
1755
+ parent ()->remove_value (position (), alloc);
1742
1756
}
1743
1757
1744
1758
// //
@@ -2020,7 +2034,7 @@ auto btree<P>::erase(iterator iter) -> iterator {
2020
2034
bool internal_delete = false ;
2021
2035
if (!iter.node ->leaf ()) {
2022
2036
// Deletion of a value on an internal node. First, move the largest value
2023
- // from our left child here, then delete that position (in remove_values ()
2037
+ // from our left child here, then delete that position (in remove_value ()
2024
2038
// below). We can get to the largest value from our left child by
2025
2039
// decrementing iter.
2026
2040
iterator internal_iter (iter);
@@ -2032,7 +2046,7 @@ auto btree<P>::erase(iterator iter) -> iterator {
2032
2046
}
2033
2047
2034
2048
// Delete the key from the leaf.
2035
- iter.node ->remove_values (iter.position , /* to_erase= */ 1 , mutable_allocator ());
2049
+ iter.node ->remove_value (iter.position , mutable_allocator ());
2036
2050
--size_;
2037
2051
2038
2052
// We want to return the next value after the one we just erased. If we
@@ -2107,9 +2121,7 @@ auto btree<P>::erase_range(iterator begin, iterator end)
2107
2121
}
2108
2122
2109
2123
if (begin.node == end.node ) {
2110
- assert (end.position > begin.position );
2111
- begin.node ->remove_values (begin.position , end.position - begin.position ,
2112
- mutable_allocator ());
2124
+ erase_same_node (begin, end);
2113
2125
size_ -= count;
2114
2126
return {count, rebalance_after_delete (begin)};
2115
2127
}
@@ -2119,18 +2131,60 @@ auto btree<P>::erase_range(iterator begin, iterator end)
2119
2131
if (begin.node ->leaf ()) {
2120
2132
const size_type remaining_to_erase = size_ - target_size;
2121
2133
const size_type remaining_in_node = begin.node ->finish () - begin.position ;
2122
- const size_type to_erase =
2123
- (std::min)(remaining_to_erase, remaining_in_node);
2124
- begin.node ->remove_values (begin.position , to_erase, mutable_allocator ());
2125
- size_ -= to_erase;
2126
- begin = rebalance_after_delete (begin);
2134
+ begin = erase_from_leaf_node (
2135
+ begin, (std::min)(remaining_to_erase, remaining_in_node));
2127
2136
} else {
2128
2137
begin = erase (begin);
2129
2138
}
2130
2139
}
2131
2140
return {count, begin};
2132
2141
}
2133
2142
2143
+ template <typename P>
2144
+ void btree<P>::erase_same_node(iterator begin, iterator end) {
2145
+ assert (begin.node == end.node );
2146
+ assert (end.position > begin.position );
2147
+
2148
+ node_type *node = begin.node ;
2149
+ size_type to_erase = end.position - begin.position ;
2150
+ if (!node->leaf ()) {
2151
+ // Delete all children between begin and end.
2152
+ for (size_type i = 0 ; i < to_erase; ++i) {
2153
+ internal_clear (node->child (begin.position + i + 1 ));
2154
+ }
2155
+ // Rotate children after end into new positions.
2156
+ for (size_type i = begin.position + to_erase + 1 ; i <= node->finish ();
2157
+ ++i) {
2158
+ node->set_child (i - to_erase, node->child (i));
2159
+ node->clear_child (i);
2160
+ }
2161
+ }
2162
+ node->remove_values_ignore_children (begin.position , to_erase,
2163
+ mutable_allocator ());
2164
+
2165
+ // Do not need to update rightmost_, because
2166
+ // * either end == this->end(), and therefore node == rightmost_, and still
2167
+ // exists
2168
+ // * or end != this->end(), and therefore rightmost_ hasn't been erased, since
2169
+ // it wasn't covered in [begin, end)
2170
+ }
2171
+
2172
+ template <typename P>
2173
+ auto btree<P>::erase_from_leaf_node(iterator begin, size_type to_erase)
2174
+ -> iterator {
2175
+ node_type *node = begin.node ;
2176
+ assert (node->leaf ());
2177
+ assert (node->finish () > begin.position );
2178
+ assert (begin.position + to_erase <= node->finish ());
2179
+
2180
+ node->remove_values_ignore_children (begin.position , to_erase,
2181
+ mutable_allocator ());
2182
+
2183
+ size_ -= to_erase;
2184
+
2185
+ return rebalance_after_delete (begin);
2186
+ }
2187
+
2134
2188
template <typename P>
2135
2189
template <typename K>
2136
2190
auto btree<P>::erase_unique(const K &key) -> size_type {
@@ -2159,7 +2213,7 @@ auto btree<P>::erase_multi(const K &key) -> size_type {
2159
2213
template <typename P>
2160
2214
void btree<P>::clear() {
2161
2215
if (!empty ()) {
2162
- node_type::clear_and_delete (root (), mutable_allocator ());
2216
+ internal_clear (root ());
2163
2217
}
2164
2218
mutable_root () = EmptyNode ();
2165
2219
rightmost_ = EmptyNode ();
@@ -2300,7 +2354,12 @@ void btree<P>::rebalance_or_split(iterator *iter) {
2300
2354
template <typename P>
2301
2355
void btree<P>::merge_nodes(node_type *left, node_type *right) {
2302
2356
left->merge (right, mutable_allocator ());
2303
- if (rightmost_ == right) rightmost_ = left;
2357
+ if (right->leaf ()) {
2358
+ if (rightmost_ == right) rightmost_ = left;
2359
+ delete_leaf_node (right);
2360
+ } else {
2361
+ delete_internal_node (right);
2362
+ }
2304
2363
}
2305
2364
2306
2365
template <typename P>
@@ -2357,20 +2416,20 @@ bool btree<P>::try_merge_or_rebalance(iterator *iter) {
2357
2416
2358
2417
template <typename P>
2359
2418
void btree<P>::try_shrink() {
2360
- node_type *orig_root = root ();
2361
- if (orig_root->count () > 0 ) {
2419
+ if (root ()->count () > 0 ) {
2362
2420
return ;
2363
2421
}
2364
2422
// Deleted the last item on the root node, shrink the height of the tree.
2365
- if (orig_root ->leaf ()) {
2423
+ if (root () ->leaf ()) {
2366
2424
assert (size () == 0 );
2425
+ delete_leaf_node (root ());
2367
2426
mutable_root () = rightmost_ = EmptyNode ();
2368
2427
} else {
2369
- node_type *child = orig_root ->start_child ();
2428
+ node_type *child = root () ->start_child ();
2370
2429
child->make_root ();
2430
+ delete_internal_node (root ());
2371
2431
mutable_root () = child;
2372
2432
}
2373
- node_type::clear_and_delete (orig_root, mutable_allocator ());
2374
2433
}
2375
2434
2376
2435
template <typename P>
@@ -2415,7 +2474,7 @@ inline auto btree<P>::internal_emplace(iterator iter, Args &&... args)
2415
2474
old_root->start (), old_root, alloc);
2416
2475
new_root->set_finish (old_root->finish ());
2417
2476
old_root->set_finish (old_root->start ());
2418
- node_type::clear_and_delete (old_root, alloc );
2477
+ delete_leaf_node (old_root);
2419
2478
mutable_root () = rightmost_ = new_root;
2420
2479
} else {
2421
2480
rebalance_or_split (&iter);
@@ -2518,6 +2577,18 @@ auto btree<P>::internal_find(const K &key) const -> iterator {
2518
2577
return {nullptr , 0 };
2519
2578
}
2520
2579
2580
+ template <typename P>
2581
+ void btree<P>::internal_clear(node_type *node) {
2582
+ if (!node->leaf ()) {
2583
+ for (int i = node->start (); i <= node->finish (); ++i) {
2584
+ internal_clear (node->child (i));
2585
+ }
2586
+ delete_internal_node (node);
2587
+ } else {
2588
+ delete_leaf_node (node);
2589
+ }
2590
+ }
2591
+
2521
2592
template <typename P>
2522
2593
int btree<P>::internal_verify(const node_type *node, const key_type *lo,
2523
2594
const key_type *hi) const {
0 commit comments