Coverage Report

Created: 2026-06-09 06:39

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