15 #include "absl/container/btree_test.h"
23 #include <type_traits>
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28 #include "absl/base/internal/raw_logging.h"
29 #include "absl/base/macros.h"
30 #include "absl/container/btree_map.h"
31 #include "absl/container/btree_set.h"
32 #include "absl/container/internal/counting_allocator.h"
33 #include "absl/container/internal/test_instance_tracker.h"
34 #include "absl/flags/flag.h"
35 #include "absl/hash/hash_testing.h"
36 #include "absl/memory/memory.h"
37 #include "absl/meta/type_traits.h"
38 #include "absl/strings/str_cat.h"
39 #include "absl/strings/str_split.h"
40 #include "absl/strings/string_view.h"
41 #include "absl/types/compare.h"
47 namespace container_internal {
50 using ::absl::test_internal::CopyableMovableInstance;
51 using ::absl::test_internal::InstanceTracker;
52 using ::absl::test_internal::MovableOnlyInstance;
60 template <
typename T,
typename U>
61 void CheckPairEquals(
const T &x,
const U &
y) {
65 template <
typename T,
typename U,
typename V,
typename W>
66 void CheckPairEquals(
const std::pair<T, U> &x,
const std::pair<V, W> &
y) {
67 CheckPairEquals(
x.first,
y.first);
68 CheckPairEquals(
x.second,
y.second);
76 template <
typename TreeType,
typename CheckerType>
82 using pointer =
typename TreeType::pointer;
97 template <
typename InputIterator>
110 template <
typename IterType,
typename CheckerIterType>
111 IterType
iter_check(IterType tree_iter, CheckerIterType checker_iter)
const {
112 if (tree_iter ==
tree_.end()) {
114 "Checker iterator not at end.");
116 CheckPairEquals(*tree_iter, *checker_iter);
120 template <
typename IterType,
typename CheckerIterType>
121 IterType
riter_check(IterType tree_iter, CheckerIterType checker_iter)
const {
122 if (tree_iter ==
tree_.rend()) {
124 "Checker iterator not at rend.");
126 CheckPairEquals(*tree_iter, *checker_iter);
163 std::pair<typename CheckerType::iterator, typename CheckerType::iterator>
165 std::pair<iterator, iterator> tree_res =
tree_.equal_range(
key);
166 iter_check(tree_res.first, checker_res.first);
167 iter_check(tree_res.second, checker_res.second);
172 std::pair<
typename CheckerType::const_iterator,
173 typename CheckerType::const_iterator>
175 std::pair<const_iterator, const_iterator> tree_res =
tree_.equal_range(
key);
176 iter_check(tree_res.first, checker_res.first);
177 iter_check(tree_res.second, checker_res.second);
217 auto checker_next = checker_iter;
244 const auto checker_ret =
checker_.erase(checker_begin, checker_end);
247 std::distance(
tree_.begin(), tree_ret));
257 tree_.swap(other.tree_);
266 auto checker_iter =
checker_.begin();
268 for (; tree_iter !=
tree_.end(); ++tree_iter, ++checker_iter) {
269 CheckPairEquals(*tree_iter, *checker_iter);
273 for (
int n =
tree_.size() - 1;
n >= 0; --
n) {
282 auto checker_riter =
checker_.rbegin();
284 for (; tree_riter !=
tree_.rend(); ++tree_riter, ++checker_riter) {
285 CheckPairEquals(*tree_riter, *checker_riter);
289 for (
int n =
tree_.size() - 1;
n >= 0; --
n) {
307 return tree_.empty();
319 template <
typename TreeType,
typename CheckerType>
320 class unique_checker :
public base_checker<TreeType, CheckerType> {
321 using super_type = base_checker<TreeType, CheckerType>;
328 unique_checker() : super_type() {}
329 unique_checker(
const unique_checker &other) : super_type(other) {}
330 template <
class InputIterator>
331 unique_checker(InputIterator
b, InputIterator e) : super_type(
b,
e) {}
332 unique_checker &operator=(
const unique_checker &) =
default;
337 std::pair<typename CheckerType::iterator, bool> checker_res =
338 this->checker_.insert(
v);
339 std::pair<iterator, bool> tree_res = this->
tree_.insert(v);
340 CheckPairEquals(*tree_res.first, *checker_res.first);
341 EXPECT_EQ(tree_res.second, checker_res.second);
348 std::pair<typename CheckerType::iterator, bool> checker_res =
349 this->checker_.insert(
v);
351 CheckPairEquals(*tree_res, *checker_res.first);
356 template <
typename InputIterator>
357 void insert(InputIterator
b, InputIterator e) {
358 for (;
b !=
e; ++
b) {
367 template <
typename TreeType,
typename CheckerType>
368 class multi_checker :
public base_checker<TreeType, CheckerType> {
369 using super_type = base_checker<TreeType, CheckerType>;
376 multi_checker() : super_type() {}
377 multi_checker(
const multi_checker &other) : super_type(other) {}
378 template <
class InputIterator>
379 multi_checker(InputIterator
b, InputIterator e) : super_type(
b,
e) {}
380 multi_checker &operator=(
const multi_checker &) =
default;
385 auto checker_res = this->checker_.insert(
v);
387 CheckPairEquals(*tree_res, *checker_res);
394 auto checker_res = this->checker_.insert(
v);
396 CheckPairEquals(*tree_res, *checker_res);
401 template <
typename InputIterator>
402 void insert(InputIterator
b, InputIterator e) {
403 for (;
b !=
e; ++
b) {
409 template <
typename T,
typename V>
414 const T &const_b = *
b;
417 for (
int i = 0;
i <
values.size(); ++
i) {
418 mutable_b.insert(
values[i]);
419 mutable_b.value_check(
values[i]);
427 EXPECT_EQ(b_copy.size(), const_b.size());
428 for (
int i = 0;
i <
values.size(); ++
i) {
429 CheckPairEquals(*b_copy.find(key_of_value(
values[i])),
values[i]);
433 T b_range(const_b.begin(), const_b.end());
434 EXPECT_EQ(b_range.size(), const_b.size());
435 for (
int i = 0;
i <
values.size(); ++
i) {
436 CheckPairEquals(*b_range.find(key_of_value(
values[i])),
values[i]);
440 b_range.insert(b_copy.begin(), b_copy.end());
445 b_range.insert(b_copy.begin(), b_copy.end());
446 EXPECT_EQ(b_range.size(), b_copy.size());
447 for (
int i = 0;
i <
values.size(); ++
i) {
448 CheckPairEquals(*b_range.find(key_of_value(
values[i])),
values[i]);
452 b_range.operator=(b_range);
453 EXPECT_EQ(b_range.size(), b_copy.size());
458 EXPECT_EQ(b_range.size(), b_copy.size());
462 b_range.swap(b_copy);
464 EXPECT_EQ(b_range.size(), const_b.size());
465 for (
int i = 0;
i <
values.size(); ++
i) {
466 CheckPairEquals(*b_range.find(key_of_value(
values[i])),
values[i]);
468 b_range.swap(b_copy);
471 swap(b_range, b_copy);
473 EXPECT_EQ(b_range.size(), const_b.size());
474 for (
int i = 0;
i <
values.size(); ++
i) {
475 CheckPairEquals(*b_range.find(key_of_value(
values[i])),
values[i]);
477 swap(b_range, b_copy);
480 for (
int i = 0;
i <
values.size(); ++
i) {
481 mutable_b.erase(key_of_value(
values[i]));
491 for (
int i = 0;
i <
values.size(); ++
i) {
492 mutable_b.erase(mutable_b.find(key_of_value(
values[i])));
499 for (
int i = 0;
i <
values.size();
i++) {
500 mutable_b.insert(mutable_b.upper_bound(key_of_value(
values[i])),
values[i]);
506 mutable_b.erase(mutable_b.begin(), mutable_b.end());
512 typename T::iterator mutable_iter_end = mutable_b.begin();
513 for (
int i = 0;
i <
values.size() / 2; ++
i) ++mutable_iter_end;
514 mutable_b.erase(mutable_b.begin(), mutable_iter_end);
520 typename T::iterator mutable_iter_begin = mutable_b.begin();
521 for (
int i = 0;
i <
values.size() / 2; ++
i) ++mutable_iter_begin;
522 mutable_b.erase(mutable_iter_begin, mutable_b.end());
528 mutable_iter_begin = mutable_b.begin();
529 for (
int i = 0;
i <
values.size() / 4; ++
i) ++mutable_iter_begin;
530 mutable_iter_end = mutable_iter_begin;
531 for (
int i = 0;
i <
values.size() / 4; ++
i) ++mutable_iter_end;
532 mutable_b.erase(mutable_iter_begin, mutable_iter_end);
539 template <
typename T>
545 const T &const_b = mutable_b;
549 mutable_b.insert(
value);
555 EXPECT_EQ(const_b.upper_bound(key_of_value(
value)), const_b.end());
559 typename T::iterator mutable_iter(mutable_b.begin());
560 EXPECT_EQ(mutable_iter, const_b.begin());
562 EXPECT_EQ(const_b.begin(), mutable_iter);
564 typename T::reverse_iterator mutable_riter(mutable_b.rbegin());
565 EXPECT_EQ(mutable_riter, const_b.rbegin());
566 EXPECT_NE(mutable_riter, const_b.rend());
567 EXPECT_EQ(const_b.rbegin(), mutable_riter);
568 EXPECT_NE(const_b.rend(), mutable_riter);
571 typename T::const_iterator const_iter(mutable_iter);
572 EXPECT_EQ(const_iter, mutable_b.begin());
574 EXPECT_EQ(mutable_b.begin(), const_iter);
576 typename T::const_reverse_iterator const_riter(mutable_riter);
577 EXPECT_EQ(const_riter, mutable_b.rbegin());
578 EXPECT_NE(const_riter, mutable_b.rend());
579 EXPECT_EQ(mutable_b.rbegin(), const_riter);
580 EXPECT_NE(mutable_b.rend(), const_riter);
591 template <
typename T,
typename C>
596 const std::vector<V> random_values = GenerateValuesWithSeed<V>(
603 std::vector<V> sorted_values(random_values);
604 std::sort(sorted_values.begin(), sorted_values.end());
608 std::reverse(sorted_values.begin(), sorted_values.end());
615 template <
typename T,
typename C>
616 void BtreeMultiTest() {
620 const std::vector<V> random_values = GenerateValuesWithSeed<V>(
627 std::vector<V> sorted_values(random_values);
628 std::sort(sorted_values.begin(), sorted_values.end());
632 std::reverse(sorted_values.begin(), sorted_values.end());
639 std::vector<V> duplicate_values(random_values);
640 duplicate_values.insert(duplicate_values.end(), random_values.begin(),
641 random_values.end());
645 std::vector<V> identical_values(100);
646 std::fill(identical_values.begin(), identical_values.end(),
651 template <
typename T>
652 struct PropagatingCountingAlloc :
public CountingAllocator<T> {
657 using Base = CountingAllocator<T>;
660 template <
typename U>
661 explicit PropagatingCountingAlloc(
const PropagatingCountingAlloc<U> &other)
662 : Base(other.bytes_used_) {}
664 template <
typename U>
666 using other = PropagatingCountingAlloc<U>;
670 template <
typename T>
671 void BtreeAllocatorTest() {
674 int64_t bytes1 = 0, bytes2 = 0;
675 PropagatingCountingAlloc<T> allocator1(&bytes1);
676 PropagatingCountingAlloc<T> allocator2(&bytes2);
677 Generator<value_type> generator(1000);
681 auto unused1 = allocator1.allocate(1);
682 auto unused2 = allocator2.allocate(1);
686 T b1(
typename T::key_compare(), allocator1);
687 T b2(
typename T::key_compare(), allocator2);
689 int64_t original_bytes1 = bytes1;
690 b1.insert(generator(0));
699 for (
int i = 1;
i < 1000;
i++) {
700 b1.insert(generator(i));
709 T b1(
typename T::key_compare(), allocator1);
710 T b2(
typename T::key_compare(), allocator2);
712 int64_t original_bytes1 = bytes1;
713 b1.insert(generator(0));
721 for (
int i = 1;
i < 1000;
i++) {
722 b1.insert(generator(i));
731 T b1(
typename T::key_compare(), allocator1);
732 T b2(
typename T::key_compare(), allocator2);
734 int64_t original_bytes1 = bytes1;
735 b1.insert(generator(0));
744 for (
int i = 1;
i < 1000;
i++) {
745 b1.insert(generator(i));
752 allocator1.deallocate(unused1, 1);
753 allocator2.deallocate(unused2, 1);
756 template <
typename T>
757 void BtreeMapTest() {
759 using mapped_type =
typename T::mapped_type;
761 mapped_type
m = Generator<mapped_type>(0)(0);
767 for (
int i = 0;
i < 1000;
i++) {
769 b[
v.first] =
v.second;
776 EXPECT_EQ(
b.begin()->first, Generator<value_type>(1000)(0).first);
777 EXPECT_EQ(
b.begin()->second, Generator<value_type>(1000)(0).second);
778 EXPECT_EQ(
b.rbegin()->first, Generator<value_type>(1000)(999).first);
779 EXPECT_EQ(
b.rbegin()->second, Generator<value_type>(1000)(999).second);
782 template <
typename T>
783 void BtreeMultiMapTest() {
784 using mapped_type =
typename T::mapped_type;
785 mapped_type
m = Generator<mapped_type>(0)(0);
789 template <
typename K,
int N = 256>
795 using CountingBtreeSet =
797 BtreeTest<BtreeSet, std::set<K>>();
798 BtreeAllocatorTest<CountingBtreeSet>();
801 template <
typename K,
int N = 256>
807 using CountingBtreeMap =
809 PropagatingCountingAlloc<std::pair<const K, K>>>;
810 BtreeTest<BtreeMap, std::map<K, K>>();
811 BtreeAllocatorTest<CountingBtreeMap>();
812 BtreeMapTest<BtreeMap>();
815 TEST(Btree, set_int32) { SetTest<int32_t>(); }
816 TEST(Btree, set_int64) { SetTest<int64_t>(); }
817 TEST(Btree, set_string) { SetTest<std::string>(); }
818 TEST(Btree, set_cord) { SetTest<absl::Cord>(); }
819 TEST(Btree, set_pair) { SetTest<std::pair<int, int>>(); }
820 TEST(Btree, map_int32) { MapTest<int32_t>(); }
821 TEST(Btree, map_int64) { MapTest<int64_t>(); }
822 TEST(Btree, map_string) { MapTest<std::string>(); }
823 TEST(Btree, map_cord) { MapTest<absl::Cord>(); }
824 TEST(Btree, map_pair) { MapTest<std::pair<int, int>>(); }
826 template <
typename K,
int N = 256>
827 void MultiSetTest() {
832 using CountingBtreeMSet =
834 BtreeMultiTest<BtreeMSet, std::multiset<K>>();
835 BtreeAllocatorTest<CountingBtreeMSet>();
838 template <
typename K,
int N = 256>
839 void MultiMapTest() {
844 using CountingBtreeMMap =
846 PropagatingCountingAlloc<std::pair<const K, K>>>;
847 BtreeMultiTest<BtreeMMap, std::multimap<K, K>>();
848 BtreeMultiMapTest<BtreeMMap>();
849 BtreeAllocatorTest<CountingBtreeMMap>();
852 TEST(Btree, multiset_int32) { MultiSetTest<int32_t>(); }
853 TEST(Btree, multiset_int64) { MultiSetTest<int64_t>(); }
854 TEST(Btree, multiset_string) { MultiSetTest<std::string>(); }
855 TEST(Btree, multiset_cord) { MultiSetTest<absl::Cord>(); }
856 TEST(Btree, multiset_pair) { MultiSetTest<std::pair<int, int>>(); }
857 TEST(Btree, multimap_int32) { MultiMapTest<int32_t>(); }
858 TEST(Btree, multimap_int64) { MultiMapTest<int64_t>(); }
859 TEST(Btree, multimap_string) { MultiMapTest<std::string>(); }
860 TEST(Btree, multimap_cord) { MultiMapTest<absl::Cord>(); }
861 TEST(Btree, multimap_pair) { MultiMapTest<std::pair<int, int>>(); }
863 struct CompareIntToString {
873 using is_transparent = void;
876 struct NonTransparentCompare {
877 template <
typename T,
typename U>
878 bool operator()(
const T &t,
const U &u)
const {
887 template <
typename T>
888 bool CanEraseWithEmptyBrace(
T t, decltype(
t.erase({})) *) {
892 template <
typename T>
893 bool CanEraseWithEmptyBrace(
T, ...) {
897 template <
typename T>
898 void TestHeterogeneous(
T table) {
899 auto lb =
table.lower_bound(
"3");
905 auto ub =
table.upper_bound(
"3");
911 auto er =
table.equal_range(
"3");
943 if (std::is_class<T>()) TestHeterogeneous<const T &>(
table);
946 TEST(Btree, HeterogeneousLookup) {
947 TestHeterogeneous(btree_set<std::string, CompareIntToString>{
"1",
"3",
"5"});
948 TestHeterogeneous(btree_map<std::string, int, CompareIntToString>{
949 {
"1", 1}, {
"3", 3}, {
"5", 5}});
951 btree_multiset<std::string, CompareIntToString>{
"1",
"3",
"5"});
952 TestHeterogeneous(btree_multimap<std::string, int, CompareIntToString>{
953 {
"1", 1}, {
"3", 3}, {
"5", 5}});
956 btree_map<std::string, int, CompareIntToString>
map{
957 {
"", -1}, {
"1", 1}, {
"3", 3}, {
"5", 5}};
961 const auto &cmap =
map;
967 TEST(Btree, NoHeterogeneousLookupWithoutAlias) {
979 using StringMultiSet =
986 EXPECT_TRUE(ms.begin() == ms.lower_bound(
"hello"));
993 TEST(Btree, DefaultTransparent) {
997 btree_set<int>
s = {1};
1005 btree_set<std::string>
s = {
"A"};
1013 StringLike() =
default;
1015 StringLike(
const char *s) :
s_(
s) {
1019 bool operator<(
const StringLike &a)
const {
return s_ <
a.s_; }
1032 TEST(Btree, HeterogeneousLookupDoesntDegradePerformance) {
1035 for (
int i = 0;
i < 100; ++
i) {
1038 StringLike::clear_constructor_call_count();
1042 StringLike::clear_constructor_call_count();
1046 StringLike::clear_constructor_call_count();
1050 StringLike::clear_constructor_call_count();
1051 s.lower_bound(
"50");
1054 StringLike::clear_constructor_call_count();
1055 s.upper_bound(
"50");
1058 StringLike::clear_constructor_call_count();
1059 s.equal_range(
"50");
1062 StringLike::clear_constructor_call_count();
1069 struct SubstringLess {
1070 SubstringLess() =
delete;
1079 TEST(Btree, SwapKeyCompare) {
1081 SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type());
1082 SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type());
1101 TEST(Btree, UpperBoundRegression) {
1105 SubstringSet my_set(SubstringLess(3));
1106 my_set.insert(
"aab");
1107 my_set.insert(
"abb");
1117 TEST(Btree, Comparison) {
1118 const int kSetSize = 1201;
1120 for (
int i = 0;
i < kSetSize; ++
i) {
1135 my_set.
erase(kSetSize - 1);
1142 for (
int i = 0;
i < kSetSize; ++
i) {
1157 my_map_copy = my_map;
1158 my_map[
"hello"] = kSetSize;
1171 TEST(Btree, RangeCtorSanity) {
1172 std::vector<int> ivec;
1174 std::map<int, int> imap;
1175 imap.insert(std::make_pair(1, 2));
1188 class BtreeNodePeer {
1191 template <
typename ValueType>
1196 false>>::SizeWithNSlots(target_values_per_node);
1200 template <
typename Btree>
1205 template <
typename Btree>
1207 return std::numeric_limits<
1211 template <
typename Btree>
1223 template <
typename T>
1224 bool operator()(
T,
T)
const {
1232 struct CmpLin : Cmp {
1239 struct CmpBin : Cmp {
1243 template <
typename K,
typename C>
1244 static bool IsLinear() {
1245 return BtreeNodePeer::UsesLinearNodeSearch<absl::btree_map<K, int, C>>();
1249 TEST_F(BtreeMapTest, TestLinearSearchPreferredForKeyLinearViaAlias) {
1257 TEST_F(BtreeMapTest, LinearChoiceTree) {
1276 EXPECT_TRUE((IsLinear<
double, std::greater<double>>()));
1283 TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) {
1286 std::unique_ptr<std::string> &
v =
m[
"A"];
1290 auto iter =
m.find(
"A");
1294 TEST(Btree, InitializerListConstructor) {
1308 auto range = mmap.equal_range(1);
1317 TEST(Btree, InitializerListInsert) {
1319 set.insert({
"a",
"b"});
1329 map.insert({{1, 5}, {2, 10}});
1331 map.insert({3, 15});
1337 mmap.insert({{1, 5}, {1, 10}});
1338 auto range = mmap.equal_range(1);
1347 template <
typename Compare,
typename K>
1348 void AssertKeyCompareToAdapted() {
1351 "key_compare_to_adapter should have adapted this comparator.");
1355 "Adapted comparator should be a key-compare-to comparator.");
1357 template <
typename Compare,
typename K>
1358 void AssertKeyCompareToNotAdapted() {
1362 "key_compare_to_adapter shouldn't have adapted this comparator.");
1366 "Un-adapted comparator should return bool.");
1369 TEST(Btree, KeyCompareToAdapter) {
1370 AssertKeyCompareToAdapted<std::less<std::string>,
std::string>();
1371 AssertKeyCompareToAdapted<std::greater<std::string>,
std::string>();
1373 AssertKeyCompareToAdapted<std::greater<absl::string_view>,
1375 AssertKeyCompareToAdapted<std::less<absl::Cord>,
absl::Cord>();
1376 AssertKeyCompareToAdapted<std::greater<absl::Cord>,
absl::Cord>();
1377 AssertKeyCompareToNotAdapted<std::less<int>,
int>();
1378 AssertKeyCompareToNotAdapted<std::greater<int>,
int>();
1381 TEST(Btree, RValueInsert) {
1385 set.insert(MovableOnlyInstance(1));
1386 set.insert(MovableOnlyInstance(3));
1387 MovableOnlyInstance two(2);
1389 auto it =
set.find(MovableOnlyInstance(2));
1395 MovableOnlyInstance zero(0);
1396 MovableOnlyInstance zero2(0);
1402 std::pair<const int, MovableOnlyInstance> p1 = {1, MovableOnlyInstance(5)};
1403 std::pair<const int, MovableOnlyInstance> p2 = {2, MovableOnlyInstance(10)};
1404 std::pair<const int, MovableOnlyInstance> p3 = {3, MovableOnlyInstance(15)};
1412 std::pair<const int, MovableOnlyInstance> p4 = {1, MovableOnlyInstance(5)};
1413 std::pair<const int, MovableOnlyInstance> p5 = {1, MovableOnlyInstance(10)};
1415 mmap.insert(mmap.find(1),
std::move(p5));
1416 auto range = mmap.equal_range(1);
1417 auto it1 =
range.first;
1429 template <
typename Key,
int TargetValuesPerNode,
typename Cmp = std::less<Key>>
1431 :
public btree_set_container<btree<
1432 set_params<Key, Cmp, std::allocator<Key>,
1433 BtreeNodePeer::GetTargetNodeSize<Key>(TargetValuesPerNode),
1435 using Base =
typename SizedBtreeSet::btree_set_container;
1442 template <
typename Set>
1443 void ExpectOperationCounts(
const int expected_moves,
1444 const int expected_comparisons,
1445 const std::vector<int> &
values,
1447 for (
const int v :
values)
set->insert(MovableOnlyInstance(
v));
1453 tracker->ResetCopiesMovesSwaps();
1458 TEST(Btree, MovesComparisonsCopiesSwapsTracking) {
1461 SizedBtreeSet<MovableOnlyInstance, 4> set4;
1464 SizedBtreeSet<MovableOnlyInstance, 61> set61;
1465 SizedBtreeSet<MovableOnlyInstance, 100> set100;
1469 std::vector<int>
values =
1470 GenerateValuesWithSeed<int>(10000, 1 << 22, 23);
1475 if (
sizeof(
void *) == 8) {
1481 ExpectOperationCounts(56540, 134212,
values, &
tracker, &set4);
1482 ExpectOperationCounts(386718, 129807,
values, &
tracker, &set61);
1483 ExpectOperationCounts(586761, 130310,
values, &
tracker, &set100);
1487 ExpectOperationCounts(24972, 85563,
values, &
tracker, &set4);
1488 ExpectOperationCounts(20208, 87757,
values, &
tracker, &set61);
1489 ExpectOperationCounts(20124, 96583,
values, &
tracker, &set100);
1493 ExpectOperationCounts(54949, 127531,
values, &
tracker, &set4);
1494 ExpectOperationCounts(338813, 118266,
values, &
tracker, &set61);
1495 ExpectOperationCounts(534529, 125279,
values, &
tracker, &set100);
1498 struct MovableOnlyInstanceThreeWayCompare {
1500 const MovableOnlyInstance &
b)
const {
1501 return a.compare(
b);
1507 TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) {
1510 SizedBtreeSet<MovableOnlyInstance, 4,
1511 MovableOnlyInstanceThreeWayCompare>
1515 SizedBtreeSet<MovableOnlyInstance, 61,
1516 MovableOnlyInstanceThreeWayCompare>
1518 SizedBtreeSet<MovableOnlyInstance, 100,
1519 MovableOnlyInstanceThreeWayCompare>
1524 std::vector<int>
values =
1525 GenerateValuesWithSeed<int>(10000, 1 << 22, 23);
1530 if (
sizeof(
void *) == 8) {
1536 ExpectOperationCounts(56540, 124221,
values, &
tracker, &set4);
1537 ExpectOperationCounts(386718, 119816,
values, &
tracker, &set61);
1538 ExpectOperationCounts(586761, 120319,
values, &
tracker, &set100);
1542 ExpectOperationCounts(24972, 85563,
values, &
tracker, &set4);
1543 ExpectOperationCounts(20208, 87757,
values, &
tracker, &set61);
1544 ExpectOperationCounts(20124, 96583,
values, &
tracker, &set100);
1548 ExpectOperationCounts(54949, 117532,
values, &
tracker, &set4);
1549 ExpectOperationCounts(338813, 108267,
values, &
tracker, &set61);
1550 ExpectOperationCounts(534529, 115280,
values, &
tracker, &set100);
1553 struct NoDefaultCtor {
1555 explicit NoDefaultCtor(
int i) :
num(
i) {}
1557 friend bool operator<(
const NoDefaultCtor &a,
const NoDefaultCtor &
b) {
1558 return a.num <
b.num;
1562 TEST(Btree, BtreeMapCanHoldNoDefaultCtorTypes) {
1565 for (
int i = 1;
i <= 99; ++
i) {
1571 auto iter99 =
m.find(NoDefaultCtor(99));
1575 auto iter1 =
m.find(NoDefaultCtor(1));
1579 auto iter50 =
m.find(NoDefaultCtor(50));
1583 auto iter25 =
m.find(NoDefaultCtor(25));
1588 TEST(Btree, BtreeMultimapCanHoldNoDefaultCtorTypes) {
1591 for (
int i = 1;
i <= 99; ++
i) {
1593 m.emplace(NoDefaultCtor(i), NoDefaultCtor(100 - i));
1596 auto iter99 =
m.find(NoDefaultCtor(99));
1600 auto iter1 =
m.find(NoDefaultCtor(1));
1604 auto iter50 =
m.find(NoDefaultCtor(50));
1608 auto iter25 =
m.find(NoDefaultCtor(25));
1613 TEST(Btree, MapAt) {
1621 #ifdef ABSL_HAVE_EXCEPTIONS
1628 TEST(Btree, BtreeMultisetEmplace) {
1629 const int value_to_insert = 123456;
1631 auto iter =
s.emplace(value_to_insert);
1634 auto iter2 =
s.emplace(value_to_insert);
1638 auto result =
s.equal_range(value_to_insert);
1642 TEST(Btree, BtreeMultisetEmplaceHint) {
1643 const int value_to_insert = 123456;
1645 auto iter =
s.emplace(value_to_insert);
1648 auto emplace_iter =
s.emplace_hint(
iter, value_to_insert);
1651 EXPECT_EQ(*emplace_iter, value_to_insert);
1654 TEST(Btree, BtreeMultimapEmplace) {
1655 const int key_to_insert = 123456;
1656 const char value0[] =
"a";
1658 auto iter =
s.emplace(key_to_insert, value0);
1662 const char value1[] =
"b";
1663 auto iter2 =
s.emplace(key_to_insert, value1);
1668 auto result =
s.equal_range(key_to_insert);
1672 TEST(Btree, BtreeMultimapEmplaceHint) {
1673 const int key_to_insert = 123456;
1674 const char value0[] =
"a";
1676 auto iter =
s.emplace(key_to_insert, value0);
1680 const char value1[] =
"b";
1681 auto emplace_iter =
s.emplace_hint(
iter, key_to_insert, value1);
1684 EXPECT_EQ(emplace_iter->first, key_to_insert);
1685 EXPECT_EQ(emplace_iter->second, value1);
1688 TEST(Btree, ConstIteratorAccessors) {
1690 for (
int i = 0;
i < 100; ++
i) {
1694 auto it =
set.cbegin();
1695 auto r_it =
set.crbegin();
1696 for (
int i = 0;
i < 100; ++
i, ++
it, ++r_it) {
1704 TEST(Btree, StrSplitCompatible) {
1716 TEST(Btree, ValueComp) {
1723 EXPECT_TRUE(m1.value_comp()(std::make_pair(1, 0), std::make_pair(2, 0)));
1724 EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(2, 0)));
1725 EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(1, 0)));
1729 m2.value_comp()(std::make_pair(
"a", 0), std::make_pair(
"b", 0)) < 0));
1731 m2.value_comp()(std::make_pair(
"b", 0), std::make_pair(
"b", 0)) == 0));
1733 m2.value_comp()(std::make_pair(
"b", 0), std::make_pair(
"a", 0)) > 0));
1736 TEST(Btree, DefaultConstruction) {
1748 TEST(Btree, SwissTableHashable) {
1749 static constexpr
int kValues = 10000;
1750 std::vector<int>
values(kValues);
1752 std::vector<std::pair<int, int>> map_values;
1753 for (
int v :
values) map_values.emplace_back(
v, -
v);
1788 map{{1, 0}, {2, 1}},
1789 map(map_values.begin(), map_values.end()),
1790 map(map_values.rbegin(), map_values.rend()),
1798 mmap{{1, 0}, {1, 1}},
1799 mmap{{1, 1}, {1, 0}},
1802 mmap{{1, 0}, {2, 1}},
1803 mmap(map_values.begin(), map_values.end()),
1804 mmap(map_values.rbegin(), map_values.rend()),
1808 TEST(Btree, ComparableSet) {
1819 TEST(Btree, ComparableSetsDifferentLength) {
1828 TEST(Btree, ComparableMultiset) {
1839 TEST(Btree, ComparableMap) {
1850 TEST(Btree, ComparableMultimap) {
1861 TEST(Btree, ComparableSetWithCustomComparator) {
1877 TEST(Btree, EraseReturnsIterator) {
1879 auto result_it =
set.erase(
set.begin(),
set.find(3));
1881 result_it =
set.erase(
set.find(5));
1885 TEST(Btree, ExtractAndInsertNodeHandleSet) {
1907 template <
typename Set>
1908 void TestExtractWithTrackingForSet() {
1913 const size_t kSize = 1000;
1914 while (
s.size() < kSize) {
1915 s.insert(MovableOnlyInstance(
s.size()));
1917 for (
int i = 0;
i <
kSize; ++
i) {
1919 auto nh =
s.extract(MovableOnlyInstance(i));
1927 auto it =
s.find(MovableOnlyInstance(i));
1939 template <
typename Map>
1940 void TestExtractWithTrackingForMap() {
1945 const size_t kSize = 1000;
1946 while (
m.size() < kSize) {
1948 {CopyableMovableInstance(
m.size()), MovableOnlyInstance(
m.size())});
1950 for (
int i = 0;
i <
kSize; ++
i) {
1952 auto nh =
m.extract(CopyableMovableInstance(i));
1961 auto it =
m.find(CopyableMovableInstance(i));
1974 TEST(Btree, ExtractTracking) {
1975 TestExtractWithTrackingForSet<absl::btree_set<MovableOnlyInstance>>();
1976 TestExtractWithTrackingForSet<absl::btree_multiset<MovableOnlyInstance>>();
1977 TestExtractWithTrackingForMap<
1979 TestExtractWithTrackingForMap<
1983 TEST(Btree, ExtractAndInsertNodeHandleMultiSet) {
2000 TEST(Btree, ExtractAndInsertNodeHandleMap) {
2002 auto nh = src1.extract(src1.find(3));
2013 nh = src2.extract(src2.find(3));
2024 TEST(Btree, ExtractAndInsertNodeHandleMultiMap) {
2026 auto nh = src1.extract(src1.find(3));
2034 nh = src2.extract(src2.find(3));
2041 TEST(Btree, ExtractMultiMapEquivalentKeys) {
2044 for (
int i = 0;
i < 100; ++
i) {
2045 for (
int j = 0;
j < 100; ++
j) {
2050 for (
int i = 0;
i < 100; ++
i) {
2052 auto node_handle =
map.extract(
key);
2057 for (
int i = 0;
i < 100; ++
i) {
2059 auto node_handle =
map.extract(
key);
2067 struct InsertMultiHintData {
2070 bool operator==(
const InsertMultiHintData other)
const {
2071 return key == other.key &&
not_key == other.not_key;
2075 struct InsertMultiHintDataKeyCompare {
2076 using is_transparent = void;
2077 bool operator()(
const InsertMultiHintData a,
2078 const InsertMultiHintData
b)
const {
2079 return a.key <
b.key;
2081 bool operator()(
const int a,
const InsertMultiHintData
b)
const {
2084 bool operator()(
const InsertMultiHintData a,
const int b)
const {
2089 TEST(Btree, InsertHintNodeHandle) {
2110 {{1, 2}, {3, 4}, {3, 5}};
2112 EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 4}));
2114 other = {{3, 1}, {3, 2}, {3, 3}};
2117 other,
ElementsAre(InsertMultiHintData{3, 1}, InsertMultiHintData{3, 2},
2118 InsertMultiHintData{3, 4}, InsertMultiHintData{3, 3}));
2122 EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 5}));
2125 ElementsAre(InsertMultiHintData{3, 5}, InsertMultiHintData{3, 1},
2126 InsertMultiHintData{3, 2}, InsertMultiHintData{3, 4},
2127 InsertMultiHintData{3, 3}));
2131 struct IntCompareToCmp {
2133 if (a <
b)
return absl::weak_ordering::less;
2134 if (a >
b)
return absl::weak_ordering::greater;
2135 return absl::weak_ordering::equivalent;
2139 TEST(Btree, MergeIntoUniqueContainers) {
2152 TEST(Btree, MergeIntoUniqueContainersWithCompareTo) {
2165 TEST(Btree, MergeIntoMultiContainers) {
2178 TEST(Btree, MergeIntoMultiContainersWithCompareTo) {
2191 TEST(Btree, MergeIntoMultiMapsWithDifferentComparators) {
2194 {5, 5}, {4, 1}, {4, 4}, {3, 2}};
2206 TEST(Btree, MergeIntoSetMovableOnly) {
2208 src.
insert(MovableOnlyInstance(1));
2210 dst1.
insert(MovableOnlyInstance(2));
2231 struct KeyCompareToWeakOrdering {
2232 template <
typename T>
2234 return a <
b ? absl::weak_ordering::less
2235 :
a ==
b ? absl::weak_ordering::equivalent
2236 : absl::weak_ordering::greater;
2240 struct KeyCompareToStrongOrdering {
2241 template <
typename T>
2243 return a <
b ? absl::strong_ordering::less
2245 : absl::strong_ordering::greater;
2249 TEST(Btree, UserProvidedKeyCompareToComparators) {
2259 TEST(Btree, TryEmplaceBasicTest) {
2263 m.try_emplace(1,
"one");
2268 m.try_emplace(
key, 3,
'a');
2273 {1,
"one"}, {2,
"two"}, {42,
"aaa"}}));
2276 TEST(Btree, TryEmplaceWithHintWorks) {
2283 using Cmp = decltype(
cmp);
2286 for (
int i = 0;
i < 128; ++
i) {
2292 m.emplace(127, 127);
2297 auto it =
m.try_emplace(
m.begin(), -1, -1);
2304 std::pair<int, int> pair1024 = {1024, 1024};
2305 it =
m.try_emplace(
m.end(), pair1024.first, pair1024.second);
2312 it =
m.try_emplace(
m.end(), 16, 17);
2319 it =
m.try_emplace(
it, 16, 17);
2326 auto hint =
m.find(3);
2329 m.try_emplace(hint, 2, 2);
2336 TEST(Btree, TryEmplaceWithBadHint) {
2340 auto it =
m.try_emplace(
m.begin(), 2, 2);
2343 std::vector<std::pair<int, int>>{{1, 1}, {2, 2}, {9, 9}}));
2346 it =
m.try_emplace(++(++
m.begin()), 0, 0);
2349 {0, 0}, {1, 1}, {2, 2}, {9, 9}}));
2352 TEST(Btree, TryEmplaceMaintainsSortedOrder) {
2354 std::pair<int, std::string> pair5 = {5,
"five"};
2357 m.try_emplace(10,
"ten");
2358 m.try_emplace(pair5.first, pair5.second);
2363 m.try_emplace(int100,
"hundred");
2364 m.try_emplace(1,
"one");
2369 TEST(Btree, TryEmplaceWithHintAndNoValueArgsWorks) {
2371 m.try_emplace(
m.end(), 1);
2375 TEST(Btree, TryEmplaceWithHintAndMultipleValueArgsWorks) {
2377 m.try_emplace(
m.end(), 1, 10,
'a');
2381 TEST(Btree, MoveAssignmentAllocatorPropagation) {
2384 int64_t bytes1 = 0, bytes2 = 0;
2385 PropagatingCountingAlloc<MovableOnlyInstance> allocator1(&bytes1);
2386 PropagatingCountingAlloc<MovableOnlyInstance> allocator2(&bytes2);
2387 std::less<MovableOnlyInstance>
cmp;
2392 PropagatingCountingAlloc<MovableOnlyInstance>>
2393 set1(
cmp, allocator1), set2(
cmp, allocator2);
2395 for (
int i = 0;
i < 100; ++
i) set1.insert(MovableOnlyInstance(i));
2397 tracker.ResetCopiesMovesSwaps();
2404 CountingAllocator<MovableOnlyInstance>>
2405 set1(
cmp, allocator1), set2(
cmp, allocator1);
2407 for (
int i = 0;
i < 100; ++
i) set1.insert(MovableOnlyInstance(i));
2409 tracker.ResetCopiesMovesSwaps();
2416 CountingAllocator<MovableOnlyInstance>>
2417 set1(
cmp, allocator1), set2(
cmp, allocator2);
2419 for (
int i = 0;
i < 100; ++
i) set1.insert(MovableOnlyInstance(i));
2421 tracker.ResetCopiesMovesSwaps();
2427 TEST(Btree, EmptyTree) {
2434 bool IsEven(
int k) {
return k % 2 == 0; }
2450 erase_if(
m, [](std::pair<const int, int> kv) {
return kv.first > 3; });
2455 {6, 6}, {6, 7}, {100, 6}};
2456 erase_if(
m, [](std::pair<const int, int> kv) {
return kv.second == 6; });
2463 for (
int i = 0;
i < 1000; ++
i)
s.insert(2 * i);
2475 TEST(Btree, InsertOrAssign) {
2479 auto ret =
m.insert_or_assign(4, 4);
2482 ret =
m.insert_or_assign(3, 100);
2486 auto hint_ret =
m.insert_or_assign(
ret.first, 3, 200);
2488 hint_ret =
m.insert_or_assign(
m.find(1), 0, 1);
2491 hint_ret =
m.insert_or_assign(
m.end(), -1, 1);
2498 TEST(Btree, InsertOrAssignMovableOnly) {
2502 auto ret =
m.insert_or_assign(4, MovableOnlyInstance(4));
2505 ret =
m.insert_or_assign(4, MovableOnlyInstance(100));
2509 auto hint_ret =
m.insert_or_assign(
ret.first, 3, MovableOnlyInstance(200));
2515 TEST(Btree, BitfieldArgument) {
2526 m.insert_or_assign(n, n);
2527 m.insert_or_assign(
m.end(), n, n);
2529 m.try_emplace(
m.end(), n);
2534 TEST(Btree, SetRangeConstructorAndInsertSupportExplicitConversionComparable) {
2546 struct ConstructorCounted {
2548 bool operator==(
int other)
const {
return i == other; }
2555 struct ConstructorCountedCompare {
2556 bool operator()(
int a,
const ConstructorCounted &
b)
const {
return a <
b.i; }
2557 bool operator()(
const ConstructorCounted &a,
int b)
const {
return a.i <
b; }
2558 bool operator()(
const ConstructorCounted &a,
2559 const ConstructorCounted &
b)
const {
2562 using is_transparent = void;
2566 SetRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
2567 const int i[] = {0, 1, 1};
2581 SetRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
2582 const int i[] = {0, 1};
2596 #if !defined(__GLIBCXX__) || \
2597 (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 7)
2598 TEST(Btree, MapRangeConstructorAndInsertSupportExplicitConversionComparable) {
2599 const std::pair<absl::string_view, int>
names[] = {{
"n1", 1}, {
"n2", 2}};
2611 MapRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
2612 const std::pair<int, int>
i[] = {{0, 1}, {1, 2}, {1, 3}};
2626 MapRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
2627 const std::pair<int, int>
i[] = {{0, 1}, {1, 2}};
2639 TEST(Btree, HeterogeneousTryEmplace) {
2643 m.try_emplace(sv, 1);
2646 m.try_emplace(
m.end(), sv, 2);
2650 TEST(Btree, HeterogeneousOperatorMapped) {
2661 TEST(Btree, HeterogeneousInsertOrAssign) {
2665 m.insert_or_assign(sv, 1);
2668 m.insert_or_assign(
m.end(), sv, 2);
2674 #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
2675 TEST(Btree, NodeHandleMutableKeyAccess) {
2679 map[
"key1"] =
"mapped";
2681 auto nh =
map.extract(
map.begin());
2691 map.emplace(
"key1",
"mapped");
2693 auto nh =
map.extract(
map.begin());
2707 bool operator==(
const MultiKey a,
const MultiKey
b) {
2708 return a.i1 ==
b.i1 &&
a.i2 ==
b.i2;
2713 struct MultiKeyComp {
2714 using is_transparent = void;
2715 bool operator()(
const MultiKey a,
const MultiKey
b)
const {
2716 if (
a.i1 !=
b.i1)
return a.i1 <
b.i1;
2719 bool operator()(
const int a,
const MultiKey
b)
const {
return a <
b.i1; }
2720 bool operator()(
const MultiKey a,
const int b)
const {
return a.i1 <
b; }
2725 struct MultiKeyThreeWayComp {
2726 using is_transparent = void;
2728 if (
a.i1 <
b.i1)
return absl::weak_ordering::less;
2729 if (
a.i1 >
b.i1)
return absl::weak_ordering::greater;
2730 if (
a.i2 <
b.i2)
return absl::weak_ordering::less;
2731 if (
a.i2 >
b.i2)
return absl::weak_ordering::greater;
2732 return absl::weak_ordering::equivalent;
2735 if (a <
b.i1)
return absl::weak_ordering::less;
2736 if (a >
b.i1)
return absl::weak_ordering::greater;
2737 return absl::weak_ordering::equivalent;
2740 if (
a.i1 <
b)
return absl::weak_ordering::less;
2741 if (
a.i1 >
b)
return absl::weak_ordering::greater;
2742 return absl::weak_ordering::equivalent;
2746 template <
typename Compare>
2753 for (
int i = 0;
i < 100; ++
i) {
2754 for (
int j = 0;
j < 100; ++
j) {
2759 for (
int i = 0;
i < 100; ++
i) {
2760 auto equal_range =
set.equal_range(i);
2763 EXPECT_EQ(std::distance(equal_range.first, equal_range.second), 100) <<
i;
2769 for (
int i = 0;
i < 100; ++
i) {
2770 for (
int j = 0;
j < 100; ++
j) {
2775 for (
int i = 0;
i < 100; ++
i) {
2776 auto node_handle =
set.extract(i);
2781 for (
int i = 0;
i < 100; ++
i) {
2782 auto node_handle =
set.extract(i);
2790 {1, 1}, {2, 1}, {2, 2}, {3, 1}};
2797 {1, 1}, {2, 1}, {2, 2}, {3, 1}};
2801 TEST(Btree, AllocConstructor) {
2802 using Alloc = CountingAllocator<int>;
2808 set.insert({1, 2, 3});
2814 TEST(Btree, AllocInitializerListConstructor) {
2815 using Alloc = CountingAllocator<int>;
2825 TEST(Btree, AllocRangeConstructor) {
2826 using Alloc = CountingAllocator<int>;
2830 std::vector<int>
v = {1, 2, 3};
2837 TEST(Btree, AllocCopyConstructor) {
2838 using Alloc = CountingAllocator<int>;
2841 Alloc alloc1(&bytes_used1);
2844 set1.insert({1, 2, 3});
2847 Alloc alloc2(&bytes_used2);
2848 Set set2(set1, alloc2);
2852 EXPECT_GT(bytes_used1, set1.size() *
sizeof(
int));
2856 TEST(Btree, AllocMoveConstructor_SameAlloc) {
2857 using Alloc = CountingAllocator<int>;
2863 set1.insert({1, 2, 3});
2865 const int64_t original_bytes_used = bytes_used;
2866 EXPECT_GT(original_bytes_used, set1.size() *
sizeof(
int));
2871 EXPECT_EQ(bytes_used, original_bytes_used);
2874 TEST(Btree, AllocMoveConstructor_DifferentAlloc) {
2875 using Alloc = CountingAllocator<int>;
2878 Alloc alloc1(&bytes_used1);
2881 set1.insert({1, 2, 3});
2883 const int64_t original_bytes_used = bytes_used1;
2884 EXPECT_GT(original_bytes_used, set1.size() *
sizeof(
int));
2887 Alloc alloc2(&bytes_used2);
2892 EXPECT_EQ(bytes_used1, original_bytes_used);
2893 EXPECT_EQ(bytes_used2, original_bytes_used);