@ -255,6 +255,10 @@ struct common_params {
static void move ( Alloc * alloc , slot_type * src , slot_type * dest ) {
slot_policy : : move ( alloc , src , dest ) ;
}
static void move ( Alloc * alloc , slot_type * first , slot_type * last ,
slot_type * result ) {
slot_policy : : move ( alloc , first , last , result ) ;
}
} ;
// A parameters structure for holding the type parameters for a btree_map.
@ -332,6 +336,13 @@ struct set_slot_policy {
static void move ( Alloc * /*alloc*/ , slot_type * src , slot_type * dest ) {
* dest = std : : move ( * src ) ;
}
template < typename Alloc >
static void move ( Alloc * alloc , slot_type * first , slot_type * last ,
slot_type * result ) {
for ( slot_type * src = first , * dest = result ; src ! = last ; + + src , + + dest )
move ( alloc , src , dest ) ;
}
} ;
// A parameters structure for holding the type parameters for a btree_set.
@ -748,10 +759,14 @@ class btree_node {
template < typename . . . Args >
void emplace_value ( size_type i , allocator_type * alloc , Args & & . . . args ) ;
// Removes the values at positions [i, i + to_erase), shifting all existing
// values and children after that range to the left by to_erase. Clears all
// children between [i, i + to_erase).
void remove_values ( field_type i , field_type to_erase , allocator_type * alloc ) ;
// Removes the value at position i, shifting all existing values and children
// at positions > i to the left by 1.
void remove_value ( int i , allocator_type * alloc ) ;
// Removes the values at positions [i, i + to_erase), shifting all values
// after that range to the left by to_erase. Does not change children at all.
void remove_values_ignore_children ( int i , int to_erase ,
allocator_type * alloc ) ;
// Rebalances a node with its right sibling.
void rebalance_right_to_left ( int to_move , btree_node * right ,
@ -763,7 +778,7 @@ class btree_node {
void split ( int insert_position , btree_node * dest , allocator_type * alloc ) ;
// Merges a node with its right sibling, moving all of the values and the
// delimiting key in the parent node onto itself, and deleting the src node .
// delimiting key in the parent node onto itself.
void merge ( btree_node * src , allocator_type * alloc ) ;
// Node allocation/deletion routines.
@ -784,27 +799,9 @@ class btree_node {
absl : : container_internal : : SanitizerPoisonMemoryRegion (
& mutable_child ( start ( ) ) , ( kNodeValues + 1 ) * sizeof ( btree_node * ) ) ;
}
// Deletes a node and all of its children.
// TODO(ezb): don't use recursion here to avoid potential stack overflows.
static void clear_and_delete ( btree_node * node , allocator_type * alloc ) {
const field_type start = node - > start ( ) ;
const field_type finish = node - > finish ( ) ;
for ( field_type i = start ; i < finish ; + + i ) {
node - > value_destroy ( i , alloc ) ;
}
if ( node - > leaf ( ) ) {
absl : : container_internal : : Deallocate < Alignment ( ) > (
alloc , node , LeafSize ( node - > max_count ( ) ) ) ;
} else {
// If the node is empty, then there are no children so don't try clearing.
if ( start < finish ) {
for ( field_type i = start ; i < = finish ; + + i ) {
clear_and_delete ( node - > child ( i ) , alloc ) ;
}
}
absl : : container_internal : : Deallocate < Alignment ( ) > ( alloc , node ,
InternalSize ( ) ) ;
void destroy ( allocator_type * alloc ) {
for ( int i = start ( ) ; i < finish ( ) ; + + i ) {
value_destroy ( i , alloc ) ;
}
}
@ -1426,8 +1423,25 @@ class btree {
}
// Deletion helper routines.
void erase_same_node ( iterator begin , iterator end ) ;
iterator erase_from_leaf_node ( iterator begin , size_type to_erase ) ;
iterator rebalance_after_delete ( iterator iter ) ;
// Deallocates a node of a certain size in bytes using the allocator.
void deallocate ( const size_type size , node_type * node ) {
absl : : container_internal : : Deallocate < node_type : : Alignment ( ) > (
mutable_allocator ( ) , node , size ) ;
}
void delete_internal_node ( node_type * node ) {
node - > destroy ( mutable_allocator ( ) ) ;
deallocate ( node_type : : InternalSize ( ) , node ) ;
}
void delete_leaf_node ( node_type * node ) {
node - > destroy ( mutable_allocator ( ) ) ;
deallocate ( node_type : : LeafSize ( node - > max_count ( ) ) , node ) ;
}
// Rebalances or splits the node iter points to.
void rebalance_or_split ( iterator * iter ) ;
@ -1496,6 +1510,9 @@ class btree {
template < typename K >
iterator internal_find ( const K & key ) const ;
// Deletes a node and all of its children.
void internal_clear ( node_type * node ) ;
// Verifies the tree structure of node.
int internal_verify ( const node_type * node , const key_type * lo ,
const key_type * hi ) const ;
@ -1563,29 +1580,26 @@ inline void btree_node<P>::emplace_value(const size_type i,
}
template < typename P >
inline void btree_node < P > : : remove_values ( const field_type i ,
const field_type to_erase ,
allocator_type * alloc ) {
// Transfer values after the removed range into their new places.
const field_type orig_finish = finish ( ) ;
const field_type src_i = i + to_erase ;
for ( field_type j = i ; j < src_i ; + + j ) {
value_destroy ( j , alloc ) ;
inline void btree_node < P > : : remove_value ( const int i , allocator_type * alloc ) {
if ( ! leaf ( ) & & finish ( ) > i + 1 ) {
assert ( child ( i + 1 ) - > count ( ) = = 0 ) ;
for ( size_type j = i + 1 ; j < finish ( ) ; + + j ) {
set_child ( j , child ( j + 1 ) ) ;
}
clear_child ( finish ( ) ) ;
}
transfer_n ( orig_finish - src_i , i , src_i , this , alloc ) ;
if ( ! leaf ( ) ) {
// Delete all children between begin and end.
for ( field_type j = 0 ; j < to_erase ; + + j ) {
clear_and_delete ( child ( i + j + 1 ) , alloc ) ;
}
// Rotate children after end into new positions.
for ( field_type j = i + to_erase + 1 ; j < = orig_finish ; + + j ) {
set_child ( j - to_erase , child ( j ) ) ;
clear_child ( j ) ;
}
remove_values_ignore_children ( i , /*to_erase=*/ 1 , alloc ) ;
}
template < typename P >
inline void btree_node < P > : : remove_values_ignore_children (
const int i , const int to_erase , allocator_type * alloc ) {
params_type : : move ( alloc , slot ( i + to_erase ) , finish_slot ( ) , slot ( i ) ) ;
for ( int j = finish ( ) - to_erase ; j < finish ( ) ; + + j ) {
value_destroy ( j , alloc ) ;
}
set_finish ( orig_ finish - to_erase ) ;
set_finish ( finish ( ) - to_erase ) ;
}
template < typename P >
@ -1737,8 +1751,8 @@ void btree_node<P>::merge(btree_node *src, allocator_type *alloc) {
set_finish ( start ( ) + 1 + count ( ) + src - > count ( ) ) ;
src - > set_finish ( src - > start ( ) ) ;
// Remove the value on the parent node and delete the src node .
parent ( ) - > remove_values ( position ( ) , /*to_erase=*/ 1 , alloc ) ;
// Remove the value on the parent node.
parent ( ) - > remove_value ( position ( ) , alloc ) ;
}
////
@ -2020,7 +2034,7 @@ auto btree<P>::erase(iterator iter) -> iterator {
bool internal_delete = false ;
if ( ! iter . node - > leaf ( ) ) {
// Deletion of a value on an internal node. First, move the largest value
// from our left child here, then delete that position (in remove_values ()
// from our left child here, then delete that position (in remove_value()
// below). We can get to the largest value from our left child by
// decrementing iter.
iterator internal_iter ( iter ) ;
@ -2032,7 +2046,7 @@ auto btree<P>::erase(iterator iter) -> iterator {
}
// Delete the key from the leaf.
iter . node - > remove_values ( iter . position , /*to_erase=*/ 1 , mutable_allocator ( ) ) ;
iter . node - > remove_value ( iter . position , mutable_allocator ( ) ) ;
- - size_ ;
// 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)
}
if ( begin . node = = end . node ) {
assert ( end . position > begin . position ) ;
begin . node - > remove_values ( begin . position , end . position - begin . position ,
mutable_allocator ( ) ) ;
erase_same_node ( begin , end ) ;
size_ - = count ;
return { count , rebalance_after_delete ( begin ) } ;
}
@ -2119,11 +2131,8 @@ auto btree<P>::erase_range(iterator begin, iterator end)
if ( begin . node - > leaf ( ) ) {
const size_type remaining_to_erase = size_ - target_size ;
const size_type remaining_in_node = begin . node - > finish ( ) - begin . position ;
const size_type to_erase =
( std : : min ) ( remaining_to_erase , remaining_in_node ) ;
begin . node - > remove_values ( begin . position , to_erase , mutable_allocator ( ) ) ;
size_ - = to_erase ;
begin = rebalance_after_delete ( begin ) ;
begin = erase_from_leaf_node (
begin , ( std : : min ) ( remaining_to_erase , remaining_in_node ) ) ;
} else {
begin = erase ( begin ) ;
}
@ -2131,6 +2140,51 @@ auto btree<P>::erase_range(iterator begin, iterator end)
return { count , begin } ;
}
template < typename P >
void btree < P > : : erase_same_node ( iterator begin , iterator end ) {
assert ( begin . node = = end . node ) ;
assert ( end . position > begin . position ) ;
node_type * node = begin . node ;
size_type to_erase = end . position - begin . position ;
if ( ! node - > leaf ( ) ) {
// Delete all children between begin and end.
for ( size_type i = 0 ; i < to_erase ; + + i ) {
internal_clear ( node - > child ( begin . position + i + 1 ) ) ;
}
// Rotate children after end into new positions.
for ( size_type i = begin . position + to_erase + 1 ; i < = node - > finish ( ) ;
+ + i ) {
node - > set_child ( i - to_erase , node - > child ( i ) ) ;
node - > clear_child ( i ) ;
}
}
node - > remove_values_ignore_children ( begin . position , to_erase ,
mutable_allocator ( ) ) ;
// Do not need to update rightmost_, because
// * either end == this->end(), and therefore node == rightmost_, and still
// exists
// * or end != this->end(), and therefore rightmost_ hasn't been erased, since
// it wasn't covered in [begin, end)
}
template < typename P >
auto btree < P > : : erase_from_leaf_node ( iterator begin , size_type to_erase )
- > iterator {
node_type * node = begin . node ;
assert ( node - > leaf ( ) ) ;
assert ( node - > finish ( ) > begin . position ) ;
assert ( begin . position + to_erase < = node - > finish ( ) ) ;
node - > remove_values_ignore_children ( begin . position , to_erase ,
mutable_allocator ( ) ) ;
size_ - = to_erase ;
return rebalance_after_delete ( begin ) ;
}
template < typename P >
template < typename K >
auto btree < P > : : erase_unique ( const K & key ) - > size_type {
@ -2159,7 +2213,7 @@ auto btree<P>::erase_multi(const K &key) -> size_type {
template < typename P >
void btree < P > : : clear ( ) {
if ( ! empty ( ) ) {
node_type : : clear_and_delete ( root ( ) , mutable_allocator ( ) ) ;
internal_clear ( root ( ) ) ;
}
mutable_root ( ) = EmptyNode ( ) ;
rightmost_ = EmptyNode ( ) ;
@ -2300,7 +2354,12 @@ void btree<P>::rebalance_or_split(iterator *iter) {
template < typename P >
void btree < P > : : merge_nodes ( node_type * left , node_type * right ) {
left - > merge ( right , mutable_allocator ( ) ) ;
if ( rightmost_ = = right ) rightmost_ = left ;
if ( right - > leaf ( ) ) {
if ( rightmost_ = = right ) rightmost_ = left ;
delete_leaf_node ( right ) ;
} else {
delete_internal_node ( right ) ;
}
}
template < typename P >
@ -2357,20 +2416,20 @@ bool btree<P>::try_merge_or_rebalance(iterator *iter) {
template < typename P >
void btree < P > : : try_shrink ( ) {
node_type * orig_root = root ( ) ;
if ( orig_root - > count ( ) > 0 ) {
if ( root ( ) - > count ( ) > 0 ) {
return ;
}
// Deleted the last item on the root node, shrink the height of the tree.
if ( orig_ root- > leaf ( ) ) {
if ( root ( ) - > leaf ( ) ) {
assert ( size ( ) = = 0 ) ;
delete_leaf_node ( root ( ) ) ;
mutable_root ( ) = rightmost_ = EmptyNode ( ) ;
} else {
node_type * child = orig_ root- > start_child ( ) ;
node_type * child = root ( ) - > start_child ( ) ;
child - > make_root ( ) ;
delete_internal_node ( root ( ) ) ;
mutable_root ( ) = child ;
}
node_type : : clear_and_delete ( orig_root , mutable_allocator ( ) ) ;
}
template < typename P >
@ -2415,7 +2474,7 @@ inline auto btree<P>::internal_emplace(iterator iter, Args &&... args)
old_root - > start ( ) , old_root , alloc ) ;
new_root - > set_finish ( old_root - > finish ( ) ) ;
old_root - > set_finish ( old_root - > start ( ) ) ;
node_type : : clear_and_delet e( old_root , alloc ) ;
delete_leaf_nod e( old_root ) ;
mutable_root ( ) = rightmost_ = new_root ;
} else {
rebalance_or_split ( & iter ) ;
@ -2518,6 +2577,18 @@ auto btree<P>::internal_find(const K &key) const -> iterator {
return { nullptr , 0 } ;
}
template < typename P >
void btree < P > : : internal_clear ( node_type * node ) {
if ( ! node - > leaf ( ) ) {
for ( int i = node - > start ( ) ; i < = node - > finish ( ) ; + + i ) {
internal_clear ( node - > child ( i ) ) ;
}
delete_internal_node ( node ) ;
} else {
delete_leaf_node ( node ) ;
}
}
template < typename P >
int btree < P > : : internal_verify ( const node_type * node , const key_type * lo ,
const key_type * hi ) const {