From 37f42d1f22383fbe0db91f0574451b32a2b851ab Mon Sep 17 00:00:00 2001 From: greg Date: Mon, 30 Dec 2019 13:50:16 -0500 Subject: [PATCH] indentation and license update --- tests/btree_test.cc | 4055 ++++++++++++++++++++++--------------------- tests/btree_test.h | 19 + 2 files changed, 2056 insertions(+), 2018 deletions(-) diff --git a/tests/btree_test.cc b/tests/btree_test.cc index f091800..775ebb3 100644 --- a/tests/btree_test.cc +++ b/tests/btree_test.cc @@ -1,3 +1,21 @@ +// --------------------------------------------------------------------------- +// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp) +// with modifications. +// // Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -11,6 +29,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// --------------------------------------------------------------------------- #include #include "btree_test.h" @@ -34,27 +53,27 @@ namespace phmap { namespace container_internal { namespace { -using ::phmap::test_internal::CopyableMovableInstance; -using ::phmap::test_internal::InstanceTracker; -using ::phmap::test_internal::MovableOnlyInstance; -using ::testing::ElementsAre; -using ::testing::ElementsAreArray; -using ::testing::IsEmpty; -using ::testing::Pair; + using ::phmap::test_internal::CopyableMovableInstance; + using ::phmap::test_internal::InstanceTracker; + using ::phmap::test_internal::MovableOnlyInstance; + using ::testing::ElementsAre; + using ::testing::ElementsAreArray; + using ::testing::IsEmpty; + using ::testing::Pair; -#define PHMAP_INTERNAL_CHECK(condition, message) \ +#define PHMAP_INTERNAL_CHECK(condition, message) \ if (!(condition)) assert(0) -template -void CheckPairEquals(const T &x, const U &y) { - PHMAP_INTERNAL_CHECK(x == y, "Values are unequal."); -} + template + void CheckPairEquals(const T &x, const U &y) { + PHMAP_INTERNAL_CHECK(x == y, "Values are unequal."); + } -template -void CheckPairEquals(const std::pair &x, const std::pair &y) { - CheckPairEquals(x.first, y.first); - CheckPairEquals(x.second, y.second); -} + template + void CheckPairEquals(const std::pair &x, const std::pair &y) { + CheckPairEquals(x.first, y.first); + CheckPairEquals(x.second, y.second); + } } // namespace // The base class for a sorted associative container checker. TreeType is the @@ -63,2290 +82,2290 @@ void CheckPairEquals(const std::pair &x, const std::pair &y) { // CheckerType is expected to be {set,map,multiset,multimap}. template class base_checker { - public: - using key_type = typename TreeType::key_type; - using value_type = typename TreeType::value_type; - using key_compare = typename TreeType::key_compare; - using pointer = typename TreeType::pointer; - using const_pointer = typename TreeType::const_pointer; - using reference = typename TreeType::reference; - using const_reference = typename TreeType::const_reference; - using size_type = typename TreeType::size_type; - using difference_type = typename TreeType::difference_type; - using iterator = typename TreeType::iterator; - using const_iterator = typename TreeType::const_iterator; - using reverse_iterator = typename TreeType::reverse_iterator; - using const_reverse_iterator = typename TreeType::const_reverse_iterator; +public: + using key_type = typename TreeType::key_type; + using value_type = typename TreeType::value_type; + using key_compare = typename TreeType::key_compare; + using pointer = typename TreeType::pointer; + using const_pointer = typename TreeType::const_pointer; + using reference = typename TreeType::reference; + using const_reference = typename TreeType::const_reference; + using size_type = typename TreeType::size_type; + using difference_type = typename TreeType::difference_type; + using iterator = typename TreeType::iterator; + using const_iterator = typename TreeType::const_iterator; + using reverse_iterator = typename TreeType::reverse_iterator; + using const_reverse_iterator = typename TreeType::const_reverse_iterator; - public: - base_checker() : const_tree_(tree_) {} - base_checker(const base_checker &x) - : tree_(x.tree_), const_tree_(tree_), checker_(x.checker_) {} - template - base_checker(InputIterator b, InputIterator e) - : tree_(b, e), const_tree_(tree_), checker_(b, e) {} +public: + base_checker() : const_tree_(tree_) {} + base_checker(const base_checker &x) + : tree_(x.tree_), const_tree_(tree_), checker_(x.checker_) {} + template + base_checker(InputIterator b, InputIterator e) + : tree_(b, e), const_tree_(tree_), checker_(b, e) {} - iterator begin() { return tree_.begin(); } - const_iterator begin() const { return tree_.begin(); } - iterator end() { return tree_.end(); } - const_iterator end() const { return tree_.end(); } - reverse_iterator rbegin() { return tree_.rbegin(); } - const_reverse_iterator rbegin() const { return tree_.rbegin(); } - reverse_iterator rend() { return tree_.rend(); } - const_reverse_iterator rend() const { return tree_.rend(); } + iterator begin() { return tree_.begin(); } + const_iterator begin() const { return tree_.begin(); } + iterator end() { return tree_.end(); } + const_iterator end() const { return tree_.end(); } + reverse_iterator rbegin() { return tree_.rbegin(); } + const_reverse_iterator rbegin() const { return tree_.rbegin(); } + reverse_iterator rend() { return tree_.rend(); } + const_reverse_iterator rend() const { return tree_.rend(); } - template - IterType iter_check(IterType tree_iter, CheckerIterType checker_iter) const { - if (tree_iter == tree_.end()) { - PHMAP_INTERNAL_CHECK(checker_iter == checker_.end(), - "Checker iterator not at end."); - } else { - CheckPairEquals(*tree_iter, *checker_iter); + template + IterType iter_check(IterType tree_iter, CheckerIterType checker_iter) const { + if (tree_iter == tree_.end()) { + PHMAP_INTERNAL_CHECK(checker_iter == checker_.end(), + "Checker iterator not at end."); + } else { + CheckPairEquals(*tree_iter, *checker_iter); + } + return tree_iter; } - return tree_iter; - } - template - IterType riter_check(IterType tree_iter, CheckerIterType checker_iter) const { - if (tree_iter == tree_.rend()) { - PHMAP_INTERNAL_CHECK(checker_iter == checker_.rend(), - "Checker iterator not at rend."); - } else { - CheckPairEquals(*tree_iter, *checker_iter); + template + IterType riter_check(IterType tree_iter, CheckerIterType checker_iter) const { + if (tree_iter == tree_.rend()) { + PHMAP_INTERNAL_CHECK(checker_iter == checker_.rend(), + "Checker iterator not at rend."); + } else { + CheckPairEquals(*tree_iter, *checker_iter); + } + return tree_iter; } - return tree_iter; - } - void value_check(const value_type &x) { - typename KeyOfValue::type key_of_value; - const key_type &key = key_of_value(x); - CheckPairEquals(*find(key), x); - lower_bound(key); - upper_bound(key); - equal_range(key); - contains(key); - count(key); - } - void erase_check(const key_type &key) { - EXPECT_FALSE(tree_.contains(key)); - EXPECT_EQ(tree_.find(key), const_tree_.end()); - EXPECT_FALSE(const_tree_.contains(key)); - EXPECT_EQ(const_tree_.find(key), tree_.end()); - EXPECT_EQ(tree_.equal_range(key).first, - const_tree_.equal_range(key).second); - } - - iterator lower_bound(const key_type &key) { - return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); - } - const_iterator lower_bound(const key_type &key) const { - return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); - } - iterator upper_bound(const key_type &key) { - return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); - } - const_iterator upper_bound(const key_type &key) const { - return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); - } - std::pair equal_range(const key_type &key) { - std::pair - checker_res = checker_.equal_range(key); - std::pair tree_res = tree_.equal_range(key); - iter_check(tree_res.first, checker_res.first); - iter_check(tree_res.second, checker_res.second); - return tree_res; - } - std::pair equal_range( - const key_type &key) const { - std::pair - checker_res = checker_.equal_range(key); - std::pair tree_res = tree_.equal_range(key); - iter_check(tree_res.first, checker_res.first); - iter_check(tree_res.second, checker_res.second); - return tree_res; - } - iterator find(const key_type &key) { - return iter_check(tree_.find(key), checker_.find(key)); - } - const_iterator find(const key_type &key) const { - return iter_check(tree_.find(key), checker_.find(key)); - } - bool contains(const key_type &key) const { - return find(key) != end(); - } - size_type count(const key_type &key) const { - size_type res = checker_.count(key); - EXPECT_EQ(res, tree_.count(key)); - return res; - } - - base_checker &operator=(const base_checker &x) { - tree_ = x.tree_; - checker_ = x.checker_; - return *this; - } - - int erase(const key_type &key) { - int size = tree_.size(); - int res = checker_.erase(key); - EXPECT_EQ(res, tree_.count(key)); - EXPECT_EQ(res, tree_.erase(key)); - EXPECT_EQ(tree_.count(key), 0); - EXPECT_EQ(tree_.size(), size - res); - erase_check(key); - return res; - } - iterator erase(iterator iter) { - key_type key = iter.key(); - int size = tree_.size(); - int count = tree_.count(key); - auto checker_iter = checker_.lower_bound(key); - for (iterator tmp(tree_.lower_bound(key)); tmp != iter; ++tmp) { - ++checker_iter; + void value_check(const value_type &x) { + typename KeyOfValue::type key_of_value; + const key_type &key = key_of_value(x); + CheckPairEquals(*find(key), x); + lower_bound(key); + upper_bound(key); + equal_range(key); + contains(key); + count(key); } - auto checker_next = checker_iter; - ++checker_next; - checker_.erase(checker_iter); - iter = tree_.erase(iter); - EXPECT_EQ(tree_.size(), checker_.size()); - EXPECT_EQ(tree_.size(), size - 1); - EXPECT_EQ(tree_.count(key), count - 1); - if (count == 1) { - erase_check(key); - } - return iter_check(iter, checker_next); - } - - void erase(iterator begin, iterator end) { - int size = tree_.size(); - int count = std::distance(begin, end); - auto checker_begin = checker_.lower_bound(begin.key()); - for (iterator tmp(tree_.lower_bound(begin.key())); tmp != begin; ++tmp) { - ++checker_begin; - } - auto checker_end = - end == tree_.end() ? checker_.end() : checker_.lower_bound(end.key()); - if (end != tree_.end()) { - for (iterator tmp(tree_.lower_bound(end.key())); tmp != end; ++tmp) { - ++checker_end; - } - } - checker_.erase(checker_begin, checker_end); - tree_.erase(begin, end); - EXPECT_EQ(tree_.size(), checker_.size()); - EXPECT_EQ(tree_.size(), size - count); - } - - void clear() { - tree_.clear(); - checker_.clear(); - } - void swap(base_checker &x) { - tree_.swap(x.tree_); - checker_.swap(x.checker_); - } - - void verify() const { - tree_.verify(); - EXPECT_EQ(tree_.size(), checker_.size()); - - // Move through the forward iterators using increment. - auto checker_iter = checker_.begin(); - const_iterator tree_iter(tree_.begin()); - for (; tree_iter != tree_.end(); ++tree_iter, ++checker_iter) { - CheckPairEquals(*tree_iter, *checker_iter); + void erase_check(const key_type &key) { + EXPECT_FALSE(tree_.contains(key)); + EXPECT_EQ(tree_.find(key), const_tree_.end()); + EXPECT_FALSE(const_tree_.contains(key)); + EXPECT_EQ(const_tree_.find(key), tree_.end()); + EXPECT_EQ(tree_.equal_range(key).first, + const_tree_.equal_range(key).second); } - // Move through the forward iterators using decrement. - for (int n = tree_.size() - 1; n >= 0; --n) { - iter_check(tree_iter, checker_iter); - --tree_iter; - --checker_iter; + iterator lower_bound(const key_type &key) { + return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); } - EXPECT_EQ(tree_iter, tree_.begin()); - EXPECT_EQ(checker_iter, checker_.begin()); - - // Move through the reverse iterators using increment. - auto checker_riter = checker_.rbegin(); - const_reverse_iterator tree_riter(tree_.rbegin()); - for (; tree_riter != tree_.rend(); ++tree_riter, ++checker_riter) { - CheckPairEquals(*tree_riter, *checker_riter); + const_iterator lower_bound(const key_type &key) const { + return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); + } + iterator upper_bound(const key_type &key) { + return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); + } + const_iterator upper_bound(const key_type &key) const { + return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); + } + std::pair equal_range(const key_type &key) { + std::pair + checker_res = checker_.equal_range(key); + std::pair tree_res = tree_.equal_range(key); + iter_check(tree_res.first, checker_res.first); + iter_check(tree_res.second, checker_res.second); + return tree_res; + } + std::pair equal_range( + const key_type &key) const { + std::pair + checker_res = checker_.equal_range(key); + std::pair tree_res = tree_.equal_range(key); + iter_check(tree_res.first, checker_res.first); + iter_check(tree_res.second, checker_res.second); + return tree_res; + } + iterator find(const key_type &key) { + return iter_check(tree_.find(key), checker_.find(key)); + } + const_iterator find(const key_type &key) const { + return iter_check(tree_.find(key), checker_.find(key)); + } + bool contains(const key_type &key) const { + return find(key) != end(); + } + size_type count(const key_type &key) const { + size_type res = checker_.count(key); + EXPECT_EQ(res, tree_.count(key)); + return res; } - // Move through the reverse iterators using decrement. - for (int n = tree_.size() - 1; n >= 0; --n) { - riter_check(tree_riter, checker_riter); - --tree_riter; - --checker_riter; + base_checker &operator=(const base_checker &x) { + tree_ = x.tree_; + checker_ = x.checker_; + return *this; } - EXPECT_EQ(tree_riter, tree_.rbegin()); - EXPECT_EQ(checker_riter, checker_.rbegin()); - } - const TreeType &tree() const { return tree_; } + int erase(const key_type &key) { + int size = tree_.size(); + int res = checker_.erase(key); + EXPECT_EQ(res, tree_.count(key)); + EXPECT_EQ(res, tree_.erase(key)); + EXPECT_EQ(tree_.count(key), 0); + EXPECT_EQ(tree_.size(), size - res); + erase_check(key); + return res; + } + iterator erase(iterator iter) { + key_type key = iter.key(); + int size = tree_.size(); + int count = tree_.count(key); + auto checker_iter = checker_.lower_bound(key); + for (iterator tmp(tree_.lower_bound(key)); tmp != iter; ++tmp) { + ++checker_iter; + } + auto checker_next = checker_iter; + ++checker_next; + checker_.erase(checker_iter); + iter = tree_.erase(iter); + EXPECT_EQ(tree_.size(), checker_.size()); + EXPECT_EQ(tree_.size(), size - 1); + EXPECT_EQ(tree_.count(key), count - 1); + if (count == 1) { + erase_check(key); + } + return iter_check(iter, checker_next); + } - size_type size() const { - EXPECT_EQ(tree_.size(), checker_.size()); - return tree_.size(); - } - size_type max_size() const { return tree_.max_size(); } - bool empty() const { - EXPECT_EQ(tree_.empty(), checker_.empty()); - return tree_.empty(); - } + void erase(iterator begin, iterator end) { + int size = tree_.size(); + int count = std::distance(begin, end); + auto checker_begin = checker_.lower_bound(begin.key()); + for (iterator tmp(tree_.lower_bound(begin.key())); tmp != begin; ++tmp) { + ++checker_begin; + } + auto checker_end = + end == tree_.end() ? checker_.end() : checker_.lower_bound(end.key()); + if (end != tree_.end()) { + for (iterator tmp(tree_.lower_bound(end.key())); tmp != end; ++tmp) { + ++checker_end; + } + } + checker_.erase(checker_begin, checker_end); + tree_.erase(begin, end); + EXPECT_EQ(tree_.size(), checker_.size()); + EXPECT_EQ(tree_.size(), size - count); + } - protected: - TreeType tree_; - const TreeType &const_tree_; - CheckerType checker_; + void clear() { + tree_.clear(); + checker_.clear(); + } + void swap(base_checker &x) { + tree_.swap(x.tree_); + checker_.swap(x.checker_); + } + + void verify() const { + tree_.verify(); + EXPECT_EQ(tree_.size(), checker_.size()); + + // Move through the forward iterators using increment. + auto checker_iter = checker_.begin(); + const_iterator tree_iter(tree_.begin()); + for (; tree_iter != tree_.end(); ++tree_iter, ++checker_iter) { + CheckPairEquals(*tree_iter, *checker_iter); + } + + // Move through the forward iterators using decrement. + for (int n = tree_.size() - 1; n >= 0; --n) { + iter_check(tree_iter, checker_iter); + --tree_iter; + --checker_iter; + } + EXPECT_EQ(tree_iter, tree_.begin()); + EXPECT_EQ(checker_iter, checker_.begin()); + + // Move through the reverse iterators using increment. + auto checker_riter = checker_.rbegin(); + const_reverse_iterator tree_riter(tree_.rbegin()); + for (; tree_riter != tree_.rend(); ++tree_riter, ++checker_riter) { + CheckPairEquals(*tree_riter, *checker_riter); + } + + // Move through the reverse iterators using decrement. + for (int n = tree_.size() - 1; n >= 0; --n) { + riter_check(tree_riter, checker_riter); + --tree_riter; + --checker_riter; + } + EXPECT_EQ(tree_riter, tree_.rbegin()); + EXPECT_EQ(checker_riter, checker_.rbegin()); + } + + const TreeType &tree() const { return tree_; } + + size_type size() const { + EXPECT_EQ(tree_.size(), checker_.size()); + return tree_.size(); + } + size_type max_size() const { return tree_.max_size(); } + bool empty() const { + EXPECT_EQ(tree_.empty(), checker_.empty()); + return tree_.empty(); + } + +protected: + TreeType tree_; + const TreeType &const_tree_; + CheckerType checker_; }; namespace { -// A checker for unique sorted associative containers. TreeType is expected to -// be btree_{set,map} and CheckerType is expected to be {set,map}. -template -class unique_checker : public base_checker { - using super_type = base_checker; + // A checker for unique sorted associative containers. TreeType is expected to + // be btree_{set,map} and CheckerType is expected to be {set,map}. + template + class unique_checker : public base_checker { + using super_type = base_checker; - public: - using iterator = typename super_type::iterator; - using value_type = typename super_type::value_type; + public: + using iterator = typename super_type::iterator; + using value_type = typename super_type::value_type; - public: - unique_checker() : super_type() {} - unique_checker(const unique_checker &x) : super_type(x) {} - template - unique_checker(InputIterator b, InputIterator e) : super_type(b, e) {} - unique_checker& operator=(const unique_checker&) = default; + public: + unique_checker() : super_type() {} + unique_checker(const unique_checker &x) : super_type(x) {} + template + unique_checker(InputIterator b, InputIterator e) : super_type(b, e) {} + unique_checker& operator=(const unique_checker&) = default; - // Insertion routines. - std::pair insert(const value_type &x) { - int size = this->tree_.size(); - std::pair checker_res = - this->checker_.insert(x); - std::pair tree_res = this->tree_.insert(x); - CheckPairEquals(*tree_res.first, *checker_res.first); - EXPECT_EQ(tree_res.second, checker_res.second); - EXPECT_EQ(this->tree_.size(), this->checker_.size()); - EXPECT_EQ(this->tree_.size(), size + tree_res.second); - return tree_res; - } - iterator insert(iterator position, const value_type &x) { - int size = this->tree_.size(); - std::pair checker_res = - this->checker_.insert(x); - iterator tree_res = this->tree_.insert(position, x); - CheckPairEquals(*tree_res, *checker_res.first); - EXPECT_EQ(this->tree_.size(), this->checker_.size()); - EXPECT_EQ(this->tree_.size(), size + checker_res.second); - return tree_res; - } - template - void insert(InputIterator b, InputIterator e) { - for (; b != e; ++b) { - insert(*b); - } - } -}; + // Insertion routines. + std::pair insert(const value_type &x) { + int size = this->tree_.size(); + std::pair checker_res = + this->checker_.insert(x); + std::pair tree_res = this->tree_.insert(x); + CheckPairEquals(*tree_res.first, *checker_res.first); + EXPECT_EQ(tree_res.second, checker_res.second); + EXPECT_EQ(this->tree_.size(), this->checker_.size()); + EXPECT_EQ(this->tree_.size(), size + tree_res.second); + return tree_res; + } + iterator insert(iterator position, const value_type &x) { + int size = this->tree_.size(); + std::pair checker_res = + this->checker_.insert(x); + iterator tree_res = this->tree_.insert(position, x); + CheckPairEquals(*tree_res, *checker_res.first); + EXPECT_EQ(this->tree_.size(), this->checker_.size()); + EXPECT_EQ(this->tree_.size(), size + checker_res.second); + return tree_res; + } + template + void insert(InputIterator b, InputIterator e) { + for (; b != e; ++b) { + insert(*b); + } + } + }; -// A checker for multiple sorted associative containers. TreeType is expected -// to be btree_{multiset,multimap} and CheckerType is expected to be -// {multiset,multimap}. -template -class multi_checker : public base_checker { - using super_type = base_checker; + // A checker for multiple sorted associative containers. TreeType is expected + // to be btree_{multiset,multimap} and CheckerType is expected to be + // {multiset,multimap}. + template + class multi_checker : public base_checker { + using super_type = base_checker; - public: - using iterator = typename super_type::iterator; - using value_type = typename super_type::value_type; + public: + using iterator = typename super_type::iterator; + using value_type = typename super_type::value_type; - public: - multi_checker() : super_type() {} - multi_checker(const multi_checker &x) : super_type(x) {} - template - multi_checker(InputIterator b, InputIterator e) : super_type(b, e) {} - multi_checker& operator=(const multi_checker&) = default; + public: + multi_checker() : super_type() {} + multi_checker(const multi_checker &x) : super_type(x) {} + template + multi_checker(InputIterator b, InputIterator e) : super_type(b, e) {} + multi_checker& operator=(const multi_checker&) = default; - // Insertion routines. - iterator insert(const value_type &x) { - int size = this->tree_.size(); - auto checker_res = this->checker_.insert(x); - iterator tree_res = this->tree_.insert(x); - CheckPairEquals(*tree_res, *checker_res); - EXPECT_EQ(this->tree_.size(), this->checker_.size()); - EXPECT_EQ(this->tree_.size(), size + 1); - return tree_res; - } - iterator insert(iterator position, const value_type &x) { - int size = this->tree_.size(); - auto checker_res = this->checker_.insert(x); - iterator tree_res = this->tree_.insert(position, x); - CheckPairEquals(*tree_res, *checker_res); - EXPECT_EQ(this->tree_.size(), this->checker_.size()); - EXPECT_EQ(this->tree_.size(), size + 1); - return tree_res; - } - template - void insert(InputIterator b, InputIterator e) { - for (; b != e; ++b) { - insert(*b); - } - } -}; + // Insertion routines. + iterator insert(const value_type &x) { + int size = this->tree_.size(); + auto checker_res = this->checker_.insert(x); + iterator tree_res = this->tree_.insert(x); + CheckPairEquals(*tree_res, *checker_res); + EXPECT_EQ(this->tree_.size(), this->checker_.size()); + EXPECT_EQ(this->tree_.size(), size + 1); + return tree_res; + } + iterator insert(iterator position, const value_type &x) { + int size = this->tree_.size(); + auto checker_res = this->checker_.insert(x); + iterator tree_res = this->tree_.insert(position, x); + CheckPairEquals(*tree_res, *checker_res); + EXPECT_EQ(this->tree_.size(), this->checker_.size()); + EXPECT_EQ(this->tree_.size(), size + 1); + return tree_res; + } + template + void insert(InputIterator b, InputIterator e) { + for (; b != e; ++b) { + insert(*b); + } + } + }; -template -void DoTest(const char *name, T *b, const std::vector &values) { - typename KeyOfValue::type key_of_value; + template + void DoTest(const char *name, T *b, const std::vector &values) { + typename KeyOfValue::type key_of_value; - T &mutable_b = *b; - const T &const_b = *b; + T &mutable_b = *b; + const T &const_b = *b; - // Test insert. - for (int i = 0; i < values.size(); ++i) { - mutable_b.insert(values[i]); - mutable_b.value_check(values[i]); - } - ASSERT_EQ(mutable_b.size(), values.size()); + // Test insert. + for (int i = 0; i < values.size(); ++i) { + mutable_b.insert(values[i]); + mutable_b.value_check(values[i]); + } + ASSERT_EQ(mutable_b.size(), values.size()); - const_b.verify(); + const_b.verify(); - // Test copy constructor. - T b_copy(const_b); - EXPECT_EQ(b_copy.size(), const_b.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_copy.find(key_of_value(values[i])), values[i]); - } + // Test copy constructor. + T b_copy(const_b); + EXPECT_EQ(b_copy.size(), const_b.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_copy.find(key_of_value(values[i])), values[i]); + } - // Test range constructor. - T b_range(const_b.begin(), const_b.end()); - EXPECT_EQ(b_range.size(), const_b.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); - } + // Test range constructor. + T b_range(const_b.begin(), const_b.end()); + EXPECT_EQ(b_range.size(), const_b.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); + } - // Test range insertion for values that already exist. - b_range.insert(b_copy.begin(), b_copy.end()); - b_range.verify(); + // Test range insertion for values that already exist. + b_range.insert(b_copy.begin(), b_copy.end()); + b_range.verify(); - // Test range insertion for new values. - b_range.clear(); - b_range.insert(b_copy.begin(), b_copy.end()); - EXPECT_EQ(b_range.size(), b_copy.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); - } + // Test range insertion for new values. + b_range.clear(); + b_range.insert(b_copy.begin(), b_copy.end()); + EXPECT_EQ(b_range.size(), b_copy.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); + } - // Test assignment to self. Nothing should change. - b_range.operator=(b_range); - EXPECT_EQ(b_range.size(), b_copy.size()); + // Test assignment to self. Nothing should change. + b_range.operator=(b_range); + EXPECT_EQ(b_range.size(), b_copy.size()); - // Test assignment of new values. - b_range.clear(); - b_range = b_copy; - EXPECT_EQ(b_range.size(), b_copy.size()); + // Test assignment of new values. + b_range.clear(); + b_range = b_copy; + EXPECT_EQ(b_range.size(), b_copy.size()); - // Test swap. - b_range.clear(); - b_range.swap(b_copy); - EXPECT_EQ(b_copy.size(), 0); - EXPECT_EQ(b_range.size(), const_b.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); - } - b_range.swap(b_copy); + // Test swap. + b_range.clear(); + b_range.swap(b_copy); + EXPECT_EQ(b_copy.size(), 0); + EXPECT_EQ(b_range.size(), const_b.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); + } + b_range.swap(b_copy); - // Test non-member function swap. - swap(b_range, b_copy); - EXPECT_EQ(b_copy.size(), 0); - EXPECT_EQ(b_range.size(), const_b.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); - } - swap(b_range, b_copy); + // Test non-member function swap. + swap(b_range, b_copy); + EXPECT_EQ(b_copy.size(), 0); + EXPECT_EQ(b_range.size(), const_b.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); + } + swap(b_range, b_copy); - // Test erase via values. - for (int i = 0; i < values.size(); ++i) { - mutable_b.erase(key_of_value(values[i])); - // Erasing a non-existent key should have no effect. - ASSERT_EQ(mutable_b.erase(key_of_value(values[i])), 0); - } + // Test erase via values. + for (int i = 0; i < values.size(); ++i) { + mutable_b.erase(key_of_value(values[i])); + // Erasing a non-existent key should have no effect. + ASSERT_EQ(mutable_b.erase(key_of_value(values[i])), 0); + } - const_b.verify(); - EXPECT_EQ(const_b.size(), 0); + const_b.verify(); + EXPECT_EQ(const_b.size(), 0); - // Test erase via iterators. - mutable_b = b_copy; - for (int i = 0; i < values.size(); ++i) { - mutable_b.erase(mutable_b.find(key_of_value(values[i]))); - } + // Test erase via iterators. + mutable_b = b_copy; + for (int i = 0; i < values.size(); ++i) { + mutable_b.erase(mutable_b.find(key_of_value(values[i]))); + } - const_b.verify(); - EXPECT_EQ(const_b.size(), 0); + const_b.verify(); + EXPECT_EQ(const_b.size(), 0); - // Test insert with hint. - for (int i = 0; i < values.size(); i++) { - mutable_b.insert(mutable_b.upper_bound(key_of_value(values[i])), values[i]); - } + // Test insert with hint. + for (int i = 0; i < values.size(); i++) { + mutable_b.insert(mutable_b.upper_bound(key_of_value(values[i])), values[i]); + } - const_b.verify(); + const_b.verify(); - // Test range erase. - mutable_b.erase(mutable_b.begin(), mutable_b.end()); - EXPECT_EQ(mutable_b.size(), 0); - const_b.verify(); + // Test range erase. + mutable_b.erase(mutable_b.begin(), mutable_b.end()); + EXPECT_EQ(mutable_b.size(), 0); + const_b.verify(); - // First half. - mutable_b = b_copy; - typename T::iterator mutable_iter_end = mutable_b.begin(); - for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end; - mutable_b.erase(mutable_b.begin(), mutable_iter_end); - EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2); - const_b.verify(); + // First half. + mutable_b = b_copy; + typename T::iterator mutable_iter_end = mutable_b.begin(); + for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end; + mutable_b.erase(mutable_b.begin(), mutable_iter_end); + EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2); + const_b.verify(); - // Second half. - mutable_b = b_copy; - typename T::iterator mutable_iter_begin = mutable_b.begin(); - for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin; - mutable_b.erase(mutable_iter_begin, mutable_b.end()); - EXPECT_EQ(mutable_b.size(), values.size() / 2); - const_b.verify(); + // Second half. + mutable_b = b_copy; + typename T::iterator mutable_iter_begin = mutable_b.begin(); + for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin; + mutable_b.erase(mutable_iter_begin, mutable_b.end()); + EXPECT_EQ(mutable_b.size(), values.size() / 2); + const_b.verify(); - // Second quarter. - mutable_b = b_copy; - mutable_iter_begin = mutable_b.begin(); - for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_begin; - mutable_iter_end = mutable_iter_begin; - for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end; - mutable_b.erase(mutable_iter_begin, mutable_iter_end); - EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4); - const_b.verify(); + // Second quarter. + mutable_b = b_copy; + mutable_iter_begin = mutable_b.begin(); + for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_begin; + mutable_iter_end = mutable_iter_begin; + for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end; + mutable_b.erase(mutable_iter_begin, mutable_iter_end); + EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4); + const_b.verify(); - mutable_b.clear(); -} - -template -void ConstTest() { - using value_type = typename T::value_type; - typename KeyOfValue::type key_of_value; - - T mutable_b; - const T &const_b = mutable_b; - - // Insert a single value into the container and test looking it up. - value_type value = Generator(2)(2); - mutable_b.insert(value); - EXPECT_TRUE(mutable_b.contains(key_of_value(value))); - EXPECT_NE(mutable_b.find(key_of_value(value)), const_b.end()); - EXPECT_TRUE(const_b.contains(key_of_value(value))); - EXPECT_NE(const_b.find(key_of_value(value)), mutable_b.end()); - EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value); - EXPECT_EQ(const_b.upper_bound(key_of_value(value)), const_b.end()); - EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value); - - // We can only create a non-const iterator from a non-const container. - typename T::iterator mutable_iter(mutable_b.begin()); - EXPECT_EQ(mutable_iter, const_b.begin()); - EXPECT_NE(mutable_iter, const_b.end()); - EXPECT_EQ(const_b.begin(), mutable_iter); - EXPECT_NE(const_b.end(), mutable_iter); - typename T::reverse_iterator mutable_riter(mutable_b.rbegin()); - EXPECT_EQ(mutable_riter, const_b.rbegin()); - EXPECT_NE(mutable_riter, const_b.rend()); - EXPECT_EQ(const_b.rbegin(), mutable_riter); - EXPECT_NE(const_b.rend(), mutable_riter); - - // We can create a const iterator from a non-const iterator. - typename T::const_iterator const_iter(mutable_iter); - EXPECT_EQ(const_iter, mutable_b.begin()); - EXPECT_NE(const_iter, mutable_b.end()); - EXPECT_EQ(mutable_b.begin(), const_iter); - EXPECT_NE(mutable_b.end(), const_iter); - typename T::const_reverse_iterator const_riter(mutable_riter); - EXPECT_EQ(const_riter, mutable_b.rbegin()); - EXPECT_NE(const_riter, mutable_b.rend()); - EXPECT_EQ(mutable_b.rbegin(), const_riter); - EXPECT_NE(mutable_b.rend(), const_riter); - - // Make sure various methods can be invoked on a const container. - const_b.verify(); - ASSERT_TRUE(!const_b.empty()); - EXPECT_EQ(const_b.size(), 1); - EXPECT_GT(const_b.max_size(), 0); - EXPECT_TRUE(const_b.contains(key_of_value(value))); - EXPECT_EQ(const_b.count(key_of_value(value)), 1); -} - -template -void BtreeTest() { - ConstTest(); - - using V = typename remove_pair_const::type; - const std::vector random_values = GenerateValuesWithSeed( - test_values, 4 * test_values, - testing::GTEST_FLAG(random_seed)); - - unique_checker container; - - // Test key insertion/deletion in sorted order. - std::vector sorted_values(random_values); - std::sort(sorted_values.begin(), sorted_values.end()); - DoTest("sorted: ", &container, sorted_values); - - // Test key insertion/deletion in reverse sorted order. - std::reverse(sorted_values.begin(), sorted_values.end()); - DoTest("rsorted: ", &container, sorted_values); - - // Test key insertion/deletion in random order. - DoTest("random: ", &container, random_values); -} - -template -void BtreeMultiTest() { - ConstTest(); - - using V = typename remove_pair_const::type; - const std::vector random_values = GenerateValuesWithSeed( - test_values, 4 * test_values, - testing::GTEST_FLAG(random_seed)); - - multi_checker container; - - // Test keys in sorted order. - std::vector sorted_values(random_values); - std::sort(sorted_values.begin(), sorted_values.end()); - DoTest("sorted: ", &container, sorted_values); - - // Test keys in reverse sorted order. - std::reverse(sorted_values.begin(), sorted_values.end()); - DoTest("rsorted: ", &container, sorted_values); - - // Test keys in random order. - DoTest("random: ", &container, random_values); - - // Test keys in random order w/ duplicates. - std::vector duplicate_values(random_values); - duplicate_values.insert(duplicate_values.end(), random_values.begin(), - random_values.end()); - DoTest("duplicates:", &container, duplicate_values); - - // Test all identical keys. - std::vector identical_values(100); - std::fill(identical_values.begin(), identical_values.end(), - Generator(2)(2)); - DoTest("identical: ", &container, identical_values); -} - -template -struct PropagatingCountingAlloc : public CountingAllocator { - using propagate_on_container_copy_assignment = std::true_type; - using propagate_on_container_move_assignment = std::true_type; - using propagate_on_container_swap = std::true_type; - - using Base = CountingAllocator; - using Base::Base; - - template - explicit PropagatingCountingAlloc(const PropagatingCountingAlloc &other) - : Base(other.bytes_used_) {} - - template - struct rebind { - using other = PropagatingCountingAlloc; - }; -}; - -template -void BtreeAllocatorTest() { - using value_type = typename T::value_type; - - int64_t bytes1 = 0, bytes2 = 0; - PropagatingCountingAlloc allocator1(&bytes1); - PropagatingCountingAlloc allocator2(&bytes2); - Generator generator(1000); - - // Test that we allocate properly aligned memory. If we don't, then Layout - // will assert fail. - auto unused1 = allocator1.allocate(1); - auto unused2 = allocator2.allocate(1); - - // Test copy assignment - { - T b1(typename T::key_compare(), allocator1); - T b2(typename T::key_compare(), allocator2); - - int64_t original_bytes1 = bytes1; - b1.insert(generator(0)); - EXPECT_GT(bytes1, original_bytes1); - - // This should propagate the allocator. - b1 = b2; - EXPECT_EQ(b1.size(), 0); - EXPECT_EQ(b2.size(), 0); - EXPECT_EQ(bytes1, original_bytes1); - - for (int i = 1; i < 1000; i++) { - b1.insert(generator(i)); + mutable_b.clear(); } - // We should have allocated out of allocator2. - EXPECT_GT(bytes2, bytes1); - } + template + void ConstTest() { + using value_type = typename T::value_type; + typename KeyOfValue::type key_of_value; - // Test move assignment - { - T b1(typename T::key_compare(), allocator1); - T b2(typename T::key_compare(), allocator2); + T mutable_b; + const T &const_b = mutable_b; - int64_t original_bytes1 = bytes1; - b1.insert(generator(0)); - EXPECT_GT(bytes1, original_bytes1); + // Insert a single value into the container and test looking it up. + value_type value = Generator(2)(2); + mutable_b.insert(value); + EXPECT_TRUE(mutable_b.contains(key_of_value(value))); + EXPECT_NE(mutable_b.find(key_of_value(value)), const_b.end()); + EXPECT_TRUE(const_b.contains(key_of_value(value))); + EXPECT_NE(const_b.find(key_of_value(value)), mutable_b.end()); + EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value); + EXPECT_EQ(const_b.upper_bound(key_of_value(value)), const_b.end()); + EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value); - // This should propagate the allocator. - b1 = std::move(b2); - EXPECT_EQ(b1.size(), 0); - EXPECT_EQ(bytes1, original_bytes1); + // We can only create a non-const iterator from a non-const container. + typename T::iterator mutable_iter(mutable_b.begin()); + EXPECT_EQ(mutable_iter, const_b.begin()); + EXPECT_NE(mutable_iter, const_b.end()); + EXPECT_EQ(const_b.begin(), mutable_iter); + EXPECT_NE(const_b.end(), mutable_iter); + typename T::reverse_iterator mutable_riter(mutable_b.rbegin()); + EXPECT_EQ(mutable_riter, const_b.rbegin()); + EXPECT_NE(mutable_riter, const_b.rend()); + EXPECT_EQ(const_b.rbegin(), mutable_riter); + EXPECT_NE(const_b.rend(), mutable_riter); - for (int i = 1; i < 1000; i++) { - b1.insert(generator(i)); + // We can create a const iterator from a non-const iterator. + typename T::const_iterator const_iter(mutable_iter); + EXPECT_EQ(const_iter, mutable_b.begin()); + EXPECT_NE(const_iter, mutable_b.end()); + EXPECT_EQ(mutable_b.begin(), const_iter); + EXPECT_NE(mutable_b.end(), const_iter); + typename T::const_reverse_iterator const_riter(mutable_riter); + EXPECT_EQ(const_riter, mutable_b.rbegin()); + EXPECT_NE(const_riter, mutable_b.rend()); + EXPECT_EQ(mutable_b.rbegin(), const_riter); + EXPECT_NE(mutable_b.rend(), const_riter); + + // Make sure various methods can be invoked on a const container. + const_b.verify(); + ASSERT_TRUE(!const_b.empty()); + EXPECT_EQ(const_b.size(), 1); + EXPECT_GT(const_b.max_size(), 0); + EXPECT_TRUE(const_b.contains(key_of_value(value))); + EXPECT_EQ(const_b.count(key_of_value(value)), 1); } - // We should have allocated out of allocator2. - EXPECT_GT(bytes2, bytes1); - } + template + void BtreeTest() { + ConstTest(); - // Test swap - { - T b1(typename T::key_compare(), allocator1); - T b2(typename T::key_compare(), allocator2); + using V = typename remove_pair_const::type; + const std::vector random_values = GenerateValuesWithSeed( + test_values, 4 * test_values, + testing::GTEST_FLAG(random_seed)); - int64_t original_bytes1 = bytes1; - b1.insert(generator(0)); - EXPECT_GT(bytes1, original_bytes1); + unique_checker container; - // This should swap the allocators. - swap(b1, b2); - EXPECT_EQ(b1.size(), 0); - EXPECT_EQ(b2.size(), 1); - EXPECT_GT(bytes1, original_bytes1); + // Test key insertion/deletion in sorted order. + std::vector sorted_values(random_values); + std::sort(sorted_values.begin(), sorted_values.end()); + DoTest("sorted: ", &container, sorted_values); - for (int i = 1; i < 1000; i++) { - b1.insert(generator(i)); + // Test key insertion/deletion in reverse sorted order. + std::reverse(sorted_values.begin(), sorted_values.end()); + DoTest("rsorted: ", &container, sorted_values); + + // Test key insertion/deletion in random order. + DoTest("random: ", &container, random_values); } - // We should have allocated out of allocator2. - EXPECT_GT(bytes2, bytes1); - } + template + void BtreeMultiTest() { + ConstTest(); - allocator1.deallocate(unused1, 1); - allocator2.deallocate(unused2, 1); -} + using V = typename remove_pair_const::type; + const std::vector random_values = GenerateValuesWithSeed( + test_values, 4 * test_values, + testing::GTEST_FLAG(random_seed)); -template -void BtreeMapTest() { - using value_type = typename T::value_type; - using mapped_type = typename T::mapped_type; + multi_checker container; - mapped_type m = Generator(0)(0); - (void)m; + // Test keys in sorted order. + std::vector sorted_values(random_values); + std::sort(sorted_values.begin(), sorted_values.end()); + DoTest("sorted: ", &container, sorted_values); - T b; + // Test keys in reverse sorted order. + std::reverse(sorted_values.begin(), sorted_values.end()); + DoTest("rsorted: ", &container, sorted_values); - // Verify we can insert using operator[]. - for (int i = 0; i < 1000; i++) { - value_type v = Generator(1000)(i); - b[v.first] = v.second; - } - EXPECT_EQ(b.size(), 1000); + // Test keys in random order. + DoTest("random: ", &container, random_values); - // Test whether we can use the "->" operator on iterators and - // reverse_iterators. This stresses the btree_map_params::pair_pointer - // mechanism. - EXPECT_EQ(b.begin()->first, Generator(1000)(0).first); - EXPECT_EQ(b.begin()->second, Generator(1000)(0).second); - EXPECT_EQ(b.rbegin()->first, Generator(1000)(999).first); - EXPECT_EQ(b.rbegin()->second, Generator(1000)(999).second); -} + // Test keys in random order w/ duplicates. + std::vector duplicate_values(random_values); + duplicate_values.insert(duplicate_values.end(), random_values.begin(), + random_values.end()); + DoTest("duplicates:", &container, duplicate_values); -template -void BtreeMultiMapTest() { - using mapped_type = typename T::mapped_type; - mapped_type m = Generator(0)(0); - (void)m; -} + // Test all identical keys. + std::vector identical_values(100); + std::fill(identical_values.begin(), identical_values.end(), + Generator(2)(2)); + DoTest("identical: ", &container, identical_values); + } -template -void SetTest() { - EXPECT_EQ( - sizeof(phmap::btree_set), - 2 * sizeof(void *) + sizeof(typename phmap::btree_set::size_type)); - using BtreeSet = phmap::btree_set; - using CountingBtreeSet = - phmap::btree_set, PropagatingCountingAlloc>; - BtreeTest>(); - BtreeAllocatorTest(); -} + template + struct PropagatingCountingAlloc : public CountingAllocator { + using propagate_on_container_copy_assignment = std::true_type; + using propagate_on_container_move_assignment = std::true_type; + using propagate_on_container_swap = std::true_type; -template -void MapTest() { - EXPECT_EQ( - sizeof(phmap::btree_map), - 2 * sizeof(void *) + sizeof(typename phmap::btree_map::size_type)); - using BtreeMap = phmap::btree_map; - using CountingBtreeMap = - phmap::btree_map, - PropagatingCountingAlloc>>; - BtreeTest>(); - BtreeAllocatorTest(); - BtreeMapTest(); -} + using Base = CountingAllocator; + using Base::Base; -TEST(Btree, set_int32) { SetTest(); } -TEST(Btree, set_int64) { SetTest(); } -TEST(Btree, set_string) { SetTest(); } -TEST(Btree, set_pair) { SetTest>(); } -TEST(Btree, map_int32) { MapTest(); } -TEST(Btree, map_int64) { MapTest(); } -TEST(Btree, map_string) { MapTest(); } -TEST(Btree, map_pair) { MapTest>(); } + template + explicit PropagatingCountingAlloc(const PropagatingCountingAlloc &other) + : Base(other.bytes_used_) {} -template -void MultiSetTest() { - EXPECT_EQ( - sizeof(phmap::btree_multiset), - 2 * sizeof(void *) + sizeof(typename phmap::btree_multiset::size_type)); - using BtreeMSet = phmap::btree_multiset; - using CountingBtreeMSet = - phmap::btree_multiset, PropagatingCountingAlloc>; - BtreeMultiTest>(); - BtreeAllocatorTest(); -} + template + struct rebind { + using other = PropagatingCountingAlloc; + }; + }; -template -void MultiMapTest() { - EXPECT_EQ(sizeof(phmap::btree_multimap), - 2 * sizeof(void *) + - sizeof(typename phmap::btree_multimap::size_type)); - using BtreeMMap = phmap::btree_multimap; - using CountingBtreeMMap = - phmap::btree_multimap, - PropagatingCountingAlloc>>; - BtreeMultiTest>(); - BtreeMultiMapTest(); - BtreeAllocatorTest(); -} + template + void BtreeAllocatorTest() { + using value_type = typename T::value_type; -TEST(Btree, multiset_int32) { MultiSetTest(); } -TEST(Btree, multiset_int64) { MultiSetTest(); } -TEST(Btree, multiset_string) { MultiSetTest(); } -TEST(Btree, multiset_pair) { MultiSetTest>(); } -TEST(Btree, multimap_int32) { MultiMapTest(); } -TEST(Btree, multimap_int64) { MultiMapTest(); } -TEST(Btree, multimap_string) { MultiMapTest(); } -TEST(Btree, multimap_pair) { MultiMapTest>(); } + int64_t bytes1 = 0, bytes2 = 0; + PropagatingCountingAlloc allocator1(&bytes1); + PropagatingCountingAlloc allocator2(&bytes2); + Generator generator(1000); -struct CompareIntToString { - bool operator()(const std::string &a, const std::string &b) const { - return a < b; - } - bool operator()(const std::string &a, int b) const { - return a < std::to_string(b); - } - bool operator()(int a, const std::string &b) const { - return std::to_string(a) < b; - } - using is_transparent = void; -}; + // Test that we allocate properly aligned memory. If we don't, then Layout + // will assert fail. + auto unused1 = allocator1.allocate(1); + auto unused2 = allocator2.allocate(1); -struct NonTransparentCompare { - template - bool operator()(const T& t, const U& u) const { - // Treating all comparators as transparent can cause inefficiencies (see - // N3657 C++ proposal). Test that for comparators without 'is_transparent' - // alias (like this one), we do not attempt heterogeneous lookup. - EXPECT_TRUE((std::is_same())); - return t < u; - } -}; + // Test copy assignment + { + T b1(typename T::key_compare(), allocator1); + T b2(typename T::key_compare(), allocator2); -template -bool CanEraseWithEmptyBrace(T t, decltype(t.erase({})) *) { - return true; -} + int64_t original_bytes1 = bytes1; + b1.insert(generator(0)); + EXPECT_GT(bytes1, original_bytes1); -template -bool CanEraseWithEmptyBrace(T, ...) { - return false; -} + // This should propagate the allocator. + b1 = b2; + EXPECT_EQ(b1.size(), 0); + EXPECT_EQ(b2.size(), 0); + EXPECT_EQ(bytes1, original_bytes1); -template -void TestHeterogeneous(T table) { - auto lb = table.lower_bound("3"); - EXPECT_EQ(lb, table.lower_bound(3)); - EXPECT_NE(lb, table.lower_bound(4)); - EXPECT_EQ(lb, table.lower_bound({"3"})); - EXPECT_NE(lb, table.lower_bound({})); + for (int i = 1; i < 1000; i++) { + b1.insert(generator(i)); + } - auto ub = table.upper_bound("3"); - EXPECT_EQ(ub, table.upper_bound(3)); - EXPECT_NE(ub, table.upper_bound(5)); - EXPECT_EQ(ub, table.upper_bound({"3"})); - EXPECT_NE(ub, table.upper_bound({})); + // We should have allocated out of allocator2. + EXPECT_GT(bytes2, bytes1); + } - auto er = table.equal_range("3"); - EXPECT_EQ(er, table.equal_range(3)); - EXPECT_NE(er, table.equal_range(4)); - EXPECT_EQ(er, table.equal_range({"3"})); - EXPECT_NE(er, table.equal_range({})); + // Test move assignment + { + T b1(typename T::key_compare(), allocator1); + T b2(typename T::key_compare(), allocator2); - auto it = table.find("3"); - EXPECT_EQ(it, table.find(3)); - EXPECT_NE(it, table.find(4)); - EXPECT_EQ(it, table.find({"3"})); - EXPECT_NE(it, table.find({})); + int64_t original_bytes1 = bytes1; + b1.insert(generator(0)); + EXPECT_GT(bytes1, original_bytes1); - EXPECT_TRUE(table.contains(3)); - EXPECT_FALSE(table.contains(4)); - EXPECT_TRUE(table.count({"3"})); - EXPECT_FALSE(table.contains({})); + // This should propagate the allocator. + b1 = std::move(b2); + EXPECT_EQ(b1.size(), 0); + EXPECT_EQ(bytes1, original_bytes1); - EXPECT_EQ(1, table.count(3)); - EXPECT_EQ(0, table.count(4)); - EXPECT_EQ(1, table.count({"3"})); - EXPECT_EQ(0, table.count({})); + for (int i = 1; i < 1000; i++) { + b1.insert(generator(i)); + } - auto copy = table; - copy.erase(3); - EXPECT_EQ(table.size() - 1, copy.size()); - copy.erase(4); - EXPECT_EQ(table.size() - 1, copy.size()); - copy.erase({"5"}); - EXPECT_EQ(table.size() - 2, copy.size()); - EXPECT_FALSE(CanEraseWithEmptyBrace(table, nullptr)); + // We should have allocated out of allocator2. + EXPECT_GT(bytes2, bytes1); + } - // Also run it with const T&. - if (std::is_class()) TestHeterogeneous(table); -} + // Test swap + { + T b1(typename T::key_compare(), allocator1); + T b2(typename T::key_compare(), allocator2); -TEST(Btree, HeterogeneousLookup) { - TestHeterogeneous(btree_set{"1", "3", "5"}); - TestHeterogeneous(btree_map{ - {"1", 1}, {"3", 3}, {"5", 5}}); - TestHeterogeneous( - btree_multiset{"1", "3", "5"}); - TestHeterogeneous(btree_multimap{ - {"1", 1}, {"3", 3}, {"5", 5}}); + int64_t original_bytes1 = bytes1; + b1.insert(generator(0)); + EXPECT_GT(bytes1, original_bytes1); - // Only maps have .at() - btree_map map{ - {"", -1}, {"1", 1}, {"3", 3}, {"5", 5}}; - EXPECT_EQ(1, map.at(1)); - EXPECT_EQ(3, map.at({"3"})); - EXPECT_EQ(-1, map.at({})); - const auto &cmap = map; - EXPECT_EQ(1, cmap.at(1)); - EXPECT_EQ(3, cmap.at({"3"})); - EXPECT_EQ(-1, cmap.at({})); -} + // This should swap the allocators. + swap(b1, b2); + EXPECT_EQ(b1.size(), 0); + EXPECT_EQ(b2.size(), 1); + EXPECT_GT(bytes1, original_bytes1); -TEST(Btree, NoHeterogeneousLookupWithoutAlias) { - using StringSet = phmap::btree_set; - StringSet s; - ASSERT_TRUE(s.insert("hello").second); - ASSERT_TRUE(s.insert("world").second); - EXPECT_TRUE(s.end() == s.find("blah")); - EXPECT_TRUE(s.begin() == s.lower_bound("hello")); - EXPECT_EQ(1, s.count("world")); - EXPECT_TRUE(s.contains("hello")); - EXPECT_TRUE(s.contains("world")); - EXPECT_FALSE(s.contains("blah")); + for (int i = 1; i < 1000; i++) { + b1.insert(generator(i)); + } - using StringMultiSet = - phmap::btree_multiset; - StringMultiSet ms; - ms.insert("hello"); - ms.insert("world"); - ms.insert("world"); - EXPECT_TRUE(ms.end() == ms.find("blah")); - EXPECT_TRUE(ms.begin() == ms.lower_bound("hello")); - EXPECT_EQ(2, ms.count("world")); - EXPECT_TRUE(ms.contains("hello")); - EXPECT_TRUE(ms.contains("world")); - EXPECT_FALSE(ms.contains("blah")); -} + // We should have allocated out of allocator2. + EXPECT_GT(bytes2, bytes1); + } -TEST(Btree, DefaultTransparent) { - { - // `int` does not have a default transparent comparator. - // The input value is converted to key_type. - btree_set s = {1}; - double d = 1.1; - EXPECT_EQ(s.begin(), s.find(d)); - EXPECT_TRUE(s.contains(d)); - } + allocator1.deallocate(unused1, 1); + allocator2.deallocate(unused2, 1); + } - { - // `std::string` has heterogeneous support. - btree_set s = {"A"}; + template + void BtreeMapTest() { + using value_type = typename T::value_type; + using mapped_type = typename T::mapped_type; + + mapped_type m = Generator(0)(0); + (void)m; + + T b; + + // Verify we can insert using operator[]. + for (int i = 0; i < 1000; i++) { + value_type v = Generator(1000)(i); + b[v.first] = v.second; + } + EXPECT_EQ(b.size(), 1000); + + // Test whether we can use the "->" operator on iterators and + // reverse_iterators. This stresses the btree_map_params::pair_pointer + // mechanism. + EXPECT_EQ(b.begin()->first, Generator(1000)(0).first); + EXPECT_EQ(b.begin()->second, Generator(1000)(0).second); + EXPECT_EQ(b.rbegin()->first, Generator(1000)(999).first); + EXPECT_EQ(b.rbegin()->second, Generator(1000)(999).second); + } + + template + void BtreeMultiMapTest() { + using mapped_type = typename T::mapped_type; + mapped_type m = Generator(0)(0); + (void)m; + } + + template + void SetTest() { + EXPECT_EQ( + sizeof(phmap::btree_set), + 2 * sizeof(void *) + sizeof(typename phmap::btree_set::size_type)); + using BtreeSet = phmap::btree_set; + using CountingBtreeSet = + phmap::btree_set, PropagatingCountingAlloc>; + BtreeTest>(); + BtreeAllocatorTest(); + } + + template + void MapTest() { + EXPECT_EQ( + sizeof(phmap::btree_map), + 2 * sizeof(void *) + sizeof(typename phmap::btree_map::size_type)); + using BtreeMap = phmap::btree_map; + using CountingBtreeMap = + phmap::btree_map, + PropagatingCountingAlloc>>; + BtreeTest>(); + BtreeAllocatorTest(); + BtreeMapTest(); + } + + TEST(Btree, set_int32) { SetTest(); } + TEST(Btree, set_int64) { SetTest(); } + TEST(Btree, set_string) { SetTest(); } + TEST(Btree, set_pair) { SetTest>(); } + TEST(Btree, map_int32) { MapTest(); } + TEST(Btree, map_int64) { MapTest(); } + TEST(Btree, map_string) { MapTest(); } + TEST(Btree, map_pair) { MapTest>(); } + + template + void MultiSetTest() { + EXPECT_EQ( + sizeof(phmap::btree_multiset), + 2 * sizeof(void *) + sizeof(typename phmap::btree_multiset::size_type)); + using BtreeMSet = phmap::btree_multiset; + using CountingBtreeMSet = + phmap::btree_multiset, PropagatingCountingAlloc>; + BtreeMultiTest>(); + BtreeAllocatorTest(); + } + + template + void MultiMapTest() { + EXPECT_EQ(sizeof(phmap::btree_multimap), + 2 * sizeof(void *) + + sizeof(typename phmap::btree_multimap::size_type)); + using BtreeMMap = phmap::btree_multimap; + using CountingBtreeMMap = + phmap::btree_multimap, + PropagatingCountingAlloc>>; + BtreeMultiTest>(); + BtreeMultiMapTest(); + BtreeAllocatorTest(); + } + + TEST(Btree, multiset_int32) { MultiSetTest(); } + TEST(Btree, multiset_int64) { MultiSetTest(); } + TEST(Btree, multiset_string) { MultiSetTest(); } + TEST(Btree, multiset_pair) { MultiSetTest>(); } + TEST(Btree, multimap_int32) { MultiMapTest(); } + TEST(Btree, multimap_int64) { MultiMapTest(); } + TEST(Btree, multimap_string) { MultiMapTest(); } + TEST(Btree, multimap_pair) { MultiMapTest>(); } + + struct CompareIntToString { + bool operator()(const std::string &a, const std::string &b) const { + return a < b; + } + bool operator()(const std::string &a, int b) const { + return a < std::to_string(b); + } + bool operator()(int a, const std::string &b) const { + return std::to_string(a) < b; + } + using is_transparent = void; + }; + + struct NonTransparentCompare { + template + bool operator()(const T& t, const U& u) const { + // Treating all comparators as transparent can cause inefficiencies (see + // N3657 C++ proposal). Test that for comparators without 'is_transparent' + // alias (like this one), we do not attempt heterogeneous lookup. + EXPECT_TRUE((std::is_same())); + return t < u; + } + }; + + template + bool CanEraseWithEmptyBrace(T t, decltype(t.erase({})) *) { + return true; + } + + template + bool CanEraseWithEmptyBrace(T, ...) { + return false; + } + + template + void TestHeterogeneous(T table) { + auto lb = table.lower_bound("3"); + EXPECT_EQ(lb, table.lower_bound(3)); + EXPECT_NE(lb, table.lower_bound(4)); + EXPECT_EQ(lb, table.lower_bound({"3"})); + EXPECT_NE(lb, table.lower_bound({})); + + auto ub = table.upper_bound("3"); + EXPECT_EQ(ub, table.upper_bound(3)); + EXPECT_NE(ub, table.upper_bound(5)); + EXPECT_EQ(ub, table.upper_bound({"3"})); + EXPECT_NE(ub, table.upper_bound({})); + + auto er = table.equal_range("3"); + EXPECT_EQ(er, table.equal_range(3)); + EXPECT_NE(er, table.equal_range(4)); + EXPECT_EQ(er, table.equal_range({"3"})); + EXPECT_NE(er, table.equal_range({})); + + auto it = table.find("3"); + EXPECT_EQ(it, table.find(3)); + EXPECT_NE(it, table.find(4)); + EXPECT_EQ(it, table.find({"3"})); + EXPECT_NE(it, table.find({})); + + EXPECT_TRUE(table.contains(3)); + EXPECT_FALSE(table.contains(4)); + EXPECT_TRUE(table.count({"3"})); + EXPECT_FALSE(table.contains({})); + + EXPECT_EQ(1, table.count(3)); + EXPECT_EQ(0, table.count(4)); + EXPECT_EQ(1, table.count({"3"})); + EXPECT_EQ(0, table.count({})); + + auto copy = table; + copy.erase(3); + EXPECT_EQ(table.size() - 1, copy.size()); + copy.erase(4); + EXPECT_EQ(table.size() - 1, copy.size()); + copy.erase({"5"}); + EXPECT_EQ(table.size() - 2, copy.size()); + EXPECT_FALSE(CanEraseWithEmptyBrace(table, nullptr)); + + // Also run it with const T&. + if (std::is_class()) TestHeterogeneous(table); + } + + TEST(Btree, HeterogeneousLookup) { + TestHeterogeneous(btree_set{"1", "3", "5"}); + TestHeterogeneous(btree_map{ + {"1", 1}, {"3", 3}, {"5", 5}}); + TestHeterogeneous( + btree_multiset{"1", "3", "5"}); + TestHeterogeneous(btree_multimap{ + {"1", 1}, {"3", 3}, {"5", 5}}); + + // Only maps have .at() + btree_map map{ + {"", -1}, {"1", 1}, {"3", 3}, {"5", 5}}; + EXPECT_EQ(1, map.at(1)); + EXPECT_EQ(3, map.at({"3"})); + EXPECT_EQ(-1, map.at({})); + const auto &cmap = map; + EXPECT_EQ(1, cmap.at(1)); + EXPECT_EQ(3, cmap.at({"3"})); + EXPECT_EQ(-1, cmap.at({})); + } + + TEST(Btree, NoHeterogeneousLookupWithoutAlias) { + using StringSet = phmap::btree_set; + StringSet s; + ASSERT_TRUE(s.insert("hello").second); + ASSERT_TRUE(s.insert("world").second); + EXPECT_TRUE(s.end() == s.find("blah")); + EXPECT_TRUE(s.begin() == s.lower_bound("hello")); + EXPECT_EQ(1, s.count("world")); + EXPECT_TRUE(s.contains("hello")); + EXPECT_TRUE(s.contains("world")); + EXPECT_FALSE(s.contains("blah")); + + using StringMultiSet = + phmap::btree_multiset; + StringMultiSet ms; + ms.insert("hello"); + ms.insert("world"); + ms.insert("world"); + EXPECT_TRUE(ms.end() == ms.find("blah")); + EXPECT_TRUE(ms.begin() == ms.lower_bound("hello")); + EXPECT_EQ(2, ms.count("world")); + EXPECT_TRUE(ms.contains("hello")); + EXPECT_TRUE(ms.contains("world")); + EXPECT_FALSE(ms.contains("blah")); + } + + TEST(Btree, DefaultTransparent) { + { + // `int` does not have a default transparent comparator. + // The input value is converted to key_type. + btree_set s = {1}; + double d = 1.1; + EXPECT_EQ(s.begin(), s.find(d)); + EXPECT_TRUE(s.contains(d)); + } + + { + // `std::string` has heterogeneous support. + btree_set s = {"A"}; #if PHMAP_HAVE_STD_STRING_VIEW - EXPECT_EQ(s.begin(), s.find(phmap::string_view("A"))); - EXPECT_TRUE(s.contains(phmap::string_view("A"))); + EXPECT_EQ(s.begin(), s.find(phmap::string_view("A"))); + EXPECT_TRUE(s.contains(phmap::string_view("A"))); #endif - } -} + } + } -class StringLike { - public: - StringLike() = default; + class StringLike { + public: + StringLike() = default; - StringLike(const char* s) : s_(s) { // NOLINT - ++constructor_calls_; - } + StringLike(const char* s) : s_(s) { // NOLINT + ++constructor_calls_; + } - bool operator<(const StringLike& a) const { - return s_ < a.s_; - } + bool operator<(const StringLike& a) const { + return s_ < a.s_; + } - static void clear_constructor_call_count() { - constructor_calls_ = 0; - } + static void clear_constructor_call_count() { + constructor_calls_ = 0; + } - static int constructor_calls() { - return constructor_calls_; - } + static int constructor_calls() { + return constructor_calls_; + } - private: - static int constructor_calls_; - std::string s_; -}; + private: + static int constructor_calls_; + std::string s_; + }; -int StringLike::constructor_calls_ = 0; + int StringLike::constructor_calls_ = 0; -TEST(Btree, HeterogeneousLookupDoesntDegradePerformance) { - using StringSet = phmap::btree_set; - StringSet s; - for (int i = 0; i < 100; ++i) { - ASSERT_TRUE(s.insert(std::to_string(i).c_str()).second); - } - StringLike::clear_constructor_call_count(); - s.find("50"); - ASSERT_EQ(1, StringLike::constructor_calls()); + TEST(Btree, HeterogeneousLookupDoesntDegradePerformance) { + using StringSet = phmap::btree_set; + StringSet s; + for (int i = 0; i < 100; ++i) { + ASSERT_TRUE(s.insert(std::to_string(i).c_str()).second); + } + StringLike::clear_constructor_call_count(); + s.find("50"); + ASSERT_EQ(1, StringLike::constructor_calls()); - StringLike::clear_constructor_call_count(); - s.contains("50"); - ASSERT_EQ(1, StringLike::constructor_calls()); + StringLike::clear_constructor_call_count(); + s.contains("50"); + ASSERT_EQ(1, StringLike::constructor_calls()); - StringLike::clear_constructor_call_count(); - s.count("50"); - ASSERT_EQ(1, StringLike::constructor_calls()); + StringLike::clear_constructor_call_count(); + s.count("50"); + ASSERT_EQ(1, StringLike::constructor_calls()); - StringLike::clear_constructor_call_count(); - s.lower_bound("50"); - ASSERT_EQ(1, StringLike::constructor_calls()); + StringLike::clear_constructor_call_count(); + s.lower_bound("50"); + ASSERT_EQ(1, StringLike::constructor_calls()); - StringLike::clear_constructor_call_count(); - s.upper_bound("50"); - ASSERT_EQ(1, StringLike::constructor_calls()); + StringLike::clear_constructor_call_count(); + s.upper_bound("50"); + ASSERT_EQ(1, StringLike::constructor_calls()); - StringLike::clear_constructor_call_count(); - s.equal_range("50"); - ASSERT_EQ(1, StringLike::constructor_calls()); + StringLike::clear_constructor_call_count(); + s.equal_range("50"); + ASSERT_EQ(1, StringLike::constructor_calls()); - StringLike::clear_constructor_call_count(); - s.erase("50"); - ASSERT_EQ(1, StringLike::constructor_calls()); -} + StringLike::clear_constructor_call_count(); + s.erase("50"); + ASSERT_EQ(1, StringLike::constructor_calls()); + } -// Verify that swapping btrees swaps the key comparison functors and that we can -// use non-default constructible comparators. -struct SubstringLess { - SubstringLess() = delete; - explicit SubstringLess(int length) : n(length) {} - bool operator()(const std::string &a, const std::string &b) const { + // Verify that swapping btrees swaps the key comparison functors and that we can + // use non-default constructible comparators. + struct SubstringLess { + SubstringLess() = delete; + explicit SubstringLess(int length) : n(length) {} + bool operator()(const std::string &a, const std::string &b) const { #if PHMAP_HAVE_STD_STRING_VIEW - return phmap::string_view(a).substr(0, n) < - phmap::string_view(b).substr(0, n); + return phmap::string_view(a).substr(0, n) < + phmap::string_view(b).substr(0, n); #else - return a.substr(0, n) < b.substr(0, n); + return a.substr(0, n) < b.substr(0, n); #endif - } - int n; -}; + } + int n; + }; -TEST(Btree, SwapKeyCompare) { - using SubstringSet = phmap::btree_set; - SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type()); - SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type()); + TEST(Btree, SwapKeyCompare) { + using SubstringSet = phmap::btree_set; + SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type()); + SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type()); - ASSERT_TRUE(s1.insert("a").second); - ASSERT_FALSE(s1.insert("aa").second); + ASSERT_TRUE(s1.insert("a").second); + ASSERT_FALSE(s1.insert("aa").second); - ASSERT_TRUE(s2.insert("a").second); - ASSERT_TRUE(s2.insert("aa").second); - ASSERT_FALSE(s2.insert("aaa").second); + ASSERT_TRUE(s2.insert("a").second); + ASSERT_TRUE(s2.insert("aa").second); + ASSERT_FALSE(s2.insert("aaa").second); - swap(s1, s2); + swap(s1, s2); - ASSERT_TRUE(s1.insert("b").second); - ASSERT_TRUE(s1.insert("bb").second); - ASSERT_FALSE(s1.insert("bbb").second); + ASSERT_TRUE(s1.insert("b").second); + ASSERT_TRUE(s1.insert("bb").second); + ASSERT_FALSE(s1.insert("bbb").second); - ASSERT_TRUE(s2.insert("b").second); - ASSERT_FALSE(s2.insert("bb").second); -} + ASSERT_TRUE(s2.insert("b").second); + ASSERT_FALSE(s2.insert("bb").second); + } -TEST(Btree, UpperBoundRegression) { - // Regress a bug where upper_bound would default-construct a new key_compare - // instead of copying the existing one. - using SubstringSet = phmap::btree_set; - SubstringSet my_set(SubstringLess(3)); - my_set.insert("aab"); - my_set.insert("abb"); - // We call upper_bound("aaa"). If this correctly uses the length 3 - // comparator, aaa < aab < abb, so we should get aab as the result. - // If it instead uses the default-constructed length 2 comparator, - // aa == aa < ab, so we'll get abb as our result. - SubstringSet::iterator it = my_set.upper_bound("aaa"); - ASSERT_TRUE(it != my_set.end()); - EXPECT_EQ("aab", *it); -} + TEST(Btree, UpperBoundRegression) { + // Regress a bug where upper_bound would default-construct a new key_compare + // instead of copying the existing one. + using SubstringSet = phmap::btree_set; + SubstringSet my_set(SubstringLess(3)); + my_set.insert("aab"); + my_set.insert("abb"); + // We call upper_bound("aaa"). If this correctly uses the length 3 + // comparator, aaa < aab < abb, so we should get aab as the result. + // If it instead uses the default-constructed length 2 comparator, + // aa == aa < ab, so we'll get abb as our result. + SubstringSet::iterator it = my_set.upper_bound("aaa"); + ASSERT_TRUE(it != my_set.end()); + EXPECT_EQ("aab", *it); + } -TEST(Btree, Comparison) { - const int kSetSize = 1201; - phmap::btree_set my_set; - for (int i = 0; i < kSetSize; ++i) { - my_set.insert(i); - } - phmap::btree_set my_set_copy(my_set); - EXPECT_TRUE(my_set_copy == my_set); - EXPECT_TRUE(my_set == my_set_copy); - EXPECT_FALSE(my_set_copy != my_set); - EXPECT_FALSE(my_set != my_set_copy); + TEST(Btree, Comparison) { + const int kSetSize = 1201; + phmap::btree_set my_set; + for (int i = 0; i < kSetSize; ++i) { + my_set.insert(i); + } + phmap::btree_set my_set_copy(my_set); + EXPECT_TRUE(my_set_copy == my_set); + EXPECT_TRUE(my_set == my_set_copy); + EXPECT_FALSE(my_set_copy != my_set); + EXPECT_FALSE(my_set != my_set_copy); - my_set.insert(kSetSize); - EXPECT_FALSE(my_set_copy == my_set); - EXPECT_FALSE(my_set == my_set_copy); - EXPECT_TRUE(my_set_copy != my_set); - EXPECT_TRUE(my_set != my_set_copy); + my_set.insert(kSetSize); + EXPECT_FALSE(my_set_copy == my_set); + EXPECT_FALSE(my_set == my_set_copy); + EXPECT_TRUE(my_set_copy != my_set); + EXPECT_TRUE(my_set != my_set_copy); - my_set.erase(kSetSize - 1); - EXPECT_FALSE(my_set_copy == my_set); - EXPECT_FALSE(my_set == my_set_copy); - EXPECT_TRUE(my_set_copy != my_set); - EXPECT_TRUE(my_set != my_set_copy); + my_set.erase(kSetSize - 1); + EXPECT_FALSE(my_set_copy == my_set); + EXPECT_FALSE(my_set == my_set_copy); + EXPECT_TRUE(my_set_copy != my_set); + EXPECT_TRUE(my_set != my_set_copy); - phmap::btree_map my_map; - for (int i = 0; i < kSetSize; ++i) { - my_map[std::string(i, 'a')] = i; - } - phmap::btree_map my_map_copy(my_map); - EXPECT_TRUE(my_map_copy == my_map); - EXPECT_TRUE(my_map == my_map_copy); - EXPECT_FALSE(my_map_copy != my_map); - EXPECT_FALSE(my_map != my_map_copy); + phmap::btree_map my_map; + for (int i = 0; i < kSetSize; ++i) { + my_map[std::string(i, 'a')] = i; + } + phmap::btree_map my_map_copy(my_map); + EXPECT_TRUE(my_map_copy == my_map); + EXPECT_TRUE(my_map == my_map_copy); + EXPECT_FALSE(my_map_copy != my_map); + EXPECT_FALSE(my_map != my_map_copy); - ++my_map_copy[std::string(7, 'a')]; - EXPECT_FALSE(my_map_copy == my_map); - EXPECT_FALSE(my_map == my_map_copy); - EXPECT_TRUE(my_map_copy != my_map); - EXPECT_TRUE(my_map != my_map_copy); + ++my_map_copy[std::string(7, 'a')]; + EXPECT_FALSE(my_map_copy == my_map); + EXPECT_FALSE(my_map == my_map_copy); + EXPECT_TRUE(my_map_copy != my_map); + EXPECT_TRUE(my_map != my_map_copy); - my_map_copy = my_map; - my_map["hello"] = kSetSize; - EXPECT_FALSE(my_map_copy == my_map); - EXPECT_FALSE(my_map == my_map_copy); - EXPECT_TRUE(my_map_copy != my_map); - EXPECT_TRUE(my_map != my_map_copy); + my_map_copy = my_map; + my_map["hello"] = kSetSize; + EXPECT_FALSE(my_map_copy == my_map); + EXPECT_FALSE(my_map == my_map_copy); + EXPECT_TRUE(my_map_copy != my_map); + EXPECT_TRUE(my_map != my_map_copy); - my_map.erase(std::string(kSetSize - 1, 'a')); - EXPECT_FALSE(my_map_copy == my_map); - EXPECT_FALSE(my_map == my_map_copy); - EXPECT_TRUE(my_map_copy != my_map); - EXPECT_TRUE(my_map != my_map_copy); -} + my_map.erase(std::string(kSetSize - 1, 'a')); + EXPECT_FALSE(my_map_copy == my_map); + EXPECT_FALSE(my_map == my_map_copy); + EXPECT_TRUE(my_map_copy != my_map); + EXPECT_TRUE(my_map != my_map_copy); + } -TEST(Btree, RangeCtorSanity) { - std::vector ivec; - ivec.push_back(1); - std::map imap; - imap.insert(std::make_pair(1, 2)); - phmap::btree_multiset tmset(ivec.begin(), ivec.end()); - phmap::btree_multimap tmmap(imap.begin(), imap.end()); - phmap::btree_set tset(ivec.begin(), ivec.end()); - phmap::btree_map tmap(imap.begin(), imap.end()); - EXPECT_EQ(1, tmset.size()); - EXPECT_EQ(1, tmmap.size()); - EXPECT_EQ(1, tset.size()); - EXPECT_EQ(1, tmap.size()); -} + TEST(Btree, RangeCtorSanity) { + std::vector ivec; + ivec.push_back(1); + std::map imap; + imap.insert(std::make_pair(1, 2)); + phmap::btree_multiset tmset(ivec.begin(), ivec.end()); + phmap::btree_multimap tmmap(imap.begin(), imap.end()); + phmap::btree_set tset(ivec.begin(), ivec.end()); + phmap::btree_map tmap(imap.begin(), imap.end()); + EXPECT_EQ(1, tmset.size()); + EXPECT_EQ(1, tmmap.size()); + EXPECT_EQ(1, tset.size()); + EXPECT_EQ(1, tmap.size()); + } -TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) { - phmap::btree_map> m; + TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) { + phmap::btree_map> m; - std::unique_ptr &v = m["A"]; - EXPECT_TRUE(v == nullptr); - v.reset(new std::string("X")); + std::unique_ptr &v = m["A"]; + EXPECT_TRUE(v == nullptr); + v.reset(new std::string("X")); - auto iter = m.find("A"); - EXPECT_EQ("X", *iter->second); -} + auto iter = m.find("A"); + EXPECT_EQ("X", *iter->second); + } -TEST(Btree, InitializerListConstructor) { - phmap::btree_set set({"a", "b"}); - EXPECT_EQ(set.count("a"), 1); - EXPECT_EQ(set.count("b"), 1); + TEST(Btree, InitializerListConstructor) { + phmap::btree_set set({"a", "b"}); + EXPECT_EQ(set.count("a"), 1); + EXPECT_EQ(set.count("b"), 1); - phmap::btree_multiset mset({1, 1, 4}); - EXPECT_EQ(mset.count(1), 2); - EXPECT_EQ(mset.count(4), 1); + phmap::btree_multiset mset({1, 1, 4}); + EXPECT_EQ(mset.count(1), 2); + EXPECT_EQ(mset.count(4), 1); - phmap::btree_map map({{1, 5}, {2, 10}}); - EXPECT_EQ(map[1], 5); - EXPECT_EQ(map[2], 10); + phmap::btree_map map({{1, 5}, {2, 10}}); + EXPECT_EQ(map[1], 5); + EXPECT_EQ(map[2], 10); - phmap::btree_multimap mmap({{1, 5}, {1, 10}}); - auto range = mmap.equal_range(1); - auto it = range.first; - ASSERT_NE(it, range.second); - EXPECT_EQ(it->second, 5); - ASSERT_NE(++it, range.second); - EXPECT_EQ(it->second, 10); - EXPECT_EQ(++it, range.second); -} + phmap::btree_multimap mmap({{1, 5}, {1, 10}}); + auto range = mmap.equal_range(1); + auto it = range.first; + ASSERT_NE(it, range.second); + EXPECT_EQ(it->second, 5); + ASSERT_NE(++it, range.second); + EXPECT_EQ(it->second, 10); + EXPECT_EQ(++it, range.second); + } -TEST(Btree, InitializerListInsert) { - phmap::btree_set set; - set.insert({"a", "b"}); - EXPECT_EQ(set.count("a"), 1); - EXPECT_EQ(set.count("b"), 1); + TEST(Btree, InitializerListInsert) { + phmap::btree_set set; + set.insert({"a", "b"}); + EXPECT_EQ(set.count("a"), 1); + EXPECT_EQ(set.count("b"), 1); - phmap::btree_multiset mset; - mset.insert({1, 1, 4}); - EXPECT_EQ(mset.count(1), 2); - EXPECT_EQ(mset.count(4), 1); + phmap::btree_multiset mset; + mset.insert({1, 1, 4}); + EXPECT_EQ(mset.count(1), 2); + EXPECT_EQ(mset.count(4), 1); - phmap::btree_map map; - map.insert({{1, 5}, {2, 10}}); - // Test that inserting one element using an initializer list also works. - map.insert({3, 15}); - EXPECT_EQ(map[1], 5); - EXPECT_EQ(map[2], 10); - EXPECT_EQ(map[3], 15); + phmap::btree_map map; + map.insert({{1, 5}, {2, 10}}); + // Test that inserting one element using an initializer list also works. + map.insert({3, 15}); + EXPECT_EQ(map[1], 5); + EXPECT_EQ(map[2], 10); + EXPECT_EQ(map[3], 15); - phmap::btree_multimap mmap; - mmap.insert({{1, 5}, {1, 10}}); - auto range = mmap.equal_range(1); - auto it = range.first; - ASSERT_NE(it, range.second); - EXPECT_EQ(it->second, 5); - ASSERT_NE(++it, range.second); - EXPECT_EQ(it->second, 10); - EXPECT_EQ(++it, range.second); -} + phmap::btree_multimap mmap; + mmap.insert({{1, 5}, {1, 10}}); + auto range = mmap.equal_range(1); + auto it = range.first; + ASSERT_NE(it, range.second); + EXPECT_EQ(it->second, 5); + ASSERT_NE(++it, range.second); + EXPECT_EQ(it->second, 10); + EXPECT_EQ(++it, range.second); + } -template -void AssertKeyCompareToAdapted() { - using Adapted = typename key_compare_to_adapter::type; - static_assert(!std::is_same::value, - "key_compare_to_adapter should have adapted this comparator."); - static_assert( - std::is_same>::value, - "Adapted comparator should be a key-compare-to comparator."); -} -template -void AssertKeyCompareToNotAdapted() { - using Unadapted = typename key_compare_to_adapter::type; - static_assert( - std::is_same::value, - "key_compare_to_adapter shouldn't have adapted this comparator."); - static_assert( - std::is_same>::value, - "Un-adapted comparator should return bool."); -} + template + void AssertKeyCompareToAdapted() { + using Adapted = typename key_compare_to_adapter::type; + static_assert(!std::is_same::value, + "key_compare_to_adapter should have adapted this comparator."); + static_assert( + std::is_same>::value, + "Adapted comparator should be a key-compare-to comparator."); + } + template + void AssertKeyCompareToNotAdapted() { + using Unadapted = typename key_compare_to_adapter::type; + static_assert( + std::is_same::value, + "key_compare_to_adapter shouldn't have adapted this comparator."); + static_assert( + std::is_same>::value, + "Un-adapted comparator should return bool."); + } -TEST(Btree, KeyCompareToAdapter) { - AssertKeyCompareToAdapted, std::string>(); - AssertKeyCompareToAdapted, std::string>(); + TEST(Btree, KeyCompareToAdapter) { + AssertKeyCompareToAdapted, std::string>(); + AssertKeyCompareToAdapted, std::string>(); #if PHMAP_HAVE_STD_STRING_VIEW - AssertKeyCompareToAdapted, phmap::string_view>(); - AssertKeyCompareToAdapted, - phmap::string_view>(); + AssertKeyCompareToAdapted, phmap::string_view>(); + AssertKeyCompareToAdapted, + phmap::string_view>(); #endif - AssertKeyCompareToNotAdapted, int>(); - AssertKeyCompareToNotAdapted, int>(); -} + AssertKeyCompareToNotAdapted, int>(); + AssertKeyCompareToNotAdapted, int>(); + } -TEST(Btree, RValueInsert) { - InstanceTracker tracker; + TEST(Btree, RValueInsert) { + InstanceTracker tracker; - phmap::btree_set set; - set.insert(MovableOnlyInstance(1)); - set.insert(MovableOnlyInstance(3)); - MovableOnlyInstance two(2); - set.insert(set.find(MovableOnlyInstance(3)), std::move(two)); - auto it = set.find(MovableOnlyInstance(2)); - ASSERT_NE(it, set.end()); - ASSERT_NE(++it, set.end()); - EXPECT_EQ(it->value(), 3); + phmap::btree_set set; + set.insert(MovableOnlyInstance(1)); + set.insert(MovableOnlyInstance(3)); + MovableOnlyInstance two(2); + set.insert(set.find(MovableOnlyInstance(3)), std::move(two)); + auto it = set.find(MovableOnlyInstance(2)); + ASSERT_NE(it, set.end()); + ASSERT_NE(++it, set.end()); + EXPECT_EQ(it->value(), 3); - phmap::btree_multiset mset; - MovableOnlyInstance zero(0); - MovableOnlyInstance zero2(0); - mset.insert(std::move(zero)); - mset.insert(mset.find(MovableOnlyInstance(0)), std::move(zero2)); - EXPECT_EQ(mset.count(MovableOnlyInstance(0)), 2); + phmap::btree_multiset mset; + MovableOnlyInstance zero(0); + MovableOnlyInstance zero2(0); + mset.insert(std::move(zero)); + mset.insert(mset.find(MovableOnlyInstance(0)), std::move(zero2)); + EXPECT_EQ(mset.count(MovableOnlyInstance(0)), 2); - phmap::btree_map map; - std::pair p1 = {1, MovableOnlyInstance(5)}; - std::pair p2 = {2, MovableOnlyInstance(10)}; - std::pair p3 = {3, MovableOnlyInstance(15)}; - map.insert(std::move(p1)); - map.insert(std::move(p3)); - map.insert(map.find(3), std::move(p2)); - ASSERT_NE(map.find(2), map.end()); - EXPECT_EQ(map.find(2)->second.value(), 10); + phmap::btree_map map; + std::pair p1 = {1, MovableOnlyInstance(5)}; + std::pair p2 = {2, MovableOnlyInstance(10)}; + std::pair p3 = {3, MovableOnlyInstance(15)}; + map.insert(std::move(p1)); + map.insert(std::move(p3)); + map.insert(map.find(3), std::move(p2)); + ASSERT_NE(map.find(2), map.end()); + EXPECT_EQ(map.find(2)->second.value(), 10); - phmap::btree_multimap mmap; - std::pair p4 = {1, MovableOnlyInstance(5)}; - std::pair p5 = {1, MovableOnlyInstance(10)}; - mmap.insert(std::move(p4)); - mmap.insert(mmap.find(1), std::move(p5)); - auto range = mmap.equal_range(1); - auto it1 = range.first; - ASSERT_NE(it1, range.second); - EXPECT_EQ(it1->second.value(), 10); - ASSERT_NE(++it1, range.second); - EXPECT_EQ(it1->second.value(), 5); - EXPECT_EQ(++it1, range.second); + phmap::btree_multimap mmap; + std::pair p4 = {1, MovableOnlyInstance(5)}; + std::pair p5 = {1, MovableOnlyInstance(10)}; + mmap.insert(std::move(p4)); + mmap.insert(mmap.find(1), std::move(p5)); + auto range = mmap.equal_range(1); + auto it1 = range.first; + ASSERT_NE(it1, range.second); + EXPECT_EQ(it1->second.value(), 10); + ASSERT_NE(++it1, range.second); + EXPECT_EQ(it1->second.value(), 5); + EXPECT_EQ(++it1, range.second); - EXPECT_EQ(tracker.copies(), 0); - EXPECT_EQ(tracker.swaps(), 0); -} + EXPECT_EQ(tracker.copies(), 0); + EXPECT_EQ(tracker.swaps(), 0); + } } // namespace class BtreeNodePeer { - public: - // Yields the size of a leaf node with a specific number of values. - template - constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) { - return btree_node< - set_params, std::allocator, - /*TargetNodeSize=*/256, // This parameter isn't used here. - /*Multi=*/false>>::SizeWithNValues(target_values_per_node); - } +public: + // Yields the size of a leaf node with a specific number of values. + template + constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) { + return btree_node< + set_params, std::allocator, + /*TargetNodeSize=*/256, // This parameter isn't used here. + /*Multi=*/false>>::SizeWithNValues(target_values_per_node); + } - // Yields the number of values in a (non-root) leaf node for this set. - template - constexpr static size_t GetNumValuesPerNode() { - return btree_node::kNodeValues; - } + // Yields the number of values in a (non-root) leaf node for this set. + template + constexpr static size_t GetNumValuesPerNode() { + return btree_node::kNodeValues; + } }; namespace { -// A btree set with a specific number of values per node. -template > -class SizedBtreeSet - : public btree_set_container, - BtreeNodePeer::GetTargetNodeSize(TargetValuesPerNode), - /*Multi=*/false>>> { - using Base = typename SizedBtreeSet::btree_set_container; + // A btree set with a specific number of values per node. + template > + class SizedBtreeSet + : public btree_set_container, + BtreeNodePeer::GetTargetNodeSize(TargetValuesPerNode), + /*Multi=*/false>>> { + using Base = typename SizedBtreeSet::btree_set_container; - public: - SizedBtreeSet() {} - using Base::Base; -}; + public: + SizedBtreeSet() {} + using Base::Base; + }; -template -void ExpectOperationCounts(const int expected_moves, - const int expected_comparisons, - const std::vector &values, - InstanceTracker *tracker, Set *set) { - for (const int v : values) set->insert(MovableOnlyInstance(v)); - set->clear(); - EXPECT_EQ(tracker->moves(), expected_moves); - EXPECT_EQ(tracker->comparisons(), expected_comparisons); - EXPECT_EQ(tracker->copies(), 0); - EXPECT_EQ(tracker->swaps(), 0); - tracker->ResetCopiesMovesSwaps(); -} + template + void ExpectOperationCounts(const int expected_moves, + const int expected_comparisons, + const std::vector &values, + InstanceTracker *tracker, Set *set) { + for (const int v : values) set->insert(MovableOnlyInstance(v)); + set->clear(); + EXPECT_EQ(tracker->moves(), expected_moves); + EXPECT_EQ(tracker->comparisons(), expected_comparisons); + EXPECT_EQ(tracker->copies(), 0); + EXPECT_EQ(tracker->swaps(), 0); + tracker->ResetCopiesMovesSwaps(); + } -// Note: when the values in this test change, it is expected to have an impact -// on performance. -TEST(Btree, MovesComparisonsCopiesSwapsTracking) { - InstanceTracker tracker; - // Note: this is minimum number of values per node. - SizedBtreeSet set3; - // Note: this is the default number of values per node for a set of int32s - // (with 64-bit pointers). - SizedBtreeSet set61; - SizedBtreeSet set100; + // Note: when the values in this test change, it is expected to have an impact + // on performance. + TEST(Btree, MovesComparisonsCopiesSwapsTracking) { + InstanceTracker tracker; + // Note: this is minimum number of values per node. + SizedBtreeSet set3; + // Note: this is the default number of values per node for a set of int32s + // (with 64-bit pointers). + SizedBtreeSet set61; + SizedBtreeSet set100; - // Don't depend on flags for random values because then the expectations will - // fail if the flags change. - std::vector values = - GenerateValuesWithSeed(10000, 1 << 22, /*seed=*/23); + // Don't depend on flags for random values because then the expectations will + // fail if the flags change. + std::vector values = + GenerateValuesWithSeed(10000, 1 << 22, /*seed=*/23); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 3); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 61); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 100); - if (sizeof(void *) == 8) { - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode>(), - BtreeNodePeer::GetNumValuesPerNode()); - } + EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 3); + EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 61); + EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 100); + if (sizeof(void *) == 8) { + EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode>(), + BtreeNodePeer::GetNumValuesPerNode()); + } - // Test key insertion/deletion in random order. - ExpectOperationCounts(45281, 132551, values, &tracker, &set3); - ExpectOperationCounts(386718, 129807, values, &tracker, &set61); - ExpectOperationCounts(586761, 130310, values, &tracker, &set100); + // Test key insertion/deletion in random order. + ExpectOperationCounts(45281, 132551, values, &tracker, &set3); + ExpectOperationCounts(386718, 129807, values, &tracker, &set61); + ExpectOperationCounts(586761, 130310, values, &tracker, &set100); - // Test key insertion/deletion in sorted order. - std::sort(values.begin(), values.end()); - ExpectOperationCounts(26638, 92134, values, &tracker, &set3); - ExpectOperationCounts(20208, 87757, values, &tracker, &set61); - ExpectOperationCounts(20124, 96583, values, &tracker, &set100); + // Test key insertion/deletion in sorted order. + std::sort(values.begin(), values.end()); + ExpectOperationCounts(26638, 92134, values, &tracker, &set3); + ExpectOperationCounts(20208, 87757, values, &tracker, &set61); + ExpectOperationCounts(20124, 96583, values, &tracker, &set100); - // Test key insertion/deletion in reverse sorted order. - std::reverse(values.begin(), values.end()); - ExpectOperationCounts(49951, 119325, values, &tracker, &set3); - ExpectOperationCounts(338813, 118266, values, &tracker, &set61); - ExpectOperationCounts(534529, 125279, values, &tracker, &set100); -} + // Test key insertion/deletion in reverse sorted order. + std::reverse(values.begin(), values.end()); + ExpectOperationCounts(49951, 119325, values, &tracker, &set3); + ExpectOperationCounts(338813, 118266, values, &tracker, &set61); + ExpectOperationCounts(534529, 125279, values, &tracker, &set100); + } -struct MovableOnlyInstanceThreeWayCompare { - phmap::weak_ordering operator()(const MovableOnlyInstance &a, - const MovableOnlyInstance &b) const { - return a.compare(b); - } -}; + struct MovableOnlyInstanceThreeWayCompare { + phmap::weak_ordering operator()(const MovableOnlyInstance &a, + const MovableOnlyInstance &b) const { + return a.compare(b); + } + }; -// Note: when the values in this test change, it is expected to have an impact -// on performance. -TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) { - InstanceTracker tracker; - // Note: this is minimum number of values per node. - SizedBtreeSet - set3; - // Note: this is the default number of values per node for a set of int32s - // (with 64-bit pointers). - SizedBtreeSet - set61; - SizedBtreeSet - set100; + // Note: when the values in this test change, it is expected to have an impact + // on performance. + TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) { + InstanceTracker tracker; + // Note: this is minimum number of values per node. + SizedBtreeSet + set3; + // Note: this is the default number of values per node for a set of int32s + // (with 64-bit pointers). + SizedBtreeSet + set61; + SizedBtreeSet + set100; - // Don't depend on flags for random values because then the expectations will - // fail if the flags change. - std::vector values = - GenerateValuesWithSeed(10000, 1 << 22, /*seed=*/23); + // Don't depend on flags for random values because then the expectations will + // fail if the flags change. + std::vector values = + GenerateValuesWithSeed(10000, 1 << 22, /*seed=*/23); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 3); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 61); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 100); - if (sizeof(void *) == 8) { - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode>(), - BtreeNodePeer::GetNumValuesPerNode()); - } + EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 3); + EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 61); + EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 100); + if (sizeof(void *) == 8) { + EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode>(), + BtreeNodePeer::GetNumValuesPerNode()); + } - // Test key insertion/deletion in random order. - ExpectOperationCounts(45281, 122560, values, &tracker, &set3); - ExpectOperationCounts(386718, 119816, values, &tracker, &set61); - ExpectOperationCounts(586761, 120319, values, &tracker, &set100); + // Test key insertion/deletion in random order. + ExpectOperationCounts(45281, 122560, values, &tracker, &set3); + ExpectOperationCounts(386718, 119816, values, &tracker, &set61); + ExpectOperationCounts(586761, 120319, values, &tracker, &set100); - // Test key insertion/deletion in sorted order. - std::sort(values.begin(), values.end()); - ExpectOperationCounts(26638, 92134, values, &tracker, &set3); - ExpectOperationCounts(20208, 87757, values, &tracker, &set61); - ExpectOperationCounts(20124, 96583, values, &tracker, &set100); + // Test key insertion/deletion in sorted order. + std::sort(values.begin(), values.end()); + ExpectOperationCounts(26638, 92134, values, &tracker, &set3); + ExpectOperationCounts(20208, 87757, values, &tracker, &set61); + ExpectOperationCounts(20124, 96583, values, &tracker, &set100); - // Test key insertion/deletion in reverse sorted order. - std::reverse(values.begin(), values.end()); - ExpectOperationCounts(49951, 109326, values, &tracker, &set3); - ExpectOperationCounts(338813, 108267, values, &tracker, &set61); - ExpectOperationCounts(534529, 115280, values, &tracker, &set100); -} + // Test key insertion/deletion in reverse sorted order. + std::reverse(values.begin(), values.end()); + ExpectOperationCounts(49951, 109326, values, &tracker, &set3); + ExpectOperationCounts(338813, 108267, values, &tracker, &set61); + ExpectOperationCounts(534529, 115280, values, &tracker, &set100); + } -struct NoDefaultCtor { - int num; - explicit NoDefaultCtor(int i) : num(i) {} + struct NoDefaultCtor { + int num; + explicit NoDefaultCtor(int i) : num(i) {} - friend bool operator<(const NoDefaultCtor& a, const NoDefaultCtor& b) { - return a.num < b.num; - } -}; + friend bool operator<(const NoDefaultCtor& a, const NoDefaultCtor& b) { + return a.num < b.num; + } + }; -TEST(Btree, BtreeMapCanHoldNoDefaultCtorTypes) { - phmap::btree_map m; + TEST(Btree, BtreeMapCanHoldNoDefaultCtorTypes) { + phmap::btree_map m; - for (int i = 1; i <= 99; ++i) { - SCOPED_TRACE(i); - EXPECT_TRUE(m.emplace(NoDefaultCtor(i), NoDefaultCtor(100 - i)).second); - } - EXPECT_FALSE(m.emplace(NoDefaultCtor(78), NoDefaultCtor(0)).second); + for (int i = 1; i <= 99; ++i) { + SCOPED_TRACE(i); + EXPECT_TRUE(m.emplace(NoDefaultCtor(i), NoDefaultCtor(100 - i)).second); + } + EXPECT_FALSE(m.emplace(NoDefaultCtor(78), NoDefaultCtor(0)).second); - auto iter99 = m.find(NoDefaultCtor(99)); - ASSERT_NE(iter99, m.end()); - EXPECT_EQ(iter99->second.num, 1); + auto iter99 = m.find(NoDefaultCtor(99)); + ASSERT_NE(iter99, m.end()); + EXPECT_EQ(iter99->second.num, 1); - auto iter1 = m.find(NoDefaultCtor(1)); - ASSERT_NE(iter1, m.end()); - EXPECT_EQ(iter1->second.num, 99); + auto iter1 = m.find(NoDefaultCtor(1)); + ASSERT_NE(iter1, m.end()); + EXPECT_EQ(iter1->second.num, 99); - auto iter50 = m.find(NoDefaultCtor(50)); - ASSERT_NE(iter50, m.end()); - EXPECT_EQ(iter50->second.num, 50); + auto iter50 = m.find(NoDefaultCtor(50)); + ASSERT_NE(iter50, m.end()); + EXPECT_EQ(iter50->second.num, 50); - auto iter25 = m.find(NoDefaultCtor(25)); - ASSERT_NE(iter25, m.end()); - EXPECT_EQ(iter25->second.num, 75); -} + auto iter25 = m.find(NoDefaultCtor(25)); + ASSERT_NE(iter25, m.end()); + EXPECT_EQ(iter25->second.num, 75); + } -TEST(Btree, BtreeMultimapCanHoldNoDefaultCtorTypes) { - phmap::btree_multimap m; + TEST(Btree, BtreeMultimapCanHoldNoDefaultCtorTypes) { + phmap::btree_multimap m; - for (int i = 1; i <= 99; ++i) { - SCOPED_TRACE(i); - m.emplace(NoDefaultCtor(i), NoDefaultCtor(100 - i)); - } + for (int i = 1; i <= 99; ++i) { + SCOPED_TRACE(i); + m.emplace(NoDefaultCtor(i), NoDefaultCtor(100 - i)); + } - auto iter99 = m.find(NoDefaultCtor(99)); - ASSERT_NE(iter99, m.end()); - EXPECT_EQ(iter99->second.num, 1); + auto iter99 = m.find(NoDefaultCtor(99)); + ASSERT_NE(iter99, m.end()); + EXPECT_EQ(iter99->second.num, 1); - auto iter1 = m.find(NoDefaultCtor(1)); - ASSERT_NE(iter1, m.end()); - EXPECT_EQ(iter1->second.num, 99); + auto iter1 = m.find(NoDefaultCtor(1)); + ASSERT_NE(iter1, m.end()); + EXPECT_EQ(iter1->second.num, 99); - auto iter50 = m.find(NoDefaultCtor(50)); - ASSERT_NE(iter50, m.end()); - EXPECT_EQ(iter50->second.num, 50); + auto iter50 = m.find(NoDefaultCtor(50)); + ASSERT_NE(iter50, m.end()); + EXPECT_EQ(iter50->second.num, 50); - auto iter25 = m.find(NoDefaultCtor(25)); - ASSERT_NE(iter25, m.end()); - EXPECT_EQ(iter25->second.num, 75); -} + auto iter25 = m.find(NoDefaultCtor(25)); + ASSERT_NE(iter25, m.end()); + EXPECT_EQ(iter25->second.num, 75); + } -TEST(Btree, MapAt) { - phmap::btree_map map = {{1, 2}, {2, 4}}; - EXPECT_EQ(map.at(1), 2); - EXPECT_EQ(map.at(2), 4); - map.at(2) = 8; - const phmap::btree_map &const_map = map; - EXPECT_EQ(const_map.at(1), 2); - EXPECT_EQ(const_map.at(2), 8); + TEST(Btree, MapAt) { + phmap::btree_map map = {{1, 2}, {2, 4}}; + EXPECT_EQ(map.at(1), 2); + EXPECT_EQ(map.at(2), 4); + map.at(2) = 8; + const phmap::btree_map &const_map = map; + EXPECT_EQ(const_map.at(1), 2); + EXPECT_EQ(const_map.at(2), 8); #ifdef PHMAP_HAVE_EXCEPTIONS - EXPECT_THROW(map.at(3), std::out_of_range); + EXPECT_THROW(map.at(3), std::out_of_range); #else - EXPECT_DEATH(map.at(3), "phmap::btree_map::at"); + EXPECT_DEATH(map.at(3), "phmap::btree_map::at"); #endif -} + } -TEST(Btree, BtreeMultisetEmplace) { - const int value_to_insert = 123456; - phmap::btree_multiset s; - auto iter = s.emplace(value_to_insert); - ASSERT_NE(iter, s.end()); - EXPECT_EQ(*iter, value_to_insert); - auto iter2 = s.emplace(value_to_insert); - EXPECT_NE(iter2, iter); - ASSERT_NE(iter2, s.end()); - EXPECT_EQ(*iter2, value_to_insert); - auto result = s.equal_range(value_to_insert); - EXPECT_EQ(std::distance(result.first, result.second), 2); -} + TEST(Btree, BtreeMultisetEmplace) { + const int value_to_insert = 123456; + phmap::btree_multiset s; + auto iter = s.emplace(value_to_insert); + ASSERT_NE(iter, s.end()); + EXPECT_EQ(*iter, value_to_insert); + auto iter2 = s.emplace(value_to_insert); + EXPECT_NE(iter2, iter); + ASSERT_NE(iter2, s.end()); + EXPECT_EQ(*iter2, value_to_insert); + auto result = s.equal_range(value_to_insert); + EXPECT_EQ(std::distance(result.first, result.second), 2); + } -TEST(Btree, BtreeMultisetEmplaceHint) { - const int value_to_insert = 123456; - phmap::btree_multiset s; - auto iter = s.emplace(value_to_insert); - ASSERT_NE(iter, s.end()); - EXPECT_EQ(*iter, value_to_insert); - auto emplace_iter = s.emplace_hint(iter, value_to_insert); - EXPECT_NE(emplace_iter, iter); - ASSERT_NE(emplace_iter, s.end()); - EXPECT_EQ(*emplace_iter, value_to_insert); -} + TEST(Btree, BtreeMultisetEmplaceHint) { + const int value_to_insert = 123456; + phmap::btree_multiset s; + auto iter = s.emplace(value_to_insert); + ASSERT_NE(iter, s.end()); + EXPECT_EQ(*iter, value_to_insert); + auto emplace_iter = s.emplace_hint(iter, value_to_insert); + EXPECT_NE(emplace_iter, iter); + ASSERT_NE(emplace_iter, s.end()); + EXPECT_EQ(*emplace_iter, value_to_insert); + } -TEST(Btree, BtreeMultimapEmplace) { - const int key_to_insert = 123456; - const char value0[] = "a"; - phmap::btree_multimap s; - auto iter = s.emplace(key_to_insert, value0); - ASSERT_NE(iter, s.end()); - EXPECT_EQ(iter->first, key_to_insert); - EXPECT_EQ(iter->second, value0); - const char value1[] = "b"; - auto iter2 = s.emplace(key_to_insert, value1); - EXPECT_NE(iter2, iter); - ASSERT_NE(iter2, s.end()); - EXPECT_EQ(iter2->first, key_to_insert); - EXPECT_EQ(iter2->second, value1); - auto result = s.equal_range(key_to_insert); - EXPECT_EQ(std::distance(result.first, result.second), 2); -} + TEST(Btree, BtreeMultimapEmplace) { + const int key_to_insert = 123456; + const char value0[] = "a"; + phmap::btree_multimap s; + auto iter = s.emplace(key_to_insert, value0); + ASSERT_NE(iter, s.end()); + EXPECT_EQ(iter->first, key_to_insert); + EXPECT_EQ(iter->second, value0); + const char value1[] = "b"; + auto iter2 = s.emplace(key_to_insert, value1); + EXPECT_NE(iter2, iter); + ASSERT_NE(iter2, s.end()); + EXPECT_EQ(iter2->first, key_to_insert); + EXPECT_EQ(iter2->second, value1); + auto result = s.equal_range(key_to_insert); + EXPECT_EQ(std::distance(result.first, result.second), 2); + } -TEST(Btree, BtreeMultimapEmplaceHint) { - const int key_to_insert = 123456; - const char value0[] = "a"; - phmap::btree_multimap s; - auto iter = s.emplace(key_to_insert, value0); - ASSERT_NE(iter, s.end()); - EXPECT_EQ(iter->first, key_to_insert); - EXPECT_EQ(iter->second, value0); - const char value1[] = "b"; - auto emplace_iter = s.emplace_hint(iter, key_to_insert, value1); - EXPECT_NE(emplace_iter, iter); - ASSERT_NE(emplace_iter, s.end()); - EXPECT_EQ(emplace_iter->first, key_to_insert); - EXPECT_EQ(emplace_iter->second, value1); -} + TEST(Btree, BtreeMultimapEmplaceHint) { + const int key_to_insert = 123456; + const char value0[] = "a"; + phmap::btree_multimap s; + auto iter = s.emplace(key_to_insert, value0); + ASSERT_NE(iter, s.end()); + EXPECT_EQ(iter->first, key_to_insert); + EXPECT_EQ(iter->second, value0); + const char value1[] = "b"; + auto emplace_iter = s.emplace_hint(iter, key_to_insert, value1); + EXPECT_NE(emplace_iter, iter); + ASSERT_NE(emplace_iter, s.end()); + EXPECT_EQ(emplace_iter->first, key_to_insert); + EXPECT_EQ(emplace_iter->second, value1); + } -TEST(Btree, ConstIteratorAccessors) { - phmap::btree_set set; - for (int i = 0; i < 100; ++i) { - set.insert(i); - } + TEST(Btree, ConstIteratorAccessors) { + phmap::btree_set set; + for (int i = 0; i < 100; ++i) { + set.insert(i); + } - auto it = set.cbegin(); - auto r_it = set.crbegin(); - for (int i = 0; i < 100; ++i, ++it, ++r_it) { - ASSERT_EQ(*it, i); - ASSERT_EQ(*r_it, 99 - i); - } - EXPECT_EQ(it, set.cend()); - EXPECT_EQ(r_it, set.crend()); -} + auto it = set.cbegin(); + auto r_it = set.crbegin(); + for (int i = 0; i < 100; ++i, ++it, ++r_it) { + ASSERT_EQ(*it, i); + ASSERT_EQ(*r_it, 99 - i); + } + EXPECT_EQ(it, set.cend()); + EXPECT_EQ(r_it, set.crend()); + } #if 0 -TEST(Btree, StrSplitCompatible) { - const phmap::btree_set split_set = phmap::StrSplit("a,b,c", ','); - const phmap::btree_set expected_set = {"a", "b", "c"}; + TEST(Btree, StrSplitCompatible) { + const phmap::btree_set split_set = phmap::StrSplit("a,b,c", ','); + const phmap::btree_set expected_set = {"a", "b", "c"}; - EXPECT_EQ(split_set, expected_set); -} + EXPECT_EQ(split_set, expected_set); + } #endif -// We can't use EXPECT_EQ/etc. to compare phmap::weak_ordering because they -// convert literal 0 to int and phmap::weak_ordering can only be compared with -// literal 0. Defining this function allows for avoiding ClangTidy warnings. -bool Identity(const bool b) { return b; } + // We can't use EXPECT_EQ/etc. to compare phmap::weak_ordering because they + // convert literal 0 to int and phmap::weak_ordering can only be compared with + // literal 0. Defining this function allows for avoiding ClangTidy warnings. + bool Identity(const bool b) { return b; } -TEST(Btree, ValueComp) { - phmap::btree_set s; - EXPECT_TRUE(s.value_comp()(1, 2)); - EXPECT_FALSE(s.value_comp()(2, 2)); - EXPECT_FALSE(s.value_comp()(2, 1)); + TEST(Btree, ValueComp) { + phmap::btree_set s; + EXPECT_TRUE(s.value_comp()(1, 2)); + EXPECT_FALSE(s.value_comp()(2, 2)); + EXPECT_FALSE(s.value_comp()(2, 1)); - phmap::btree_map m1; - EXPECT_TRUE(m1.value_comp()(std::make_pair(1, 0), std::make_pair(2, 0))); - EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(2, 0))); - EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(1, 0))); + phmap::btree_map m1; + EXPECT_TRUE(m1.value_comp()(std::make_pair(1, 0), std::make_pair(2, 0))); + EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(2, 0))); + EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(1, 0))); - phmap::btree_map m2; - EXPECT_TRUE(Identity( - m2.value_comp()(std::make_pair("a", 0), std::make_pair("b", 0)) < 0)); - EXPECT_TRUE(Identity( - m2.value_comp()(std::make_pair("b", 0), std::make_pair("b", 0)) == 0)); - EXPECT_TRUE(Identity( - m2.value_comp()(std::make_pair("b", 0), std::make_pair("a", 0)) > 0)); -} + phmap::btree_map m2; + EXPECT_TRUE(Identity( + m2.value_comp()(std::make_pair("a", 0), std::make_pair("b", 0)) < 0)); + EXPECT_TRUE(Identity( + m2.value_comp()(std::make_pair("b", 0), std::make_pair("b", 0)) == 0)); + EXPECT_TRUE(Identity( + m2.value_comp()(std::make_pair("b", 0), std::make_pair("a", 0)) > 0)); + } -TEST(Btree, DefaultConstruction) { - phmap::btree_set s; - phmap::btree_map m; - phmap::btree_multiset ms; - phmap::btree_multimap mm; + TEST(Btree, DefaultConstruction) { + phmap::btree_set s; + phmap::btree_map m; + phmap::btree_multiset ms; + phmap::btree_multimap mm; - EXPECT_TRUE(s.empty()); - EXPECT_TRUE(m.empty()); - EXPECT_TRUE(ms.empty()); - EXPECT_TRUE(mm.empty()); -} + EXPECT_TRUE(s.empty()); + EXPECT_TRUE(m.empty()); + EXPECT_TRUE(ms.empty()); + EXPECT_TRUE(mm.empty()); + } #if 0 -TEST(Btree, SwissTableHashable) { - static constexpr int kValues = 10000; - std::vector values(kValues); - std::iota(values.begin(), values.end(), 0); - std::vector> map_values; - for (int v : values) map_values.emplace_back(v, -v); + TEST(Btree, SwissTableHashable) { + static constexpr int kValues = 10000; + std::vector values(kValues); + std::iota(values.begin(), values.end(), 0); + std::vector> map_values; + for (int v : values) map_values.emplace_back(v, -v); - using set = phmap::btree_set; - EXPECT_TRUE(phmap::VerifyTypeImplementsPhmapHashCorrectly({ - set{}, - set{1}, - set{2}, - set{1, 2}, - set{2, 1}, - set(values.begin(), values.end()), - set(values.rbegin(), values.rend()), - })); + using set = phmap::btree_set; + EXPECT_TRUE(phmap::VerifyTypeImplementsPhmapHashCorrectly({ + set{}, + set{1}, + set{2}, + set{1, 2}, + set{2, 1}, + set(values.begin(), values.end()), + set(values.rbegin(), values.rend()), + })); - using mset = phmap::btree_multiset; - EXPECT_TRUE(phmap::VerifyTypeImplementsPhmapHashCorrectly({ - mset{}, - mset{1}, - mset{1, 1}, - mset{2}, - mset{2, 2}, - mset{1, 2}, - mset{1, 1, 2}, - mset{1, 2, 2}, - mset{1, 1, 2, 2}, - mset(values.begin(), values.end()), - mset(values.rbegin(), values.rend()), - })); + using mset = phmap::btree_multiset; + EXPECT_TRUE(phmap::VerifyTypeImplementsPhmapHashCorrectly({ + mset{}, + mset{1}, + mset{1, 1}, + mset{2}, + mset{2, 2}, + mset{1, 2}, + mset{1, 1, 2}, + mset{1, 2, 2}, + mset{1, 1, 2, 2}, + mset(values.begin(), values.end()), + mset(values.rbegin(), values.rend()), + })); - using map = phmap::btree_map; - EXPECT_TRUE(phmap::VerifyTypeImplementsPhmapHashCorrectly({ - map{}, - map{{1, 0}}, - map{{1, 1}}, - map{{2, 0}}, - map{{2, 2}}, - map{{1, 0}, {2, 1}}, - map(map_values.begin(), map_values.end()), - map(map_values.rbegin(), map_values.rend()), - })); + using map = phmap::btree_map; + EXPECT_TRUE(phmap::VerifyTypeImplementsPhmapHashCorrectly({ + map{}, + map{{1, 0}}, + map{{1, 1}}, + map{{2, 0}}, + map{{2, 2}}, + map{{1, 0}, {2, 1}}, + map(map_values.begin(), map_values.end()), + map(map_values.rbegin(), map_values.rend()), + })); - using mmap = phmap::btree_multimap; - EXPECT_TRUE(phmap::VerifyTypeImplementsPhmapHashCorrectly({ - mmap{}, - mmap{{1, 0}}, - mmap{{1, 1}}, - mmap{{1, 0}, {1, 1}}, - mmap{{1, 1}, {1, 0}}, - mmap{{2, 0}}, - mmap{{2, 2}}, - mmap{{1, 0}, {2, 1}}, - mmap(map_values.begin(), map_values.end()), - mmap(map_values.rbegin(), map_values.rend()), - })); -} + using mmap = phmap::btree_multimap; + EXPECT_TRUE(phmap::VerifyTypeImplementsPhmapHashCorrectly({ + mmap{}, + mmap{{1, 0}}, + mmap{{1, 1}}, + mmap{{1, 0}, {1, 1}}, + mmap{{1, 1}, {1, 0}}, + mmap{{2, 0}}, + mmap{{2, 2}}, + mmap{{1, 0}, {2, 1}}, + mmap(map_values.begin(), map_values.end()), + mmap(map_values.rbegin(), map_values.rend()), + })); + } #endif -TEST(Btree, ComparableSet) { - phmap::btree_set s1 = {1, 2}; - phmap::btree_set s2 = {2, 3}; - EXPECT_LT(s1, s2); - EXPECT_LE(s1, s2); - EXPECT_LE(s1, s1); - EXPECT_GT(s2, s1); - EXPECT_GE(s2, s1); - EXPECT_GE(s1, s1); -} - -TEST(Btree, ComparableSetsDifferentLength) { - phmap::btree_set s1 = {1, 2}; - phmap::btree_set s2 = {1, 2, 3}; - EXPECT_LT(s1, s2); - EXPECT_LE(s1, s2); - EXPECT_GT(s2, s1); - EXPECT_GE(s2, s1); -} - -TEST(Btree, ComparableMultiset) { - phmap::btree_multiset s1 = {1, 2}; - phmap::btree_multiset s2 = {2, 3}; - EXPECT_LT(s1, s2); - EXPECT_LE(s1, s2); - EXPECT_LE(s1, s1); - EXPECT_GT(s2, s1); - EXPECT_GE(s2, s1); - EXPECT_GE(s1, s1); -} - -TEST(Btree, ComparableMap) { - phmap::btree_map s1 = {{1, 2}}; - phmap::btree_map s2 = {{2, 3}}; - EXPECT_LT(s1, s2); - EXPECT_LE(s1, s2); - EXPECT_LE(s1, s1); - EXPECT_GT(s2, s1); - EXPECT_GE(s2, s1); - EXPECT_GE(s1, s1); -} - -TEST(Btree, ComparableMultimap) { - phmap::btree_multimap s1 = {{1, 2}}; - phmap::btree_multimap s2 = {{2, 3}}; - EXPECT_LT(s1, s2); - EXPECT_LE(s1, s2); - EXPECT_LE(s1, s1); - EXPECT_GT(s2, s1); - EXPECT_GE(s2, s1); - EXPECT_GE(s1, s1); -} - -TEST(Btree, ComparableSetWithCustomComparator) { - // As specified by - // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf section - // [container.requirements.general].12, ordering associative containers always - // uses default '<' operator - // - even if otherwise the container uses custom functor. - phmap::btree_set> s1 = {1, 2}; - phmap::btree_set> s2 = {2, 3}; - EXPECT_LT(s1, s2); - EXPECT_LE(s1, s2); - EXPECT_LE(s1, s1); - EXPECT_GT(s2, s1); - EXPECT_GE(s2, s1); - EXPECT_GE(s1, s1); -} - -TEST(Btree, EraseReturnsIterator) { - phmap::btree_set set = {1, 2, 3, 4, 5}; - auto result_it = set.erase(set.begin(), set.find(3)); - EXPECT_EQ(result_it, set.find(3)); - result_it = set.erase(set.find(5)); - EXPECT_EQ(result_it, set.end()); -} - -TEST(Btree, ExtractAndInsertNodeHandleSet) { - phmap::btree_set src1 = {1, 2, 3, 4, 5}; - auto nh = src1.extract(src1.find(3)); - EXPECT_THAT(src1, ElementsAre(1, 2, 4, 5)); - phmap::btree_set other; - phmap::btree_set::insert_return_type res = other.insert(std::move(nh)); - EXPECT_THAT(other, ElementsAre(3)); - EXPECT_EQ(res.position, other.find(3)); - EXPECT_TRUE(res.inserted); - EXPECT_TRUE(res.node.empty()); - - phmap::btree_set src2 = {3, 4}; - nh = src2.extract(src2.find(3)); - EXPECT_THAT(src2, ElementsAre(4)); - res = other.insert(std::move(nh)); - EXPECT_THAT(other, ElementsAre(3)); - EXPECT_EQ(res.position, other.find(3)); - EXPECT_FALSE(res.inserted); - ASSERT_FALSE(res.node.empty()); - EXPECT_EQ(res.node.value(), 3); -} - -template -void TestExtractWithTrackingForSet() { - InstanceTracker tracker; - { - Set s; - // Add enough elements to make sure we test internal nodes too. - const size_t kSize = 1000; - while (s.size() < kSize) { - s.insert(MovableOnlyInstance(s.size())); + TEST(Btree, ComparableSet) { + phmap::btree_set s1 = {1, 2}; + phmap::btree_set s2 = {2, 3}; + EXPECT_LT(s1, s2); + EXPECT_LE(s1, s2); + EXPECT_LE(s1, s1); + EXPECT_GT(s2, s1); + EXPECT_GE(s2, s1); + EXPECT_GE(s1, s1); } - for (int i = 0; i < kSize; ++i) { - // Extract with key - auto nh = s.extract(MovableOnlyInstance(i)); - EXPECT_EQ(s.size(), kSize - 1); - EXPECT_EQ(nh.value().value(), i); - // Insert with node - s.insert(std::move(nh)); - EXPECT_EQ(s.size(), kSize); - // Extract with iterator - auto it = s.find(MovableOnlyInstance(i)); - nh = s.extract(it); - EXPECT_EQ(s.size(), kSize - 1); - EXPECT_EQ(nh.value().value(), i); - // Insert with node and hint - s.insert(s.begin(), std::move(nh)); - EXPECT_EQ(s.size(), kSize); + TEST(Btree, ComparableSetsDifferentLength) { + phmap::btree_set s1 = {1, 2}; + phmap::btree_set s2 = {1, 2, 3}; + EXPECT_LT(s1, s2); + EXPECT_LE(s1, s2); + EXPECT_GT(s2, s1); + EXPECT_GE(s2, s1); } - } - EXPECT_EQ(0, tracker.instances()); -} -template -void TestExtractWithTrackingForMap() { - InstanceTracker tracker; - { - Map m; - // Add enough elements to make sure we test internal nodes too. - const size_t kSize = 1000; - while (m.size() < kSize) { - m.insert( - {CopyableMovableInstance(m.size()), MovableOnlyInstance(m.size())}); + TEST(Btree, ComparableMultiset) { + phmap::btree_multiset s1 = {1, 2}; + phmap::btree_multiset s2 = {2, 3}; + EXPECT_LT(s1, s2); + EXPECT_LE(s1, s2); + EXPECT_LE(s1, s1); + EXPECT_GT(s2, s1); + EXPECT_GE(s2, s1); + EXPECT_GE(s1, s1); } - for (int i = 0; i < kSize; ++i) { - // Extract with key - auto nh = m.extract(CopyableMovableInstance(i)); - EXPECT_EQ(m.size(), kSize - 1); - EXPECT_EQ(nh.key().value(), i); - EXPECT_EQ(nh.mapped().value(), i); - // Insert with node - m.insert(std::move(nh)); - EXPECT_EQ(m.size(), kSize); - // Extract with iterator - auto it = m.find(CopyableMovableInstance(i)); - nh = m.extract(it); - EXPECT_EQ(m.size(), kSize - 1); - EXPECT_EQ(nh.key().value(), i); - EXPECT_EQ(nh.mapped().value(), i); - // Insert with node and hint - m.insert(m.begin(), std::move(nh)); - EXPECT_EQ(m.size(), kSize); + TEST(Btree, ComparableMap) { + phmap::btree_map s1 = {{1, 2}}; + phmap::btree_map s2 = {{2, 3}}; + EXPECT_LT(s1, s2); + EXPECT_LE(s1, s2); + EXPECT_LE(s1, s1); + EXPECT_GT(s2, s1); + EXPECT_GE(s2, s1); + EXPECT_GE(s1, s1); } - } - EXPECT_EQ(0, tracker.instances()); -} -TEST(Btree, ExtractTracking) { - TestExtractWithTrackingForSet>(); - TestExtractWithTrackingForSet>(); - TestExtractWithTrackingForMap< - phmap::btree_map>(); - TestExtractWithTrackingForMap< - phmap::btree_multimap>(); -} + TEST(Btree, ComparableMultimap) { + phmap::btree_multimap s1 = {{1, 2}}; + phmap::btree_multimap s2 = {{2, 3}}; + EXPECT_LT(s1, s2); + EXPECT_LE(s1, s2); + EXPECT_LE(s1, s1); + EXPECT_GT(s2, s1); + EXPECT_GE(s2, s1); + EXPECT_GE(s1, s1); + } -TEST(Btree, ExtractAndInsertNodeHandleMultiSet) { - phmap::btree_multiset src1 = {1, 2, 3, 3, 4, 5}; - auto nh = src1.extract(src1.find(3)); - EXPECT_THAT(src1, ElementsAre(1, 2, 3, 4, 5)); - phmap::btree_multiset other; - auto res = other.insert(std::move(nh)); - EXPECT_THAT(other, ElementsAre(3)); - EXPECT_EQ(res, other.find(3)); + TEST(Btree, ComparableSetWithCustomComparator) { + // As specified by + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf section + // [container.requirements.general].12, ordering associative containers always + // uses default '<' operator + // - even if otherwise the container uses custom functor. + phmap::btree_set> s1 = {1, 2}; + phmap::btree_set> s2 = {2, 3}; + EXPECT_LT(s1, s2); + EXPECT_LE(s1, s2); + EXPECT_LE(s1, s1); + EXPECT_GT(s2, s1); + EXPECT_GE(s2, s1); + EXPECT_GE(s1, s1); + } - phmap::btree_multiset src2 = {3, 4}; - nh = src2.extract(src2.find(3)); - EXPECT_THAT(src2, ElementsAre(4)); - res = other.insert(std::move(nh)); - EXPECT_THAT(other, ElementsAre(3, 3)); - EXPECT_EQ(res, ++other.find(3)); -} + TEST(Btree, EraseReturnsIterator) { + phmap::btree_set set = {1, 2, 3, 4, 5}; + auto result_it = set.erase(set.begin(), set.find(3)); + EXPECT_EQ(result_it, set.find(3)); + result_it = set.erase(set.find(5)); + EXPECT_EQ(result_it, set.end()); + } -TEST(Btree, ExtractAndInsertNodeHandleMap) { - phmap::btree_map src1 = {{1, 2}, {3, 4}, {5, 6}}; - auto nh = src1.extract(src1.find(3)); - EXPECT_THAT(src1, ElementsAre(Pair(1, 2), Pair(5, 6))); - phmap::btree_map other; - phmap::btree_map::insert_return_type res = - other.insert(std::move(nh)); - EXPECT_THAT(other, ElementsAre(Pair(3, 4))); - EXPECT_EQ(res.position, other.find(3)); - EXPECT_TRUE(res.inserted); - EXPECT_TRUE(res.node.empty()); + TEST(Btree, ExtractAndInsertNodeHandleSet) { + phmap::btree_set src1 = {1, 2, 3, 4, 5}; + auto nh = src1.extract(src1.find(3)); + EXPECT_THAT(src1, ElementsAre(1, 2, 4, 5)); + phmap::btree_set other; + phmap::btree_set::insert_return_type res = other.insert(std::move(nh)); + EXPECT_THAT(other, ElementsAre(3)); + EXPECT_EQ(res.position, other.find(3)); + EXPECT_TRUE(res.inserted); + EXPECT_TRUE(res.node.empty()); - phmap::btree_map src2 = {{3, 6}}; - nh = src2.extract(src2.find(3)); - EXPECT_TRUE(src2.empty()); - res = other.insert(std::move(nh)); - EXPECT_THAT(other, ElementsAre(Pair(3, 4))); - EXPECT_EQ(res.position, other.find(3)); - EXPECT_FALSE(res.inserted); - ASSERT_FALSE(res.node.empty()); - EXPECT_EQ(res.node.key(), 3); - EXPECT_EQ(res.node.mapped(), 6); -} + phmap::btree_set src2 = {3, 4}; + nh = src2.extract(src2.find(3)); + EXPECT_THAT(src2, ElementsAre(4)); + res = other.insert(std::move(nh)); + EXPECT_THAT(other, ElementsAre(3)); + EXPECT_EQ(res.position, other.find(3)); + EXPECT_FALSE(res.inserted); + ASSERT_FALSE(res.node.empty()); + EXPECT_EQ(res.node.value(), 3); + } -TEST(Btree, ExtractAndInsertNodeHandleMultiMap) { - phmap::btree_multimap src1 = {{1, 2}, {3, 4}, {5, 6}}; - auto nh = src1.extract(src1.find(3)); - EXPECT_THAT(src1, ElementsAre(Pair(1, 2), Pair(5, 6))); - phmap::btree_multimap other; - auto res = other.insert(std::move(nh)); - EXPECT_THAT(other, ElementsAre(Pair(3, 4))); - EXPECT_EQ(res, other.find(3)); + template + void TestExtractWithTrackingForSet() { + InstanceTracker tracker; + { + Set s; + // Add enough elements to make sure we test internal nodes too. + const size_t kSize = 1000; + while (s.size() < kSize) { + s.insert(MovableOnlyInstance(s.size())); + } + for (int i = 0; i < kSize; ++i) { + // Extract with key + auto nh = s.extract(MovableOnlyInstance(i)); + EXPECT_EQ(s.size(), kSize - 1); + EXPECT_EQ(nh.value().value(), i); + // Insert with node + s.insert(std::move(nh)); + EXPECT_EQ(s.size(), kSize); - phmap::btree_multimap src2 = {{3, 6}}; - nh = src2.extract(src2.find(3)); - EXPECT_TRUE(src2.empty()); - res = other.insert(std::move(nh)); - EXPECT_THAT(other, ElementsAre(Pair(3, 4), Pair(3, 6))); - EXPECT_EQ(res, ++other.begin()); -} + // Extract with iterator + auto it = s.find(MovableOnlyInstance(i)); + nh = s.extract(it); + EXPECT_EQ(s.size(), kSize - 1); + EXPECT_EQ(nh.value().value(), i); + // Insert with node and hint + s.insert(s.begin(), std::move(nh)); + EXPECT_EQ(s.size(), kSize); + } + } + EXPECT_EQ(0, tracker.instances()); + } -// For multisets, insert with hint also affects correctness because we need to -// insert immediately before the hint if possible. -struct InsertMultiHintData { - int key; - int not_key; - bool operator==(const InsertMultiHintData other) const { - return key == other.key && not_key == other.not_key; - } -}; + template + void TestExtractWithTrackingForMap() { + InstanceTracker tracker; + { + Map m; + // Add enough elements to make sure we test internal nodes too. + const size_t kSize = 1000; + while (m.size() < kSize) { + m.insert( + {CopyableMovableInstance(m.size()), MovableOnlyInstance(m.size())}); + } + for (int i = 0; i < kSize; ++i) { + // Extract with key + auto nh = m.extract(CopyableMovableInstance(i)); + EXPECT_EQ(m.size(), kSize - 1); + EXPECT_EQ(nh.key().value(), i); + EXPECT_EQ(nh.mapped().value(), i); + // Insert with node + m.insert(std::move(nh)); + EXPECT_EQ(m.size(), kSize); -struct InsertMultiHintDataKeyCompare { - using is_transparent = void; - bool operator()(const InsertMultiHintData a, - const InsertMultiHintData b) const { - return a.key < b.key; - } - bool operator()(const int a, const InsertMultiHintData b) const { - return a < b.key; - } - bool operator()(const InsertMultiHintData a, const int b) const { - return a.key < b; - } -}; + // Extract with iterator + auto it = m.find(CopyableMovableInstance(i)); + nh = m.extract(it); + EXPECT_EQ(m.size(), kSize - 1); + EXPECT_EQ(nh.key().value(), i); + EXPECT_EQ(nh.mapped().value(), i); + // Insert with node and hint + m.insert(m.begin(), std::move(nh)); + EXPECT_EQ(m.size(), kSize); + } + } + EXPECT_EQ(0, tracker.instances()); + } -TEST(Btree, InsertHintNodeHandle) { - // For unique sets, insert with hint is just a performance optimization. - // Test that insert works correctly when the hint is right or wrong. - { - phmap::btree_set src = {1, 2, 3, 4, 5}; - auto nh = src.extract(src.find(3)); - EXPECT_THAT(src, ElementsAre(1, 2, 4, 5)); - phmap::btree_set other = {0, 100}; - // Test a correct hint. - auto it = other.insert(other.lower_bound(3), std::move(nh)); - EXPECT_THAT(other, ElementsAre(0, 3, 100)); - EXPECT_EQ(it, other.find(3)); + TEST(Btree, ExtractTracking) { + TestExtractWithTrackingForSet>(); + TestExtractWithTrackingForSet>(); + TestExtractWithTrackingForMap< + phmap::btree_map>(); + TestExtractWithTrackingForMap< + phmap::btree_multimap>(); + } - nh = src.extract(src.find(5)); - // Test an incorrect hint. - it = other.insert(other.end(), std::move(nh)); - EXPECT_THAT(other, ElementsAre(0, 3, 5, 100)); - EXPECT_EQ(it, other.find(5)); - } + TEST(Btree, ExtractAndInsertNodeHandleMultiSet) { + phmap::btree_multiset src1 = {1, 2, 3, 3, 4, 5}; + auto nh = src1.extract(src1.find(3)); + EXPECT_THAT(src1, ElementsAre(1, 2, 3, 4, 5)); + phmap::btree_multiset other; + auto res = other.insert(std::move(nh)); + EXPECT_THAT(other, ElementsAre(3)); + EXPECT_EQ(res, other.find(3)); - phmap::btree_multiset src = - {{1, 2}, {3, 4}, {3, 5}}; - auto nh = src.extract(src.lower_bound(3)); - EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 4})); - phmap::btree_multiset - other = {{3, 1}, {3, 2}, {3, 3}}; - auto it = other.insert(--other.end(), std::move(nh)); - EXPECT_THAT( - other, ElementsAre(InsertMultiHintData{3, 1}, InsertMultiHintData{3, 2}, - InsertMultiHintData{3, 4}, InsertMultiHintData{3, 3})); - EXPECT_EQ(it, --(--other.end())); + phmap::btree_multiset src2 = {3, 4}; + nh = src2.extract(src2.find(3)); + EXPECT_THAT(src2, ElementsAre(4)); + res = other.insert(std::move(nh)); + EXPECT_THAT(other, ElementsAre(3, 3)); + EXPECT_EQ(res, ++other.find(3)); + } - nh = src.extract(src.find(3)); - EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 5})); - it = other.insert(other.begin(), std::move(nh)); - EXPECT_THAT(other, - ElementsAre(InsertMultiHintData{3, 5}, InsertMultiHintData{3, 1}, - InsertMultiHintData{3, 2}, InsertMultiHintData{3, 4}, - InsertMultiHintData{3, 3})); - EXPECT_EQ(it, other.begin()); -} + TEST(Btree, ExtractAndInsertNodeHandleMap) { + phmap::btree_map src1 = {{1, 2}, {3, 4}, {5, 6}}; + auto nh = src1.extract(src1.find(3)); + EXPECT_THAT(src1, ElementsAre(Pair(1, 2), Pair(5, 6))); + phmap::btree_map other; + phmap::btree_map::insert_return_type res = + other.insert(std::move(nh)); + EXPECT_THAT(other, ElementsAre(Pair(3, 4))); + EXPECT_EQ(res.position, other.find(3)); + EXPECT_TRUE(res.inserted); + EXPECT_TRUE(res.node.empty()); -struct IntCompareToCmp { - phmap::weak_ordering operator()(int a, int b) const { - if (a < b) return phmap::weak_ordering::less; - if (a > b) return phmap::weak_ordering::greater; - return phmap::weak_ordering::equivalent; - } -}; + phmap::btree_map src2 = {{3, 6}}; + nh = src2.extract(src2.find(3)); + EXPECT_TRUE(src2.empty()); + res = other.insert(std::move(nh)); + EXPECT_THAT(other, ElementsAre(Pair(3, 4))); + EXPECT_EQ(res.position, other.find(3)); + EXPECT_FALSE(res.inserted); + ASSERT_FALSE(res.node.empty()); + EXPECT_EQ(res.node.key(), 3); + EXPECT_EQ(res.node.mapped(), 6); + } -TEST(Btree, MergeIntoUniqueContainers) { - phmap::btree_set src1 = {1, 2, 3}; - phmap::btree_multiset src2 = {3, 4, 4, 5}; - phmap::btree_set dst; + TEST(Btree, ExtractAndInsertNodeHandleMultiMap) { + phmap::btree_multimap src1 = {{1, 2}, {3, 4}, {5, 6}}; + auto nh = src1.extract(src1.find(3)); + EXPECT_THAT(src1, ElementsAre(Pair(1, 2), Pair(5, 6))); + phmap::btree_multimap other; + auto res = other.insert(std::move(nh)); + EXPECT_THAT(other, ElementsAre(Pair(3, 4))); + EXPECT_EQ(res, other.find(3)); - dst.merge(src1); - EXPECT_TRUE(src1.empty()); - EXPECT_THAT(dst, ElementsAre(1, 2, 3)); - dst.merge(src2); - EXPECT_THAT(src2, ElementsAre(3, 4)); - EXPECT_THAT(dst, ElementsAre(1, 2, 3, 4, 5)); -} + phmap::btree_multimap src2 = {{3, 6}}; + nh = src2.extract(src2.find(3)); + EXPECT_TRUE(src2.empty()); + res = other.insert(std::move(nh)); + EXPECT_THAT(other, ElementsAre(Pair(3, 4), Pair(3, 6))); + EXPECT_EQ(res, ++other.begin()); + } -TEST(Btree, MergeIntoUniqueContainersWithCompareTo) { - phmap::btree_set src1 = {1, 2, 3}; - phmap::btree_multiset src2 = {3, 4, 4, 5}; - phmap::btree_set dst; + // For multisets, insert with hint also affects correctness because we need to + // insert immediately before the hint if possible. + struct InsertMultiHintData { + int key; + int not_key; + bool operator==(const InsertMultiHintData other) const { + return key == other.key && not_key == other.not_key; + } + }; - dst.merge(src1); - EXPECT_TRUE(src1.empty()); - EXPECT_THAT(dst, ElementsAre(1, 2, 3)); - dst.merge(src2); - EXPECT_THAT(src2, ElementsAre(3, 4)); - EXPECT_THAT(dst, ElementsAre(1, 2, 3, 4, 5)); -} + struct InsertMultiHintDataKeyCompare { + using is_transparent = void; + bool operator()(const InsertMultiHintData a, + const InsertMultiHintData b) const { + return a.key < b.key; + } + bool operator()(const int a, const InsertMultiHintData b) const { + return a < b.key; + } + bool operator()(const InsertMultiHintData a, const int b) const { + return a.key < b; + } + }; -TEST(Btree, MergeIntoMultiContainers) { - phmap::btree_set src1 = {1, 2, 3}; - phmap::btree_multiset src2 = {3, 4, 4, 5}; - phmap::btree_multiset dst; + TEST(Btree, InsertHintNodeHandle) { + // For unique sets, insert with hint is just a performance optimization. + // Test that insert works correctly when the hint is right or wrong. + { + phmap::btree_set src = {1, 2, 3, 4, 5}; + auto nh = src.extract(src.find(3)); + EXPECT_THAT(src, ElementsAre(1, 2, 4, 5)); + phmap::btree_set other = {0, 100}; + // Test a correct hint. + auto it = other.insert(other.lower_bound(3), std::move(nh)); + EXPECT_THAT(other, ElementsAre(0, 3, 100)); + EXPECT_EQ(it, other.find(3)); - dst.merge(src1); - EXPECT_TRUE(src1.empty()); - EXPECT_THAT(dst, ElementsAre(1, 2, 3)); - dst.merge(src2); - EXPECT_TRUE(src2.empty()); - EXPECT_THAT(dst, ElementsAre(1, 2, 3, 3, 4, 4, 5)); -} + nh = src.extract(src.find(5)); + // Test an incorrect hint. + it = other.insert(other.end(), std::move(nh)); + EXPECT_THAT(other, ElementsAre(0, 3, 5, 100)); + EXPECT_EQ(it, other.find(5)); + } -TEST(Btree, MergeIntoMultiContainersWithCompareTo) { - phmap::btree_set src1 = {1, 2, 3}; - phmap::btree_multiset src2 = {3, 4, 4, 5}; - phmap::btree_multiset dst; + phmap::btree_multiset src = + {{1, 2}, {3, 4}, {3, 5}}; + auto nh = src.extract(src.lower_bound(3)); + EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 4})); + phmap::btree_multiset + other = {{3, 1}, {3, 2}, {3, 3}}; + auto it = other.insert(--other.end(), std::move(nh)); + EXPECT_THAT( + other, ElementsAre(InsertMultiHintData{3, 1}, InsertMultiHintData{3, 2}, + InsertMultiHintData{3, 4}, InsertMultiHintData{3, 3})); + EXPECT_EQ(it, --(--other.end())); - dst.merge(src1); - EXPECT_TRUE(src1.empty()); - EXPECT_THAT(dst, ElementsAre(1, 2, 3)); - dst.merge(src2); - EXPECT_TRUE(src2.empty()); - EXPECT_THAT(dst, ElementsAre(1, 2, 3, 3, 4, 4, 5)); -} + nh = src.extract(src.find(3)); + EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 5})); + it = other.insert(other.begin(), std::move(nh)); + EXPECT_THAT(other, + ElementsAre(InsertMultiHintData{3, 5}, InsertMultiHintData{3, 1}, + InsertMultiHintData{3, 2}, InsertMultiHintData{3, 4}, + InsertMultiHintData{3, 3})); + EXPECT_EQ(it, other.begin()); + } -TEST(Btree, MergeIntoMultiMapsWithDifferentComparators) { - phmap::btree_map src1 = {{1, 1}, {2, 2}, {3, 3}}; - phmap::btree_multimap> src2 = { - {5, 5}, {4, 1}, {4, 4}, {3, 2}}; - phmap::btree_multimap dst; + struct IntCompareToCmp { + phmap::weak_ordering operator()(int a, int b) const { + if (a < b) return phmap::weak_ordering::less; + if (a > b) return phmap::weak_ordering::greater; + return phmap::weak_ordering::equivalent; + } + }; - dst.merge(src1); - EXPECT_TRUE(src1.empty()); - EXPECT_THAT(dst, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3))); - dst.merge(src2); - EXPECT_TRUE(src2.empty()); - EXPECT_THAT(dst, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3), Pair(3, 2), - Pair(4, 1), Pair(4, 4), Pair(5, 5))); -} + TEST(Btree, MergeIntoUniqueContainers) { + phmap::btree_set src1 = {1, 2, 3}; + phmap::btree_multiset src2 = {3, 4, 4, 5}; + phmap::btree_set dst; -struct KeyCompareToWeakOrdering { - template - phmap::weak_ordering operator()(const T &a, const T &b) const { - return a < b ? phmap::weak_ordering::less - : a == b ? phmap::weak_ordering::equivalent - : phmap::weak_ordering::greater; - } -}; + dst.merge(src1); + EXPECT_TRUE(src1.empty()); + EXPECT_THAT(dst, ElementsAre(1, 2, 3)); + dst.merge(src2); + EXPECT_THAT(src2, ElementsAre(3, 4)); + EXPECT_THAT(dst, ElementsAre(1, 2, 3, 4, 5)); + } -struct KeyCompareToStrongOrdering { - template - phmap::strong_ordering operator()(const T &a, const T &b) const { - return a < b ? phmap::strong_ordering::less - : a == b ? phmap::strong_ordering::equal - : phmap::strong_ordering::greater; - } -}; + TEST(Btree, MergeIntoUniqueContainersWithCompareTo) { + phmap::btree_set src1 = {1, 2, 3}; + phmap::btree_multiset src2 = {3, 4, 4, 5}; + phmap::btree_set dst; -TEST(Btree, UserProvidedKeyCompareToComparators) { - phmap::btree_set weak_set = {1, 2, 3}; - EXPECT_TRUE(weak_set.contains(2)); - EXPECT_FALSE(weak_set.contains(4)); + dst.merge(src1); + EXPECT_TRUE(src1.empty()); + EXPECT_THAT(dst, ElementsAre(1, 2, 3)); + dst.merge(src2); + EXPECT_THAT(src2, ElementsAre(3, 4)); + EXPECT_THAT(dst, ElementsAre(1, 2, 3, 4, 5)); + } - phmap::btree_set strong_set = {1, 2, 3}; - EXPECT_TRUE(strong_set.contains(2)); - EXPECT_FALSE(strong_set.contains(4)); -} + TEST(Btree, MergeIntoMultiContainers) { + phmap::btree_set src1 = {1, 2, 3}; + phmap::btree_multiset src2 = {3, 4, 4, 5}; + phmap::btree_multiset dst; -TEST(Btree, TryEmplaceBasicTest) { - phmap::btree_map m; + dst.merge(src1); + EXPECT_TRUE(src1.empty()); + EXPECT_THAT(dst, ElementsAre(1, 2, 3)); + dst.merge(src2); + EXPECT_TRUE(src2.empty()); + EXPECT_THAT(dst, ElementsAre(1, 2, 3, 3, 4, 4, 5)); + } - // Should construct a std::string from the literal. - m.try_emplace(1, "one"); - EXPECT_EQ(1, m.size()); + TEST(Btree, MergeIntoMultiContainersWithCompareTo) { + phmap::btree_set src1 = {1, 2, 3}; + phmap::btree_multiset src2 = {3, 4, 4, 5}; + phmap::btree_multiset dst; - // Try other std::string constructors and const lvalue key. - const int key(42); - m.try_emplace(key, 3, 'a'); - m.try_emplace(2, std::string("two")); + dst.merge(src1); + EXPECT_TRUE(src1.empty()); + EXPECT_THAT(dst, ElementsAre(1, 2, 3)); + dst.merge(src2); + EXPECT_TRUE(src2.empty()); + EXPECT_THAT(dst, ElementsAre(1, 2, 3, 3, 4, 4, 5)); + } - EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); - EXPECT_THAT(m, ElementsAreArray(std::vector>{ - {1, "one"}, {2, "two"}, {42, "aaa"}})); -} + TEST(Btree, MergeIntoMultiMapsWithDifferentComparators) { + phmap::btree_map src1 = {{1, 1}, {2, 2}, {3, 3}}; + phmap::btree_multimap> src2 = { + {5, 5}, {4, 1}, {4, 4}, {3, 2}}; + phmap::btree_multimap dst; -TEST(Btree, TryEmplaceWithHintWorks) { - // Use a counting comparator here to verify that hint is used. - int calls = 0; - auto cmp = [&calls](int x, int y) { - ++calls; - return x < y; - }; - using Cmp = decltype(cmp); + dst.merge(src1); + EXPECT_TRUE(src1.empty()); + EXPECT_THAT(dst, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3))); + dst.merge(src2); + EXPECT_TRUE(src2.empty()); + EXPECT_THAT(dst, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3), Pair(3, 2), + Pair(4, 1), Pair(4, 4), Pair(5, 5))); + } - phmap::btree_map m(cmp); - for (int i = 0; i < 128; ++i) { - m.emplace(i, i); - } + struct KeyCompareToWeakOrdering { + template + phmap::weak_ordering operator()(const T &a, const T &b) const { + return a < b ? phmap::weak_ordering::less + : a == b ? phmap::weak_ordering::equivalent + : phmap::weak_ordering::greater; + } + }; - // Sanity check for the comparator - calls = 0; - m.emplace(127, 127); - EXPECT_GE(calls, 4); + struct KeyCompareToStrongOrdering { + template + phmap::strong_ordering operator()(const T &a, const T &b) const { + return a < b ? phmap::strong_ordering::less + : a == b ? phmap::strong_ordering::equal + : phmap::strong_ordering::greater; + } + }; - // Try with begin hint: - calls = 0; - auto it = m.try_emplace(m.begin(), -1, -1); - EXPECT_EQ(129, m.size()); - EXPECT_EQ(it, m.begin()); - EXPECT_LE(calls, 2); + TEST(Btree, UserProvidedKeyCompareToComparators) { + phmap::btree_set weak_set = {1, 2, 3}; + EXPECT_TRUE(weak_set.contains(2)); + EXPECT_FALSE(weak_set.contains(4)); - // Try with end hint: - calls = 0; - std::pair pair1024 = {1024, 1024}; - it = m.try_emplace(m.end(), pair1024.first, pair1024.second); - EXPECT_EQ(130, m.size()); - EXPECT_EQ(it, --m.end()); - EXPECT_LE(calls, 2); + phmap::btree_set strong_set = {1, 2, 3}; + EXPECT_TRUE(strong_set.contains(2)); + EXPECT_FALSE(strong_set.contains(4)); + } - // Try value already present, bad hint; ensure no duplicate added: - calls = 0; - it = m.try_emplace(m.end(), 16, 17); - EXPECT_EQ(130, m.size()); - EXPECT_GE(calls, 4); - EXPECT_EQ(it, m.find(16)); + TEST(Btree, TryEmplaceBasicTest) { + phmap::btree_map m; - // Try value already present, hint points directly to it: - calls = 0; - it = m.try_emplace(it, 16, 17); - EXPECT_EQ(130, m.size()); - EXPECT_LE(calls, 2); - EXPECT_EQ(it, m.find(16)); + // Should construct a std::string from the literal. + m.try_emplace(1, "one"); + EXPECT_EQ(1, m.size()); - m.erase(2); - EXPECT_EQ(129, m.size()); - auto hint = m.find(3); - // Try emplace in the middle of two other elements. - calls = 0; - m.try_emplace(hint, 2, 2); - EXPECT_EQ(130, m.size()); - EXPECT_LE(calls, 2); + // Try other std::string constructors and const lvalue key. + const int key(42); + m.try_emplace(key, 3, 'a'); + m.try_emplace(2, std::string("two")); - EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); -} + EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); + EXPECT_THAT(m, ElementsAreArray(std::vector>{ + {1, "one"}, {2, "two"}, {42, "aaa"}})); + } -TEST(Btree, TryEmplaceWithBadHint) { - phmap::btree_map m = {{1, 1}, {9, 9}}; + TEST(Btree, TryEmplaceWithHintWorks) { + // Use a counting comparator here to verify that hint is used. + int calls = 0; + auto cmp = [&calls](int x, int y) { + ++calls; + return x < y; + }; + using Cmp = decltype(cmp); - // Bad hint (too small), should still emplace: - auto it = m.try_emplace(m.begin(), 2, 2); - EXPECT_EQ(it, ++m.begin()); - EXPECT_THAT(m, ElementsAreArray( - std::vector>{{1, 1}, {2, 2}, {9, 9}})); + phmap::btree_map m(cmp); + for (int i = 0; i < 128; ++i) { + m.emplace(i, i); + } - // Bad hint, too large this time: - it = m.try_emplace(++(++m.begin()), 0, 0); - EXPECT_EQ(it, m.begin()); - EXPECT_THAT(m, ElementsAreArray(std::vector>{ - {0, 0}, {1, 1}, {2, 2}, {9, 9}})); -} + // Sanity check for the comparator + calls = 0; + m.emplace(127, 127); + EXPECT_GE(calls, 4); -TEST(Btree, TryEmplaceMaintainsSortedOrder) { - phmap::btree_map m; - std::pair pair5 = {5, "five"}; + // Try with begin hint: + calls = 0; + auto it = m.try_emplace(m.begin(), -1, -1); + EXPECT_EQ(129, m.size()); + EXPECT_EQ(it, m.begin()); + EXPECT_LE(calls, 2); - // Test both lvalue & rvalue emplace. - m.try_emplace(10, "ten"); - m.try_emplace(pair5.first, pair5.second); - EXPECT_EQ(2, m.size()); - EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); + // Try with end hint: + calls = 0; + std::pair pair1024 = {1024, 1024}; + it = m.try_emplace(m.end(), pair1024.first, pair1024.second); + EXPECT_EQ(130, m.size()); + EXPECT_EQ(it, --m.end()); + EXPECT_LE(calls, 2); - int int100{100}; - m.try_emplace(int100, "hundred"); - m.try_emplace(1, "one"); - EXPECT_EQ(4, m.size()); - EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); -} + // Try value already present, bad hint; ensure no duplicate added: + calls = 0; + it = m.try_emplace(m.end(), 16, 17); + EXPECT_EQ(130, m.size()); + EXPECT_GE(calls, 4); + EXPECT_EQ(it, m.find(16)); -TEST(Btree, TryEmplaceWithHintAndNoValueArgsWorks) { - phmap::btree_map m; - m.try_emplace(m.end(), 1); - EXPECT_EQ(0, m[1]); -} + // Try value already present, hint points directly to it: + calls = 0; + it = m.try_emplace(it, 16, 17); + EXPECT_EQ(130, m.size()); + EXPECT_LE(calls, 2); + EXPECT_EQ(it, m.find(16)); -TEST(Btree, TryEmplaceWithHintAndMultipleValueArgsWorks) { - phmap::btree_map m; - m.try_emplace(m.end(), 1, 10, 'a'); - EXPECT_EQ(std::string(10, 'a'), m[1]); -} + m.erase(2); + EXPECT_EQ(129, m.size()); + auto hint = m.find(3); + // Try emplace in the middle of two other elements. + calls = 0; + m.try_emplace(hint, 2, 2); + EXPECT_EQ(130, m.size()); + EXPECT_LE(calls, 2); -TEST(Btree, MoveAssignmentAllocatorPropagation) { - InstanceTracker tracker; + EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); + } - int64_t bytes1 = 0, bytes2 = 0; - PropagatingCountingAlloc allocator1(&bytes1); - PropagatingCountingAlloc allocator2(&bytes2); - std::less cmp; + TEST(Btree, TryEmplaceWithBadHint) { + phmap::btree_map m = {{1, 1}, {9, 9}}; - // Test propagating allocator_type. - { - phmap::btree_set, - PropagatingCountingAlloc> - set1(cmp, allocator1), set2(cmp, allocator2); + // Bad hint (too small), should still emplace: + auto it = m.try_emplace(m.begin(), 2, 2); + EXPECT_EQ(it, ++m.begin()); + EXPECT_THAT(m, ElementsAreArray( + std::vector>{{1, 1}, {2, 2}, {9, 9}})); - for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); + // Bad hint, too large this time: + it = m.try_emplace(++(++m.begin()), 0, 0); + EXPECT_EQ(it, m.begin()); + EXPECT_THAT(m, ElementsAreArray(std::vector>{ + {0, 0}, {1, 1}, {2, 2}, {9, 9}})); + } - tracker.ResetCopiesMovesSwaps(); - set2 = std::move(set1); - EXPECT_EQ(tracker.moves(), 0); - } - // Test non-propagating allocator_type with equal allocators. - { - phmap::btree_set, - CountingAllocator> - set1(cmp, allocator1), set2(cmp, allocator1); + TEST(Btree, TryEmplaceMaintainsSortedOrder) { + phmap::btree_map m; + std::pair pair5 = {5, "five"}; - for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); + // Test both lvalue & rvalue emplace. + m.try_emplace(10, "ten"); + m.try_emplace(pair5.first, pair5.second); + EXPECT_EQ(2, m.size()); + EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); - tracker.ResetCopiesMovesSwaps(); - set2 = std::move(set1); - EXPECT_EQ(tracker.moves(), 0); - } - // Test non-propagating allocator_type with different allocators. - { - phmap::btree_set, - CountingAllocator> - set1(cmp, allocator1), set2(cmp, allocator2); + int int100{100}; + m.try_emplace(int100, "hundred"); + m.try_emplace(1, "one"); + EXPECT_EQ(4, m.size()); + EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); + } - for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); + TEST(Btree, TryEmplaceWithHintAndNoValueArgsWorks) { + phmap::btree_map m; + m.try_emplace(m.end(), 1); + EXPECT_EQ(0, m[1]); + } - tracker.ResetCopiesMovesSwaps(); - set2 = std::move(set1); - EXPECT_GE(tracker.moves(), 100); - } -} + TEST(Btree, TryEmplaceWithHintAndMultipleValueArgsWorks) { + phmap::btree_map m; + m.try_emplace(m.end(), 1, 10, 'a'); + EXPECT_EQ(std::string(10, 'a'), m[1]); + } -TEST(Btree, EmptyTree) { - phmap::btree_set s; - EXPECT_TRUE(s.empty()); - EXPECT_EQ(s.size(), 0); - EXPECT_GT(s.max_size(), 0); -} + TEST(Btree, MoveAssignmentAllocatorPropagation) { + InstanceTracker tracker; -bool IsEven(int k) { return k % 2 == 0; } + int64_t bytes1 = 0, bytes2 = 0; + PropagatingCountingAlloc allocator1(&bytes1); + PropagatingCountingAlloc allocator2(&bytes2); + std::less cmp; -TEST(Btree, EraseIf) { - // Test that erase_if works with all the container types and supports lambdas. - { - phmap::btree_set s = {1, 3, 5, 6, 100}; - erase_if(s, [](int k) { return k > 3; }); - EXPECT_THAT(s, ElementsAre(1, 3)); - } - { - phmap::btree_multiset s = {1, 3, 3, 5, 6, 6, 100}; - erase_if(s, [](int k) { return k <= 3; }); - EXPECT_THAT(s, ElementsAre(5, 6, 6, 100)); - } - { - phmap::btree_map m = {{1, 1}, {3, 3}, {6, 6}, {100, 100}}; - erase_if(m, [](std::pair kv) { return kv.first > 3; }); - EXPECT_THAT(m, ElementsAre(Pair(1, 1), Pair(3, 3))); - } - { - phmap::btree_multimap m = {{1, 1}, {3, 3}, {3, 6}, - {6, 6}, {6, 7}, {100, 6}}; - erase_if(m, [](std::pair kv) { return kv.second == 6; }); - EXPECT_THAT(m, ElementsAre(Pair(1, 1), Pair(3, 3), Pair(6, 7))); - } - // Test that erasing all elements from a large set works and test support for - // function pointers. - { - phmap::btree_set s; - for (int i = 0; i < 1000; ++i) s.insert(2 * i); - erase_if(s, IsEven); - EXPECT_THAT(s, IsEmpty()); - } - // Test that erase_if supports other format of function pointers. - { - phmap::btree_set s = {1, 3, 5, 6, 100}; - erase_if(s, &IsEven); - EXPECT_THAT(s, ElementsAre(1, 3, 5)); - } -} + // Test propagating allocator_type. + { + phmap::btree_set, + PropagatingCountingAlloc> + set1(cmp, allocator1), set2(cmp, allocator2); + + for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); + + tracker.ResetCopiesMovesSwaps(); + set2 = std::move(set1); + EXPECT_EQ(tracker.moves(), 0); + } + // Test non-propagating allocator_type with equal allocators. + { + phmap::btree_set, + CountingAllocator> + set1(cmp, allocator1), set2(cmp, allocator1); + + for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); + + tracker.ResetCopiesMovesSwaps(); + set2 = std::move(set1); + EXPECT_EQ(tracker.moves(), 0); + } + // Test non-propagating allocator_type with different allocators. + { + phmap::btree_set, + CountingAllocator> + set1(cmp, allocator1), set2(cmp, allocator2); + + for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); + + tracker.ResetCopiesMovesSwaps(); + set2 = std::move(set1); + EXPECT_GE(tracker.moves(), 100); + } + } + + TEST(Btree, EmptyTree) { + phmap::btree_set s; + EXPECT_TRUE(s.empty()); + EXPECT_EQ(s.size(), 0); + EXPECT_GT(s.max_size(), 0); + } + + bool IsEven(int k) { return k % 2 == 0; } + + TEST(Btree, EraseIf) { + // Test that erase_if works with all the container types and supports lambdas. + { + phmap::btree_set s = {1, 3, 5, 6, 100}; + erase_if(s, [](int k) { return k > 3; }); + EXPECT_THAT(s, ElementsAre(1, 3)); + } + { + phmap::btree_multiset s = {1, 3, 3, 5, 6, 6, 100}; + erase_if(s, [](int k) { return k <= 3; }); + EXPECT_THAT(s, ElementsAre(5, 6, 6, 100)); + } + { + phmap::btree_map m = {{1, 1}, {3, 3}, {6, 6}, {100, 100}}; + erase_if(m, [](std::pair kv) { return kv.first > 3; }); + EXPECT_THAT(m, ElementsAre(Pair(1, 1), Pair(3, 3))); + } + { + phmap::btree_multimap m = {{1, 1}, {3, 3}, {3, 6}, + {6, 6}, {6, 7}, {100, 6}}; + erase_if(m, [](std::pair kv) { return kv.second == 6; }); + EXPECT_THAT(m, ElementsAre(Pair(1, 1), Pair(3, 3), Pair(6, 7))); + } + // Test that erasing all elements from a large set works and test support for + // function pointers. + { + phmap::btree_set s; + for (int i = 0; i < 1000; ++i) s.insert(2 * i); + erase_if(s, IsEven); + EXPECT_THAT(s, IsEmpty()); + } + // Test that erase_if supports other format of function pointers. + { + phmap::btree_set s = {1, 3, 5, 6, 100}; + erase_if(s, &IsEven); + EXPECT_THAT(s, ElementsAre(1, 3, 5)); + } + } } // namespace } // namespace container_internal diff --git a/tests/btree_test.h b/tests/btree_test.h index e467402..4472916 100644 --- a/tests/btree_test.h +++ b/tests/btree_test.h @@ -1,3 +1,21 @@ +// --------------------------------------------------------------------------- +// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp) +// with modifications. +// // Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -11,6 +29,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// --------------------------------------------------------------------------- #ifndef PHMAP_CONTAINER_BTREE_TEST_H_ #define PHMAP_CONTAINER_BTREE_TEST_H_