Coverage Report

Created: 2026-06-22 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sentencepiece/third_party/absl/container/internal/btree.h
Line
Count
Source
1
// Copyright 2018 The Abseil Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
// A btree implementation of the STL set and map interfaces. A btree is smaller
16
// and generally also faster than STL set/map (refer to the benchmarks below).
17
// The red-black tree implementation of STL set/map has an overhead of 3
18
// pointers (left, right and parent) plus the node color information for each
19
// stored value. So a set<int32_t> consumes 40 bytes for each value stored in
20
// 64-bit mode. This btree implementation stores multiple values on fixed
21
// size nodes (usually 256 bytes) and doesn't store child pointers for leaf
22
// nodes. The result is that a btree_set<int32_t> may use much less memory per
23
// stored value. For the random insertion benchmark in btree_bench.cc, a
24
// btree_set<int32_t> with node-size of 256 uses 5.1 bytes per stored value.
25
//
26
// The packing of multiple values on to each node of a btree has another effect
27
// besides better space utilization: better cache locality due to fewer cache
28
// lines being accessed. Better cache locality translates into faster
29
// operations.
30
//
31
// CAVEATS
32
//
33
// Insertions and deletions on a btree can cause splitting, merging or
34
// rebalancing of btree nodes. And even without these operations, insertions
35
// and deletions on a btree will move values around within a node. In both
36
// cases, the result is that insertions and deletions can invalidate iterators
37
// pointing to values other than the one being inserted/deleted. Therefore, this
38
// container does not provide pointer stability. This is notably different from
39
// STL set/map which takes care to not invalidate iterators on insert/erase
40
// except, of course, for iterators pointing to the value being erased.  A
41
// partial workaround when erasing is available: erase() returns an iterator
42
// pointing to the item just after the one that was erased (or end() if none
43
// exists).
44
45
#ifndef ABSL_CONTAINER_INTERNAL_BTREE_H_
46
#define ABSL_CONTAINER_INTERNAL_BTREE_H_
47
48
#include <algorithm>
49
#include <cassert>
50
#include <cstddef>
51
#include <cstdint>
52
#include <cstring>
53
#include <functional>
54
#include <iterator>
55
#include <limits>
56
#include <memory>
57
#include <string>
58
#include <type_traits>
59
#include <utility>
60
61
#include "absl/base/config.h"
62
#include "absl/base/internal/hardening.h"
63
#include "absl/base/internal/raw_logging.h"
64
#include "absl/base/macros.h"
65
#include "absl/base/optimization.h"
66
#include "absl/container/internal/common.h"
67
#include "absl/container/internal/common_policy_traits.h"
68
#include "absl/container/internal/compressed_tuple.h"
69
#include "absl/container/internal/container_memory.h"
70
#include "absl/container/internal/layout.h"
71
#include "absl/memory/memory.h"
72
#include "absl/meta/type_traits.h"
73
#include "absl/strings/cord.h"
74
#include "absl/strings/string_view.h"
75
#include "absl/types/compare.h"
76
77
namespace absl {
78
ABSL_NAMESPACE_BEGIN
79
namespace container_internal {
80
81
#ifdef ABSL_BTREE_ENABLE_GENERATIONS
82
#error ABSL_BTREE_ENABLE_GENERATIONS cannot be directly set
83
#elif (defined(ABSL_HAVE_ADDRESS_SANITIZER) ||   \
84
       defined(ABSL_HAVE_HWADDRESS_SANITIZER) || \
85
       defined(ABSL_HAVE_MEMORY_SANITIZER)) &&   \
86
    !defined(NDEBUG_SANITIZER)  // If defined, performance is important.
87
// When compiled in sanitizer mode, we add generation integers to the nodes and
88
// iterators. When iterators are used, we validate that the container has not
89
// been mutated since the iterator was constructed.
90
#define ABSL_BTREE_ENABLE_GENERATIONS
91
#endif
92
93
#ifdef ABSL_BTREE_ENABLE_GENERATIONS
94
constexpr bool BtreeGenerationsEnabled() { return true; }
95
#else
96
0
constexpr bool BtreeGenerationsEnabled() { return false; }
97
#endif
98
99
template <typename Compare, typename T, typename U>
100
using compare_result_t = absl::result_of_t<const Compare(const T &, const U &)>;
101
102
// A helper class that indicates if the Compare parameter is a key-compare-to
103
// comparator.
104
template <typename Compare, typename T>
105
using btree_is_key_compare_to =
106
    std::is_convertible<compare_result_t<Compare, T, T>, absl::weak_ordering>;
107
108
struct StringBtreeDefaultLess {
109
  using is_transparent = void;
110
111
  StringBtreeDefaultLess() = default;
112
113
  // Compatibility constructor.
114
0
  StringBtreeDefaultLess(std::less<std::string>) {}        // NOLINT
115
0
  StringBtreeDefaultLess(std::less<absl::string_view>) {}  // NOLINT
116
117
  // Allow converting to std::less for use in key_comp()/value_comp().
118
0
  explicit operator std::less<std::string>() const { return {}; }
119
0
  explicit operator std::less<absl::string_view>() const { return {}; }
120
0
  explicit operator std::less<absl::Cord>() const { return {}; }
121
122
  absl::weak_ordering operator()(absl::string_view lhs,
123
0
                                 absl::string_view rhs) const {
124
0
    return compare_internal::compare_result_as_ordering(lhs.compare(rhs));
125
0
  }
126
0
  StringBtreeDefaultLess(std::less<absl::Cord>) {}  // NOLINT
127
  absl::weak_ordering operator()(const absl::Cord &lhs,
128
0
                                 const absl::Cord &rhs) const {
129
0
    return compare_internal::compare_result_as_ordering(lhs.Compare(rhs));
130
0
  }
131
  absl::weak_ordering operator()(const absl::Cord &lhs,
132
0
                                 absl::string_view rhs) const {
133
0
    return compare_internal::compare_result_as_ordering(lhs.Compare(rhs));
134
0
  }
135
  absl::weak_ordering operator()(absl::string_view lhs,
136
0
                                 const absl::Cord &rhs) const {
137
0
    return compare_internal::compare_result_as_ordering(-rhs.Compare(lhs));
138
0
  }
139
};
140
141
struct StringBtreeDefaultGreater {
142
  using is_transparent = void;
143
144
  StringBtreeDefaultGreater() = default;
145
146
0
  StringBtreeDefaultGreater(std::greater<std::string>) {}        // NOLINT
147
0
  StringBtreeDefaultGreater(std::greater<absl::string_view>) {}  // NOLINT
148
149
  // Allow converting to std::greater for use in key_comp()/value_comp().
150
0
  explicit operator std::greater<std::string>() const { return {}; }
151
0
  explicit operator std::greater<absl::string_view>() const { return {}; }
152
0
  explicit operator std::greater<absl::Cord>() const { return {}; }
153
154
  absl::weak_ordering operator()(absl::string_view lhs,
155
0
                                 absl::string_view rhs) const {
156
0
    return compare_internal::compare_result_as_ordering(rhs.compare(lhs));
157
0
  }
158
0
  StringBtreeDefaultGreater(std::greater<absl::Cord>) {}  // NOLINT
159
  absl::weak_ordering operator()(const absl::Cord &lhs,
160
0
                                 const absl::Cord &rhs) const {
161
0
    return compare_internal::compare_result_as_ordering(rhs.Compare(lhs));
162
0
  }
163
  absl::weak_ordering operator()(const absl::Cord &lhs,
164
0
                                 absl::string_view rhs) const {
165
0
    return compare_internal::compare_result_as_ordering(-lhs.Compare(rhs));
166
0
  }
167
  absl::weak_ordering operator()(absl::string_view lhs,
168
0
                                 const absl::Cord &rhs) const {
169
0
    return compare_internal::compare_result_as_ordering(rhs.Compare(lhs));
170
0
  }
171
};
172
173
// See below comments for checked_compare.
174
template <typename Compare, bool is_class = std::is_class<Compare>::value>
175
struct checked_compare_base : Compare {
176
  using Compare::Compare;
177
293k
  explicit checked_compare_base(Compare c) : Compare(std::move(c)) {}
178
38.5M
  const Compare &comp() const { return *this; }
179
};
180
template <typename Compare>
181
struct checked_compare_base<Compare, false> {
182
  explicit checked_compare_base(Compare c) : compare(std::move(c)) {}
183
  const Compare &comp() const { return compare; }
184
  Compare compare;
185
};
186
187
// A mechanism for opting out of checked_compare for use only in btree_test.cc.
188
struct BtreeTestOnlyCheckedCompareOptOutBase {};
189
190
// A helper class to adapt the specified comparator for two use cases:
191
// (1) When using common Abseil string types with common comparison functors,
192
// convert a boolean comparison into a three-way comparison that returns an
193
// `absl::weak_ordering`. This helper class is specialized for
194
// less<std::string>, greater<std::string>, less<string_view>,
195
// greater<string_view>, less<absl::Cord>, and greater<absl::Cord>.
196
// (2) Adapt the comparator to diagnose cases of non-strict-weak-ordering (see
197
// https://en.cppreference.com/w/cpp/named_req/Compare) in debug mode. Whenever
198
// a comparison is made, we will make assertions to verify that the comparator
199
// is valid.
200
template <typename Compare, typename Key>
201
struct key_compare_adapter {
202
  // Inherit from checked_compare_base to support function pointers and also
203
  // keep empty-base-optimization (EBO) support for classes.
204
  // Note: we can't use CompressedTuple here because that would interfere
205
  // with the EBO for `btree::rightmost_`. `btree::rightmost_` is itself a
206
  // CompressedTuple and nested `CompressedTuple`s don't support EBO.
207
  // TODO(b/214288561): use CompressedTuple instead once it supports EBO for
208
  // nested `CompressedTuple`s.
209
  struct checked_compare : checked_compare_base<Compare> {
210
   private:
211
    using Base = typename checked_compare::checked_compare_base;
212
    using Base::comp;
213
214
    // If possible, returns whether `t` is equivalent to itself. We can only do
215
    // this for `Key`s because we can't be sure that it's safe to call
216
    // `comp()(k, k)` otherwise. Even if SFINAE allows it, there could be a
217
    // compilation failure inside the implementation of the comparison operator.
218
    bool is_self_equivalent(const Key &k) const {
219
      // Note: this works for both boolean and three-way comparators.
220
      return comp()(k, k) == 0;
221
    }
222
    // If we can't compare `t` with itself, returns true unconditionally.
223
    template <typename T>
224
    bool is_self_equivalent(const T &) const {
225
      return true;
226
    }
227
228
   public:
229
    using Base::Base;
230
293k
    checked_compare(Compare cmp) : Base(std::move(cmp)) {}  // NOLINT
231
232
    // Allow converting to Compare for use in key_comp()/value_comp().
233
    explicit operator Compare() const { return comp(); }
234
235
    template <typename T, typename U,
236
              std::enable_if_t<
237
                  std::is_same<bool, compare_result_t<Compare, T, U>>::value,
238
                  int> = 0>
239
38.5M
    bool operator()(const T &lhs, const U &rhs) const {
240
      // NOTE: if any of these assertions fail, then the comparator does not
241
      // establish a strict-weak-ordering (see
242
      // https://en.cppreference.com/w/cpp/named_req/Compare).
243
38.5M
      assert(is_self_equivalent(lhs));
244
38.5M
      assert(is_self_equivalent(rhs));
245
38.5M
      const bool lhs_comp_rhs = comp()(lhs, rhs);
246
38.5M
      assert(!lhs_comp_rhs || !comp()(rhs, lhs));
247
38.5M
      return lhs_comp_rhs;
248
38.5M
    }
249
250
    template <
251
        typename T, typename U,
252
        std::enable_if_t<std::is_convertible<compare_result_t<Compare, T, U>,
253
                                              absl::weak_ordering>::value,
254
                          int> = 0>
255
    absl::weak_ordering operator()(const T &lhs, const U &rhs) const {
256
      // NOTE: if any of these assertions fail, then the comparator does not
257
      // establish a strict-weak-ordering (see
258
      // https://en.cppreference.com/w/cpp/named_req/Compare).
259
      assert(is_self_equivalent(lhs));
260
      assert(is_self_equivalent(rhs));
261
      const absl::weak_ordering lhs_comp_rhs = comp()(lhs, rhs);
262
#ifndef NDEBUG
263
      const absl::weak_ordering rhs_comp_lhs = comp()(rhs, lhs);
264
      if (lhs_comp_rhs > 0) {
265
        assert(rhs_comp_lhs < 0 && "lhs_comp_rhs > 0 -> rhs_comp_lhs < 0");
266
      } else if (lhs_comp_rhs == 0) {
267
        assert(rhs_comp_lhs == 0 && "lhs_comp_rhs == 0 -> rhs_comp_lhs == 0");
268
      } else {
269
        assert(rhs_comp_lhs > 0 && "lhs_comp_rhs < 0 -> rhs_comp_lhs > 0");
270
      }
271
#endif
272
      return lhs_comp_rhs;
273
    }
274
  };
275
  using type = std::conditional_t<
276
      std::is_base_of<BtreeTestOnlyCheckedCompareOptOutBase, Compare>::value,
277
      Compare, checked_compare>;
278
};
279
280
template <>
281
struct key_compare_adapter<std::less<std::string>, std::string> {
282
  using type = StringBtreeDefaultLess;
283
};
284
285
template <>
286
struct key_compare_adapter<std::greater<std::string>, std::string> {
287
  using type = StringBtreeDefaultGreater;
288
};
289
290
template <>
291
struct key_compare_adapter<std::less<absl::string_view>, absl::string_view> {
292
  using type = StringBtreeDefaultLess;
293
};
294
295
template <>
296
struct key_compare_adapter<std::greater<absl::string_view>, absl::string_view> {
297
  using type = StringBtreeDefaultGreater;
298
};
299
300
template <>
301
struct key_compare_adapter<std::less<absl::Cord>, absl::Cord> {
302
  using type = StringBtreeDefaultLess;
303
};
304
305
template <>
306
struct key_compare_adapter<std::greater<absl::Cord>, absl::Cord> {
307
  using type = StringBtreeDefaultGreater;
308
};
309
310
// Detects an 'absl_btree_prefer_linear_node_search' member. This is
311
// a protocol used as an opt-in or opt-out of linear search.
312
//
313
//  For example, this would be useful for key types that wrap an integer
314
//  and define their own cheap operator<(). For example:
315
//
316
//   class K {
317
//    public:
318
//     using absl_btree_prefer_linear_node_search = std::true_type;
319
//     ...
320
//    private:
321
//     friend bool operator<(K a, K b) { return a.k_ < b.k_; }
322
//     int k_;
323
//   };
324
//
325
//   btree_map<K, V> m;  // Uses linear search
326
//
327
// If T has the preference tag, then it has a preference.
328
// Btree will use the tag's truth value.
329
template <typename T, typename = void>
330
struct has_linear_node_search_preference : std::false_type {};
331
template <typename T, typename = void>
332
struct prefers_linear_node_search : std::false_type {};
333
template <typename T>
334
struct has_linear_node_search_preference<
335
    T, std::void_t<typename T::absl_btree_prefer_linear_node_search>>
336
    : std::true_type {};
337
template <typename T>
338
struct prefers_linear_node_search<
339
    T, std::void_t<typename T::absl_btree_prefer_linear_node_search>>
340
    : T::absl_btree_prefer_linear_node_search {};
341
342
template <typename Compare, typename Key>
343
0
constexpr bool compare_has_valid_result_type() {
344
0
  using compare_result_type = compare_result_t<Compare, Key, Key>;
345
0
  return std::is_same<compare_result_type, bool>::value ||
346
0
         std::is_convertible<compare_result_type, absl::weak_ordering>::value;
347
0
}
Unexecuted instantiation: bool absl::lts_20260526::container_internal::compare_has_valid_result_type<std::__1::less<unsigned long>, unsigned long>()
Unexecuted instantiation: bool absl::lts_20260526::container_internal::compare_has_valid_result_type<absl::lts_20260526::container_internal::key_compare_adapter<std::__1::less<unsigned long>, unsigned long>::checked_compare, unsigned long>()
348
349
template <typename original_key_compare, typename value_type>
350
class map_value_compare {
351
  template <typename Params>
352
  friend class btree;
353
354
  // Note: this `protected` is part of the API of std::map::value_compare. See
355
  // https://en.cppreference.com/w/cpp/container/map/value_compare.
356
 protected:
357
  explicit map_value_compare(original_key_compare c) : comp(std::move(c)) {}
358
359
  original_key_compare comp;  // NOLINT
360
361
 public:
362
  auto operator()(const value_type &lhs, const value_type &rhs) const
363
      -> decltype(comp(lhs.first, rhs.first)) {
364
    return comp(lhs.first, rhs.first);
365
  }
366
};
367
368
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
369
          bool IsMulti, bool IsMap, typename SlotPolicy>
370
struct common_params : common_policy_traits<SlotPolicy> {
371
  using original_key_compare = Compare;
372
373
  // If Compare is a common comparator for a string-like type, then we adapt it
374
  // to use heterogeneous lookup and to be a key-compare-to comparator.
375
  // We also adapt the comparator to diagnose invalid comparators in debug mode.
376
  // We disable this when `Compare` is invalid in a way that will cause
377
  // adaptation to fail (having invalid return type) so that we can give a
378
  // better compilation failure in static_assert_validation. If we don't do
379
  // this, then there will be cascading compilation failures that are confusing
380
  // for users.
381
  using key_compare =
382
      std::conditional_t<!compare_has_valid_result_type<Compare, Key>(),
383
                          Compare,
384
                          typename key_compare_adapter<Compare, Key>::type>;
385
386
  static constexpr bool kIsKeyCompareStringAdapted =
387
      std::is_same<key_compare, StringBtreeDefaultLess>::value ||
388
      std::is_same<key_compare, StringBtreeDefaultGreater>::value;
389
  static constexpr bool kIsKeyCompareTransparent =
390
      IsTransparent<original_key_compare>::value || kIsKeyCompareStringAdapted;
391
392
  // A type which indicates if we have a key-compare-to functor or a plain old
393
  // key-compare functor.
394
  using is_key_compare_to = btree_is_key_compare_to<key_compare, Key>;
395
396
  using allocator_type = Alloc;
397
  using key_type = Key;
398
  using size_type = size_t;
399
  using difference_type = ptrdiff_t;
400
401
  using slot_policy = SlotPolicy;
402
  using slot_type = typename slot_policy::slot_type;
403
  using value_type = typename slot_policy::value_type;
404
  using init_type = typename slot_policy::mutable_value_type;
405
  using pointer = value_type *;
406
  using const_pointer = const value_type *;
407
  using reference = value_type &;
408
  using const_reference = const value_type &;
409
410
  using value_compare =
411
      std::conditional_t<IsMap,
412
                          map_value_compare<original_key_compare, value_type>,
413
                          original_key_compare>;
414
  using is_map_container = std::integral_constant<bool, IsMap>;
415
416
  // For the given lookup key type, returns whether we can have multiple
417
  // equivalent keys in the btree. If this is a multi-container, then we can.
418
  // Otherwise, we can have multiple equivalent keys only if all of the
419
  // following conditions are met:
420
  // - The comparator is transparent.
421
  // - The lookup key type is not the same as key_type.
422
  // - The comparator is not a StringBtreeDefault{Less,Greater} comparator
423
  //   that we know has the same equivalence classes for all lookup types.
424
  template <typename LookupKey>
425
  constexpr static bool can_have_multiple_equivalent_keys() {
426
    return IsMulti || (IsTransparent<key_compare>::value &&
427
                       !std::is_same<LookupKey, Key>::value &&
428
                       !kIsKeyCompareStringAdapted);
429
  }
430
431
  enum {
432
    kTargetNodeSize = TargetNodeSize,
433
434
    // Upper bound for the available space for slots. This is largest for leaf
435
    // nodes, which have overhead of at least a pointer + 4 bytes (for storing
436
    // 3 field_types and an enum).
437
    kNodeSlotSpace = TargetNodeSize - /*minimum overhead=*/(sizeof(void *) + 4),
438
  };
439
440
  // This is an integral type large enough to hold as many slots as will fit a
441
  // node of TargetNodeSize bytes.
442
  using node_count_type =
443
      std::conditional_t<(kNodeSlotSpace / sizeof(slot_type) >
444
                           (std::numeric_limits<uint8_t>::max)()),
445
                          uint16_t, uint8_t>;  // NOLINT
446
};
447
448
// An adapter class that converts a lower-bound compare into an upper-bound
449
// compare. Note: there is no need to make a version of this adapter specialized
450
// for key-compare-to functors because the upper-bound (the first value greater
451
// than the input) is never an exact match.
452
template <typename Compare>
453
struct upper_bound_adapter {
454
  explicit upper_bound_adapter(const Compare &c) : comp(c) {}
455
  template <typename K1, typename K2>
456
  bool operator()(const K1 &a, const K2 &b) const {
457
    // Returns true when a is not greater than b.
458
    return !compare_internal::compare_result_as_less_than(comp(b, a));
459
  }
460
461
 private:
462
  Compare comp;
463
};
464
465
enum class MatchKind : uint8_t { kEq, kNe };
466
467
template <typename V, bool IsCompareTo>
468
struct SearchResult {
469
  V value;
470
  MatchKind match;
471
472
  static constexpr bool HasMatch() { return true; }
473
  bool IsEq() const { return match == MatchKind::kEq; }
474
};
475
476
// When we don't use CompareTo, `match` is not present.
477
// This ensures that callers can't use it accidentally when it provides no
478
// useful information.
479
template <typename V>
480
struct SearchResult<V, false> {
481
  SearchResult() = default;
482
3.67M
  explicit SearchResult(V v) : value(v) {}
483
2.09M
  SearchResult(V v, MatchKind /*match*/) : value(v) {}
484
485
  V value;
486
487
0
  static constexpr bool HasMatch() { return false; }
488
0
  static constexpr bool IsEq() { return false; }
Unexecuted instantiation: absl::lts_20260526::container_internal::SearchResult<absl::lts_20260526::container_internal::btree_iterator<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >, unsigned long const&, unsigned long const*>, false>::IsEq()
Unexecuted instantiation: absl::lts_20260526::container_internal::SearchResult<unsigned long, false>::IsEq()
489
};
490
491
// A node in the btree holding. The same node type is used for both internal
492
// and leaf nodes in the btree, though the nodes are allocated in such a way
493
// that the children array is only valid in internal nodes.
494
template <typename Params>
495
class btree_node {
496
  using is_key_compare_to = typename Params::is_key_compare_to;
497
  using field_type = typename Params::node_count_type;
498
  using allocator_type = typename Params::allocator_type;
499
  using slot_type = typename Params::slot_type;
500
  using original_key_compare = typename Params::original_key_compare;
501
502
 public:
503
  using params_type = Params;
504
  using key_type = typename Params::key_type;
505
  using value_type = typename Params::value_type;
506
  using pointer = typename Params::pointer;
507
  using const_pointer = typename Params::const_pointer;
508
  using reference = typename Params::reference;
509
  using const_reference = typename Params::const_reference;
510
  using key_compare = typename Params::key_compare;
511
  using size_type = typename Params::size_type;
512
  using difference_type = typename Params::difference_type;
513
514
  // Btree decides whether to use linear node search as follows:
515
  //   - If the comparator expresses a preference, use that.
516
  //   - If the key expresses a preference, use that.
517
  //   - If the key is arithmetic and the comparator is std::less or
518
  //     std::greater, choose linear.
519
  //   - Otherwise, choose binary.
520
  // TODO(ezb): Might make sense to add condition(s) based on node-size.
521
  using use_linear_search = std::integral_constant<
522
      bool, has_linear_node_search_preference<original_key_compare>::value
523
                ? prefers_linear_node_search<original_key_compare>::value
524
            : has_linear_node_search_preference<key_type>::value
525
                ? prefers_linear_node_search<key_type>::value
526
                : std::is_arithmetic<key_type>::value &&
527
                      (std::is_same<std::less<key_type>,
528
                                    original_key_compare>::value ||
529
                       std::is_same<std::greater<key_type>,
530
                                    original_key_compare>::value)>;
531
532
  // This class is organized by absl::container_internal::Layout as if it had
533
  // the following structure:
534
  //   // A pointer to the node's parent.
535
  //   btree_node *parent;
536
  //
537
  //   // When ABSL_BTREE_ENABLE_GENERATIONS is defined, we also have a
538
  //   // generation integer in order to check that when iterators are
539
  //   // used, they haven't been invalidated already. Only the generation on
540
  //   // the root is used, but we have one on each node because whether a node
541
  //   // is root or not can change.
542
  //   uint32_t generation;
543
  //
544
  //   // The position of the node in the node's parent.
545
  //   field_type position;
546
  //   // The index of the first populated value in `values`.
547
  //   // TODO(ezb): right now, `start` is always 0. Update insertion/merge
548
  //   // logic to allow for floating storage within nodes.
549
  //   field_type start;
550
  //   // The index after the last populated value in `values`. Currently, this
551
  //   // is the same as the count of values.
552
  //   field_type finish;
553
  //   // The maximum number of values the node can hold. This is an integer in
554
  //   // [1, kNodeSlots] for root leaf nodes, kNodeSlots for non-root leaf
555
  //   // nodes, and kInternalNodeMaxCount (as a sentinel value) for internal
556
  //   // nodes (even though there are still kNodeSlots values in the node).
557
  //   // TODO(ezb): make max_count use only 4 bits and record log2(capacity)
558
  //   // to free extra bits for is_root, etc.
559
  //   field_type max_count;
560
  //
561
  //   // The array of values. The capacity is `max_count` for leaf nodes and
562
  //   // kNodeSlots for internal nodes. Only the values in
563
  //   // [start, finish) have been initialized and are valid.
564
  //   slot_type values[max_count];
565
  //
566
  //   // The array of child pointers. The keys in children[i] are all less
567
  //   // than key(i). The keys in children[i + 1] are all greater than key(i).
568
  //   // There are 0 children for leaf nodes and kNodeSlots + 1 children for
569
  //   // internal nodes.
570
  //   btree_node *children[kNodeSlots + 1];
571
  //
572
  // This class is only constructed by EmptyNodeType. Normally, pointers to the
573
  // layout above are allocated, cast to btree_node*, and de-allocated within
574
  // the btree implementation.
575
  ~btree_node() = default;
576
  btree_node(btree_node const &) = delete;
577
  btree_node &operator=(btree_node const &) = delete;
578
579
 protected:
580
  btree_node() = default;
581
582
 private:
583
  using layout_type =
584
      absl::container_internal::Layout<btree_node *, uint32_t, field_type,
585
                                       slot_type, btree_node *>;
586
  using leaf_layout_type = typename layout_type::template WithStaticSizes<
587
      /*parent*/ 1,
588
      /*generation*/ BtreeGenerationsEnabled() ? 1 : 0,
589
      /*position, start, finish, max_count*/ 4>;
590
0
  constexpr static size_type SizeWithNSlots(size_type n) {
591
0
    return leaf_layout_type(/*slots*/ n, /*children*/ 0).AllocSize();
592
0
  }
593
  // A lower bound for the overhead of fields other than slots in a leaf node.
594
0
  constexpr static size_type MinimumOverhead() {
595
0
    return SizeWithNSlots(1) - sizeof(slot_type);
596
0
  }
597
598
  // Compute how many values we can fit onto a leaf node taking into account
599
  // padding.
600
  constexpr static size_type NodeTargetSlots(const size_type begin,
601
0
                                             const size_type end) {
602
0
    return begin == end ? begin
603
0
           : SizeWithNSlots((begin + end) / 2 + 1) >
604
0
                   params_type::kTargetNodeSize
605
0
               ? NodeTargetSlots(begin, (begin + end) / 2)
606
0
               : NodeTargetSlots((begin + end) / 2 + 1, end);
607
0
  }
608
609
  constexpr static size_type kTargetNodeSize = params_type::kTargetNodeSize;
610
  constexpr static size_type kNodeTargetSlots =
611
      NodeTargetSlots(0, kTargetNodeSize);
612
613
  // We need a minimum of 3 slots per internal node in order to perform
614
  // splitting (1 value for the two nodes involved in the split and 1 value
615
  // propagated to the parent as the delimiter for the split). For performance
616
  // reasons, we don't allow 3 slots-per-node due to bad worst case occupancy of
617
  // 1/3 (for a node, not a b-tree).
618
  constexpr static size_type kMinNodeSlots = 4;
619
620
  constexpr static size_type kNodeSlots =
621
      kNodeTargetSlots >= kMinNodeSlots ? kNodeTargetSlots : kMinNodeSlots;
622
623
  using internal_layout_type = typename layout_type::template WithStaticSizes<
624
      /*parent*/ 1,
625
      /*generation*/ BtreeGenerationsEnabled() ? 1 : 0,
626
      /*position, start, finish, max_count*/ 4, /*slots*/ kNodeSlots,
627
      /*children*/ kNodeSlots + 1>;
628
629
  // The node is internal (i.e. is not a leaf node) if and only if `max_count`
630
  // has this value.
631
  constexpr static field_type kInternalNodeMaxCount = 0;
632
633
  // Leaves can have less than kNodeSlots values.
634
  constexpr static leaf_layout_type LeafLayout(
635
1.09M
      const size_type slot_count = kNodeSlots) {
636
1.09M
    return leaf_layout_type(slot_count, 0);
637
1.09M
  }
638
122M
  constexpr static auto InternalLayout() { return internal_layout_type(); }
639
1.09M
  constexpr static size_type LeafSize(const size_type slot_count = kNodeSlots) {
640
1.09M
    return LeafLayout(slot_count).AllocSize();
641
1.09M
  }
642
19.0k
  constexpr static size_type InternalSize() {
643
19.0k
    return InternalLayout().AllocSize();
644
19.0k
  }
645
646
0
  constexpr static size_type Alignment() {
647
0
    static_assert(LeafLayout(1).Alignment() == InternalLayout().Alignment(),
648
0
                  "Alignment of all nodes must be equal.");
649
0
    return InternalLayout().Alignment();
650
0
  }
651
652
  // N is the index of the type in the Layout definition.
653
  // ElementType<N> is the Nth type in the Layout definition.
654
  template <size_type N>
655
21.6M
  inline typename layout_type::template ElementType<N> *GetField() {
656
    // We assert that we don't read from values that aren't there.
657
21.6M
    assert(N < 4 || is_internal());
658
21.6M
    return InternalLayout().template Pointer<N>(reinterpret_cast<char *>(this));
659
21.6M
  }
std::__1::tuple_element<3ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<3ul>()
Line
Count
Source
655
14.3M
  inline typename layout_type::template ElementType<N> *GetField() {
656
    // We assert that we don't read from values that aren't there.
657
    assert(N < 4 || is_internal());
658
14.3M
    return InternalLayout().template Pointer<N>(reinterpret_cast<char *>(this));
659
14.3M
  }
std::__1::tuple_element<2ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<2ul>()
Line
Count
Source
655
6.12M
  inline typename layout_type::template ElementType<N> *GetField() {
656
    // We assert that we don't read from values that aren't there.
657
    assert(N < 4 || is_internal());
658
6.12M
    return InternalLayout().template Pointer<N>(reinterpret_cast<char *>(this));
659
6.12M
  }
std::__1::tuple_element<0ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<0ul>()
Line
Count
Source
655
585k
  inline typename layout_type::template ElementType<N> *GetField() {
656
    // We assert that we don't read from values that aren't there.
657
    assert(N < 4 || is_internal());
658
585k
    return InternalLayout().template Pointer<N>(reinterpret_cast<char *>(this));
659
585k
  }
std::__1::tuple_element<4ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<4ul>()
Line
Count
Source
655
607k
  inline typename layout_type::template ElementType<N> *GetField() {
656
    // We assert that we don't read from values that aren't there.
657
    assert(N < 4 || is_internal());
658
607k
    return InternalLayout().template Pointer<N>(reinterpret_cast<char *>(this));
659
607k
  }
Unexecuted instantiation: std::__1::tuple_element<1ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<1ul>()
660
  template <size_type N>
661
101M
  inline const typename layout_type::template ElementType<N> *GetField() const {
662
101M
    assert(N < 4 || is_internal());
663
101M
    return InternalLayout().template Pointer<N>(
664
101M
        reinterpret_cast<const char *>(this));
665
101M
  }
std::__1::tuple_element<2ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type const* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<2ul>() const
Line
Count
Source
661
55.3M
  inline const typename layout_type::template ElementType<N> *GetField() const {
662
    assert(N < 4 || is_internal());
663
55.3M
    return InternalLayout().template Pointer<N>(
664
55.3M
        reinterpret_cast<const char *>(this));
665
55.3M
  }
Unexecuted instantiation: std::__1::tuple_element<1ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type const* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<1ul>() const
std::__1::tuple_element<0ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type const* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<0ul>() const
Line
Count
Source
661
5.08M
  inline const typename layout_type::template ElementType<N> *GetField() const {
662
    assert(N < 4 || is_internal());
663
5.08M
    return InternalLayout().template Pointer<N>(
664
5.08M
        reinterpret_cast<const char *>(this));
665
5.08M
  }
std::__1::tuple_element<4ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type const* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<4ul>() const
Line
Count
Source
661
2.06M
  inline const typename layout_type::template ElementType<N> *GetField() const {
662
    assert(N < 4 || is_internal());
663
2.06M
    return InternalLayout().template Pointer<N>(
664
2.06M
        reinterpret_cast<const char *>(this));
665
2.06M
  }
std::__1::tuple_element<3ul, std::__1::tuple<absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*, unsigned int, unsigned char, unsigned long, absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >*> >::type const* absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::GetField<3ul>() const
Line
Count
Source
661
38.5M
  inline const typename layout_type::template ElementType<N> *GetField() const {
662
    assert(N < 4 || is_internal());
663
38.5M
    return InternalLayout().template Pointer<N>(
664
38.5M
        reinterpret_cast<const char *>(this));
665
38.5M
  }
666
585k
  void set_parent(btree_node *p) { *GetField<0>() = p; }
667
44.9k
  field_type &mutable_finish() { return GetField<2>()[2]; }
668
14.3M
  slot_type *slot(size_type i) { return &GetField<3>()[i]; }
669
555k
  slot_type *start_slot() { return slot(start()); }
670
44.9k
  slot_type *finish_slot() { return slot(finish()); }
671
38.5M
  const slot_type *slot(size_type i) const { return &GetField<3>()[i]; }
672
728k
  void set_position(field_type v) { GetField<2>()[0] = v; }
673
555k
  void set_start(field_type v) { GetField<2>()[1] = v; }
674
4.23M
  void set_finish(field_type v) { GetField<2>()[2] = v; }
675
  // This method is only called by the node init methods.
676
564k
  void set_max_count(field_type v) { GetField<2>()[3] = v; }
677
678
 public:
679
  // Whether this is a leaf node or not. This value doesn't change after the
680
  // node is created.
681
17.2M
  bool is_leaf() const { return GetField<2>()[3] != kInternalNodeMaxCount; }
682
  // Whether this is an internal node or not. This value doesn't change after
683
  // the node is created.
684
5.26M
  bool is_internal() const { return !is_leaf(); }
685
686
  // Getter for the position of this node in its parent.
687
4.67M
  field_type position() const { return GetField<2>()[0]; }
688
689
  // Getter for the offset of the first value in the `values` array.
690
17.4M
  field_type start() const {
691
    // TODO(ezb): when floating storage is implemented, return GetField<2>()[1];
692
17.4M
    assert(GetField<2>()[1] == 0);
693
17.4M
    return 0;
694
17.4M
  }
695
696
  // Getter for the offset after the last value in the `values` array.
697
30.7M
  field_type finish() const { return GetField<2>()[2]; }
698
699
  // Getters for the number of values stored in this node.
700
4.63M
  field_type count() const {
701
4.63M
    assert(finish() >= start());
702
4.63M
    return finish() - start();
703
4.63M
  }
704
2.64M
  field_type max_count() const {
705
    // Internal nodes have max_count==kInternalNodeMaxCount.
706
    // Leaf nodes have max_count in [1, kNodeSlots].
707
2.64M
    const field_type max_count = GetField<2>()[3];
708
2.64M
    return max_count == field_type{kInternalNodeMaxCount}
709
2.64M
               ? field_type{kNodeSlots}
710
2.64M
               : max_count;
711
2.64M
  }
712
713
  // Getter for the parent of this node.
714
  // TODO(ezb): assert that the child of the returned node at position
715
  // `node_->position()` maps to the current node.
716
5.08M
  btree_node *parent() const { return *GetField<0>(); }
717
  // Getter for whether the node is the root of the tree. The parent of the
718
  // root of the tree is the leftmost node in the tree which is guaranteed to
719
  // be a leaf.
720
420k
  bool is_root() const { return parent()->is_leaf(); }
721
4.66k
  void make_root() {
722
4.66k
    assert(parent()->is_root());
723
4.66k
    set_generation(parent()->generation());
724
4.66k
    set_parent(parent()->parent());
725
4.66k
  }
726
727
  // Gets the root node's generation integer, which is the one used by the tree.
728
0
  uint32_t *get_root_generation() const {
729
0
    assert(BtreeGenerationsEnabled());
730
0
    const btree_node *curr = this;
731
0
    for (; !curr->is_root(); curr = curr->parent()) continue;
732
0
    return const_cast<uint32_t *>(&curr->GetField<1>()[0]);
733
0
  }
734
735
  // Returns the generation for iterator validation.
736
6.21M
  uint32_t generation() const {
737
6.21M
    return BtreeGenerationsEnabled() ? *get_root_generation() : 0;
738
6.21M
  }
739
  // Updates generation. Should only be called on a root node or during node
740
  // initialization.
741
806k
  void set_generation(uint32_t generation) {
742
806k
    if (BtreeGenerationsEnabled()) GetField<1>()[0] = generation;
743
806k
  }
744
  // Updates the generation. We do this whenever the node is mutated.
745
4.92M
  void next_generation() {
746
4.92M
    if (BtreeGenerationsEnabled()) ++*get_root_generation();
747
4.92M
  }
748
749
  // Getters for the key/value at position i in the node.
750
38.5M
  const key_type &key(size_type i) const { return params_type::key(slot(i)); }
751
3.84M
  reference value(size_type i) { return params_type::element(slot(i)); }
752
  const_reference value(size_type i) const {
753
    return params_type::element(slot(i));
754
  }
755
756
  // Getters/setter for the child at position i in the node.
757
2.06M
  btree_node *child(field_type i) const { return GetField<4>()[i]; }
758
10.2k
  btree_node *start_child() const { return child(start()); }
759
607k
  btree_node *&mutable_child(field_type i) { return GetField<4>()[i]; }
760
162k
  void clear_child(field_type i) {
761
162k
    absl::container_internal::SanitizerPoisonObject(&mutable_child(i));
762
162k
  }
763
217k
  void set_child_noupdate_position(field_type i, btree_node *c) {
764
217k
    absl::container_internal::SanitizerUnpoisonObject(&mutable_child(i));
765
217k
    mutable_child(i) = c;
766
217k
  }
767
172k
  void set_child(field_type i, btree_node *c) {
768
172k
    set_child_noupdate_position(i, c);
769
172k
    c->set_position(i);
770
172k
  }
771
25.3k
  void init_child(field_type i, btree_node *c) {
772
25.3k
    set_child(i, c);
773
25.3k
    c->set_parent(this);
774
25.3k
  }
775
776
  // Returns the position of the first value whose key is not less than k.
777
  template <typename K>
778
  SearchResult<size_type, is_key_compare_to::value> lower_bound(
779
3.67M
      const K &k, const key_compare &comp) const {
780
3.67M
    return use_linear_search::value ? linear_search(k, comp)
781
3.67M
                                    : binary_search(k, comp);
782
3.67M
  }
783
  // Returns the position of the first value whose key is greater than k.
784
  template <typename K>
785
  size_type upper_bound(const K &k, const key_compare &comp) const {
786
    auto upper_compare = upper_bound_adapter<key_compare>(comp);
787
    return use_linear_search::value ? linear_search(k, upper_compare).value
788
                                    : binary_search(k, upper_compare).value;
789
  }
790
791
  template <typename K, typename Compare>
792
  SearchResult<size_type, btree_is_key_compare_to<Compare, key_type>::value>
793
3.67M
  linear_search(const K &k, const Compare &comp) const {
794
3.67M
    return linear_search_impl(k, start(), finish(), comp,
795
3.67M
                              btree_is_key_compare_to<Compare, key_type>());
796
3.67M
  }
797
798
  template <typename K, typename Compare>
799
  SearchResult<size_type, btree_is_key_compare_to<Compare, key_type>::value>
800
0
  binary_search(const K &k, const Compare &comp) const {
801
0
    return binary_search_impl(k, start(), finish(), comp,
802
0
                              btree_is_key_compare_to<Compare, key_type>());
803
0
  }
804
805
  // Returns the position of the first value whose key is not less than k using
806
  // linear search performed using plain compare.
807
  template <typename K, typename Compare>
808
  SearchResult<size_type, false> linear_search_impl(
809
      const K &k, size_type s, const size_type e, const Compare &comp,
810
3.67M
      std::false_type /* IsCompareTo */) const {
811
42.2M
    while (s < e) {
812
38.5M
      if (!comp(key(s), k)) {
813
0
        break;
814
0
      }
815
38.5M
      ++s;
816
38.5M
    }
817
3.67M
    return SearchResult<size_type, false>{s};
818
3.67M
  }
819
820
  // Returns the position of the first value whose key is not less than k using
821
  // linear search performed using compare-to.
822
  template <typename K, typename Compare>
823
  SearchResult<size_type, true> linear_search_impl(
824
      const K &k, size_type s, const size_type e, const Compare &comp,
825
      std::true_type /* IsCompareTo */) const {
826
    while (s < e) {
827
      const absl::weak_ordering c = comp(key(s), k);
828
      if (c == 0) {
829
        return {s, MatchKind::kEq};
830
      } else if (c > 0) {
831
        break;
832
      }
833
      ++s;
834
    }
835
    return {s, MatchKind::kNe};
836
  }
837
838
  // Returns the position of the first value whose key is not less than k using
839
  // binary search performed using plain compare.
840
  template <typename K, typename Compare>
841
  SearchResult<size_type, false> binary_search_impl(
842
      const K &k, size_type s, size_type e, const Compare &comp,
843
0
      std::false_type /* IsCompareTo */) const {
844
0
    while (s != e) {
845
0
      const size_type mid = (s + e) >> 1;
846
0
      if (comp(key(mid), k)) {
847
0
        s = mid + 1;
848
0
      } else {
849
0
        e = mid;
850
0
      }
851
0
    }
852
0
    return SearchResult<size_type, false>{s};
853
0
  }
854
855
  // Returns the position of the first value whose key is not less than k using
856
  // binary search performed using compare-to.
857
  template <typename K, typename CompareTo>
858
  SearchResult<size_type, true> binary_search_impl(
859
      const K &k, size_type s, size_type e, const CompareTo &comp,
860
      std::true_type /* IsCompareTo */) const {
861
    if (params_type::template can_have_multiple_equivalent_keys<K>()) {
862
      MatchKind exact_match = MatchKind::kNe;
863
      while (s != e) {
864
        const size_type mid = (s + e) >> 1;
865
        const absl::weak_ordering c = comp(key(mid), k);
866
        if (c < 0) {
867
          s = mid + 1;
868
        } else {
869
          e = mid;
870
          if (c == 0) {
871
            // Need to return the first value whose key is not less than k,
872
            // which requires continuing the binary search if there could be
873
            // multiple equivalent keys.
874
            exact_match = MatchKind::kEq;
875
          }
876
        }
877
      }
878
      return {s, exact_match};
879
    } else {  // Can't have multiple equivalent keys.
880
      while (s != e) {
881
        const size_type mid = (s + e) >> 1;
882
        const absl::weak_ordering c = comp(key(mid), k);
883
        if (c < 0) {
884
          s = mid + 1;
885
        } else if (c > 0) {
886
          e = mid;
887
        } else {
888
          return {mid, MatchKind::kEq};
889
        }
890
      }
891
      return {s, MatchKind::kNe};
892
    }
893
  }
894
895
  // Returns whether key i is ordered correctly with respect to the other keys
896
  // in the node. The motivation here is to detect comparators that violate
897
  // transitivity. Note: we only do comparisons of keys on this node rather than
898
  // the whole tree so that this is constant time.
899
  template <typename Compare>
900
  bool is_ordered_correctly(field_type i, const Compare &comp) const {
901
    if (std::is_base_of<BtreeTestOnlyCheckedCompareOptOutBase,
902
                        Compare>::value ||
903
        params_type::kIsKeyCompareStringAdapted) {
904
      return true;
905
    }
906
907
    const auto compare = [&](field_type a, field_type b) {
908
      const absl::weak_ordering cmp =
909
          compare_internal::do_three_way_comparison(comp, key(a), key(b));
910
      return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
911
    };
912
    int cmp = -1;
913
    constexpr bool kCanHaveEquivKeys =
914
        params_type::template can_have_multiple_equivalent_keys<key_type>();
915
    for (field_type j = start(); j < finish(); ++j) {
916
      if (j == i) {
917
        if (cmp > 0) return false;
918
        continue;
919
      }
920
      int new_cmp = compare(j, i);
921
      if (new_cmp < cmp || (!kCanHaveEquivKeys && new_cmp == 0)) return false;
922
      cmp = new_cmp;
923
    }
924
    return true;
925
  }
926
927
  // Emplaces a value at position i, shifting all existing values and
928
  // children at positions >= i to the right by 1.
929
  template <typename... Args>
930
  void emplace_value(field_type i, allocator_type *alloc, Args &&...args);
931
932
  // Removes the values at positions [i, i + to_erase), shifting all existing
933
  // values and children after that range to the left by to_erase. Clears all
934
  // children between [i, i + to_erase).
935
  void remove_values(field_type i, field_type to_erase, allocator_type *alloc);
936
937
  // Rebalances a node with its right sibling.
938
  void rebalance_right_to_left(field_type to_move, btree_node *right,
939
                               allocator_type *alloc);
940
  void rebalance_left_to_right(field_type to_move, btree_node *right,
941
                               allocator_type *alloc);
942
943
  // Splits a node, moving a portion of the node's values to its right sibling.
944
  void split(int insert_position, btree_node *dest, allocator_type *alloc);
945
946
  // Merges a node with its right sibling, moving all of the values and the
947
  // delimiting key in the parent node onto itself, and deleting the src node.
948
  void merge(btree_node *src, allocator_type *alloc);
949
950
  // Node allocation/deletion routines.
951
  void init_leaf(field_type position, field_type max_count,
952
555k
                 btree_node *parent) {
953
555k
    set_generation(0);
954
555k
    set_parent(parent);
955
555k
    set_position(position);
956
555k
    set_start(0);
957
555k
    set_finish(0);
958
555k
    set_max_count(max_count);
959
555k
    absl::container_internal::SanitizerPoisonMemoryRegion(
960
555k
        start_slot(), max_count * sizeof(slot_type));
961
555k
  }
962
9.53k
  void init_internal(field_type position, btree_node *parent) {
963
9.53k
    init_leaf(position, kNodeSlots, parent);
964
    // Set `max_count` to a sentinel value to indicate that this node is
965
    // internal.
966
9.53k
    set_max_count(kInternalNodeMaxCount);
967
9.53k
    absl::container_internal::SanitizerPoisonMemoryRegion(
968
9.53k
        &mutable_child(start()), (kNodeSlots + 1) * sizeof(btree_node *));
969
9.53k
  }
970
971
  static void deallocate(const size_type size, btree_node *node,
972
555k
                         allocator_type *alloc) {
973
555k
    absl::container_internal::SanitizerUnpoisonMemoryRegion(node, size);
974
555k
    absl::container_internal::Deallocate<Alignment()>(alloc, node, size);
975
555k
  }
976
977
  // Deletes a node and all of its children.
978
  static void clear_and_delete(btree_node *node, allocator_type *alloc);
979
980
 private:
981
  template <typename... Args>
982
2.16M
  void value_init(const field_type i, allocator_type *alloc, Args &&...args) {
983
2.16M
    next_generation();
984
2.16M
    absl::container_internal::SanitizerUnpoisonObject(slot(i));
985
2.16M
    params_type::construct(alloc, slot(i), std::forward<Args>(args)...);
986
2.16M
  }
void absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::value_init<unsigned long*>(unsigned char, std::__1::allocator<unsigned long>*, unsigned long*&&)
Line
Count
Source
982
63.6k
  void value_init(const field_type i, allocator_type *alloc, Args &&...args) {
983
63.6k
    next_generation();
984
63.6k
    absl::container_internal::SanitizerUnpoisonObject(slot(i));
985
63.6k
    params_type::construct(alloc, slot(i), std::forward<Args>(args)...);
986
63.6k
  }
void absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::value_init<unsigned long>(unsigned char, std::__1::allocator<unsigned long>*, unsigned long&&)
Line
Count
Source
982
2.09M
  void value_init(const field_type i, allocator_type *alloc, Args &&...args) {
983
2.09M
    next_generation();
984
2.09M
    absl::container_internal::SanitizerUnpoisonObject(slot(i));
985
2.09M
    params_type::construct(alloc, slot(i), std::forward<Args>(args)...);
986
2.09M
  }
987
797k
  void value_destroy(const field_type i, allocator_type *alloc) {
988
797k
    next_generation();
989
797k
    params_type::destroy(alloc, slot(i));
990
797k
    absl::container_internal::SanitizerPoisonObject(slot(i));
991
797k
  }
992
  void value_destroy_n(const field_type i, const field_type n,
993
569k
                       allocator_type *alloc) {
994
569k
    next_generation();
995
1.93M
    for (slot_type *s = slot(i), *end = slot(i + n); s != end; ++s) {
996
1.36M
      params_type::destroy(alloc, s);
997
1.36M
      absl::container_internal::SanitizerPoisonObject(s);
998
1.36M
    }
999
569k
  }
1000
1001
11.8M
  static void transfer(slot_type *dest, slot_type *src, allocator_type *alloc) {
1002
11.8M
    absl::container_internal::SanitizerUnpoisonObject(dest);
1003
11.8M
    params_type::transfer(alloc, dest, src);
1004
11.8M
    absl::container_internal::SanitizerPoisonObject(src);
1005
11.8M
  }
1006
1007
  // Transfers value from slot `src_i` in `src_node` to slot `dest_i` in `this`.
1008
  void transfer(const size_type dest_i, const size_type src_i,
1009
168k
                btree_node *src_node, allocator_type *alloc) {
1010
168k
    next_generation();
1011
168k
    transfer(slot(dest_i), src_node->slot(src_i), alloc);
1012
168k
  }
1013
1014
  // Transfers `n` values starting at value `src_i` in `src_node` into the
1015
  // values starting at value `dest_i` in `this`.
1016
  void transfer_n(const size_type n, const size_type dest_i,
1017
                  const size_type src_i, btree_node *src_node,
1018
1.22M
                  allocator_type *alloc) {
1019
1.22M
    next_generation();
1020
1.22M
    for (slot_type *src = src_node->slot(src_i), *end = src + n,
1021
1.22M
                   *dest = slot(dest_i);
1022
12.8M
         src != end; ++src, ++dest) {
1023
11.6M
      transfer(dest, src, alloc);
1024
11.6M
    }
1025
1.22M
  }
1026
1027
  // Same as above, except that we start at the end and work our way to the
1028
  // beginning.
1029
  void transfer_n_backward(const size_type n, const size_type dest_i,
1030
                           const size_type src_i, btree_node *src_node,
1031
2.61k
                           allocator_type *alloc) {
1032
2.61k
    next_generation();
1033
2.61k
    for (slot_type *src = src_node->slot(src_i + n), *end = src - n,
1034
2.61k
                   *dest = slot(dest_i + n);
1035
36.9k
         src != end; --src, --dest) {
1036
      // If we modified the loop index calculations above to avoid the -1s here,
1037
      // it would result in UB in the computation of `end` (and possibly `src`
1038
      // as well, if n == 0), since slot() is effectively an array index and it
1039
      // is UB to compute the address of any out-of-bounds array element except
1040
      // for one-past-the-end.
1041
34.3k
      transfer(dest - 1, src - 1, alloc);
1042
34.3k
    }
1043
2.61k
  }
1044
1045
  template <typename P>
1046
  friend class btree;
1047
  template <typename N, typename R, typename P>
1048
  friend class btree_iterator;
1049
  friend class BtreeNodePeer;
1050
  friend struct btree_access;
1051
};
1052
1053
template <typename Node>
1054
bool AreNodesFromSameContainer(const Node *node_a, const Node *node_b) {
1055
  // If either node is null, then give up on checking whether they're from the
1056
  // same container. (If exactly one is null, then we'll trigger the
1057
  // default-constructed assert in Equals.)
1058
  if (node_a == nullptr || node_b == nullptr) return true;
1059
  while (!node_a->is_root()) node_a = node_a->parent();
1060
  while (!node_b->is_root()) node_b = node_b->parent();
1061
  return node_a == node_b;
1062
}
1063
1064
class btree_iterator_generation_info_enabled {
1065
 public:
1066
  explicit btree_iterator_generation_info_enabled(uint32_t g)
1067
0
      : generation_(g) {}
1068
1069
  // Updates the generation. For use internally right before we return an
1070
  // iterator to the user.
1071
  template <typename Node>
1072
  void update_generation(const Node *node) {
1073
    if (node != nullptr) generation_ = node->generation();
1074
  }
1075
0
  uint32_t generation() const { return generation_; }
1076
1077
  template <typename Node>
1078
  void assert_valid_generation(const Node *node) const {
1079
    if (node != nullptr && node->generation() != generation_) {
1080
      ABSL_INTERNAL_LOG(
1081
          FATAL,
1082
          "Attempting to use an invalidated iterator. The corresponding b-tree "
1083
          "container has been mutated since this iterator was constructed.");
1084
    }
1085
  }
1086
1087
 private:
1088
  // Used to check that the iterator hasn't been invalidated.
1089
  uint32_t generation_;
1090
};
1091
1092
class btree_iterator_generation_info_disabled {
1093
 public:
1094
5.96M
  explicit btree_iterator_generation_info_disabled(uint32_t) {}
1095
5.66M
  static void update_generation(const void *) {}
1096
0
  static uint32_t generation() { return 0; }
1097
15.4M
  static void assert_valid_generation(const void *) {}
1098
};
1099
1100
#ifdef ABSL_BTREE_ENABLE_GENERATIONS
1101
using btree_iterator_generation_info = btree_iterator_generation_info_enabled;
1102
#else
1103
using btree_iterator_generation_info = btree_iterator_generation_info_disabled;
1104
#endif
1105
1106
template <typename Node, typename Reference, typename Pointer>
1107
class btree_iterator : private btree_iterator_generation_info {
1108
  using field_type = typename Node::field_type;
1109
  using key_type = typename Node::key_type;
1110
  using size_type = typename Node::size_type;
1111
  using params_type = typename Node::params_type;
1112
  using is_map_container = typename params_type::is_map_container;
1113
1114
  using node_type = Node;
1115
  using normal_node = typename std::remove_const<Node>::type;
1116
  using const_node = const Node;
1117
  using normal_pointer = typename params_type::pointer;
1118
  using normal_reference = typename params_type::reference;
1119
  using const_pointer = typename params_type::const_pointer;
1120
  using const_reference = typename params_type::const_reference;
1121
  using slot_type = typename params_type::slot_type;
1122
1123
  // In sets, all iterators are const.
1124
  using iterator = std::conditional_t<
1125
      is_map_container::value,
1126
      btree_iterator<normal_node, normal_reference, normal_pointer>,
1127
      btree_iterator<normal_node, const_reference, const_pointer>>;
1128
  using const_iterator =
1129
      btree_iterator<const_node, const_reference, const_pointer>;
1130
1131
 public:
1132
  // These aliases are public for std::iterator_traits.
1133
  using difference_type = typename Node::difference_type;
1134
  using value_type = typename params_type::value_type;
1135
  using pointer = Pointer;
1136
  using reference = Reference;
1137
  using iterator_category = std::bidirectional_iterator_tag;
1138
1139
  btree_iterator() : btree_iterator(nullptr, -1) {}
1140
2.47M
  explicit btree_iterator(Node *n) : btree_iterator(n, n->start()) {}
1141
  btree_iterator(Node *n, int p)
1142
5.96M
      : btree_iterator_generation_info(n != nullptr ? n->generation()
1143
5.96M
                                                    : ~uint32_t{}),
1144
5.96M
        node_(n),
1145
5.96M
        position_(p) {}
1146
1147
  // NOTE: this SFINAE allows for implicit conversions from iterator to
1148
  // const_iterator, but it specifically avoids hiding the copy constructor so
1149
  // that the trivial one will be used when possible.
1150
  template <typename N, typename R, typename P,
1151
            std::enable_if_t<
1152
                std::is_same<btree_iterator<N, R, P>, iterator>::value &&
1153
                    std::is_same<btree_iterator, const_iterator>::value,
1154
                int> = 0>
1155
  btree_iterator(const btree_iterator<N, R, P> other)  // NOLINT
1156
4.22M
      : btree_iterator_generation_info(other),
1157
4.22M
        node_(other.node_),
1158
4.22M
        position_(other.position_) {}
1159
1160
  bool operator==(const iterator &other) const {
1161
    return Equals(other);
1162
  }
1163
  bool operator==(const const_iterator &other) const {
1164
    return Equals(other);
1165
  }
1166
4.22M
  bool operator!=(const iterator &other) const {
1167
4.22M
    return !Equals(other);
1168
4.22M
  }
1169
  bool operator!=(const const_iterator &other) const {
1170
    return !Equals(other);
1171
  }
1172
1173
  // Returns n such that n calls to ++other yields *this.
1174
  // Precondition: n exists.
1175
  difference_type operator-(const_iterator other) const {
1176
    if (node_ == other.node_) {
1177
      if (node_->is_leaf()) return position_ - other.position_;
1178
      if (position_ == other.position_) return 0;
1179
    }
1180
    return distance_slow(other);
1181
  }
1182
1183
  // Advances the iterator by `n`. Values of `n` must not result in going past
1184
  // the `end` iterator (for a positive `n`) or before the `begin` iterator (for
1185
  // a negative `n`).
1186
  btree_iterator &operator+=(difference_type n) {
1187
    assert_valid_generation(node_);
1188
    if (n == 0) return *this;
1189
    if (n < 0) return decrement_n_slow(-n);
1190
    return increment_n_slow(n);
1191
  }
1192
1193
  // Moves the iterator by `n` positions backwards. Values of `n` must not
1194
  // result in going before the `begin` iterator (for a positive `n`) or past
1195
  // the `end` iterator (for a negative `n`).
1196
  btree_iterator &operator-=(difference_type n) {
1197
    assert_valid_generation(node_);
1198
    if (n == 0) return *this;
1199
    if (n < 0) return increment_n_slow(-n);
1200
    return decrement_n_slow(n);
1201
  }
1202
1203
  // Accessors for the key/value the iterator is pointing at.
1204
3.84M
  reference operator*() const {
1205
3.84M
    absl::base_internal::HardeningAssertNonNull(node_);
1206
3.84M
    assert_valid_generation(node_);
1207
3.84M
    absl::base_internal::HardeningAssertGE(position_,
1208
3.84M
                                           static_cast<int>(node_->start()));
1209
3.84M
    if (position_ >= node_->finish()) {
1210
      // If this assertion fails, we have tried to dereference an end()
1211
      // iterator.
1212
0
      absl::base_internal::HardeningAssert(!IsEndIterator());
1213
0
      absl::base_internal::HardeningAssertLT(position_,
1214
0
                                             static_cast<int>(node_->finish()));
1215
0
    }
1216
3.84M
    return node_->value(static_cast<field_type>(position_));
1217
3.84M
  }
1218
  pointer operator->() const { return &operator*(); }
1219
1220
3.11M
  btree_iterator &operator++() {
1221
3.11M
    increment();
1222
3.11M
    return *this;
1223
3.11M
  }
1224
5.19k
  btree_iterator &operator--() {
1225
5.19k
    decrement();
1226
5.19k
    return *this;
1227
5.19k
  }
1228
  btree_iterator operator++(int) {
1229
    btree_iterator tmp = *this;
1230
    ++*this;
1231
    return tmp;
1232
  }
1233
  btree_iterator operator--(int) {
1234
    btree_iterator tmp = *this;
1235
    --*this;
1236
    return tmp;
1237
  }
1238
1239
 private:
1240
  friend iterator;
1241
  friend const_iterator;
1242
  template <typename Params>
1243
  friend class btree;
1244
  template <typename Tree>
1245
  friend class btree_container;
1246
  template <typename Tree>
1247
  friend class btree_set_container;
1248
  template <typename Tree>
1249
  friend class btree_map_container;
1250
  template <typename Tree>
1251
  friend class btree_multiset_container;
1252
  template <typename TreeType, typename CheckerType>
1253
  friend class base_checker;
1254
  friend struct btree_access;
1255
1256
  // This SFINAE allows explicit conversions from const_iterator to
1257
  // iterator, but also avoids hiding the copy constructor.
1258
  // NOTE: the const_cast is safe because this constructor is only called by
1259
  // non-const methods and the container owns the nodes.
1260
  template <typename N, typename R, typename P,
1261
            std::enable_if_t<
1262
                std::is_same<btree_iterator<N, R, P>, const_iterator>::value &&
1263
                    std::is_same<btree_iterator, iterator>::value,
1264
                int> = 0>
1265
  explicit btree_iterator(const btree_iterator<N, R, P> other)
1266
      : btree_iterator_generation_info(other.generation()),
1267
        node_(const_cast<node_type *>(other.node_)),
1268
        position_(other.position_) {}
1269
1270
4.22M
  bool Equals(const const_iterator other) const {
1271
4.22M
    absl::base_internal::HardeningAssert(
1272
4.22M
        ((node_ == nullptr && other.node_ == nullptr) ||
1273
4.22M
         (node_ != nullptr && other.node_ != nullptr)) &&
1274
4.22M
        "Comparing default-constructed iterator with "
1275
4.22M
        "non-default-constructed iterator.");
1276
    // Note: we use assert instead of ABSL_HARDENING_ASSERT here because this
1277
    // changes the complexity of Equals from O(1) to O(log(N) + log(M)) where
1278
    // N/M are sizes of the containers containing node_/other.node_.
1279
4.22M
    assert(AreNodesFromSameContainer(node_, other.node_) &&
1280
4.22M
           "Comparing iterators from different containers.");
1281
4.22M
    assert_valid_generation(node_);
1282
4.22M
    other.assert_valid_generation(other.node_);
1283
4.22M
    return node_ == other.node_ && position_ == other.position_;
1284
4.22M
  }
1285
1286
0
  bool IsEndIterator() const {
1287
0
    if (position_ != node_->finish()) return false;
1288
0
    node_type *node = node_;
1289
0
    while (!node->is_root()) {
1290
0
      if (node->position() != node->parent()->finish()) return false;
1291
0
      node = node->parent();
1292
0
    }
1293
0
    return true;
1294
0
  }
1295
1296
  // Returns n such that n calls to ++other yields *this.
1297
  // Precondition: n exists && (this->node_ != other.node_ ||
1298
  // !this->node_->is_leaf() || this->position_ != other.position_).
1299
  difference_type distance_slow(const_iterator other) const;
1300
1301
  // Increment/decrement the iterator.
1302
3.11M
  void increment() {
1303
3.11M
    assert_valid_generation(node_);
1304
3.11M
    if (node_->is_leaf() && ++position_ < node_->finish()) {
1305
2.64M
      return;
1306
2.64M
    }
1307
472k
    increment_slow();
1308
472k
  }
1309
  void increment_slow();
1310
  btree_iterator &increment_n_slow(difference_type n);
1311
1312
5.19k
  void decrement() {
1313
5.19k
    assert_valid_generation(node_);
1314
5.19k
    if (node_->is_leaf() && --position_ >= node_->start()) {
1315
0
      return;
1316
0
    }
1317
5.19k
    decrement_slow();
1318
5.19k
  }
1319
  void decrement_slow();
1320
  btree_iterator &decrement_n_slow(difference_type n);
1321
1322
0
  const key_type &key() const {
1323
0
    return node_->key(static_cast<size_type>(position_));
1324
0
  }
1325
  decltype(std::declval<Node *>()->slot(0)) slot() {
1326
    return node_->slot(static_cast<size_type>(position_));
1327
  }
1328
1329
5.66M
  void update_generation() {
1330
5.66M
    btree_iterator_generation_info::update_generation(node_);
1331
5.66M
  }
1332
1333
  // The node in the tree the iterator is pointing at.
1334
  Node *node_;
1335
  // The position within the node of the tree the iterator is pointing at.
1336
  // NOTE: this is an int rather than a field_type because iterators can point
1337
  // to invalid positions (such as -1) in certain circumstances.
1338
  int position_;
1339
};
1340
1341
template <typename Params>
1342
class btree {
1343
  using node_type = btree_node<Params>;
1344
  using is_key_compare_to = typename Params::is_key_compare_to;
1345
  using field_type = typename node_type::field_type;
1346
1347
  // We use a static empty node for the root/leftmost/rightmost of empty btrees
1348
  // in order to avoid branching in begin()/end().
1349
  struct EmptyNodeType : node_type {
1350
    using field_type = typename node_type::field_type;
1351
    node_type *parent;
1352
#ifdef ABSL_BTREE_ENABLE_GENERATIONS
1353
    uint32_t generation = 0;
1354
#endif
1355
    field_type position = 0;
1356
    field_type start = 0;
1357
    field_type finish = 0;
1358
    // max_count must be != kInternalNodeMaxCount (so that this node is regarded
1359
    // as a leaf node). max_count() is never called when the tree is empty.
1360
    field_type max_count = node_type::kInternalNodeMaxCount + 1;
1361
1362
    constexpr EmptyNodeType() : parent(this) {}
1363
  };
1364
1365
916k
  static node_type *EmptyNode() {
1366
916k
    alignas(node_type::Alignment()) static constexpr EmptyNodeType empty_node;
1367
916k
    return const_cast<EmptyNodeType *>(&empty_node);
1368
916k
  }
1369
1370
  enum : uint32_t {
1371
    kNodeSlots = node_type::kNodeSlots,
1372
    kMinNodeValues = kNodeSlots / 2,
1373
  };
1374
1375
  struct node_stats {
1376
    using size_type = typename Params::size_type;
1377
1378
    node_stats(size_type l, size_type i) : leaf_nodes(l), internal_nodes(i) {}
1379
1380
    node_stats &operator+=(const node_stats &other) {
1381
      leaf_nodes += other.leaf_nodes;
1382
      internal_nodes += other.internal_nodes;
1383
      return *this;
1384
    }
1385
1386
    size_type leaf_nodes;
1387
    size_type internal_nodes;
1388
  };
1389
1390
 public:
1391
  using key_type = typename Params::key_type;
1392
  using value_type = typename Params::value_type;
1393
  using size_type = typename Params::size_type;
1394
  using difference_type = typename Params::difference_type;
1395
  using key_compare = typename Params::key_compare;
1396
  using original_key_compare = typename Params::original_key_compare;
1397
  using value_compare = typename Params::value_compare;
1398
  using allocator_type = typename Params::allocator_type;
1399
  using reference = typename Params::reference;
1400
  using const_reference = typename Params::const_reference;
1401
  using pointer = typename Params::pointer;
1402
  using const_pointer = typename Params::const_pointer;
1403
  using iterator =
1404
      typename btree_iterator<node_type, reference, pointer>::iterator;
1405
  using const_iterator = typename iterator::const_iterator;
1406
  using reverse_iterator = std::reverse_iterator<iterator>;
1407
  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1408
  using node_handle_type = node_handle<Params, Params, allocator_type>;
1409
1410
  // Internal types made public for use by btree_container types.
1411
  using params_type = Params;
1412
  using slot_type = typename Params::slot_type;
1413
1414
 private:
1415
  // Copies or moves (depending on the template parameter) the values in
1416
  // other into this btree in their order in other. This btree must be empty
1417
  // before this method is called. This method is used in copy construction,
1418
  // copy assignment, and move assignment.
1419
  template <typename Btree>
1420
  void copy_or_move_values_in_order(Btree &other);
1421
1422
  // Validates that various assumptions/requirements are true at compile time.
1423
  constexpr static bool static_assert_validation();
1424
1425
 public:
1426
  btree(const key_compare &comp, const allocator_type &alloc)
1427
293k
      : root_(EmptyNode()), rightmost_(comp, alloc, EmptyNode()), size_(0) {}
1428
1429
  btree(const btree &other) : btree(other, other.allocator()) {}
1430
  btree(const btree &other, const allocator_type &alloc)
1431
      : btree(other.key_comp(), alloc) {
1432
    copy_or_move_values_in_order(other);
1433
  }
1434
  btree(btree &&other) noexcept
1435
      : root_(std::exchange(other.root_, EmptyNode())),
1436
        rightmost_(std::move(other.rightmost_)),
1437
        size_(std::exchange(other.size_, 0u)) {
1438
    other.mutable_rightmost() = EmptyNode();
1439
  }
1440
  btree(btree &&other, const allocator_type &alloc)
1441
      : btree(other.key_comp(), alloc) {
1442
    if (alloc == other.allocator()) {
1443
      swap(other);
1444
    } else {
1445
      // Move values from `other` one at a time when allocators are different.
1446
      copy_or_move_values_in_order(other);
1447
    }
1448
  }
1449
1450
293k
  ~btree() {
1451
    // Put static_asserts in destructor to avoid triggering them before the type
1452
    // is complete.
1453
293k
    static_assert(static_assert_validation(), "This call must be elided.");
1454
293k
    clear();
1455
293k
  }
1456
1457
  // Assign the contents of other to *this.
1458
  btree &operator=(const btree &other);
1459
  btree &operator=(btree &&other) noexcept;
1460
1461
380k
  iterator begin() { return iterator(leftmost()); }
1462
  const_iterator begin() const { return const_iterator(leftmost()); }
1463
3.34M
  iterator end() { return iterator(rightmost(), rightmost()->finish()); }
1464
  const_iterator end() const {
1465
    return const_iterator(rightmost(), rightmost()->finish());
1466
  }
1467
  reverse_iterator rbegin() { return reverse_iterator(end()); }
1468
  const_reverse_iterator rbegin() const {
1469
    return const_reverse_iterator(end());
1470
  }
1471
  reverse_iterator rend() { return reverse_iterator(begin()); }
1472
  const_reverse_iterator rend() const {
1473
    return const_reverse_iterator(begin());
1474
  }
1475
1476
  // Finds the first element whose key is not less than `key`.
1477
  template <typename K>
1478
  iterator lower_bound(const K &key) {
1479
    return internal_end(internal_lower_bound(key).value);
1480
  }
1481
  template <typename K>
1482
  const_iterator lower_bound(const K &key) const {
1483
    return internal_end(internal_lower_bound(key).value);
1484
  }
1485
1486
  // Finds the first element whose key is not less than `key` and also returns
1487
  // whether that element is equal to `key`.
1488
  template <typename K>
1489
  std::pair<iterator, bool> lower_bound_equal(const K &key) const;
1490
1491
  // Finds the first element whose key is greater than `key`.
1492
  template <typename K>
1493
  iterator upper_bound(const K &key) {
1494
    return internal_end(internal_upper_bound(key));
1495
  }
1496
  template <typename K>
1497
  const_iterator upper_bound(const K &key) const {
1498
    return internal_end(internal_upper_bound(key));
1499
  }
1500
1501
  // Finds the range of values which compare equal to key. The first member of
1502
  // the returned pair is equal to lower_bound(key). The second member of the
1503
  // pair is equal to upper_bound(key).
1504
  template <typename K>
1505
  std::pair<iterator, iterator> equal_range(const K &key);
1506
  template <typename K>
1507
  std::pair<const_iterator, const_iterator> equal_range(const K &key) const {
1508
    return const_cast<btree *>(this)->equal_range(key);
1509
  }
1510
1511
  // Inserts a value into the btree only if it does not already exist. The
1512
  // boolean return value indicates whether insertion succeeded or failed.
1513
  // Requirement: if `key` already exists in the btree, does not consume `args`.
1514
  // Requirement: `key` is never referenced after consuming `args`.
1515
  template <typename K, typename... Args>
1516
  std::pair<iterator, bool> insert_unique(const K &key, Args &&...args);
1517
1518
  // Inserts with hint. Checks to see if the value should be placed immediately
1519
  // before `position` in the tree. If so, then the insertion will take
1520
  // amortized constant time. If not, the insertion will take amortized
1521
  // logarithmic time as if a call to insert_unique() were made.
1522
  // Requirement: if `key` already exists in the btree, does not consume `args`.
1523
  // Requirement: `key` is never referenced after consuming `args`.
1524
  template <typename K, typename... Args>
1525
  std::pair<iterator, bool> insert_hint_unique(iterator position, const K &key,
1526
                                               Args &&...args);
1527
1528
  // Insert a range of values into the btree.
1529
  // Note: the first overload avoids constructing a value_type if the key
1530
  // already exists in the btree.
1531
  template <typename InputIterator,
1532
            typename = decltype(std::declval<const key_compare &>()(
1533
                params_type::key(*std::declval<InputIterator>()),
1534
                std::declval<const key_type &>()))>
1535
  void insert_iterator_unique(InputIterator b, InputIterator e, int);
1536
  // We need the second overload for cases in which we need to construct a
1537
  // value_type in order to compare it with the keys already in the btree.
1538
  template <typename InputIterator>
1539
  void insert_iterator_unique(InputIterator b, InputIterator e, char);
1540
1541
  // Inserts a value into the btree.
1542
  template <typename ValueType>
1543
  iterator insert_multi(const key_type &key, ValueType &&v);
1544
1545
  // Inserts a value into the btree.
1546
  template <typename ValueType>
1547
  iterator insert_multi(ValueType &&v) {
1548
    return insert_multi(params_type::key(v), std::forward<ValueType>(v));
1549
  }
1550
1551
  // Insert with hint. Check to see if the value should be placed immediately
1552
  // before position in the tree. If it does, then the insertion will take
1553
  // amortized constant time. If not, the insertion will take amortized
1554
  // logarithmic time as if a call to insert_multi(v) were made.
1555
  template <typename ValueType>
1556
  iterator insert_hint_multi(iterator position, ValueType &&v);
1557
1558
  // Insert a range of values into the btree.
1559
  template <typename InputIterator>
1560
  void insert_iterator_multi(InputIterator b,
1561
                             InputIterator e);
1562
1563
  // Erase the specified iterator from the btree. The iterator must be valid
1564
  // (i.e. not equal to end()).  Return an iterator pointing to the node after
1565
  // the one that was erased (or end() if none exists).
1566
  // Requirement: does not read the value at `*iter`.
1567
  iterator erase(iterator iter);
1568
1569
  // Erases range. Returns the number of keys erased and an iterator pointing
1570
  // to the element after the last erased element.
1571
  std::pair<size_type, iterator> erase_range(iterator begin, iterator end);
1572
1573
  // Finds an element with key equivalent to `key` or returns `end()` if `key`
1574
  // is not present.
1575
  template <typename K>
1576
  iterator find(const K &key) {
1577
    return internal_end(internal_find(key));
1578
  }
1579
  template <typename K>
1580
  const_iterator find(const K &key) const {
1581
    return internal_end(internal_find(key));
1582
  }
1583
1584
  // Clear the btree, deleting all of the values it contains.
1585
  void clear();
1586
1587
  // Swaps the contents of `this` and `other`.
1588
  void swap(btree &other);
1589
1590
3.67M
  const key_compare &key_comp() const noexcept {
1591
3.67M
    return rightmost_.template get<0>();
1592
3.67M
  }
1593
  template <typename K1, typename K2>
1594
0
  bool compare_keys(const K1 &a, const K2 &b) const {
1595
0
    return compare_internal::compare_result_as_less_than(key_comp()(a, b));
1596
0
  }
1597
1598
  value_compare value_comp() const {
1599
    return value_compare(original_key_compare(key_comp()));
1600
  }
1601
1602
  // Verifies the structure of the btree.
1603
  void verify() const;
1604
1605
  // Size routines.
1606
  size_type size() const { return size_; }
1607
  size_type max_size() const { return (std::numeric_limits<size_type>::max)(); }
1608
2.64M
  bool empty() const { return size_ == 0; }
1609
1610
  // The height of the btree. An empty tree will have height 0.
1611
  size_type height() const {
1612
    size_type h = 0;
1613
    if (!empty()) {
1614
      // Count the length of the chain from the leftmost node up to the
1615
      // root. We actually count from the root back around to the level below
1616
      // the root, but the calculation is the same because of the circularity
1617
      // of that traversal.
1618
      const node_type *n = root();
1619
      do {
1620
        ++h;
1621
        n = n->parent();
1622
      } while (n != root());
1623
    }
1624
    return h;
1625
  }
1626
1627
  // The number of internal, leaf and total nodes used by the btree.
1628
  size_type leaf_nodes() const { return internal_stats(root()).leaf_nodes; }
1629
  size_type internal_nodes() const {
1630
    return internal_stats(root()).internal_nodes;
1631
  }
1632
  size_type nodes() const {
1633
    node_stats stats = internal_stats(root());
1634
    return stats.leaf_nodes + stats.internal_nodes;
1635
  }
1636
1637
  // The total number of bytes used by the btree.
1638
  // TODO(b/169338300): update to support node_btree_*.
1639
  size_type bytes_used() const {
1640
    node_stats stats = internal_stats(root());
1641
    if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) {
1642
      return sizeof(*this) + node_type::LeafSize(root()->max_count());
1643
    } else {
1644
      return sizeof(*this) + stats.leaf_nodes * node_type::LeafSize() +
1645
             stats.internal_nodes * node_type::InternalSize();
1646
    }
1647
  }
1648
1649
  // The average number of bytes used per value stored in the btree assuming
1650
  // random insertion order.
1651
  static double average_bytes_per_value() {
1652
    // The expected number of values per node with random insertion order is the
1653
    // average of the maximum and minimum numbers of values per node.
1654
    const double expected_values_per_node = (kNodeSlots + kMinNodeValues) / 2.0;
1655
    return node_type::LeafSize() / expected_values_per_node;
1656
  }
1657
1658
  // The fullness of the btree. Computed as the number of elements in the btree
1659
  // divided by the maximum number of elements a tree with the current number
1660
  // of nodes could hold. A value of 1 indicates perfect space
1661
  // utilization. Smaller values indicate space wastage.
1662
  // Returns 0 for empty trees.
1663
  double fullness() const {
1664
    if (empty()) return 0.0;
1665
    return static_cast<double>(size()) / (nodes() * kNodeSlots);
1666
  }
1667
  // The overhead of the btree structure in bytes per node. Computed as the
1668
  // total number of bytes used by the btree minus the number of bytes used for
1669
  // storing elements divided by the number of elements.
1670
  // Returns 0 for empty trees.
1671
  double overhead() const {
1672
    if (empty()) return 0.0;
1673
    return (bytes_used() - size() * sizeof(value_type)) /
1674
           static_cast<double>(size());
1675
  }
1676
1677
  // The allocator used by the btree.
1678
  allocator_type get_allocator() const { return allocator(); }
1679
1680
 private:
1681
  friend struct btree_access;
1682
1683
  // Internal accessor routines.
1684
1.72M
  node_type *root() { return root_; }
1685
2.09M
  const node_type *root() const { return root_; }
1686
844k
  node_type *&mutable_root() noexcept { return root_; }
1687
6.75M
  node_type *rightmost() { return rightmost_.template get<2>(); }
1688
  const node_type *rightmost() const { return rightmost_.template get<2>(); }
1689
880k
  node_type *&mutable_rightmost() noexcept {
1690
880k
    return rightmost_.template get<2>();
1691
880k
  }
1692
  key_compare *mutable_key_comp() noexcept {
1693
    return &rightmost_.template get<0>();
1694
  }
1695
1696
  // The leftmost node is stored as the parent of the root node.
1697
380k
  node_type *leftmost() { return root()->parent(); }
1698
  const node_type *leftmost() const { return root()->parent(); }
1699
1700
  // Allocator routines.
1701
4.57M
  allocator_type *mutable_allocator() noexcept {
1702
4.57M
    return &rightmost_.template get<1>();
1703
4.57M
  }
1704
  const allocator_type &allocator() const noexcept {
1705
    return rightmost_.template get<1>();
1706
  }
1707
1708
  // Allocates a correctly aligned node of at least size bytes using the
1709
  // allocator.
1710
555k
  node_type *allocate(size_type size) {
1711
555k
    return reinterpret_cast<node_type *>(
1712
555k
        absl::container_internal::Allocate<node_type::Alignment()>(
1713
555k
            mutable_allocator(), size));
1714
555k
  }
1715
1716
  // Node creation/deletion routines.
1717
9.53k
  node_type *new_internal_node(field_type position, node_type *parent) {
1718
9.53k
    node_type *n = allocate(node_type::InternalSize());
1719
9.53k
    n->init_internal(position, parent);
1720
9.53k
    return n;
1721
9.53k
  }
1722
44.3k
  node_type *new_leaf_node(field_type position, node_type *parent) {
1723
44.3k
    node_type *n = allocate(node_type::LeafSize());
1724
44.3k
    n->init_leaf(position, kNodeSlots, parent);
1725
44.3k
    return n;
1726
44.3k
  }
1727
501k
  node_type *new_leaf_root_node(field_type max_count) {
1728
501k
    node_type *n = allocate(node_type::LeafSize(max_count));
1729
501k
    n->init_leaf(/*position=*/0, max_count, /*parent=*/n);
1730
501k
    return n;
1731
501k
  }
1732
1733
  // Deletion helper routines.
1734
  iterator rebalance_after_delete(iterator iter);
1735
1736
  // Rebalances or splits the node iter points to.
1737
  void rebalance_or_split(iterator *iter);
1738
1739
  // Merges the values of left, right and the delimiting key on their parent
1740
  // onto left, removing the delimiting key and deleting right.
1741
  void merge_nodes(node_type *left, node_type *right);
1742
1743
  // Tries to merge node with its left or right sibling, and failing that,
1744
  // rebalance with its left or right sibling. Returns true if a merge
1745
  // occurred, at which point it is no longer valid to access node. Returns
1746
  // false if no merging took place.
1747
  bool try_merge_or_rebalance(iterator *iter);
1748
1749
  // Tries to shrink the height of the tree by 1.
1750
  void try_shrink();
1751
1752
  iterator internal_end(iterator iter) {
1753
    return iter.node_ != nullptr ? iter : end();
1754
  }
1755
  const_iterator internal_end(const_iterator iter) const {
1756
    return iter.node_ != nullptr ? iter : end();
1757
  }
1758
1759
  // Emplaces a value into the btree immediately before iter. Requires that
1760
  // key(v) <= iter.key() and (--iter).key() <= key(v).
1761
  template <typename... Args>
1762
  iterator internal_emplace(iterator iter, Args &&...args);
1763
1764
  // Returns an iterator pointing to the first value >= the value "iter" is
1765
  // pointing at. Note that "iter" might be pointing to an invalid location such
1766
  // as iter.position_ == iter.node_->finish(). This routine simply moves iter
1767
  // up in the tree to a valid location. Requires: iter.node_ is non-null.
1768
  template <typename IterType>
1769
  static IterType internal_last(IterType iter);
1770
1771
  // Returns an iterator pointing to the leaf position at which key would
1772
  // reside in the tree, unless there is an exact match - in which case, the
1773
  // result may not be on a leaf. When there's a three-way comparator, we can
1774
  // return whether there was an exact match. This allows the caller to avoid a
1775
  // subsequent comparison to determine if an exact match was made, which is
1776
  // important for keys with expensive comparison, such as strings.
1777
  template <typename K>
1778
  SearchResult<iterator, is_key_compare_to::value> internal_locate(
1779
      const K &key) const;
1780
1781
  // Internal routine which implements lower_bound().
1782
  template <typename K>
1783
  SearchResult<iterator, is_key_compare_to::value> internal_lower_bound(
1784
      const K &key) const;
1785
1786
  // Internal routine which implements upper_bound().
1787
  template <typename K>
1788
  iterator internal_upper_bound(const K &key) const;
1789
1790
  // Internal routine which implements find().
1791
  template <typename K>
1792
  iterator internal_find(const K &key) const;
1793
1794
  // Verifies the tree structure of node.
1795
  size_type internal_verify(const node_type *node, const key_type *lo,
1796
                            const key_type *hi) const;
1797
1798
  node_stats internal_stats(const node_type *node) const {
1799
    // The root can be a static empty node.
1800
    if (node == nullptr || (node == root() && empty())) {
1801
      return node_stats(0, 0);
1802
    }
1803
    if (node->is_leaf()) {
1804
      return node_stats(1, 0);
1805
    }
1806
    node_stats res(0, 1);
1807
    for (int i = node->start(); i <= node->finish(); ++i) {
1808
      res += internal_stats(node->child(i));
1809
    }
1810
    return res;
1811
  }
1812
1813
  node_type *root_;
1814
1815
  // A pointer to the rightmost node. Note that the leftmost node is stored as
1816
  // the root's parent. We use compressed tuple in order to save space because
1817
  // key_compare and allocator_type are usually empty.
1818
  absl::container_internal::CompressedTuple<key_compare, allocator_type,
1819
                                            node_type *>
1820
      rightmost_;
1821
1822
  // Number of values.
1823
  size_type size_;
1824
};
1825
1826
////
1827
// btree_node methods
1828
template <typename P>
1829
template <typename... Args>
1830
inline void btree_node<P>::emplace_value(const field_type i,
1831
                                         allocator_type *alloc,
1832
2.14M
                                         Args &&...args) {
1833
2.14M
  assert(i >= start());
1834
2.14M
  assert(i <= finish());
1835
  // Shift old values to create space for new value and then construct it in
1836
  // place.
1837
2.14M
  if (i < finish()) {
1838
0
    transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this,
1839
0
                        alloc);
1840
0
  }
1841
2.14M
  value_init(static_cast<field_type>(i), alloc, std::forward<Args>(args)...);
1842
2.14M
  set_finish(finish() + 1);
1843
1844
2.14M
  if (is_internal() && finish() > i + 1) {
1845
0
    for (field_type j = finish(); j > i + 1; --j) {
1846
0
      set_child(j, child(j - 1));
1847
0
    }
1848
0
    clear_child(i + 1);
1849
0
  }
1850
2.14M
}
void absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::emplace_value<unsigned long*>(unsigned char, std::__1::allocator<unsigned long>*, unsigned long*&&)
Line
Count
Source
1832
44.9k
                                         Args &&...args) {
1833
44.9k
  assert(i >= start());
1834
44.9k
  assert(i <= finish());
1835
  // Shift old values to create space for new value and then construct it in
1836
  // place.
1837
44.9k
  if (i < finish()) {
1838
0
    transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this,
1839
0
                        alloc);
1840
0
  }
1841
44.9k
  value_init(static_cast<field_type>(i), alloc, std::forward<Args>(args)...);
1842
44.9k
  set_finish(finish() + 1);
1843
1844
44.9k
  if (is_internal() && finish() > i + 1) {
1845
0
    for (field_type j = finish(); j > i + 1; --j) {
1846
0
      set_child(j, child(j - 1));
1847
0
    }
1848
0
    clear_child(i + 1);
1849
0
  }
1850
44.9k
}
void absl::lts_20260526::container_internal::btree_node<absl::lts_20260526::container_internal::set_params_impl<unsigned long> >::emplace_value<unsigned long>(unsigned char, std::__1::allocator<unsigned long>*, unsigned long&&)
Line
Count
Source
1832
2.09M
                                         Args &&...args) {
1833
2.09M
  assert(i >= start());
1834
2.09M
  assert(i <= finish());
1835
  // Shift old values to create space for new value and then construct it in
1836
  // place.
1837
2.09M
  if (i < finish()) {
1838
0
    transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this,
1839
0
                        alloc);
1840
0
  }
1841
2.09M
  value_init(static_cast<field_type>(i), alloc, std::forward<Args>(args)...);
1842
2.09M
  set_finish(finish() + 1);
1843
1844
2.09M
  if (is_internal() && finish() > i + 1) {
1845
0
    for (field_type j = finish(); j > i + 1; --j) {
1846
0
      set_child(j, child(j - 1));
1847
0
    }
1848
0
    clear_child(i + 1);
1849
0
  }
1850
2.09M
}
1851
1852
template <typename P>
1853
inline void btree_node<P>::remove_values(const field_type i,
1854
                                         const field_type to_erase,
1855
18.6k
                                         allocator_type *alloc) {
1856
  // Transfer values after the removed range into their new places.
1857
18.6k
  value_destroy_n(i, to_erase, alloc);
1858
18.6k
  const field_type orig_finish = finish();
1859
18.6k
  const field_type src_i = i + to_erase;
1860
18.6k
  transfer_n(orig_finish - src_i, i, src_i, this, alloc);
1861
1862
18.6k
  if (is_internal()) {
1863
    // Delete all children between begin and end.
1864
37.3k
    for (field_type j = 0; j < to_erase; ++j) {
1865
18.6k
      clear_and_delete(child(i + j + 1), alloc);
1866
18.6k
    }
1867
    // Rotate children after end into new positions.
1868
166k
    for (field_type j = i + to_erase + 1; j <= orig_finish; ++j) {
1869
147k
      set_child(j - to_erase, child(j));
1870
147k
      clear_child(j);
1871
147k
    }
1872
18.6k
  }
1873
18.6k
  set_finish(orig_finish - to_erase);
1874
18.6k
}
1875
1876
template <typename P>
1877
void btree_node<P>::rebalance_right_to_left(field_type to_move,
1878
                                            btree_node *right,
1879
79.1k
                                            allocator_type *alloc) {
1880
79.1k
  assert(parent() == right->parent());
1881
79.1k
  assert(position() + 1 == right->position());
1882
79.1k
  assert(right->count() >= count());
1883
79.1k
  assert(to_move >= 1);
1884
79.1k
  assert(to_move <= right->count());
1885
1886
  // 1) Move the delimiting value in the parent to the left node.
1887
79.1k
  transfer(finish(), position(), parent(), alloc);
1888
1889
  // 2) Move the (to_move - 1) values from the right node to the left node.
1890
79.1k
  transfer_n(to_move - 1, finish() + 1, right->start(), right, alloc);
1891
1892
  // 3) Move the new delimiting value to the parent from the right node.
1893
79.1k
  parent()->transfer(position(), right->start() + to_move - 1, right, alloc);
1894
1895
  // 4) Shift the values in the right node to their correct positions.
1896
79.1k
  right->transfer_n(right->count() - to_move, right->start(),
1897
79.1k
                    right->start() + to_move, right, alloc);
1898
1899
79.1k
  if (is_internal()) {
1900
    // Move the child pointers from the right to the left node.
1901
1.49k
    for (field_type i = 0; i < to_move; ++i) {
1902
1.05k
      init_child(finish() + i + 1, right->child(i));
1903
1.05k
    }
1904
11.8k
    for (field_type i = right->start(); i <= right->finish() - to_move; ++i) {
1905
11.4k
      assert(i + to_move <= right->max_count());
1906
11.4k
      right->init_child(i, right->child(i + to_move));
1907
11.4k
      right->clear_child(i + to_move);
1908
11.4k
    }
1909
439
  }
1910
1911
  // Fixup `finish` on the left and right nodes.
1912
79.1k
  set_finish(finish() + to_move);
1913
79.1k
  right->set_finish(right->finish() - to_move);
1914
79.1k
}
1915
1916
template <typename P>
1917
void btree_node<P>::rebalance_left_to_right(field_type to_move,
1918
                                            btree_node *right,
1919
2.61k
                                            allocator_type *alloc) {
1920
2.61k
  assert(parent() == right->parent());
1921
2.61k
  assert(position() + 1 == right->position());
1922
2.61k
  assert(count() >= right->count());
1923
2.61k
  assert(to_move >= 1);
1924
2.61k
  assert(to_move <= count());
1925
1926
  // Values in the right node are shifted to the right to make room for the
1927
  // new to_move values. Then, the delimiting value in the parent and the
1928
  // other (to_move - 1) values in the left node are moved into the right node.
1929
  // Lastly, a new delimiting value is moved from the left node into the
1930
  // parent, and the remaining empty left node entries are destroyed.
1931
1932
  // 1) Shift existing values in the right node to their correct positions.
1933
2.61k
  right->transfer_n_backward(right->count(), right->start() + to_move,
1934
2.61k
                             right->start(), right, alloc);
1935
1936
  // 2) Move the delimiting value in the parent to the right node.
1937
2.61k
  right->transfer(right->start() + to_move - 1, position(), parent(), alloc);
1938
1939
  // 3) Move the (to_move - 1) values from the left node to the right node.
1940
2.61k
  right->transfer_n(to_move - 1, right->start(), finish() - (to_move - 1), this,
1941
2.61k
                    alloc);
1942
1943
  // 4) Move the new delimiting value to the parent from the left node.
1944
2.61k
  parent()->transfer(position(), finish() - to_move, this, alloc);
1945
1946
2.61k
  if (is_internal()) {
1947
    // Move the child pointers from the left to the right node.
1948
307
    for (field_type i = right->finish() + 1; i > right->start(); --i) {
1949
280
      right->init_child(i - 1 + to_move, right->child(i - 1));
1950
280
      right->clear_child(i - 1);
1951
280
    }
1952
193
    for (field_type i = 1; i <= to_move; ++i) {
1953
166
      right->init_child(i - 1, child(finish() - to_move + i));
1954
166
      clear_child(finish() - to_move + i);
1955
166
    }
1956
27
  }
1957
1958
  // Fixup the counts on the left and right nodes.
1959
2.61k
  set_finish(finish() - to_move);
1960
2.61k
  right->set_finish(right->finish() + to_move);
1961
2.61k
}
1962
1963
template <typename P>
1964
void btree_node<P>::split(const int insert_position, btree_node *dest,
1965
44.9k
                          allocator_type *alloc) {
1966
44.9k
  assert(dest->count() == 0);
1967
44.9k
  assert(max_count() == kNodeSlots);
1968
44.9k
  assert(position() + 1 == dest->position());
1969
44.9k
  assert(parent() == dest->parent());
1970
1971
  // We bias the split based on the position being inserted. If we're
1972
  // inserting at the beginning of the left node then bias the split to put
1973
  // more values on the right node. If we're inserting at the end of the
1974
  // right node then bias the split to put more values on the left node.
1975
44.9k
  if (insert_position == start()) {
1976
0
    dest->set_finish(dest->start() + finish() - 1);
1977
44.9k
  } else if (insert_position == kNodeSlots) {
1978
44.9k
    dest->set_finish(dest->start());
1979
44.9k
  } else {
1980
0
    dest->set_finish(dest->start() + count() / 2);
1981
0
  }
1982
44.9k
  set_finish(finish() - dest->count());
1983
44.9k
  assert(count() >= 1);
1984
1985
  // Move values from the left sibling to the right sibling.
1986
44.9k
  dest->transfer_n(dest->count(), dest->start(), finish(), this, alloc);
1987
1988
  // The split key is the largest value in the left sibling.
1989
44.9k
  --mutable_finish();
1990
44.9k
  parent()->emplace_value(position(), alloc, finish_slot());
1991
44.9k
  value_destroy(finish(), alloc);
1992
44.9k
  parent()->set_child_noupdate_position(position() + 1, dest);
1993
1994
44.9k
  if (is_internal()) {
1995
1.21k
    for (field_type i = dest->start(), j = finish() + 1; i <= dest->finish();
1996
608
         ++i, ++j) {
1997
608
      assert(child(j) != nullptr);
1998
608
      dest->init_child(i, child(j));
1999
608
      clear_child(j);
2000
608
    }
2001
608
  }
2002
44.9k
}
2003
2004
template <typename P>
2005
18.6k
void btree_node<P>::merge(btree_node *src, allocator_type *alloc) {
2006
18.6k
  assert(parent() == src->parent());
2007
18.6k
  assert(position() + 1 == src->position());
2008
2009
  // Move the delimiting value to the left node.
2010
18.6k
  value_init(finish(), alloc, parent()->slot(position()));
2011
2012
  // Move the values from the right to the left node.
2013
18.6k
  transfer_n(src->count(), finish() + 1, src->start(), src, alloc);
2014
2015
18.6k
  if (is_internal()) {
2016
    // Move the child pointers from the right to the left node.
2017
3.06k
    for (field_type i = src->start(), j = finish() + 1; i <= src->finish();
2018
2.86k
         ++i, ++j) {
2019
2.86k
      init_child(j, src->child(i));
2020
2.86k
      src->clear_child(i);
2021
2.86k
    }
2022
204
  }
2023
2024
  // Fixup `finish` on the src and dest nodes.
2025
18.6k
  set_finish(start() + 1 + count() + src->count());
2026
18.6k
  src->set_finish(src->start());
2027
2028
  // Remove the value on the parent node and delete the src node.
2029
18.6k
  parent()->remove_values(position(), /*to_erase=*/1, alloc);
2030
18.6k
}
2031
2032
template <typename P>
2033
524k
void btree_node<P>::clear_and_delete(btree_node *node, allocator_type *alloc) {
2034
524k
  if (node->is_leaf()) {
2035
516k
    node->value_destroy_n(node->start(), node->count(), alloc);
2036
516k
    deallocate(LeafSize(node->max_count()), node, alloc);
2037
516k
    return;
2038
516k
  }
2039
8.94k
  if (node->count() == 0) {
2040
4.87k
    deallocate(InternalSize(), node, alloc);
2041
4.87k
    return;
2042
4.87k
  }
2043
2044
  // The parent of the root of the subtree we are deleting.
2045
4.07k
  btree_node *delete_root_parent = node->parent();
2046
2047
  // Navigate to the leftmost leaf under node, and then delete upwards.
2048
8.33k
  while (node->is_internal()) node = node->start_child();
2049
#ifdef ABSL_BTREE_ENABLE_GENERATIONS
2050
  // When generations are enabled, we delete the leftmost leaf last in case it's
2051
  // the parent of the root and we need to check whether it's a leaf before we
2052
  // can update the root's generation.
2053
  // TODO(ezb): if we change btree_node::is_root to check a bool inside the node
2054
  // instead of checking whether the parent is a leaf, we can remove this logic.
2055
  btree_node *leftmost_leaf = node;
2056
#endif
2057
  // Use `size_type` because `pos` needs to be able to hold `kNodeSlots+1`,
2058
  // which isn't guaranteed to be a valid `field_type`.
2059
4.07k
  size_type pos = node->position();
2060
4.07k
  btree_node *parent = node->parent();
2061
4.47k
  for (;;) {
2062
    // In each iteration of the next loop, we delete one leaf node and go right.
2063
4.47k
    assert(pos <= parent->finish());
2064
29.8k
    do {
2065
29.8k
      node = parent->child(static_cast<field_type>(pos));
2066
29.8k
      if (node->is_internal()) {
2067
        // Navigate to the leftmost leaf under node.
2068
808
        while (node->is_internal()) node = node->start_child();
2069
404
        pos = node->position();
2070
404
        parent = node->parent();
2071
404
      }
2072
29.8k
      node->value_destroy_n(node->start(), node->count(), alloc);
2073
#ifdef ABSL_BTREE_ENABLE_GENERATIONS
2074
      if (leftmost_leaf != node)
2075
#endif
2076
29.8k
        deallocate(LeafSize(node->max_count()), node, alloc);
2077
29.8k
      ++pos;
2078
29.8k
    } while (pos <= parent->finish());
2079
2080
    // Once we've deleted all children of parent, delete parent and go up/right.
2081
4.47k
    assert(pos > parent->finish());
2082
4.66k
    do {
2083
4.66k
      node = parent;
2084
4.66k
      pos = node->position();
2085
4.66k
      parent = node->parent();
2086
4.66k
      node->value_destroy_n(node->start(), node->count(), alloc);
2087
4.66k
      deallocate(InternalSize(), node, alloc);
2088
4.66k
      if (parent == delete_root_parent) {
2089
#ifdef ABSL_BTREE_ENABLE_GENERATIONS
2090
        deallocate(LeafSize(leftmost_leaf->max_count()), leftmost_leaf, alloc);
2091
#endif
2092
4.07k
        return;
2093
4.07k
      }
2094
593
      ++pos;
2095
593
    } while (pos > parent->finish());
2096
4.47k
  }
2097
4.07k
}
2098
2099
////
2100
// btree_iterator methods
2101
2102
// Note: the implementation here is based on btree_node::clear_and_delete.
2103
template <typename N, typename R, typename P>
2104
auto btree_iterator<N, R, P>::distance_slow(const_iterator other) const
2105
    -> difference_type {
2106
  const_iterator begin = other;
2107
  const_iterator end = *this;
2108
  assert(begin.node_ != end.node_ || !begin.node_->is_leaf() ||
2109
         begin.position_ != end.position_);
2110
2111
  const node_type *node = begin.node_;
2112
  // We need to compensate for double counting if begin.node_ is a leaf node.
2113
  difference_type count = node->is_leaf() ? -begin.position_ : 0;
2114
2115
  // First navigate to the leftmost leaf node past begin.
2116
  if (node->is_internal()) {
2117
    ++count;
2118
    node = node->child(begin.position_ + 1);
2119
  }
2120
  while (node->is_internal()) node = node->start_child();
2121
2122
  // Use `size_type` because `pos` needs to be able to hold `kNodeSlots+1`,
2123
  // which isn't guaranteed to be a valid `field_type`.
2124
  size_type pos = node->position();
2125
  const node_type *parent = node->parent();
2126
  for (;;) {
2127
    // In each iteration of the next loop, we count one leaf node and go right.
2128
    assert(pos <= parent->finish());
2129
    do {
2130
      node = parent->child(static_cast<field_type>(pos));
2131
      if (node->is_internal()) {
2132
        // Navigate to the leftmost leaf under node.
2133
        while (node->is_internal()) node = node->start_child();
2134
        pos = node->position();
2135
        parent = node->parent();
2136
      }
2137
      if (node == end.node_) return count + end.position_;
2138
      if (parent == end.node_ && pos == static_cast<size_type>(end.position_))
2139
        return count + node->count();
2140
      // +1 is for the next internal node value.
2141
      count += node->count() + 1;
2142
      ++pos;
2143
    } while (pos <= parent->finish());
2144
2145
    // Once we've counted all children of parent, go up/right.
2146
    assert(pos > parent->finish());
2147
    do {
2148
      node = parent;
2149
      pos = node->position();
2150
      parent = node->parent();
2151
      // -1 because we counted the value at end and shouldn't.
2152
      if (parent == end.node_ && pos == static_cast<size_type>(end.position_))
2153
        return count - 1;
2154
      ++pos;
2155
    } while (pos > parent->finish());
2156
  }
2157
}
2158
2159
template <typename N, typename R, typename P>
2160
472k
void btree_iterator<N, R, P>::increment_slow() {
2161
472k
  N* node = node_;
2162
472k
  int position = position_;
2163
472k
  if (node->is_leaf()) {
2164
405k
    assert(position >= node->finish());
2165
493k
    while (position == node->finish() && !node->is_root()) {
2166
88.1k
      assert(node->parent()->child(node->position()) == node);
2167
88.1k
      position = node->position();
2168
88.1k
      node = node->parent();
2169
88.1k
    }
2170
    // TODO(ezb): assert we aren't incrementing end() instead of handling.
2171
405k
    if (position == node->finish()) {
2172
332k
      return;
2173
332k
    }
2174
405k
  } else {
2175
67.5k
    assert(position < node->finish());
2176
67.5k
    node = node->child(static_cast<field_type>(position + 1));
2177
68.3k
    while (node->is_internal()) {
2178
878
      node = node->start_child();
2179
878
    }
2180
67.5k
    position = node->start();
2181
67.5k
  }
2182
140k
  *this = {node, position};
2183
140k
}
2184
2185
template <typename N, typename R, typename P>
2186
5.19k
void btree_iterator<N, R, P>::decrement_slow() {
2187
5.19k
  N* node = node_;
2188
5.19k
  int position = position_;
2189
5.19k
  if (node->is_leaf()) {
2190
0
    assert(position <= -1);
2191
0
    while (position < node->start() && !node->is_root()) {
2192
0
      assert(node->parent()->child(node->position()) == node);
2193
0
      position = node->position() - 1;
2194
0
      node = node->parent();
2195
0
    }
2196
    // TODO(ezb): assert we aren't decrementing begin() instead of handling.
2197
0
    if (position < node->start()) {
2198
0
      return;
2199
0
    }
2200
5.19k
  } else {
2201
5.19k
    assert(position >= node->start());
2202
5.19k
    node = node->child(static_cast<field_type>(position));
2203
5.21k
    while (node->is_internal()) {
2204
22
      node = node->child(node->finish());
2205
22
    }
2206
5.19k
    position = node->finish() - 1;
2207
5.19k
  }
2208
5.19k
  *this = {node, position};
2209
5.19k
}
2210
2211
template <typename N, typename R, typename P>
2212
btree_iterator<N, R, P> &btree_iterator<N, R, P>::increment_n_slow(
2213
    difference_type n) {
2214
  N *node = node_;
2215
  int position = position_;
2216
  ABSL_ASSUME(n > 0);
2217
  while (n > 0) {
2218
    if (node->is_leaf()) {
2219
      if (position + n < node->finish()) {
2220
        position += n;
2221
        break;
2222
      } else {
2223
        n -= node->finish() - position;
2224
        position = node->finish();
2225
        btree_iterator save = {node, position};
2226
        while (position == node->finish() && !node->is_root()) {
2227
          position = node->position();
2228
          node = node->parent();
2229
        }
2230
        if (position == node->finish()) {
2231
          absl::base_internal::HardeningAssert(n == 0);
2232
          return *this = save;
2233
        }
2234
      }
2235
    } else {
2236
      --n;
2237
      assert(position < node->finish());
2238
      node = node->child(static_cast<field_type>(position + 1));
2239
      while (node->is_internal()) {
2240
        node = node->start_child();
2241
      }
2242
      position = node->start();
2243
    }
2244
  }
2245
  node_ = node;
2246
  position_ = position;
2247
  return *this;
2248
}
2249
2250
template <typename N, typename R, typename P>
2251
btree_iterator<N, R, P> &btree_iterator<N, R, P>::decrement_n_slow(
2252
    difference_type n) {
2253
  N *node = node_;
2254
  int position = position_;
2255
  ABSL_ASSUME(n > 0);
2256
  while (n > 0) {
2257
    if (node->is_leaf()) {
2258
      if (position - n >= node->start()) {
2259
        position -= n;
2260
        break;
2261
      } else {
2262
        n -= 1 + position - node->start();
2263
        position = node->start() - 1;
2264
        while (position < node->start() && !node->is_root()) {
2265
          position = node->position() - 1;
2266
          node = node->parent();
2267
        }
2268
        absl::base_internal::HardeningAssertGE(position,
2269
                                               static_cast<int>(node->start()));
2270
      }
2271
    } else {
2272
      --n;
2273
      assert(position >= node->start());
2274
      node = node->child(static_cast<field_type>(position));
2275
      while (node->is_internal()) {
2276
        node = node->child(node->finish());
2277
      }
2278
      position = node->finish() - 1;
2279
    }
2280
  }
2281
  node_ = node;
2282
  position_ = position;
2283
  return *this;
2284
}
2285
2286
////
2287
// btree methods
2288
template <typename P>
2289
template <typename Btree>
2290
void btree<P>::copy_or_move_values_in_order(Btree &other) {
2291
  static_assert(std::is_same<btree, Btree>::value ||
2292
                    std::is_same<const btree, Btree>::value,
2293
                "Btree type must be same or const.");
2294
  assert(empty());
2295
2296
  // We can avoid key comparisons because we know the order of the
2297
  // values is the same order we'll store them in.
2298
  auto iter = other.begin();
2299
  if (iter == other.end()) return;
2300
  insert_multi(iter.slot());
2301
  ++iter;
2302
  for (; iter != other.end(); ++iter) {
2303
    // If the btree is not empty, we can just insert the new value at the end
2304
    // of the tree.
2305
    internal_emplace(end(), iter.slot());
2306
  }
2307
}
2308
2309
template <typename P>
2310
0
constexpr bool btree<P>::static_assert_validation() {
2311
0
  static_assert(std::is_nothrow_copy_constructible<key_compare>::value,
2312
0
                "Key comparison must be nothrow copy constructible");
2313
0
  static_assert(std::is_nothrow_copy_constructible<allocator_type>::value,
2314
0
                "Allocator must be nothrow copy constructible");
2315
0
  static_assert(std::is_trivially_copyable<iterator>::value,
2316
0
                "iterator not trivially copyable.");
2317
0
2318
0
  // Note: We assert that kTargetValues, which is computed from
2319
0
  // Params::kTargetNodeSize, must fit the node_type::field_type.
2320
0
  static_assert(
2321
0
      kNodeSlots < (1 << (8 * sizeof(typename node_type::field_type))),
2322
0
      "target node size too large");
2323
0
2324
0
  // Verify that key_compare returns an absl::{weak,strong}_ordering or bool.
2325
0
  static_assert(
2326
0
      compare_has_valid_result_type<key_compare, key_type>(),
2327
0
      "key comparison function must return absl::{weak,strong}_ordering or "
2328
0
      "bool.");
2329
0
2330
0
  // Test the assumption made in setting kNodeSlotSpace.
2331
0
  static_assert(node_type::MinimumOverhead() >= sizeof(void *) + 4,
2332
0
                "node space assumption incorrect");
2333
0
2334
0
  return true;
2335
0
}
2336
2337
template <typename P>
2338
template <typename K>
2339
auto btree<P>::lower_bound_equal(const K &key) const
2340
    -> std::pair<iterator, bool> {
2341
  const SearchResult<iterator, is_key_compare_to::value> res =
2342
      internal_lower_bound(key);
2343
  const iterator lower = iterator(internal_end(res.value));
2344
  const bool equal = res.HasMatch()
2345
                         ? res.IsEq()
2346
                         : lower != end() && !compare_keys(key, lower.key());
2347
  return {lower, equal};
2348
}
2349
2350
template <typename P>
2351
template <typename K>
2352
auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> {
2353
  const std::pair<iterator, bool> lower_and_equal = lower_bound_equal(key);
2354
  const iterator lower = lower_and_equal.first;
2355
  if (!lower_and_equal.second) {
2356
    return {lower, lower};
2357
  }
2358
2359
  const iterator next = std::next(lower);
2360
  if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
2361
    // The next iterator after lower must point to a key greater than `key`.
2362
    // Note: if this assert fails, then it may indicate that the comparator does
2363
    // not meet the equivalence requirements for Compare
2364
    // (see https://en.cppreference.com/w/cpp/named_req/Compare).
2365
    assert(next == end() || compare_keys(key, next.key()));
2366
    return {lower, next};
2367
  }
2368
  // Try once more to avoid the call to upper_bound() if there's only one
2369
  // equivalent key. This should prevent all calls to upper_bound() in cases of
2370
  // unique-containers with heterogeneous comparators in which all comparison
2371
  // operators have the same equivalence classes.
2372
  if (next == end() || compare_keys(key, next.key())) return {lower, next};
2373
2374
  // In this case, we need to call upper_bound() to avoid worst case O(N)
2375
  // behavior if we were to iterate over equal keys.
2376
  return {lower, upper_bound(key)};
2377
}
2378
2379
template <typename P>
2380
template <typename K, typename... Args>
2381
auto btree<P>::insert_unique(const K &key, Args &&...args)
2382
2.09M
    -> std::pair<iterator, bool> {
2383
2.09M
  if (empty()) {
2384
264k
    mutable_root() = mutable_rightmost() = new_leaf_root_node(1);
2385
264k
  }
2386
2387
2.09M
  SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
2388
2.09M
  iterator iter = res.value;
2389
2390
2.09M
  if (res.HasMatch()) {
2391
0
    if (res.IsEq()) {
2392
      // The key already exists in the tree, do nothing.
2393
0
      return {iter, false};
2394
0
    }
2395
2.09M
  } else {
2396
2.09M
    iterator last = internal_last(iter);
2397
2.09M
    if (last.node_ && !compare_keys(key, last.key())) {
2398
      // The key already exists in the tree, do nothing.
2399
0
      return {last, false};
2400
0
    }
2401
2.09M
  }
2402
2.09M
  return {internal_emplace(iter, std::forward<Args>(args)...), true};
2403
2.09M
}
2404
2405
template <typename P>
2406
template <typename K, typename... Args>
2407
inline auto btree<P>::insert_hint_unique(iterator position, const K &key,
2408
                                         Args &&...args)
2409
    -> std::pair<iterator, bool> {
2410
  if (!empty()) {
2411
    if (position == end() || compare_keys(key, position.key())) {
2412
      if (position == begin() || compare_keys(std::prev(position).key(), key)) {
2413
        // prev.key() < key < position.key()
2414
        return {internal_emplace(position, std::forward<Args>(args)...), true};
2415
      }
2416
    } else if (compare_keys(position.key(), key)) {
2417
      ++position;
2418
      if (position == end() || compare_keys(key, position.key())) {
2419
        // {original `position`}.key() < key < {current `position`}.key()
2420
        return {internal_emplace(position, std::forward<Args>(args)...), true};
2421
      }
2422
    } else {
2423
      // position.key() == key
2424
      return {position, false};
2425
    }
2426
  }
2427
  return insert_unique(key, std::forward<Args>(args)...);
2428
}
2429
2430
template <typename P>
2431
template <typename InputIterator, typename>
2432
void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, int) {
2433
  for (; b != e; ++b) {
2434
    insert_hint_unique(end(), params_type::key(*b), *b);
2435
  }
2436
}
2437
2438
template <typename P>
2439
template <typename InputIterator>
2440
void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, char) {
2441
  for (; b != e; ++b) {
2442
    // Use a node handle to manage a temp slot.
2443
    auto node_handle =
2444
        CommonAccess::Construct<node_handle_type>(get_allocator(), *b);
2445
    slot_type *slot = CommonAccess::GetSlot(node_handle);
2446
    insert_hint_unique(end(), params_type::key(slot), slot);
2447
  }
2448
}
2449
2450
template <typename P>
2451
template <typename ValueType>
2452
auto btree<P>::insert_multi(const key_type &key, ValueType &&v) -> iterator {
2453
  if (empty()) {
2454
    mutable_root() = mutable_rightmost() = new_leaf_root_node(1);
2455
  }
2456
2457
  iterator iter = internal_upper_bound(key);
2458
  if (iter.node_ == nullptr) {
2459
    iter = end();
2460
  }
2461
  return internal_emplace(iter, std::forward<ValueType>(v));
2462
}
2463
2464
template <typename P>
2465
template <typename ValueType>
2466
auto btree<P>::insert_hint_multi(iterator position, ValueType &&v) -> iterator {
2467
  if (!empty()) {
2468
    const key_type &key = params_type::key(v);
2469
    if (position == end() || !compare_keys(position.key(), key)) {
2470
      if (position == begin() ||
2471
          !compare_keys(key, std::prev(position).key())) {
2472
        // prev.key() <= key <= position.key()
2473
        return internal_emplace(position, std::forward<ValueType>(v));
2474
      }
2475
    } else {
2476
      ++position;
2477
      if (position == end() || !compare_keys(position.key(), key)) {
2478
        // {original `position`}.key() < key < {current `position`}.key()
2479
        return internal_emplace(position, std::forward<ValueType>(v));
2480
      }
2481
    }
2482
  }
2483
  return insert_multi(std::forward<ValueType>(v));
2484
}
2485
2486
template <typename P>
2487
template <typename InputIterator>
2488
void btree<P>::insert_iterator_multi(InputIterator b, InputIterator e) {
2489
  for (; b != e; ++b) {
2490
    insert_hint_multi(end(), *b);
2491
  }
2492
}
2493
2494
template <typename P>
2495
auto btree<P>::operator=(const btree &other) -> btree & {
2496
  if (this != &other) {
2497
    clear();
2498
2499
    *mutable_key_comp() = other.key_comp();
2500
    if (std::allocator_traits<
2501
            allocator_type>::propagate_on_container_copy_assignment::value) {
2502
      *mutable_allocator() = other.allocator();
2503
    }
2504
2505
    copy_or_move_values_in_order(other);
2506
  }
2507
  return *this;
2508
}
2509
2510
template <typename P>
2511
auto btree<P>::operator=(btree &&other) noexcept -> btree & {
2512
  if (this != &other) {
2513
    clear();
2514
2515
    using std::swap;
2516
    if (std::allocator_traits<
2517
            allocator_type>::propagate_on_container_move_assignment::value) {
2518
      swap(root_, other.root_);
2519
      // Note: `rightmost_` also contains the allocator and the key comparator.
2520
      swap(rightmost_, other.rightmost_);
2521
      swap(size_, other.size_);
2522
    } else {
2523
      if (allocator() == other.allocator()) {
2524
        swap(mutable_root(), other.mutable_root());
2525
        swap(*mutable_key_comp(), *other.mutable_key_comp());
2526
        swap(mutable_rightmost(), other.mutable_rightmost());
2527
        swap(size_, other.size_);
2528
      } else {
2529
        // We aren't allowed to propagate the allocator and the allocator is
2530
        // different so we can't take over its memory. We must move each element
2531
        // individually. We need both `other` and `this` to have `other`s key
2532
        // comparator while moving the values so we can't swap the key
2533
        // comparators.
2534
        *mutable_key_comp() = other.key_comp();
2535
        copy_or_move_values_in_order(other);
2536
      }
2537
    }
2538
  }
2539
  return *this;
2540
}
2541
2542
template <typename P>
2543
752k
auto btree<P>::erase(iterator iter) -> iterator {
2544
752k
  iter.node_->value_destroy(static_cast<field_type>(iter.position_),
2545
752k
                            mutable_allocator());
2546
752k
  iter.update_generation();
2547
2548
752k
  const bool internal_delete = iter.node_->is_internal();
2549
752k
  if (internal_delete) {
2550
    // Deletion of a value on an internal node. First, transfer the largest
2551
    // value from our left child here, then erase/rebalance from that position.
2552
    // We can get to the largest value from our left child by decrementing iter.
2553
5.19k
    iterator internal_iter(iter);
2554
5.19k
    --iter;
2555
5.19k
    assert(iter.node_->is_leaf());
2556
5.19k
    internal_iter.node_->transfer(
2557
5.19k
        static_cast<size_type>(internal_iter.position_),
2558
5.19k
        static_cast<size_type>(iter.position_), iter.node_,
2559
5.19k
        mutable_allocator());
2560
747k
  } else {
2561
    // Shift values after erased position in leaf. In the internal case, we
2562
    // don't need to do this because the leaf position is the end of the node.
2563
747k
    const field_type transfer_from =
2564
747k
        static_cast<field_type>(iter.position_ + 1);
2565
747k
    const field_type num_to_transfer = iter.node_->finish() - transfer_from;
2566
747k
    iter.node_->transfer_n(num_to_transfer,
2567
747k
                           static_cast<size_type>(iter.position_),
2568
747k
                           transfer_from, iter.node_, mutable_allocator());
2569
747k
  }
2570
  // Update node finish and container size.
2571
752k
  iter.node_->set_finish(iter.node_->finish() - 1);
2572
752k
  --size_;
2573
2574
  // We want to return the next value after the one we just erased. If we
2575
  // erased from an internal node (internal_delete == true), then the next
2576
  // value is ++(++iter). If we erased from a leaf node (internal_delete ==
2577
  // false) then the next value is ++iter. Note that ++iter may point to an
2578
  // internal node and the value in the internal node may move to a leaf node
2579
  // (iter.node_) when rebalancing is performed at the leaf level.
2580
2581
752k
  iterator res = rebalance_after_delete(iter);
2582
2583
  // If we erased from an internal node, advance the iterator.
2584
752k
  if (internal_delete) {
2585
5.19k
    ++res;
2586
5.19k
  }
2587
752k
  return res;
2588
752k
}
2589
2590
template <typename P>
2591
752k
auto btree<P>::rebalance_after_delete(iterator iter) -> iterator {
2592
  // Merge/rebalance as we walk back up the tree.
2593
752k
  iterator res(iter);
2594
752k
  bool first_iteration = true;
2595
771k
  for (;;) {
2596
771k
    if (iter.node_ == root()) {
2597
251k
      try_shrink();
2598
251k
      if (empty()) {
2599
36.1k
        return end();
2600
36.1k
      }
2601
215k
      break;
2602
251k
    }
2603
519k
    if (iter.node_->count() >= kMinNodeValues) {
2604
415k
      break;
2605
415k
    }
2606
104k
    bool merged = try_merge_or_rebalance(&iter);
2607
    // On the first iteration, we should update `res` with `iter` because `res`
2608
    // may have been invalidated.
2609
104k
    if (first_iteration) {
2610
103k
      res = iter;
2611
103k
      first_iteration = false;
2612
103k
    }
2613
104k
    if (!merged) {
2614
85.8k
      break;
2615
85.8k
    }
2616
18.6k
    iter.position_ = iter.node_->position();
2617
18.6k
    iter.node_ = iter.node_->parent();
2618
18.6k
  }
2619
716k
  res.update_generation();
2620
2621
  // Adjust our return value. If we're pointing at the end of a node, advance
2622
  // the iterator.
2623
716k
  if (res.position_ == res.node_->finish()) {
2624
22.4k
    res.position_ = res.node_->finish() - 1;
2625
22.4k
    ++res;
2626
22.4k
  }
2627
2628
716k
  return res;
2629
752k
}
2630
2631
// Note: we tried implementing this more efficiently by erasing all of the
2632
// elements in [begin, end) at once and then doing rebalancing once at the end
2633
// (rather than interleaving deletion and rebalancing), but that adds a lot of
2634
// complexity, which seems to outweigh the performance win.
2635
template <typename P>
2636
auto btree<P>::erase_range(iterator begin, iterator end)
2637
    -> std::pair<size_type, iterator> {
2638
  size_type count = static_cast<size_type>(end - begin);
2639
  assert(count >= 0);
2640
2641
  if (count == 0) {
2642
    return {0, begin};
2643
  }
2644
2645
  if (static_cast<size_type>(count) == size_) {
2646
    clear();
2647
    return {count, this->end()};
2648
  }
2649
2650
  if (begin.node_ == end.node_) {
2651
    assert(end.position_ > begin.position_);
2652
    begin.node_->remove_values(
2653
        static_cast<field_type>(begin.position_),
2654
        static_cast<field_type>(end.position_ - begin.position_),
2655
        mutable_allocator());
2656
    size_ -= count;
2657
    return {count, rebalance_after_delete(begin)};
2658
  }
2659
2660
  const size_type target_size = size_ - count;
2661
  while (size_ > target_size) {
2662
    if (begin.node_->is_leaf()) {
2663
      const size_type remaining_to_erase = size_ - target_size;
2664
      const size_type remaining_in_node =
2665
          static_cast<size_type>(begin.node_->finish() - begin.position_);
2666
      const field_type to_erase = static_cast<field_type>(
2667
          (std::min)(remaining_to_erase, remaining_in_node));
2668
      begin.node_->remove_values(static_cast<field_type>(begin.position_),
2669
                                 to_erase, mutable_allocator());
2670
      size_ -= to_erase;
2671
      begin = rebalance_after_delete(begin);
2672
    } else {
2673
      begin = erase(begin);
2674
    }
2675
  }
2676
  begin.update_generation();
2677
  return {count, begin};
2678
}
2679
2680
template <typename P>
2681
293k
void btree<P>::clear() {
2682
293k
  if (!empty()) {
2683
228k
    node_type::clear_and_delete(root(), mutable_allocator());
2684
228k
  }
2685
293k
  mutable_root() = mutable_rightmost() = EmptyNode();
2686
293k
  size_ = 0;
2687
293k
}
2688
2689
template <typename P>
2690
void btree<P>::swap(btree &other) {
2691
  using std::swap;
2692
  if (std::allocator_traits<
2693
          allocator_type>::propagate_on_container_swap::value) {
2694
    // Note: `rightmost_` also contains the allocator and the key comparator.
2695
    swap(rightmost_, other.rightmost_);
2696
  } else {
2697
    // It's undefined behavior if the allocators are unequal here.
2698
    assert(allocator() == other.allocator());
2699
    swap(mutable_rightmost(), other.mutable_rightmost());
2700
    swap(*mutable_key_comp(), *other.mutable_key_comp());
2701
  }
2702
  swap(mutable_root(), other.mutable_root());
2703
  swap(size_, other.size_);
2704
}
2705
2706
template <typename P>
2707
void btree<P>::verify() const {
2708
  assert(root() != nullptr);
2709
  assert(leftmost() != nullptr);
2710
  assert(rightmost() != nullptr);
2711
  assert(empty() || size() == internal_verify(root(), nullptr, nullptr));
2712
  assert(leftmost() == (++const_iterator(root(), -1)).node_);
2713
  assert(rightmost() == (--const_iterator(root(), root()->finish())).node_);
2714
  assert(leftmost()->is_leaf());
2715
  assert(rightmost()->is_leaf());
2716
}
2717
2718
template <typename P>
2719
81.0k
void btree<P>::rebalance_or_split(iterator *iter) {
2720
81.0k
  node_type *&node = iter->node_;
2721
81.0k
  int &insert_position = iter->position_;
2722
81.0k
  assert(node->count() == node->max_count());
2723
81.0k
  assert(kNodeSlots == node->max_count());
2724
2725
  // First try to make room on the node by rebalancing.
2726
81.0k
  node_type *parent = node->parent();
2727
81.0k
  if (node != root()) {
2728
72.1k
    if (node->position() > parent->start()) {
2729
      // Try rebalancing with our left sibling.
2730
72.1k
      node_type *left = parent->child(node->position() - 1);
2731
72.1k
      assert(left->max_count() == kNodeSlots);
2732
72.1k
      if (left->count() < kNodeSlots) {
2733
        // We bias rebalancing based on the position being inserted. If we're
2734
        // inserting at the end of the right node then we bias rebalancing to
2735
        // fill up the left node.
2736
36.1k
        field_type to_move =
2737
36.1k
            (kNodeSlots - left->count()) /
2738
36.1k
            (1 + (static_cast<field_type>(insert_position) < kNodeSlots));
2739
36.1k
        to_move = (std::max)(field_type{1}, to_move);
2740
2741
36.1k
        if (static_cast<field_type>(insert_position) - to_move >=
2742
36.1k
                node->start() ||
2743
36.1k
            left->count() + to_move < kNodeSlots) {
2744
36.1k
          left->rebalance_right_to_left(to_move, node, mutable_allocator());
2745
2746
36.1k
          assert(node->max_count() - node->count() == to_move);
2747
36.1k
          insert_position = static_cast<int>(
2748
36.1k
              static_cast<field_type>(insert_position) - to_move);
2749
36.1k
          if (insert_position < node->start()) {
2750
0
            insert_position = insert_position + left->count() + 1;
2751
0
            node = left;
2752
0
          }
2753
2754
36.1k
          assert(node->count() < node->max_count());
2755
36.1k
          return;
2756
36.1k
        }
2757
36.1k
      }
2758
72.1k
    }
2759
2760
35.9k
    if (node->position() < parent->finish()) {
2761
      // Try rebalancing with our right sibling.
2762
0
      node_type *right = parent->child(node->position() + 1);
2763
0
      assert(right->max_count() == kNodeSlots);
2764
0
      if (right->count() < kNodeSlots) {
2765
        // We bias rebalancing based on the position being inserted. If we're
2766
        // inserting at the beginning of the left node then we bias rebalancing
2767
        // to fill up the right node.
2768
0
        field_type to_move = (kNodeSlots - right->count()) /
2769
0
                             (1 + (insert_position > node->start()));
2770
0
        to_move = (std::max)(field_type{1}, to_move);
2771
2772
0
        if (static_cast<field_type>(insert_position) <=
2773
0
                node->finish() - to_move ||
2774
0
            right->count() + to_move < kNodeSlots) {
2775
0
          node->rebalance_left_to_right(to_move, right, mutable_allocator());
2776
2777
0
          if (insert_position > node->finish()) {
2778
0
            insert_position = insert_position - node->count() - 1;
2779
0
            node = right;
2780
0
          }
2781
2782
0
          assert(node->count() < node->max_count());
2783
0
          return;
2784
0
        }
2785
0
      }
2786
0
    }
2787
2788
    // Rebalancing failed, make sure there is room on the parent node for a new
2789
    // value.
2790
35.9k
    assert(parent->max_count() == kNodeSlots);
2791
35.9k
    if (parent->count() == kNodeSlots) {
2792
902
      iterator parent_iter(parent, node->position());
2793
902
      rebalance_or_split(&parent_iter);
2794
902
      parent = node->parent();
2795
902
    }
2796
35.9k
  } else {
2797
    // Rebalancing not possible because this is the root node.
2798
    // Create a new root node and set the current root node as the child of the
2799
    // new root.
2800
8.92k
    parent = new_internal_node(/*position=*/0, parent);
2801
8.92k
    parent->set_generation(root()->generation());
2802
8.92k
    parent->init_child(parent->start(), node);
2803
8.92k
    mutable_root() = parent;
2804
    // If the former root was a leaf node, then it's now the rightmost node.
2805
8.92k
    assert(parent->start_child()->is_internal() ||
2806
8.92k
           parent->start_child() == rightmost());
2807
8.92k
  }
2808
2809
  // Split the node.
2810
44.9k
  node_type *split_node;
2811
44.9k
  if (node->is_leaf()) {
2812
44.3k
    split_node = new_leaf_node(node->position() + 1, parent);
2813
44.3k
    node->split(insert_position, split_node, mutable_allocator());
2814
44.3k
    if (rightmost() == node) mutable_rightmost() = split_node;
2815
44.3k
  } else {
2816
608
    split_node = new_internal_node(node->position() + 1, parent);
2817
608
    node->split(insert_position, split_node, mutable_allocator());
2818
608
  }
2819
2820
44.9k
  if (insert_position > node->finish()) {
2821
44.9k
    insert_position = insert_position - node->count() - 1;
2822
44.9k
    node = split_node;
2823
44.9k
  }
2824
44.9k
}
2825
2826
template <typename P>
2827
18.6k
void btree<P>::merge_nodes(node_type *left, node_type *right) {
2828
18.6k
  left->merge(right, mutable_allocator());
2829
18.6k
  if (rightmost() == right) mutable_rightmost() = left;
2830
18.6k
}
2831
2832
template <typename P>
2833
104k
bool btree<P>::try_merge_or_rebalance(iterator *iter) {
2834
104k
  node_type *parent = iter->node_->parent();
2835
104k
  if (iter->node_->position() > parent->start()) {
2836
    // Try merging with our left sibling.
2837
21.0k
    node_type *left = parent->child(iter->node_->position() - 1);
2838
21.0k
    assert(left->max_count() == kNodeSlots);
2839
21.0k
    if (1U + left->count() + iter->node_->count() <= kNodeSlots) {
2840
3.04k
      iter->position_ += 1 + left->count();
2841
3.04k
      merge_nodes(left, iter->node_);
2842
3.04k
      iter->node_ = left;
2843
3.04k
      return true;
2844
3.04k
    }
2845
21.0k
  }
2846
101k
  if (iter->node_->position() < parent->finish()) {
2847
    // Try merging with our right sibling.
2848
99.0k
    node_type *right = parent->child(iter->node_->position() + 1);
2849
99.0k
    assert(right->max_count() == kNodeSlots);
2850
99.0k
    if (1U + iter->node_->count() + right->count() <= kNodeSlots) {
2851
15.6k
      merge_nodes(iter->node_, right);
2852
15.6k
      return true;
2853
15.6k
    }
2854
    // Try rebalancing with our right sibling. We don't perform rebalancing if
2855
    // we deleted the first element from iter->node_ and the node is not
2856
    // empty. This is a small optimization for the common pattern of deleting
2857
    // from the front of the tree.
2858
83.4k
    if (right->count() > kMinNodeValues &&
2859
83.4k
        (iter->node_->count() == 0 || iter->position_ > iter->node_->start())) {
2860
42.9k
      field_type to_move = (right->count() - iter->node_->count()) / 2;
2861
42.9k
      to_move =
2862
42.9k
          (std::min)(to_move, static_cast<field_type>(right->count() - 1));
2863
42.9k
      iter->node_->rebalance_right_to_left(to_move, right, mutable_allocator());
2864
42.9k
      return false;
2865
42.9k
    }
2866
83.4k
  }
2867
42.8k
  if (iter->node_->position() > parent->start()) {
2868
    // Try rebalancing with our left sibling. We don't perform rebalancing if
2869
    // we deleted the last element from iter->node_ and the node is not
2870
    // empty. This is a small optimization for the common pattern of deleting
2871
    // from the back of the tree.
2872
2.77k
    node_type *left = parent->child(iter->node_->position() - 1);
2873
2.77k
    if (left->count() > kMinNodeValues &&
2874
2.77k
        (iter->node_->count() == 0 ||
2875
2.76k
         iter->position_ < iter->node_->finish())) {
2876
2.61k
      field_type to_move = (left->count() - iter->node_->count()) / 2;
2877
2.61k
      to_move = (std::min)(to_move, static_cast<field_type>(left->count() - 1));
2878
2.61k
      left->rebalance_left_to_right(to_move, iter->node_, mutable_allocator());
2879
2.61k
      iter->position_ += to_move;
2880
2.61k
      return false;
2881
2.61k
    }
2882
2.77k
  }
2883
40.2k
  return false;
2884
42.8k
}
2885
2886
template <typename P>
2887
251k
void btree<P>::try_shrink() {
2888
251k
  node_type *orig_root = root();
2889
251k
  if (orig_root->count() > 0) {
2890
210k
    return;
2891
210k
  }
2892
  // Deleted the last item on the root node, shrink the height of the tree.
2893
40.8k
  if (orig_root->is_leaf()) {
2894
36.1k
    assert(size() == 0);
2895
36.1k
    mutable_root() = mutable_rightmost() = EmptyNode();
2896
36.1k
  } else {
2897
4.66k
    node_type *child = orig_root->start_child();
2898
4.66k
    child->make_root();
2899
4.66k
    mutable_root() = child;
2900
4.66k
  }
2901
40.8k
  node_type::clear_and_delete(orig_root, mutable_allocator());
2902
40.8k
}
2903
2904
template <typename P>
2905
template <typename IterType>
2906
2.09M
inline IterType btree<P>::internal_last(IterType iter) {
2907
2.09M
  assert(iter.node_ != nullptr);
2908
3.67M
  while (iter.position_ == iter.node_->finish()) {
2909
3.67M
    iter.position_ = iter.node_->position();
2910
3.67M
    iter.node_ = iter.node_->parent();
2911
3.67M
    if (iter.node_->is_leaf()) {
2912
2.09M
      iter.node_ = nullptr;
2913
2.09M
      break;
2914
2.09M
    }
2915
3.67M
  }
2916
2.09M
  iter.update_generation();
2917
2.09M
  return iter;
2918
2.09M
}
2919
2920
template <typename P>
2921
template <typename... Args>
2922
inline auto btree<P>::internal_emplace(iterator iter, Args &&...args)
2923
2.09M
    -> iterator {
2924
2.09M
  if (iter.node_->is_internal()) {
2925
    // We can't insert on an internal node. Instead, we'll insert after the
2926
    // previous value which is guaranteed to be on a leaf node.
2927
0
    --iter;
2928
0
    ++iter.position_;
2929
0
  }
2930
2.09M
  const field_type max_count = iter.node_->max_count();
2931
2.09M
  allocator_type *alloc = mutable_allocator();
2932
2933
2.09M
  const auto transfer_and_delete = [&](node_type *old_node,
2934
2.09M
                                       node_type *new_node) {
2935
237k
    new_node->transfer_n(old_node->count(), new_node->start(),
2936
237k
                         old_node->start(), old_node, alloc);
2937
237k
    new_node->set_finish(old_node->finish());
2938
237k
    old_node->set_finish(old_node->start());
2939
237k
    new_node->set_generation(old_node->generation());
2940
237k
    node_type::clear_and_delete(old_node, alloc);
2941
237k
  };
2942
2.09M
  const auto replace_leaf_root_node = [&](field_type new_node_size) {
2943
237k
    assert(iter.node_ == root());
2944
237k
    node_type *old_root = iter.node_;
2945
237k
    node_type *new_root = iter.node_ = new_leaf_root_node(new_node_size);
2946
237k
    transfer_and_delete(old_root, new_root);
2947
237k
    mutable_root() = mutable_rightmost() = new_root;
2948
237k
  };
2949
2950
2.09M
  bool replaced_node = false;
2951
2.09M
  if (iter.node_->count() == max_count) {
2952
    // Make room in the leaf for the new item.
2953
317k
    if (max_count < kNodeSlots) {
2954
      // Insertion into the root where the root is smaller than the full node
2955
      // size. Simply grow the size of the root node.
2956
237k
      replace_leaf_root_node(static_cast<field_type>(
2957
237k
          (std::min)(static_cast<int>(kNodeSlots), 2 * max_count)));
2958
237k
      replaced_node = true;
2959
237k
    } else {
2960
80.1k
      rebalance_or_split(&iter);
2961
80.1k
    }
2962
317k
  }
2963
2.09M
  (void)replaced_node;
2964
#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
2965
    defined(ABSL_HAVE_HWADDRESS_SANITIZER)
2966
  if (!replaced_node) {
2967
    assert(iter.node_->is_leaf());
2968
    if (iter.node_->is_root()) {
2969
      replace_leaf_root_node(max_count);
2970
    } else {
2971
      node_type *old_node = iter.node_;
2972
      const bool was_rightmost = rightmost() == old_node;
2973
      const bool was_leftmost = leftmost() == old_node;
2974
      node_type *parent = old_node->parent();
2975
      const field_type position = old_node->position();
2976
      node_type *new_node = iter.node_ = new_leaf_node(position, parent);
2977
      parent->set_child_noupdate_position(position, new_node);
2978
      transfer_and_delete(old_node, new_node);
2979
      if (was_rightmost) mutable_rightmost() = new_node;
2980
      // The leftmost node is stored as the parent of the root node.
2981
      if (was_leftmost) root()->set_parent(new_node);
2982
    }
2983
  }
2984
#endif
2985
2.09M
  iter.node_->emplace_value(static_cast<field_type>(iter.position_), alloc,
2986
2.09M
                            std::forward<Args>(args)...);
2987
2.09M
  assert(
2988
2.09M
      iter.node_->is_ordered_correctly(static_cast<field_type>(iter.position_),
2989
2.09M
                                       original_key_compare(key_comp())) &&
2990
2.09M
      "If this assert fails, then either (1) the comparator may violate "
2991
2.09M
      "transitivity, i.e. comp(a,b) && comp(b,c) -> comp(a,c) (see "
2992
2.09M
      "https://en.cppreference.com/w/cpp/named_req/Compare), or (2) a "
2993
2.09M
      "key may have been mutated after it was inserted into the tree.");
2994
2.09M
  ++size_;
2995
2.09M
  iter.update_generation();
2996
2.09M
  return iter;
2997
2.09M
}
2998
2999
template <typename P>
3000
template <typename K>
3001
inline auto btree<P>::internal_locate(const K &key) const
3002
2.09M
    -> SearchResult<iterator, is_key_compare_to::value> {
3003
2.09M
  iterator iter(const_cast<node_type *>(root()));
3004
3.67M
  for (;;) {
3005
3.67M
    SearchResult<size_type, is_key_compare_to::value> res =
3006
3.67M
        iter.node_->lower_bound(key, key_comp());
3007
3.67M
    iter.position_ = static_cast<int>(res.value);
3008
3.67M
    if (res.IsEq()) {
3009
0
      return {iter, MatchKind::kEq};
3010
0
    }
3011
    // Note: in the non-key-compare-to case, we don't need to walk all the way
3012
    // down the tree if the keys are equal, but determining equality would
3013
    // require doing an extra comparison on each node on the way down, and we
3014
    // will need to go all the way to the leaf node in the expected case.
3015
3.67M
    if (iter.node_->is_leaf()) {
3016
2.09M
      break;
3017
2.09M
    }
3018
1.57M
    iter.node_ = iter.node_->child(static_cast<field_type>(iter.position_));
3019
1.57M
  }
3020
  // Note: in the non-key-compare-to case, the key may actually be equivalent
3021
  // here (and the MatchKind::kNe is ignored).
3022
2.09M
  return {iter, MatchKind::kNe};
3023
2.09M
}
3024
3025
template <typename P>
3026
template <typename K>
3027
auto btree<P>::internal_lower_bound(const K &key) const
3028
    -> SearchResult<iterator, is_key_compare_to::value> {
3029
  if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
3030
    SearchResult<iterator, is_key_compare_to::value> ret = internal_locate(key);
3031
    ret.value = internal_last(ret.value);
3032
    return ret;
3033
  }
3034
  iterator iter(const_cast<node_type *>(root()));
3035
  SearchResult<size_type, is_key_compare_to::value> res;
3036
  bool seen_eq = false;
3037
  for (;;) {
3038
    res = iter.node_->lower_bound(key, key_comp());
3039
    iter.position_ = static_cast<int>(res.value);
3040
    if (iter.node_->is_leaf()) {
3041
      break;
3042
    }
3043
    seen_eq = seen_eq || res.IsEq();
3044
    iter.node_ = iter.node_->child(static_cast<field_type>(iter.position_));
3045
  }
3046
  if (res.IsEq()) return {iter, MatchKind::kEq};
3047
  return {internal_last(iter), seen_eq ? MatchKind::kEq : MatchKind::kNe};
3048
}
3049
3050
template <typename P>
3051
template <typename K>
3052
auto btree<P>::internal_upper_bound(const K &key) const -> iterator {
3053
  iterator iter(const_cast<node_type *>(root()));
3054
  for (;;) {
3055
    iter.position_ = static_cast<int>(iter.node_->upper_bound(key, key_comp()));
3056
    if (iter.node_->is_leaf()) {
3057
      break;
3058
    }
3059
    iter.node_ = iter.node_->child(static_cast<field_type>(iter.position_));
3060
  }
3061
  return internal_last(iter);
3062
}
3063
3064
template <typename P>
3065
template <typename K>
3066
auto btree<P>::internal_find(const K &key) const -> iterator {
3067
  SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
3068
  if (res.HasMatch()) {
3069
    if (res.IsEq()) {
3070
      return res.value;
3071
    }
3072
  } else {
3073
    const iterator iter = internal_last(res.value);
3074
    if (iter.node_ != nullptr && !compare_keys(key, iter.key())) {
3075
      return iter;
3076
    }
3077
  }
3078
  return {nullptr, 0};
3079
}
3080
3081
template <typename P>
3082
typename btree<P>::size_type btree<P>::internal_verify(
3083
    const node_type *node, const key_type *lo, const key_type *hi) const {
3084
  assert(node->count() > 0);
3085
  assert(node->count() <= node->max_count());
3086
  if (lo) {
3087
    assert(!compare_keys(node->key(node->start()), *lo));
3088
  }
3089
  if (hi) {
3090
    assert(!compare_keys(*hi, node->key(node->finish() - 1)));
3091
  }
3092
  for (int i = node->start() + 1; i < node->finish(); ++i) {
3093
    assert(!compare_keys(node->key(i), node->key(i - 1)));
3094
  }
3095
  size_type count = node->count();
3096
  if (node->is_internal()) {
3097
    for (field_type i = node->start(); i <= node->finish(); ++i) {
3098
      assert(node->child(i) != nullptr);
3099
      assert(node->child(i)->parent() == node);
3100
      assert(node->child(i)->position() == i);
3101
      count += internal_verify(node->child(i),
3102
                               i == node->start() ? lo : &node->key(i - 1),
3103
                               i == node->finish() ? hi : &node->key(i));
3104
    }
3105
  }
3106
  return count;
3107
}
3108
3109
struct btree_access {
3110
  template <typename BtreeContainer, typename Pred>
3111
  static auto erase_if(BtreeContainer &container, Pred pred) ->
3112
      typename BtreeContainer::size_type {
3113
    const auto initial_size = container.size();
3114
    auto &tree = container.tree_;
3115
    auto *alloc = tree.mutable_allocator();
3116
    for (auto it = container.begin(); it != container.end();) {
3117
      if (!pred(*it)) {
3118
        ++it;
3119
        continue;
3120
      }
3121
      auto *node = it.node_;
3122
      if (node->is_internal()) {
3123
        // Handle internal nodes normally.
3124
        it = container.erase(it);
3125
        continue;
3126
      }
3127
      // If this is a leaf node, then we do all the erases from this node
3128
      // at once before doing rebalancing.
3129
3130
      // The current position to transfer slots to.
3131
      int to_pos = it.position_;
3132
      node->value_destroy(it.position_, alloc);
3133
      while (++it.position_ < node->finish()) {
3134
        it.update_generation();
3135
        if (pred(*it)) {
3136
          node->value_destroy(it.position_, alloc);
3137
        } else {
3138
          node->transfer(node->slot(to_pos++), node->slot(it.position_), alloc);
3139
        }
3140
      }
3141
      const int num_deleted = node->finish() - to_pos;
3142
      tree.size_ -= num_deleted;
3143
      node->set_finish(to_pos);
3144
      it.position_ = to_pos;
3145
      it = tree.rebalance_after_delete(it);
3146
    }
3147
    return initial_size - container.size();
3148
  }
3149
};
3150
3151
#undef ABSL_BTREE_ENABLE_GENERATIONS
3152
3153
}  // namespace container_internal
3154
ABSL_NAMESPACE_END
3155
}  // namespace absl
3156
3157
#endif  // ABSL_CONTAINER_INTERNAL_BTREE_H_