Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1 | // Copyright 2018 The Abseil Authors. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "absl/container/btree_test.h" |
| 16 | |
| 17 | #include <cstdint> |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 18 | #include <limits> |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 19 | #include <map> |
| 20 | #include <memory> |
| 21 | #include <stdexcept> |
| 22 | #include <string> |
| 23 | #include <type_traits> |
| 24 | #include <utility> |
| 25 | |
| 26 | #include "gmock/gmock.h" |
| 27 | #include "gtest/gtest.h" |
| 28 | #include "absl/base/internal/raw_logging.h" |
| 29 | #include "absl/base/macros.h" |
| 30 | #include "absl/container/btree_map.h" |
| 31 | #include "absl/container/btree_set.h" |
| 32 | #include "absl/container/internal/counting_allocator.h" |
| 33 | #include "absl/container/internal/test_instance_tracker.h" |
| 34 | #include "absl/flags/flag.h" |
| 35 | #include "absl/hash/hash_testing.h" |
| 36 | #include "absl/memory/memory.h" |
| 37 | #include "absl/meta/type_traits.h" |
| 38 | #include "absl/strings/str_cat.h" |
| 39 | #include "absl/strings/str_split.h" |
| 40 | #include "absl/strings/string_view.h" |
| 41 | #include "absl/types/compare.h" |
| 42 | |
| 43 | ABSL_FLAG(int, test_values, 10000, "The number of values to use for tests"); |
| 44 | |
| 45 | namespace absl { |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 46 | ABSL_NAMESPACE_BEGIN |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 47 | namespace container_internal { |
| 48 | namespace { |
| 49 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 50 | using ::absl::test_internal::CopyableMovableInstance; |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 51 | using ::absl::test_internal::InstanceTracker; |
| 52 | using ::absl::test_internal::MovableOnlyInstance; |
| 53 | using ::testing::ElementsAre; |
| 54 | using ::testing::ElementsAreArray; |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 55 | using ::testing::IsEmpty; |
| 56 | using ::testing::IsNull; |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 57 | using ::testing::Pair; |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 58 | using ::testing::SizeIs; |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 59 | |
| 60 | template <typename T, typename U> |
| 61 | void CheckPairEquals(const T &x, const U &y) { |
| 62 | ABSL_INTERNAL_CHECK(x == y, "Values are unequal."); |
| 63 | } |
| 64 | |
| 65 | template <typename T, typename U, typename V, typename W> |
| 66 | void CheckPairEquals(const std::pair<T, U> &x, const std::pair<V, W> &y) { |
| 67 | CheckPairEquals(x.first, y.first); |
| 68 | CheckPairEquals(x.second, y.second); |
| 69 | } |
| 70 | } // namespace |
| 71 | |
| 72 | // The base class for a sorted associative container checker. TreeType is the |
| 73 | // container type to check and CheckerType is the container type to check |
| 74 | // against. TreeType is expected to be btree_{set,map,multiset,multimap} and |
| 75 | // CheckerType is expected to be {set,map,multiset,multimap}. |
| 76 | template <typename TreeType, typename CheckerType> |
| 77 | class base_checker { |
| 78 | public: |
| 79 | using key_type = typename TreeType::key_type; |
| 80 | using value_type = typename TreeType::value_type; |
| 81 | using key_compare = typename TreeType::key_compare; |
| 82 | using pointer = typename TreeType::pointer; |
| 83 | using const_pointer = typename TreeType::const_pointer; |
| 84 | using reference = typename TreeType::reference; |
| 85 | using const_reference = typename TreeType::const_reference; |
| 86 | using size_type = typename TreeType::size_type; |
| 87 | using difference_type = typename TreeType::difference_type; |
| 88 | using iterator = typename TreeType::iterator; |
| 89 | using const_iterator = typename TreeType::const_iterator; |
| 90 | using reverse_iterator = typename TreeType::reverse_iterator; |
| 91 | using const_reverse_iterator = typename TreeType::const_reverse_iterator; |
| 92 | |
| 93 | public: |
| 94 | base_checker() : const_tree_(tree_) {} |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 95 | base_checker(const base_checker &other) |
| 96 | : tree_(other.tree_), const_tree_(tree_), checker_(other.checker_) {} |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 97 | template <typename InputIterator> |
| 98 | base_checker(InputIterator b, InputIterator e) |
| 99 | : tree_(b, e), const_tree_(tree_), checker_(b, e) {} |
| 100 | |
| 101 | iterator begin() { return tree_.begin(); } |
| 102 | const_iterator begin() const { return tree_.begin(); } |
| 103 | iterator end() { return tree_.end(); } |
| 104 | const_iterator end() const { return tree_.end(); } |
| 105 | reverse_iterator rbegin() { return tree_.rbegin(); } |
| 106 | const_reverse_iterator rbegin() const { return tree_.rbegin(); } |
| 107 | reverse_iterator rend() { return tree_.rend(); } |
| 108 | const_reverse_iterator rend() const { return tree_.rend(); } |
| 109 | |
| 110 | template <typename IterType, typename CheckerIterType> |
| 111 | IterType iter_check(IterType tree_iter, CheckerIterType checker_iter) const { |
| 112 | if (tree_iter == tree_.end()) { |
| 113 | ABSL_INTERNAL_CHECK(checker_iter == checker_.end(), |
| 114 | "Checker iterator not at end."); |
| 115 | } else { |
| 116 | CheckPairEquals(*tree_iter, *checker_iter); |
| 117 | } |
| 118 | return tree_iter; |
| 119 | } |
| 120 | template <typename IterType, typename CheckerIterType> |
| 121 | IterType riter_check(IterType tree_iter, CheckerIterType checker_iter) const { |
| 122 | if (tree_iter == tree_.rend()) { |
| 123 | ABSL_INTERNAL_CHECK(checker_iter == checker_.rend(), |
| 124 | "Checker iterator not at rend."); |
| 125 | } else { |
| 126 | CheckPairEquals(*tree_iter, *checker_iter); |
| 127 | } |
| 128 | return tree_iter; |
| 129 | } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 130 | void value_check(const value_type &v) { |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 131 | typename KeyOfValue<typename TreeType::key_type, |
| 132 | typename TreeType::value_type>::type key_of_value; |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 133 | const key_type &key = key_of_value(v); |
| 134 | CheckPairEquals(*find(key), v); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 135 | lower_bound(key); |
| 136 | upper_bound(key); |
| 137 | equal_range(key); |
| 138 | contains(key); |
| 139 | count(key); |
| 140 | } |
| 141 | void erase_check(const key_type &key) { |
| 142 | EXPECT_FALSE(tree_.contains(key)); |
| 143 | EXPECT_EQ(tree_.find(key), const_tree_.end()); |
| 144 | EXPECT_FALSE(const_tree_.contains(key)); |
| 145 | EXPECT_EQ(const_tree_.find(key), tree_.end()); |
| 146 | EXPECT_EQ(tree_.equal_range(key).first, |
| 147 | const_tree_.equal_range(key).second); |
| 148 | } |
| 149 | |
| 150 | iterator lower_bound(const key_type &key) { |
| 151 | return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); |
| 152 | } |
| 153 | const_iterator lower_bound(const key_type &key) const { |
| 154 | return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); |
| 155 | } |
| 156 | iterator upper_bound(const key_type &key) { |
| 157 | return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); |
| 158 | } |
| 159 | const_iterator upper_bound(const key_type &key) const { |
| 160 | return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); |
| 161 | } |
| 162 | std::pair<iterator, iterator> equal_range(const key_type &key) { |
| 163 | std::pair<typename CheckerType::iterator, typename CheckerType::iterator> |
| 164 | checker_res = checker_.equal_range(key); |
| 165 | std::pair<iterator, iterator> tree_res = tree_.equal_range(key); |
| 166 | iter_check(tree_res.first, checker_res.first); |
| 167 | iter_check(tree_res.second, checker_res.second); |
| 168 | return tree_res; |
| 169 | } |
| 170 | std::pair<const_iterator, const_iterator> equal_range( |
| 171 | const key_type &key) const { |
| 172 | std::pair<typename CheckerType::const_iterator, |
| 173 | typename CheckerType::const_iterator> |
| 174 | checker_res = checker_.equal_range(key); |
| 175 | std::pair<const_iterator, const_iterator> tree_res = tree_.equal_range(key); |
| 176 | iter_check(tree_res.first, checker_res.first); |
| 177 | iter_check(tree_res.second, checker_res.second); |
| 178 | return tree_res; |
| 179 | } |
| 180 | iterator find(const key_type &key) { |
| 181 | return iter_check(tree_.find(key), checker_.find(key)); |
| 182 | } |
| 183 | const_iterator find(const key_type &key) const { |
| 184 | return iter_check(tree_.find(key), checker_.find(key)); |
| 185 | } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 186 | bool contains(const key_type &key) const { return find(key) != end(); } |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 187 | size_type count(const key_type &key) const { |
| 188 | size_type res = checker_.count(key); |
| 189 | EXPECT_EQ(res, tree_.count(key)); |
| 190 | return res; |
| 191 | } |
| 192 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 193 | base_checker &operator=(const base_checker &other) { |
| 194 | tree_ = other.tree_; |
| 195 | checker_ = other.checker_; |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 196 | return *this; |
| 197 | } |
| 198 | |
| 199 | int erase(const key_type &key) { |
| 200 | int size = tree_.size(); |
| 201 | int res = checker_.erase(key); |
| 202 | EXPECT_EQ(res, tree_.count(key)); |
| 203 | EXPECT_EQ(res, tree_.erase(key)); |
| 204 | EXPECT_EQ(tree_.count(key), 0); |
| 205 | EXPECT_EQ(tree_.size(), size - res); |
| 206 | erase_check(key); |
| 207 | return res; |
| 208 | } |
| 209 | iterator erase(iterator iter) { |
| 210 | key_type key = iter.key(); |
| 211 | int size = tree_.size(); |
| 212 | int count = tree_.count(key); |
| 213 | auto checker_iter = checker_.lower_bound(key); |
| 214 | for (iterator tmp(tree_.lower_bound(key)); tmp != iter; ++tmp) { |
| 215 | ++checker_iter; |
| 216 | } |
| 217 | auto checker_next = checker_iter; |
| 218 | ++checker_next; |
| 219 | checker_.erase(checker_iter); |
| 220 | iter = tree_.erase(iter); |
| 221 | EXPECT_EQ(tree_.size(), checker_.size()); |
| 222 | EXPECT_EQ(tree_.size(), size - 1); |
| 223 | EXPECT_EQ(tree_.count(key), count - 1); |
| 224 | if (count == 1) { |
| 225 | erase_check(key); |
| 226 | } |
| 227 | return iter_check(iter, checker_next); |
| 228 | } |
| 229 | |
| 230 | void erase(iterator begin, iterator end) { |
| 231 | int size = tree_.size(); |
| 232 | int count = std::distance(begin, end); |
| 233 | auto checker_begin = checker_.lower_bound(begin.key()); |
| 234 | for (iterator tmp(tree_.lower_bound(begin.key())); tmp != begin; ++tmp) { |
| 235 | ++checker_begin; |
| 236 | } |
| 237 | auto checker_end = |
| 238 | end == tree_.end() ? checker_.end() : checker_.lower_bound(end.key()); |
| 239 | if (end != tree_.end()) { |
| 240 | for (iterator tmp(tree_.lower_bound(end.key())); tmp != end; ++tmp) { |
| 241 | ++checker_end; |
| 242 | } |
| 243 | } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 244 | const auto checker_ret = checker_.erase(checker_begin, checker_end); |
| 245 | const auto tree_ret = tree_.erase(begin, end); |
| 246 | EXPECT_EQ(std::distance(checker_.begin(), checker_ret), |
| 247 | std::distance(tree_.begin(), tree_ret)); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 248 | EXPECT_EQ(tree_.size(), checker_.size()); |
| 249 | EXPECT_EQ(tree_.size(), size - count); |
| 250 | } |
| 251 | |
| 252 | void clear() { |
| 253 | tree_.clear(); |
| 254 | checker_.clear(); |
| 255 | } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 256 | void swap(base_checker &other) { |
| 257 | tree_.swap(other.tree_); |
| 258 | checker_.swap(other.checker_); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 259 | } |
| 260 | |
| 261 | void verify() const { |
| 262 | tree_.verify(); |
| 263 | EXPECT_EQ(tree_.size(), checker_.size()); |
| 264 | |
| 265 | // Move through the forward iterators using increment. |
| 266 | auto checker_iter = checker_.begin(); |
| 267 | const_iterator tree_iter(tree_.begin()); |
| 268 | for (; tree_iter != tree_.end(); ++tree_iter, ++checker_iter) { |
| 269 | CheckPairEquals(*tree_iter, *checker_iter); |
| 270 | } |
| 271 | |
| 272 | // Move through the forward iterators using decrement. |
| 273 | for (int n = tree_.size() - 1; n >= 0; --n) { |
| 274 | iter_check(tree_iter, checker_iter); |
| 275 | --tree_iter; |
| 276 | --checker_iter; |
| 277 | } |
| 278 | EXPECT_EQ(tree_iter, tree_.begin()); |
| 279 | EXPECT_EQ(checker_iter, checker_.begin()); |
| 280 | |
| 281 | // Move through the reverse iterators using increment. |
| 282 | auto checker_riter = checker_.rbegin(); |
| 283 | const_reverse_iterator tree_riter(tree_.rbegin()); |
| 284 | for (; tree_riter != tree_.rend(); ++tree_riter, ++checker_riter) { |
| 285 | CheckPairEquals(*tree_riter, *checker_riter); |
| 286 | } |
| 287 | |
| 288 | // Move through the reverse iterators using decrement. |
| 289 | for (int n = tree_.size() - 1; n >= 0; --n) { |
| 290 | riter_check(tree_riter, checker_riter); |
| 291 | --tree_riter; |
| 292 | --checker_riter; |
| 293 | } |
| 294 | EXPECT_EQ(tree_riter, tree_.rbegin()); |
| 295 | EXPECT_EQ(checker_riter, checker_.rbegin()); |
| 296 | } |
| 297 | |
| 298 | const TreeType &tree() const { return tree_; } |
| 299 | |
| 300 | size_type size() const { |
| 301 | EXPECT_EQ(tree_.size(), checker_.size()); |
| 302 | return tree_.size(); |
| 303 | } |
| 304 | size_type max_size() const { return tree_.max_size(); } |
| 305 | bool empty() const { |
| 306 | EXPECT_EQ(tree_.empty(), checker_.empty()); |
| 307 | return tree_.empty(); |
| 308 | } |
| 309 | |
| 310 | protected: |
| 311 | TreeType tree_; |
| 312 | const TreeType &const_tree_; |
| 313 | CheckerType checker_; |
| 314 | }; |
| 315 | |
| 316 | namespace { |
| 317 | // A checker for unique sorted associative containers. TreeType is expected to |
| 318 | // be btree_{set,map} and CheckerType is expected to be {set,map}. |
| 319 | template <typename TreeType, typename CheckerType> |
| 320 | class unique_checker : public base_checker<TreeType, CheckerType> { |
| 321 | using super_type = base_checker<TreeType, CheckerType>; |
| 322 | |
| 323 | public: |
| 324 | using iterator = typename super_type::iterator; |
| 325 | using value_type = typename super_type::value_type; |
| 326 | |
| 327 | public: |
| 328 | unique_checker() : super_type() {} |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 329 | unique_checker(const unique_checker &other) : super_type(other) {} |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 330 | template <class InputIterator> |
| 331 | unique_checker(InputIterator b, InputIterator e) : super_type(b, e) {} |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 332 | unique_checker &operator=(const unique_checker &) = default; |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 333 | |
| 334 | // Insertion routines. |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 335 | std::pair<iterator, bool> insert(const value_type &v) { |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 336 | int size = this->tree_.size(); |
| 337 | std::pair<typename CheckerType::iterator, bool> checker_res = |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 338 | this->checker_.insert(v); |
| 339 | std::pair<iterator, bool> tree_res = this->tree_.insert(v); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 340 | CheckPairEquals(*tree_res.first, *checker_res.first); |
| 341 | EXPECT_EQ(tree_res.second, checker_res.second); |
| 342 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); |
| 343 | EXPECT_EQ(this->tree_.size(), size + tree_res.second); |
| 344 | return tree_res; |
| 345 | } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 346 | iterator insert(iterator position, const value_type &v) { |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 347 | int size = this->tree_.size(); |
| 348 | std::pair<typename CheckerType::iterator, bool> checker_res = |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 349 | this->checker_.insert(v); |
| 350 | iterator tree_res = this->tree_.insert(position, v); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 351 | CheckPairEquals(*tree_res, *checker_res.first); |
| 352 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); |
| 353 | EXPECT_EQ(this->tree_.size(), size + checker_res.second); |
| 354 | return tree_res; |
| 355 | } |
| 356 | template <typename InputIterator> |
| 357 | void insert(InputIterator b, InputIterator e) { |
| 358 | for (; b != e; ++b) { |
| 359 | insert(*b); |
| 360 | } |
| 361 | } |
| 362 | }; |
| 363 | |
| 364 | // A checker for multiple sorted associative containers. TreeType is expected |
| 365 | // to be btree_{multiset,multimap} and CheckerType is expected to be |
| 366 | // {multiset,multimap}. |
| 367 | template <typename TreeType, typename CheckerType> |
| 368 | class multi_checker : public base_checker<TreeType, CheckerType> { |
| 369 | using super_type = base_checker<TreeType, CheckerType>; |
| 370 | |
| 371 | public: |
| 372 | using iterator = typename super_type::iterator; |
| 373 | using value_type = typename super_type::value_type; |
| 374 | |
| 375 | public: |
| 376 | multi_checker() : super_type() {} |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 377 | multi_checker(const multi_checker &other) : super_type(other) {} |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 378 | template <class InputIterator> |
| 379 | multi_checker(InputIterator b, InputIterator e) : super_type(b, e) {} |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 380 | multi_checker &operator=(const multi_checker &) = default; |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 381 | |
| 382 | // Insertion routines. |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 383 | iterator insert(const value_type &v) { |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 384 | int size = this->tree_.size(); |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 385 | auto checker_res = this->checker_.insert(v); |
| 386 | iterator tree_res = this->tree_.insert(v); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 387 | CheckPairEquals(*tree_res, *checker_res); |
| 388 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); |
| 389 | EXPECT_EQ(this->tree_.size(), size + 1); |
| 390 | return tree_res; |
| 391 | } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 392 | iterator insert(iterator position, const value_type &v) { |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 393 | int size = this->tree_.size(); |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 394 | auto checker_res = this->checker_.insert(v); |
| 395 | iterator tree_res = this->tree_.insert(position, v); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 396 | CheckPairEquals(*tree_res, *checker_res); |
| 397 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); |
| 398 | EXPECT_EQ(this->tree_.size(), size + 1); |
| 399 | return tree_res; |
| 400 | } |
| 401 | template <typename InputIterator> |
| 402 | void insert(InputIterator b, InputIterator e) { |
| 403 | for (; b != e; ++b) { |
| 404 | insert(*b); |
| 405 | } |
| 406 | } |
| 407 | }; |
| 408 | |
| 409 | template <typename T, typename V> |
| 410 | void DoTest(const char *name, T *b, const std::vector<V> &values) { |
| 411 | typename KeyOfValue<typename T::key_type, V>::type key_of_value; |
| 412 | |
| 413 | T &mutable_b = *b; |
| 414 | const T &const_b = *b; |
| 415 | |
| 416 | // Test insert. |
| 417 | for (int i = 0; i < values.size(); ++i) { |
| 418 | mutable_b.insert(values[i]); |
| 419 | mutable_b.value_check(values[i]); |
| 420 | } |
| 421 | ASSERT_EQ(mutable_b.size(), values.size()); |
| 422 | |
| 423 | const_b.verify(); |
| 424 | |
| 425 | // Test copy constructor. |
| 426 | T b_copy(const_b); |
| 427 | EXPECT_EQ(b_copy.size(), const_b.size()); |
| 428 | for (int i = 0; i < values.size(); ++i) { |
| 429 | CheckPairEquals(*b_copy.find(key_of_value(values[i])), values[i]); |
| 430 | } |
| 431 | |
| 432 | // Test range constructor. |
| 433 | T b_range(const_b.begin(), const_b.end()); |
| 434 | EXPECT_EQ(b_range.size(), const_b.size()); |
| 435 | for (int i = 0; i < values.size(); ++i) { |
| 436 | CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); |
| 437 | } |
| 438 | |
| 439 | // Test range insertion for values that already exist. |
| 440 | b_range.insert(b_copy.begin(), b_copy.end()); |
| 441 | b_range.verify(); |
| 442 | |
| 443 | // Test range insertion for new values. |
| 444 | b_range.clear(); |
| 445 | b_range.insert(b_copy.begin(), b_copy.end()); |
| 446 | EXPECT_EQ(b_range.size(), b_copy.size()); |
| 447 | for (int i = 0; i < values.size(); ++i) { |
| 448 | CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); |
| 449 | } |
| 450 | |
| 451 | // Test assignment to self. Nothing should change. |
| 452 | b_range.operator=(b_range); |
| 453 | EXPECT_EQ(b_range.size(), b_copy.size()); |
| 454 | |
| 455 | // Test assignment of new values. |
| 456 | b_range.clear(); |
| 457 | b_range = b_copy; |
| 458 | EXPECT_EQ(b_range.size(), b_copy.size()); |
| 459 | |
| 460 | // Test swap. |
| 461 | b_range.clear(); |
| 462 | b_range.swap(b_copy); |
| 463 | EXPECT_EQ(b_copy.size(), 0); |
| 464 | EXPECT_EQ(b_range.size(), const_b.size()); |
| 465 | for (int i = 0; i < values.size(); ++i) { |
| 466 | CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); |
| 467 | } |
| 468 | b_range.swap(b_copy); |
| 469 | |
| 470 | // Test non-member function swap. |
| 471 | swap(b_range, b_copy); |
| 472 | EXPECT_EQ(b_copy.size(), 0); |
| 473 | EXPECT_EQ(b_range.size(), const_b.size()); |
| 474 | for (int i = 0; i < values.size(); ++i) { |
| 475 | CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); |
| 476 | } |
| 477 | swap(b_range, b_copy); |
| 478 | |
| 479 | // Test erase via values. |
| 480 | for (int i = 0; i < values.size(); ++i) { |
| 481 | mutable_b.erase(key_of_value(values[i])); |
| 482 | // Erasing a non-existent key should have no effect. |
| 483 | ASSERT_EQ(mutable_b.erase(key_of_value(values[i])), 0); |
| 484 | } |
| 485 | |
| 486 | const_b.verify(); |
| 487 | EXPECT_EQ(const_b.size(), 0); |
| 488 | |
| 489 | // Test erase via iterators. |
| 490 | mutable_b = b_copy; |
| 491 | for (int i = 0; i < values.size(); ++i) { |
| 492 | mutable_b.erase(mutable_b.find(key_of_value(values[i]))); |
| 493 | } |
| 494 | |
| 495 | const_b.verify(); |
| 496 | EXPECT_EQ(const_b.size(), 0); |
| 497 | |
| 498 | // Test insert with hint. |
| 499 | for (int i = 0; i < values.size(); i++) { |
| 500 | mutable_b.insert(mutable_b.upper_bound(key_of_value(values[i])), values[i]); |
| 501 | } |
| 502 | |
| 503 | const_b.verify(); |
| 504 | |
| 505 | // Test range erase. |
| 506 | mutable_b.erase(mutable_b.begin(), mutable_b.end()); |
| 507 | EXPECT_EQ(mutable_b.size(), 0); |
| 508 | const_b.verify(); |
| 509 | |
| 510 | // First half. |
| 511 | mutable_b = b_copy; |
| 512 | typename T::iterator mutable_iter_end = mutable_b.begin(); |
| 513 | for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end; |
| 514 | mutable_b.erase(mutable_b.begin(), mutable_iter_end); |
| 515 | EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2); |
| 516 | const_b.verify(); |
| 517 | |
| 518 | // Second half. |
| 519 | mutable_b = b_copy; |
| 520 | typename T::iterator mutable_iter_begin = mutable_b.begin(); |
| 521 | for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin; |
| 522 | mutable_b.erase(mutable_iter_begin, mutable_b.end()); |
| 523 | EXPECT_EQ(mutable_b.size(), values.size() / 2); |
| 524 | const_b.verify(); |
| 525 | |
| 526 | // Second quarter. |
| 527 | mutable_b = b_copy; |
| 528 | mutable_iter_begin = mutable_b.begin(); |
| 529 | for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_begin; |
| 530 | mutable_iter_end = mutable_iter_begin; |
| 531 | for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end; |
| 532 | mutable_b.erase(mutable_iter_begin, mutable_iter_end); |
| 533 | EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4); |
| 534 | const_b.verify(); |
| 535 | |
| 536 | mutable_b.clear(); |
| 537 | } |
| 538 | |
| 539 | template <typename T> |
| 540 | void ConstTest() { |
| 541 | using value_type = typename T::value_type; |
| 542 | typename KeyOfValue<typename T::key_type, value_type>::type key_of_value; |
| 543 | |
| 544 | T mutable_b; |
| 545 | const T &const_b = mutable_b; |
| 546 | |
| 547 | // Insert a single value into the container and test looking it up. |
| 548 | value_type value = Generator<value_type>(2)(2); |
| 549 | mutable_b.insert(value); |
| 550 | EXPECT_TRUE(mutable_b.contains(key_of_value(value))); |
| 551 | EXPECT_NE(mutable_b.find(key_of_value(value)), const_b.end()); |
| 552 | EXPECT_TRUE(const_b.contains(key_of_value(value))); |
| 553 | EXPECT_NE(const_b.find(key_of_value(value)), mutable_b.end()); |
| 554 | EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value); |
| 555 | EXPECT_EQ(const_b.upper_bound(key_of_value(value)), const_b.end()); |
| 556 | EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value); |
| 557 | |
| 558 | // We can only create a non-const iterator from a non-const container. |
| 559 | typename T::iterator mutable_iter(mutable_b.begin()); |
| 560 | EXPECT_EQ(mutable_iter, const_b.begin()); |
| 561 | EXPECT_NE(mutable_iter, const_b.end()); |
| 562 | EXPECT_EQ(const_b.begin(), mutable_iter); |
| 563 | EXPECT_NE(const_b.end(), mutable_iter); |
| 564 | typename T::reverse_iterator mutable_riter(mutable_b.rbegin()); |
| 565 | EXPECT_EQ(mutable_riter, const_b.rbegin()); |
| 566 | EXPECT_NE(mutable_riter, const_b.rend()); |
| 567 | EXPECT_EQ(const_b.rbegin(), mutable_riter); |
| 568 | EXPECT_NE(const_b.rend(), mutable_riter); |
| 569 | |
| 570 | // We can create a const iterator from a non-const iterator. |
| 571 | typename T::const_iterator const_iter(mutable_iter); |
| 572 | EXPECT_EQ(const_iter, mutable_b.begin()); |
| 573 | EXPECT_NE(const_iter, mutable_b.end()); |
| 574 | EXPECT_EQ(mutable_b.begin(), const_iter); |
| 575 | EXPECT_NE(mutable_b.end(), const_iter); |
| 576 | typename T::const_reverse_iterator const_riter(mutable_riter); |
| 577 | EXPECT_EQ(const_riter, mutable_b.rbegin()); |
| 578 | EXPECT_NE(const_riter, mutable_b.rend()); |
| 579 | EXPECT_EQ(mutable_b.rbegin(), const_riter); |
| 580 | EXPECT_NE(mutable_b.rend(), const_riter); |
| 581 | |
| 582 | // Make sure various methods can be invoked on a const container. |
| 583 | const_b.verify(); |
| 584 | ASSERT_TRUE(!const_b.empty()); |
| 585 | EXPECT_EQ(const_b.size(), 1); |
| 586 | EXPECT_GT(const_b.max_size(), 0); |
| 587 | EXPECT_TRUE(const_b.contains(key_of_value(value))); |
| 588 | EXPECT_EQ(const_b.count(key_of_value(value)), 1); |
| 589 | } |
| 590 | |
| 591 | template <typename T, typename C> |
| 592 | void BtreeTest() { |
| 593 | ConstTest<T>(); |
| 594 | |
| 595 | using V = typename remove_pair_const<typename T::value_type>::type; |
| 596 | const std::vector<V> random_values = GenerateValuesWithSeed<V>( |
| 597 | absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), |
| 598 | testing::GTEST_FLAG(random_seed)); |
| 599 | |
| 600 | unique_checker<T, C> container; |
| 601 | |
| 602 | // Test key insertion/deletion in sorted order. |
| 603 | std::vector<V> sorted_values(random_values); |
| 604 | std::sort(sorted_values.begin(), sorted_values.end()); |
| 605 | DoTest("sorted: ", &container, sorted_values); |
| 606 | |
| 607 | // Test key insertion/deletion in reverse sorted order. |
| 608 | std::reverse(sorted_values.begin(), sorted_values.end()); |
| 609 | DoTest("rsorted: ", &container, sorted_values); |
| 610 | |
| 611 | // Test key insertion/deletion in random order. |
| 612 | DoTest("random: ", &container, random_values); |
| 613 | } |
| 614 | |
| 615 | template <typename T, typename C> |
| 616 | void BtreeMultiTest() { |
| 617 | ConstTest<T>(); |
| 618 | |
| 619 | using V = typename remove_pair_const<typename T::value_type>::type; |
| 620 | const std::vector<V> random_values = GenerateValuesWithSeed<V>( |
| 621 | absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), |
| 622 | testing::GTEST_FLAG(random_seed)); |
| 623 | |
| 624 | multi_checker<T, C> container; |
| 625 | |
| 626 | // Test keys in sorted order. |
| 627 | std::vector<V> sorted_values(random_values); |
| 628 | std::sort(sorted_values.begin(), sorted_values.end()); |
| 629 | DoTest("sorted: ", &container, sorted_values); |
| 630 | |
| 631 | // Test keys in reverse sorted order. |
| 632 | std::reverse(sorted_values.begin(), sorted_values.end()); |
| 633 | DoTest("rsorted: ", &container, sorted_values); |
| 634 | |
| 635 | // Test keys in random order. |
| 636 | DoTest("random: ", &container, random_values); |
| 637 | |
| 638 | // Test keys in random order w/ duplicates. |
| 639 | std::vector<V> duplicate_values(random_values); |
| 640 | duplicate_values.insert(duplicate_values.end(), random_values.begin(), |
| 641 | random_values.end()); |
| 642 | DoTest("duplicates:", &container, duplicate_values); |
| 643 | |
| 644 | // Test all identical keys. |
| 645 | std::vector<V> identical_values(100); |
| 646 | std::fill(identical_values.begin(), identical_values.end(), |
| 647 | Generator<V>(2)(2)); |
| 648 | DoTest("identical: ", &container, identical_values); |
| 649 | } |
| 650 | |
| 651 | template <typename T> |
| 652 | struct PropagatingCountingAlloc : public CountingAllocator<T> { |
| 653 | using propagate_on_container_copy_assignment = std::true_type; |
| 654 | using propagate_on_container_move_assignment = std::true_type; |
| 655 | using propagate_on_container_swap = std::true_type; |
| 656 | |
| 657 | using Base = CountingAllocator<T>; |
| 658 | using Base::Base; |
| 659 | |
| 660 | template <typename U> |
| 661 | explicit PropagatingCountingAlloc(const PropagatingCountingAlloc<U> &other) |
| 662 | : Base(other.bytes_used_) {} |
| 663 | |
| 664 | template <typename U> |
| 665 | struct rebind { |
| 666 | using other = PropagatingCountingAlloc<U>; |
| 667 | }; |
| 668 | }; |
| 669 | |
| 670 | template <typename T> |
| 671 | void BtreeAllocatorTest() { |
| 672 | using value_type = typename T::value_type; |
| 673 | |
| 674 | int64_t bytes1 = 0, bytes2 = 0; |
| 675 | PropagatingCountingAlloc<T> allocator1(&bytes1); |
| 676 | PropagatingCountingAlloc<T> allocator2(&bytes2); |
| 677 | Generator<value_type> generator(1000); |
| 678 | |
| 679 | // Test that we allocate properly aligned memory. If we don't, then Layout |
| 680 | // will assert fail. |
| 681 | auto unused1 = allocator1.allocate(1); |
| 682 | auto unused2 = allocator2.allocate(1); |
| 683 | |
| 684 | // Test copy assignment |
| 685 | { |
| 686 | T b1(typename T::key_compare(), allocator1); |
| 687 | T b2(typename T::key_compare(), allocator2); |
| 688 | |
| 689 | int64_t original_bytes1 = bytes1; |
| 690 | b1.insert(generator(0)); |
| 691 | EXPECT_GT(bytes1, original_bytes1); |
| 692 | |
| 693 | // This should propagate the allocator. |
| 694 | b1 = b2; |
| 695 | EXPECT_EQ(b1.size(), 0); |
| 696 | EXPECT_EQ(b2.size(), 0); |
| 697 | EXPECT_EQ(bytes1, original_bytes1); |
| 698 | |
| 699 | for (int i = 1; i < 1000; i++) { |
| 700 | b1.insert(generator(i)); |
| 701 | } |
| 702 | |
| 703 | // We should have allocated out of allocator2. |
| 704 | EXPECT_GT(bytes2, bytes1); |
| 705 | } |
| 706 | |
| 707 | // Test move assignment |
| 708 | { |
| 709 | T b1(typename T::key_compare(), allocator1); |
| 710 | T b2(typename T::key_compare(), allocator2); |
| 711 | |
| 712 | int64_t original_bytes1 = bytes1; |
| 713 | b1.insert(generator(0)); |
| 714 | EXPECT_GT(bytes1, original_bytes1); |
| 715 | |
| 716 | // This should propagate the allocator. |
| 717 | b1 = std::move(b2); |
| 718 | EXPECT_EQ(b1.size(), 0); |
| 719 | EXPECT_EQ(bytes1, original_bytes1); |
| 720 | |
| 721 | for (int i = 1; i < 1000; i++) { |
| 722 | b1.insert(generator(i)); |
| 723 | } |
| 724 | |
| 725 | // We should have allocated out of allocator2. |
| 726 | EXPECT_GT(bytes2, bytes1); |
| 727 | } |
| 728 | |
| 729 | // Test swap |
| 730 | { |
| 731 | T b1(typename T::key_compare(), allocator1); |
| 732 | T b2(typename T::key_compare(), allocator2); |
| 733 | |
| 734 | int64_t original_bytes1 = bytes1; |
| 735 | b1.insert(generator(0)); |
| 736 | EXPECT_GT(bytes1, original_bytes1); |
| 737 | |
| 738 | // This should swap the allocators. |
| 739 | swap(b1, b2); |
| 740 | EXPECT_EQ(b1.size(), 0); |
| 741 | EXPECT_EQ(b2.size(), 1); |
| 742 | EXPECT_GT(bytes1, original_bytes1); |
| 743 | |
| 744 | for (int i = 1; i < 1000; i++) { |
| 745 | b1.insert(generator(i)); |
| 746 | } |
| 747 | |
| 748 | // We should have allocated out of allocator2. |
| 749 | EXPECT_GT(bytes2, bytes1); |
| 750 | } |
| 751 | |
| 752 | allocator1.deallocate(unused1, 1); |
| 753 | allocator2.deallocate(unused2, 1); |
| 754 | } |
| 755 | |
| 756 | template <typename T> |
| 757 | void BtreeMapTest() { |
| 758 | using value_type = typename T::value_type; |
| 759 | using mapped_type = typename T::mapped_type; |
| 760 | |
| 761 | mapped_type m = Generator<mapped_type>(0)(0); |
| 762 | (void)m; |
| 763 | |
| 764 | T b; |
| 765 | |
| 766 | // Verify we can insert using operator[]. |
| 767 | for (int i = 0; i < 1000; i++) { |
| 768 | value_type v = Generator<value_type>(1000)(i); |
| 769 | b[v.first] = v.second; |
| 770 | } |
| 771 | EXPECT_EQ(b.size(), 1000); |
| 772 | |
| 773 | // Test whether we can use the "->" operator on iterators and |
| 774 | // reverse_iterators. This stresses the btree_map_params::pair_pointer |
| 775 | // mechanism. |
| 776 | EXPECT_EQ(b.begin()->first, Generator<value_type>(1000)(0).first); |
| 777 | EXPECT_EQ(b.begin()->second, Generator<value_type>(1000)(0).second); |
| 778 | EXPECT_EQ(b.rbegin()->first, Generator<value_type>(1000)(999).first); |
| 779 | EXPECT_EQ(b.rbegin()->second, Generator<value_type>(1000)(999).second); |
| 780 | } |
| 781 | |
| 782 | template <typename T> |
| 783 | void BtreeMultiMapTest() { |
| 784 | using mapped_type = typename T::mapped_type; |
| 785 | mapped_type m = Generator<mapped_type>(0)(0); |
| 786 | (void)m; |
| 787 | } |
| 788 | |
| 789 | template <typename K, int N = 256> |
| 790 | void SetTest() { |
| 791 | EXPECT_EQ( |
| 792 | sizeof(absl::btree_set<K>), |
| 793 | 2 * sizeof(void *) + sizeof(typename absl::btree_set<K>::size_type)); |
| 794 | using BtreeSet = absl::btree_set<K>; |
| 795 | using CountingBtreeSet = |
| 796 | absl::btree_set<K, std::less<K>, PropagatingCountingAlloc<K>>; |
| 797 | BtreeTest<BtreeSet, std::set<K>>(); |
| 798 | BtreeAllocatorTest<CountingBtreeSet>(); |
| 799 | } |
| 800 | |
| 801 | template <typename K, int N = 256> |
| 802 | void MapTest() { |
| 803 | EXPECT_EQ( |
| 804 | sizeof(absl::btree_map<K, K>), |
| 805 | 2 * sizeof(void *) + sizeof(typename absl::btree_map<K, K>::size_type)); |
| 806 | using BtreeMap = absl::btree_map<K, K>; |
| 807 | using CountingBtreeMap = |
| 808 | absl::btree_map<K, K, std::less<K>, |
| 809 | PropagatingCountingAlloc<std::pair<const K, K>>>; |
| 810 | BtreeTest<BtreeMap, std::map<K, K>>(); |
| 811 | BtreeAllocatorTest<CountingBtreeMap>(); |
| 812 | BtreeMapTest<BtreeMap>(); |
| 813 | } |
| 814 | |
| 815 | TEST(Btree, set_int32) { SetTest<int32_t>(); } |
| 816 | TEST(Btree, set_int64) { SetTest<int64_t>(); } |
| 817 | TEST(Btree, set_string) { SetTest<std::string>(); } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 818 | TEST(Btree, set_cord) { SetTest<absl::Cord>(); } |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 819 | TEST(Btree, set_pair) { SetTest<std::pair<int, int>>(); } |
| 820 | TEST(Btree, map_int32) { MapTest<int32_t>(); } |
| 821 | TEST(Btree, map_int64) { MapTest<int64_t>(); } |
| 822 | TEST(Btree, map_string) { MapTest<std::string>(); } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 823 | TEST(Btree, map_cord) { MapTest<absl::Cord>(); } |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 824 | TEST(Btree, map_pair) { MapTest<std::pair<int, int>>(); } |
| 825 | |
| 826 | template <typename K, int N = 256> |
| 827 | void MultiSetTest() { |
| 828 | EXPECT_EQ( |
| 829 | sizeof(absl::btree_multiset<K>), |
| 830 | 2 * sizeof(void *) + sizeof(typename absl::btree_multiset<K>::size_type)); |
| 831 | using BtreeMSet = absl::btree_multiset<K>; |
| 832 | using CountingBtreeMSet = |
| 833 | absl::btree_multiset<K, std::less<K>, PropagatingCountingAlloc<K>>; |
| 834 | BtreeMultiTest<BtreeMSet, std::multiset<K>>(); |
| 835 | BtreeAllocatorTest<CountingBtreeMSet>(); |
| 836 | } |
| 837 | |
| 838 | template <typename K, int N = 256> |
| 839 | void MultiMapTest() { |
| 840 | EXPECT_EQ(sizeof(absl::btree_multimap<K, K>), |
| 841 | 2 * sizeof(void *) + |
| 842 | sizeof(typename absl::btree_multimap<K, K>::size_type)); |
| 843 | using BtreeMMap = absl::btree_multimap<K, K>; |
| 844 | using CountingBtreeMMap = |
| 845 | absl::btree_multimap<K, K, std::less<K>, |
| 846 | PropagatingCountingAlloc<std::pair<const K, K>>>; |
| 847 | BtreeMultiTest<BtreeMMap, std::multimap<K, K>>(); |
| 848 | BtreeMultiMapTest<BtreeMMap>(); |
| 849 | BtreeAllocatorTest<CountingBtreeMMap>(); |
| 850 | } |
| 851 | |
| 852 | TEST(Btree, multiset_int32) { MultiSetTest<int32_t>(); } |
| 853 | TEST(Btree, multiset_int64) { MultiSetTest<int64_t>(); } |
| 854 | TEST(Btree, multiset_string) { MultiSetTest<std::string>(); } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 855 | TEST(Btree, multiset_cord) { MultiSetTest<absl::Cord>(); } |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 856 | TEST(Btree, multiset_pair) { MultiSetTest<std::pair<int, int>>(); } |
| 857 | TEST(Btree, multimap_int32) { MultiMapTest<int32_t>(); } |
| 858 | TEST(Btree, multimap_int64) { MultiMapTest<int64_t>(); } |
| 859 | TEST(Btree, multimap_string) { MultiMapTest<std::string>(); } |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 860 | TEST(Btree, multimap_cord) { MultiMapTest<absl::Cord>(); } |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 861 | TEST(Btree, multimap_pair) { MultiMapTest<std::pair<int, int>>(); } |
| 862 | |
| 863 | struct CompareIntToString { |
| 864 | bool operator()(const std::string &a, const std::string &b) const { |
| 865 | return a < b; |
| 866 | } |
| 867 | bool operator()(const std::string &a, int b) const { |
| 868 | return a < absl::StrCat(b); |
| 869 | } |
| 870 | bool operator()(int a, const std::string &b) const { |
| 871 | return absl::StrCat(a) < b; |
| 872 | } |
| 873 | using is_transparent = void; |
| 874 | }; |
| 875 | |
| 876 | struct NonTransparentCompare { |
| 877 | template <typename T, typename U> |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 878 | bool operator()(const T &t, const U &u) const { |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 879 | // Treating all comparators as transparent can cause inefficiencies (see |
| 880 | // N3657 C++ proposal). Test that for comparators without 'is_transparent' |
| 881 | // alias (like this one), we do not attempt heterogeneous lookup. |
| 882 | EXPECT_TRUE((std::is_same<T, U>())); |
| 883 | return t < u; |
| 884 | } |
| 885 | }; |
| 886 | |
| 887 | template <typename T> |
| 888 | bool CanEraseWithEmptyBrace(T t, decltype(t.erase({})) *) { |
| 889 | return true; |
| 890 | } |
| 891 | |
| 892 | template <typename T> |
| 893 | bool CanEraseWithEmptyBrace(T, ...) { |
| 894 | return false; |
| 895 | } |
| 896 | |
| 897 | template <typename T> |
| 898 | void TestHeterogeneous(T table) { |
| 899 | auto lb = table.lower_bound("3"); |
| 900 | EXPECT_EQ(lb, table.lower_bound(3)); |
| 901 | EXPECT_NE(lb, table.lower_bound(4)); |
| 902 | EXPECT_EQ(lb, table.lower_bound({"3"})); |
| 903 | EXPECT_NE(lb, table.lower_bound({})); |
| 904 | |
| 905 | auto ub = table.upper_bound("3"); |
| 906 | EXPECT_EQ(ub, table.upper_bound(3)); |
| 907 | EXPECT_NE(ub, table.upper_bound(5)); |
| 908 | EXPECT_EQ(ub, table.upper_bound({"3"})); |
| 909 | EXPECT_NE(ub, table.upper_bound({})); |
| 910 | |
| 911 | auto er = table.equal_range("3"); |
| 912 | EXPECT_EQ(er, table.equal_range(3)); |
| 913 | EXPECT_NE(er, table.equal_range(4)); |
| 914 | EXPECT_EQ(er, table.equal_range({"3"})); |
| 915 | EXPECT_NE(er, table.equal_range({})); |
| 916 | |
| 917 | auto it = table.find("3"); |
| 918 | EXPECT_EQ(it, table.find(3)); |
| 919 | EXPECT_NE(it, table.find(4)); |
| 920 | EXPECT_EQ(it, table.find({"3"})); |
| 921 | EXPECT_NE(it, table.find({})); |
| 922 | |
| 923 | EXPECT_TRUE(table.contains(3)); |
| 924 | EXPECT_FALSE(table.contains(4)); |
| 925 | EXPECT_TRUE(table.count({"3"})); |
| 926 | EXPECT_FALSE(table.contains({})); |
| 927 | |
| 928 | EXPECT_EQ(1, table.count(3)); |
| 929 | EXPECT_EQ(0, table.count(4)); |
| 930 | EXPECT_EQ(1, table.count({"3"})); |
| 931 | EXPECT_EQ(0, table.count({})); |
| 932 | |
| 933 | auto copy = table; |
| 934 | copy.erase(3); |
| 935 | EXPECT_EQ(table.size() - 1, copy.size()); |
| 936 | copy.erase(4); |
| 937 | EXPECT_EQ(table.size() - 1, copy.size()); |
| 938 | copy.erase({"5"}); |
| 939 | EXPECT_EQ(table.size() - 2, copy.size()); |
| 940 | EXPECT_FALSE(CanEraseWithEmptyBrace(table, nullptr)); |
| 941 | |
| 942 | // Also run it with const T&. |
| 943 | if (std::is_class<T>()) TestHeterogeneous<const T &>(table); |
| 944 | } |
| 945 | |
| 946 | TEST(Btree, HeterogeneousLookup) { |
| 947 | TestHeterogeneous(btree_set<std::string, CompareIntToString>{"1", "3", "5"}); |
| 948 | TestHeterogeneous(btree_map<std::string, int, CompareIntToString>{ |
| 949 | {"1", 1}, {"3", 3}, {"5", 5}}); |
| 950 | TestHeterogeneous( |
| 951 | btree_multiset<std::string, CompareIntToString>{"1", "3", "5"}); |
| 952 | TestHeterogeneous(btree_multimap<std::string, int, CompareIntToString>{ |
| 953 | {"1", 1}, {"3", 3}, {"5", 5}}); |
| 954 | |
| 955 | // Only maps have .at() |
| 956 | btree_map<std::string, int, CompareIntToString> map{ |
| 957 | {"", -1}, {"1", 1}, {"3", 3}, {"5", 5}}; |
| 958 | EXPECT_EQ(1, map.at(1)); |
| 959 | EXPECT_EQ(3, map.at({"3"})); |
| 960 | EXPECT_EQ(-1, map.at({})); |
| 961 | const auto &cmap = map; |
| 962 | EXPECT_EQ(1, cmap.at(1)); |
| 963 | EXPECT_EQ(3, cmap.at({"3"})); |
| 964 | EXPECT_EQ(-1, cmap.at({})); |
| 965 | } |
| 966 | |
| 967 | TEST(Btree, NoHeterogeneousLookupWithoutAlias) { |
| 968 | using StringSet = absl::btree_set<std::string, NonTransparentCompare>; |
| 969 | StringSet s; |
| 970 | ASSERT_TRUE(s.insert("hello").second); |
| 971 | ASSERT_TRUE(s.insert("world").second); |
| 972 | EXPECT_TRUE(s.end() == s.find("blah")); |
| 973 | EXPECT_TRUE(s.begin() == s.lower_bound("hello")); |
| 974 | EXPECT_EQ(1, s.count("world")); |
| 975 | EXPECT_TRUE(s.contains("hello")); |
| 976 | EXPECT_TRUE(s.contains("world")); |
| 977 | EXPECT_FALSE(s.contains("blah")); |
| 978 | |
| 979 | using StringMultiSet = |
| 980 | absl::btree_multiset<std::string, NonTransparentCompare>; |
| 981 | StringMultiSet ms; |
| 982 | ms.insert("hello"); |
| 983 | ms.insert("world"); |
| 984 | ms.insert("world"); |
| 985 | EXPECT_TRUE(ms.end() == ms.find("blah")); |
| 986 | EXPECT_TRUE(ms.begin() == ms.lower_bound("hello")); |
| 987 | EXPECT_EQ(2, ms.count("world")); |
| 988 | EXPECT_TRUE(ms.contains("hello")); |
| 989 | EXPECT_TRUE(ms.contains("world")); |
| 990 | EXPECT_FALSE(ms.contains("blah")); |
| 991 | } |
| 992 | |
| 993 | TEST(Btree, DefaultTransparent) { |
| 994 | { |
| 995 | // `int` does not have a default transparent comparator. |
| 996 | // The input value is converted to key_type. |
| 997 | btree_set<int> s = {1}; |
| 998 | double d = 1.1; |
| 999 | EXPECT_EQ(s.begin(), s.find(d)); |
| 1000 | EXPECT_TRUE(s.contains(d)); |
| 1001 | } |
| 1002 | |
| 1003 | { |
| 1004 | // `std::string` has heterogeneous support. |
| 1005 | btree_set<std::string> s = {"A"}; |
| 1006 | EXPECT_EQ(s.begin(), s.find(absl::string_view("A"))); |
| 1007 | EXPECT_TRUE(s.contains(absl::string_view("A"))); |
| 1008 | } |
| 1009 | } |
| 1010 | |
| 1011 | class StringLike { |
| 1012 | public: |
| 1013 | StringLike() = default; |
| 1014 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1015 | StringLike(const char *s) : s_(s) { // NOLINT |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1016 | ++constructor_calls_; |
| 1017 | } |
| 1018 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1019 | bool operator<(const StringLike &a) const { return s_ < a.s_; } |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1020 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1021 | static void clear_constructor_call_count() { constructor_calls_ = 0; } |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1022 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1023 | static int constructor_calls() { return constructor_calls_; } |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1024 | |
| 1025 | private: |
| 1026 | static int constructor_calls_; |
| 1027 | std::string s_; |
| 1028 | }; |
| 1029 | |
| 1030 | int StringLike::constructor_calls_ = 0; |
| 1031 | |
| 1032 | TEST(Btree, HeterogeneousLookupDoesntDegradePerformance) { |
| 1033 | using StringSet = absl::btree_set<StringLike>; |
| 1034 | StringSet s; |
| 1035 | for (int i = 0; i < 100; ++i) { |
| 1036 | ASSERT_TRUE(s.insert(absl::StrCat(i).c_str()).second); |
| 1037 | } |
| 1038 | StringLike::clear_constructor_call_count(); |
| 1039 | s.find("50"); |
| 1040 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1041 | |
| 1042 | StringLike::clear_constructor_call_count(); |
| 1043 | s.contains("50"); |
| 1044 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1045 | |
| 1046 | StringLike::clear_constructor_call_count(); |
| 1047 | s.count("50"); |
| 1048 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1049 | |
| 1050 | StringLike::clear_constructor_call_count(); |
| 1051 | s.lower_bound("50"); |
| 1052 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1053 | |
| 1054 | StringLike::clear_constructor_call_count(); |
| 1055 | s.upper_bound("50"); |
| 1056 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1057 | |
| 1058 | StringLike::clear_constructor_call_count(); |
| 1059 | s.equal_range("50"); |
| 1060 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1061 | |
| 1062 | StringLike::clear_constructor_call_count(); |
| 1063 | s.erase("50"); |
| 1064 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1065 | } |
| 1066 | |
| 1067 | // Verify that swapping btrees swaps the key comparison functors and that we can |
| 1068 | // use non-default constructible comparators. |
| 1069 | struct SubstringLess { |
| 1070 | SubstringLess() = delete; |
| 1071 | explicit SubstringLess(int length) : n(length) {} |
| 1072 | bool operator()(const std::string &a, const std::string &b) const { |
| 1073 | return absl::string_view(a).substr(0, n) < |
| 1074 | absl::string_view(b).substr(0, n); |
| 1075 | } |
| 1076 | int n; |
| 1077 | }; |
| 1078 | |
| 1079 | TEST(Btree, SwapKeyCompare) { |
| 1080 | using SubstringSet = absl::btree_set<std::string, SubstringLess>; |
| 1081 | SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type()); |
| 1082 | SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type()); |
| 1083 | |
| 1084 | ASSERT_TRUE(s1.insert("a").second); |
| 1085 | ASSERT_FALSE(s1.insert("aa").second); |
| 1086 | |
| 1087 | ASSERT_TRUE(s2.insert("a").second); |
| 1088 | ASSERT_TRUE(s2.insert("aa").second); |
| 1089 | ASSERT_FALSE(s2.insert("aaa").second); |
| 1090 | |
| 1091 | swap(s1, s2); |
| 1092 | |
| 1093 | ASSERT_TRUE(s1.insert("b").second); |
| 1094 | ASSERT_TRUE(s1.insert("bb").second); |
| 1095 | ASSERT_FALSE(s1.insert("bbb").second); |
| 1096 | |
| 1097 | ASSERT_TRUE(s2.insert("b").second); |
| 1098 | ASSERT_FALSE(s2.insert("bb").second); |
| 1099 | } |
| 1100 | |
| 1101 | TEST(Btree, UpperBoundRegression) { |
| 1102 | // Regress a bug where upper_bound would default-construct a new key_compare |
| 1103 | // instead of copying the existing one. |
| 1104 | using SubstringSet = absl::btree_set<std::string, SubstringLess>; |
| 1105 | SubstringSet my_set(SubstringLess(3)); |
| 1106 | my_set.insert("aab"); |
| 1107 | my_set.insert("abb"); |
| 1108 | // We call upper_bound("aaa"). If this correctly uses the length 3 |
| 1109 | // comparator, aaa < aab < abb, so we should get aab as the result. |
| 1110 | // If it instead uses the default-constructed length 2 comparator, |
| 1111 | // aa == aa < ab, so we'll get abb as our result. |
| 1112 | SubstringSet::iterator it = my_set.upper_bound("aaa"); |
| 1113 | ASSERT_TRUE(it != my_set.end()); |
| 1114 | EXPECT_EQ("aab", *it); |
| 1115 | } |
| 1116 | |
| 1117 | TEST(Btree, Comparison) { |
| 1118 | const int kSetSize = 1201; |
| 1119 | absl::btree_set<int64_t> my_set; |
| 1120 | for (int i = 0; i < kSetSize; ++i) { |
| 1121 | my_set.insert(i); |
| 1122 | } |
| 1123 | absl::btree_set<int64_t> my_set_copy(my_set); |
| 1124 | EXPECT_TRUE(my_set_copy == my_set); |
| 1125 | EXPECT_TRUE(my_set == my_set_copy); |
| 1126 | EXPECT_FALSE(my_set_copy != my_set); |
| 1127 | EXPECT_FALSE(my_set != my_set_copy); |
| 1128 | |
| 1129 | my_set.insert(kSetSize); |
| 1130 | EXPECT_FALSE(my_set_copy == my_set); |
| 1131 | EXPECT_FALSE(my_set == my_set_copy); |
| 1132 | EXPECT_TRUE(my_set_copy != my_set); |
| 1133 | EXPECT_TRUE(my_set != my_set_copy); |
| 1134 | |
| 1135 | my_set.erase(kSetSize - 1); |
| 1136 | EXPECT_FALSE(my_set_copy == my_set); |
| 1137 | EXPECT_FALSE(my_set == my_set_copy); |
| 1138 | EXPECT_TRUE(my_set_copy != my_set); |
| 1139 | EXPECT_TRUE(my_set != my_set_copy); |
| 1140 | |
| 1141 | absl::btree_map<std::string, int64_t> my_map; |
| 1142 | for (int i = 0; i < kSetSize; ++i) { |
| 1143 | my_map[std::string(i, 'a')] = i; |
| 1144 | } |
| 1145 | absl::btree_map<std::string, int64_t> my_map_copy(my_map); |
| 1146 | EXPECT_TRUE(my_map_copy == my_map); |
| 1147 | EXPECT_TRUE(my_map == my_map_copy); |
| 1148 | EXPECT_FALSE(my_map_copy != my_map); |
| 1149 | EXPECT_FALSE(my_map != my_map_copy); |
| 1150 | |
| 1151 | ++my_map_copy[std::string(7, 'a')]; |
| 1152 | EXPECT_FALSE(my_map_copy == my_map); |
| 1153 | EXPECT_FALSE(my_map == my_map_copy); |
| 1154 | EXPECT_TRUE(my_map_copy != my_map); |
| 1155 | EXPECT_TRUE(my_map != my_map_copy); |
| 1156 | |
| 1157 | my_map_copy = my_map; |
| 1158 | my_map["hello"] = kSetSize; |
| 1159 | EXPECT_FALSE(my_map_copy == my_map); |
| 1160 | EXPECT_FALSE(my_map == my_map_copy); |
| 1161 | EXPECT_TRUE(my_map_copy != my_map); |
| 1162 | EXPECT_TRUE(my_map != my_map_copy); |
| 1163 | |
| 1164 | my_map.erase(std::string(kSetSize - 1, 'a')); |
| 1165 | EXPECT_FALSE(my_map_copy == my_map); |
| 1166 | EXPECT_FALSE(my_map == my_map_copy); |
| 1167 | EXPECT_TRUE(my_map_copy != my_map); |
| 1168 | EXPECT_TRUE(my_map != my_map_copy); |
| 1169 | } |
| 1170 | |
| 1171 | TEST(Btree, RangeCtorSanity) { |
| 1172 | std::vector<int> ivec; |
| 1173 | ivec.push_back(1); |
| 1174 | std::map<int, int> imap; |
| 1175 | imap.insert(std::make_pair(1, 2)); |
| 1176 | absl::btree_multiset<int> tmset(ivec.begin(), ivec.end()); |
| 1177 | absl::btree_multimap<int, int> tmmap(imap.begin(), imap.end()); |
| 1178 | absl::btree_set<int> tset(ivec.begin(), ivec.end()); |
| 1179 | absl::btree_map<int, int> tmap(imap.begin(), imap.end()); |
| 1180 | EXPECT_EQ(1, tmset.size()); |
| 1181 | EXPECT_EQ(1, tmmap.size()); |
| 1182 | EXPECT_EQ(1, tset.size()); |
| 1183 | EXPECT_EQ(1, tmap.size()); |
| 1184 | } |
| 1185 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1186 | } // namespace |
| 1187 | |
| 1188 | class BtreeNodePeer { |
| 1189 | public: |
| 1190 | // Yields the size of a leaf node with a specific number of values. |
| 1191 | template <typename ValueType> |
| 1192 | constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) { |
| 1193 | return btree_node< |
| 1194 | set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>, |
| 1195 | /*TargetNodeSize=*/256, // This parameter isn't used here. |
| 1196 | /*Multi=*/false>>::SizeWithNValues(target_values_per_node); |
| 1197 | } |
| 1198 | |
| 1199 | // Yields the number of values in a (non-root) leaf node for this btree. |
| 1200 | template <typename Btree> |
| 1201 | constexpr static size_t GetNumValuesPerNode() { |
| 1202 | return btree_node<typename Btree::params_type>::kNodeValues; |
| 1203 | } |
| 1204 | |
| 1205 | template <typename Btree> |
| 1206 | constexpr static size_t GetMaxFieldType() { |
| 1207 | return std::numeric_limits< |
| 1208 | typename btree_node<typename Btree::params_type>::field_type>::max(); |
| 1209 | } |
| 1210 | |
| 1211 | template <typename Btree> |
| 1212 | constexpr static bool UsesLinearNodeSearch() { |
| 1213 | return btree_node<typename Btree::params_type>::use_linear_search::value; |
| 1214 | } |
| 1215 | }; |
| 1216 | |
| 1217 | namespace { |
| 1218 | |
| 1219 | class BtreeMapTest : public ::testing::Test { |
| 1220 | public: |
| 1221 | struct Key {}; |
| 1222 | struct Cmp { |
| 1223 | template <typename T> |
| 1224 | bool operator()(T, T) const { |
| 1225 | return false; |
| 1226 | } |
| 1227 | }; |
| 1228 | |
| 1229 | struct KeyLin { |
| 1230 | using absl_btree_prefer_linear_node_search = std::true_type; |
| 1231 | }; |
| 1232 | struct CmpLin : Cmp { |
| 1233 | using absl_btree_prefer_linear_node_search = std::true_type; |
| 1234 | }; |
| 1235 | |
| 1236 | struct KeyBin { |
| 1237 | using absl_btree_prefer_linear_node_search = std::false_type; |
| 1238 | }; |
| 1239 | struct CmpBin : Cmp { |
| 1240 | using absl_btree_prefer_linear_node_search = std::false_type; |
| 1241 | }; |
| 1242 | |
| 1243 | template <typename K, typename C> |
| 1244 | static bool IsLinear() { |
| 1245 | return BtreeNodePeer::UsesLinearNodeSearch<absl::btree_map<K, int, C>>(); |
| 1246 | } |
| 1247 | }; |
| 1248 | |
| 1249 | TEST_F(BtreeMapTest, TestLinearSearchPreferredForKeyLinearViaAlias) { |
| 1250 | // Test requesting linear search by directly exporting an alias. |
| 1251 | EXPECT_FALSE((IsLinear<Key, Cmp>())); |
| 1252 | EXPECT_TRUE((IsLinear<KeyLin, Cmp>())); |
| 1253 | EXPECT_TRUE((IsLinear<Key, CmpLin>())); |
| 1254 | EXPECT_TRUE((IsLinear<KeyLin, CmpLin>())); |
| 1255 | } |
| 1256 | |
| 1257 | TEST_F(BtreeMapTest, LinearChoiceTree) { |
| 1258 | // Cmp has precedence, and is forcing binary |
| 1259 | EXPECT_FALSE((IsLinear<Key, CmpBin>())); |
| 1260 | EXPECT_FALSE((IsLinear<KeyLin, CmpBin>())); |
| 1261 | EXPECT_FALSE((IsLinear<KeyBin, CmpBin>())); |
| 1262 | EXPECT_FALSE((IsLinear<int, CmpBin>())); |
| 1263 | EXPECT_FALSE((IsLinear<std::string, CmpBin>())); |
| 1264 | // Cmp has precedence, and is forcing linear |
| 1265 | EXPECT_TRUE((IsLinear<Key, CmpLin>())); |
| 1266 | EXPECT_TRUE((IsLinear<KeyLin, CmpLin>())); |
| 1267 | EXPECT_TRUE((IsLinear<KeyBin, CmpLin>())); |
| 1268 | EXPECT_TRUE((IsLinear<int, CmpLin>())); |
| 1269 | EXPECT_TRUE((IsLinear<std::string, CmpLin>())); |
| 1270 | // Cmp has no preference, Key determines linear vs binary. |
| 1271 | EXPECT_FALSE((IsLinear<Key, Cmp>())); |
| 1272 | EXPECT_TRUE((IsLinear<KeyLin, Cmp>())); |
| 1273 | EXPECT_FALSE((IsLinear<KeyBin, Cmp>())); |
| 1274 | // arithmetic key w/ std::less or std::greater: linear |
| 1275 | EXPECT_TRUE((IsLinear<int, std::less<int>>())); |
| 1276 | EXPECT_TRUE((IsLinear<double, std::greater<double>>())); |
| 1277 | // arithmetic key w/ custom compare: binary |
| 1278 | EXPECT_FALSE((IsLinear<int, Cmp>())); |
| 1279 | // non-arithmetic key: binary |
| 1280 | EXPECT_FALSE((IsLinear<std::string, std::less<std::string>>())); |
| 1281 | } |
| 1282 | |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1283 | TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) { |
| 1284 | absl::btree_map<std::string, std::unique_ptr<std::string>> m; |
| 1285 | |
| 1286 | std::unique_ptr<std::string> &v = m["A"]; |
| 1287 | EXPECT_TRUE(v == nullptr); |
| 1288 | v.reset(new std::string("X")); |
| 1289 | |
| 1290 | auto iter = m.find("A"); |
| 1291 | EXPECT_EQ("X", *iter->second); |
| 1292 | } |
| 1293 | |
| 1294 | TEST(Btree, InitializerListConstructor) { |
| 1295 | absl::btree_set<std::string> set({"a", "b"}); |
| 1296 | EXPECT_EQ(set.count("a"), 1); |
| 1297 | EXPECT_EQ(set.count("b"), 1); |
| 1298 | |
| 1299 | absl::btree_multiset<int> mset({1, 1, 4}); |
| 1300 | EXPECT_EQ(mset.count(1), 2); |
| 1301 | EXPECT_EQ(mset.count(4), 1); |
| 1302 | |
| 1303 | absl::btree_map<int, int> map({{1, 5}, {2, 10}}); |
| 1304 | EXPECT_EQ(map[1], 5); |
| 1305 | EXPECT_EQ(map[2], 10); |
| 1306 | |
| 1307 | absl::btree_multimap<int, int> mmap({{1, 5}, {1, 10}}); |
| 1308 | auto range = mmap.equal_range(1); |
| 1309 | auto it = range.first; |
| 1310 | ASSERT_NE(it, range.second); |
| 1311 | EXPECT_EQ(it->second, 5); |
| 1312 | ASSERT_NE(++it, range.second); |
| 1313 | EXPECT_EQ(it->second, 10); |
| 1314 | EXPECT_EQ(++it, range.second); |
| 1315 | } |
| 1316 | |
| 1317 | TEST(Btree, InitializerListInsert) { |
| 1318 | absl::btree_set<std::string> set; |
| 1319 | set.insert({"a", "b"}); |
| 1320 | EXPECT_EQ(set.count("a"), 1); |
| 1321 | EXPECT_EQ(set.count("b"), 1); |
| 1322 | |
| 1323 | absl::btree_multiset<int> mset; |
| 1324 | mset.insert({1, 1, 4}); |
| 1325 | EXPECT_EQ(mset.count(1), 2); |
| 1326 | EXPECT_EQ(mset.count(4), 1); |
| 1327 | |
| 1328 | absl::btree_map<int, int> map; |
| 1329 | map.insert({{1, 5}, {2, 10}}); |
| 1330 | // Test that inserting one element using an initializer list also works. |
| 1331 | map.insert({3, 15}); |
| 1332 | EXPECT_EQ(map[1], 5); |
| 1333 | EXPECT_EQ(map[2], 10); |
| 1334 | EXPECT_EQ(map[3], 15); |
| 1335 | |
| 1336 | absl::btree_multimap<int, int> mmap; |
| 1337 | mmap.insert({{1, 5}, {1, 10}}); |
| 1338 | auto range = mmap.equal_range(1); |
| 1339 | auto it = range.first; |
| 1340 | ASSERT_NE(it, range.second); |
| 1341 | EXPECT_EQ(it->second, 5); |
| 1342 | ASSERT_NE(++it, range.second); |
| 1343 | EXPECT_EQ(it->second, 10); |
| 1344 | EXPECT_EQ(++it, range.second); |
| 1345 | } |
| 1346 | |
| 1347 | template <typename Compare, typename K> |
| 1348 | void AssertKeyCompareToAdapted() { |
| 1349 | using Adapted = typename key_compare_to_adapter<Compare>::type; |
| 1350 | static_assert(!std::is_same<Adapted, Compare>::value, |
| 1351 | "key_compare_to_adapter should have adapted this comparator."); |
| 1352 | static_assert( |
| 1353 | std::is_same<absl::weak_ordering, |
| 1354 | absl::result_of_t<Adapted(const K &, const K &)>>::value, |
| 1355 | "Adapted comparator should be a key-compare-to comparator."); |
| 1356 | } |
| 1357 | template <typename Compare, typename K> |
| 1358 | void AssertKeyCompareToNotAdapted() { |
| 1359 | using Unadapted = typename key_compare_to_adapter<Compare>::type; |
| 1360 | static_assert( |
| 1361 | std::is_same<Unadapted, Compare>::value, |
| 1362 | "key_compare_to_adapter shouldn't have adapted this comparator."); |
| 1363 | static_assert( |
| 1364 | std::is_same<bool, |
| 1365 | absl::result_of_t<Unadapted(const K &, const K &)>>::value, |
| 1366 | "Un-adapted comparator should return bool."); |
| 1367 | } |
| 1368 | |
| 1369 | TEST(Btree, KeyCompareToAdapter) { |
| 1370 | AssertKeyCompareToAdapted<std::less<std::string>, std::string>(); |
| 1371 | AssertKeyCompareToAdapted<std::greater<std::string>, std::string>(); |
| 1372 | AssertKeyCompareToAdapted<std::less<absl::string_view>, absl::string_view>(); |
| 1373 | AssertKeyCompareToAdapted<std::greater<absl::string_view>, |
| 1374 | absl::string_view>(); |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1375 | AssertKeyCompareToAdapted<std::less<absl::Cord>, absl::Cord>(); |
| 1376 | AssertKeyCompareToAdapted<std::greater<absl::Cord>, absl::Cord>(); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1377 | AssertKeyCompareToNotAdapted<std::less<int>, int>(); |
| 1378 | AssertKeyCompareToNotAdapted<std::greater<int>, int>(); |
| 1379 | } |
| 1380 | |
| 1381 | TEST(Btree, RValueInsert) { |
| 1382 | InstanceTracker tracker; |
| 1383 | |
| 1384 | absl::btree_set<MovableOnlyInstance> set; |
| 1385 | set.insert(MovableOnlyInstance(1)); |
| 1386 | set.insert(MovableOnlyInstance(3)); |
| 1387 | MovableOnlyInstance two(2); |
| 1388 | set.insert(set.find(MovableOnlyInstance(3)), std::move(two)); |
| 1389 | auto it = set.find(MovableOnlyInstance(2)); |
| 1390 | ASSERT_NE(it, set.end()); |
| 1391 | ASSERT_NE(++it, set.end()); |
| 1392 | EXPECT_EQ(it->value(), 3); |
| 1393 | |
| 1394 | absl::btree_multiset<MovableOnlyInstance> mset; |
| 1395 | MovableOnlyInstance zero(0); |
| 1396 | MovableOnlyInstance zero2(0); |
| 1397 | mset.insert(std::move(zero)); |
| 1398 | mset.insert(mset.find(MovableOnlyInstance(0)), std::move(zero2)); |
| 1399 | EXPECT_EQ(mset.count(MovableOnlyInstance(0)), 2); |
| 1400 | |
| 1401 | absl::btree_map<int, MovableOnlyInstance> map; |
| 1402 | std::pair<const int, MovableOnlyInstance> p1 = {1, MovableOnlyInstance(5)}; |
| 1403 | std::pair<const int, MovableOnlyInstance> p2 = {2, MovableOnlyInstance(10)}; |
| 1404 | std::pair<const int, MovableOnlyInstance> p3 = {3, MovableOnlyInstance(15)}; |
| 1405 | map.insert(std::move(p1)); |
| 1406 | map.insert(std::move(p3)); |
| 1407 | map.insert(map.find(3), std::move(p2)); |
| 1408 | ASSERT_NE(map.find(2), map.end()); |
| 1409 | EXPECT_EQ(map.find(2)->second.value(), 10); |
| 1410 | |
| 1411 | absl::btree_multimap<int, MovableOnlyInstance> mmap; |
| 1412 | std::pair<const int, MovableOnlyInstance> p4 = {1, MovableOnlyInstance(5)}; |
| 1413 | std::pair<const int, MovableOnlyInstance> p5 = {1, MovableOnlyInstance(10)}; |
| 1414 | mmap.insert(std::move(p4)); |
| 1415 | mmap.insert(mmap.find(1), std::move(p5)); |
| 1416 | auto range = mmap.equal_range(1); |
| 1417 | auto it1 = range.first; |
| 1418 | ASSERT_NE(it1, range.second); |
| 1419 | EXPECT_EQ(it1->second.value(), 10); |
| 1420 | ASSERT_NE(++it1, range.second); |
| 1421 | EXPECT_EQ(it1->second.value(), 5); |
| 1422 | EXPECT_EQ(++it1, range.second); |
| 1423 | |
| 1424 | EXPECT_EQ(tracker.copies(), 0); |
| 1425 | EXPECT_EQ(tracker.swaps(), 0); |
| 1426 | } |
| 1427 | |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1428 | // A btree set with a specific number of values per node. |
| 1429 | template <typename Key, int TargetValuesPerNode, typename Cmp = std::less<Key>> |
| 1430 | class SizedBtreeSet |
| 1431 | : public btree_set_container<btree< |
| 1432 | set_params<Key, Cmp, std::allocator<Key>, |
| 1433 | BtreeNodePeer::GetTargetNodeSize<Key>(TargetValuesPerNode), |
| 1434 | /*Multi=*/false>>> { |
| 1435 | using Base = typename SizedBtreeSet::btree_set_container; |
| 1436 | |
| 1437 | public: |
| 1438 | SizedBtreeSet() {} |
| 1439 | using Base::Base; |
| 1440 | }; |
| 1441 | |
| 1442 | template <typename Set> |
| 1443 | void ExpectOperationCounts(const int expected_moves, |
| 1444 | const int expected_comparisons, |
| 1445 | const std::vector<int> &values, |
| 1446 | InstanceTracker *tracker, Set *set) { |
| 1447 | for (const int v : values) set->insert(MovableOnlyInstance(v)); |
| 1448 | set->clear(); |
| 1449 | EXPECT_EQ(tracker->moves(), expected_moves); |
| 1450 | EXPECT_EQ(tracker->comparisons(), expected_comparisons); |
| 1451 | EXPECT_EQ(tracker->copies(), 0); |
| 1452 | EXPECT_EQ(tracker->swaps(), 0); |
| 1453 | tracker->ResetCopiesMovesSwaps(); |
| 1454 | } |
| 1455 | |
| 1456 | // Note: when the values in this test change, it is expected to have an impact |
| 1457 | // on performance. |
| 1458 | TEST(Btree, MovesComparisonsCopiesSwapsTracking) { |
| 1459 | InstanceTracker tracker; |
| 1460 | // Note: this is minimum number of values per node. |
| 1461 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3> set3; |
| 1462 | // Note: this is the default number of values per node for a set of int32s |
| 1463 | // (with 64-bit pointers). |
| 1464 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61> set61; |
| 1465 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/100> set100; |
| 1466 | |
| 1467 | // Don't depend on flags for random values because then the expectations will |
| 1468 | // fail if the flags change. |
| 1469 | std::vector<int> values = |
| 1470 | GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23); |
| 1471 | |
| 1472 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3); |
| 1473 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61); |
| 1474 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100); |
| 1475 | if (sizeof(void *) == 8) { |
| 1476 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(), |
| 1477 | BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>()); |
| 1478 | } |
| 1479 | |
| 1480 | // Test key insertion/deletion in random order. |
| 1481 | ExpectOperationCounts(45281, 132551, values, &tracker, &set3); |
| 1482 | ExpectOperationCounts(386718, 129807, values, &tracker, &set61); |
| 1483 | ExpectOperationCounts(586761, 130310, values, &tracker, &set100); |
| 1484 | |
| 1485 | // Test key insertion/deletion in sorted order. |
| 1486 | std::sort(values.begin(), values.end()); |
| 1487 | ExpectOperationCounts(26638, 92134, values, &tracker, &set3); |
| 1488 | ExpectOperationCounts(20208, 87757, values, &tracker, &set61); |
| 1489 | ExpectOperationCounts(20124, 96583, values, &tracker, &set100); |
| 1490 | |
| 1491 | // Test key insertion/deletion in reverse sorted order. |
| 1492 | std::reverse(values.begin(), values.end()); |
| 1493 | ExpectOperationCounts(49951, 119325, values, &tracker, &set3); |
| 1494 | ExpectOperationCounts(338813, 118266, values, &tracker, &set61); |
| 1495 | ExpectOperationCounts(534529, 125279, values, &tracker, &set100); |
| 1496 | } |
| 1497 | |
| 1498 | struct MovableOnlyInstanceThreeWayCompare { |
| 1499 | absl::weak_ordering operator()(const MovableOnlyInstance &a, |
| 1500 | const MovableOnlyInstance &b) const { |
| 1501 | return a.compare(b); |
| 1502 | } |
| 1503 | }; |
| 1504 | |
| 1505 | // Note: when the values in this test change, it is expected to have an impact |
| 1506 | // on performance. |
| 1507 | TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) { |
| 1508 | InstanceTracker tracker; |
| 1509 | // Note: this is minimum number of values per node. |
| 1510 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3, |
| 1511 | MovableOnlyInstanceThreeWayCompare> |
| 1512 | set3; |
| 1513 | // Note: this is the default number of values per node for a set of int32s |
| 1514 | // (with 64-bit pointers). |
| 1515 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61, |
| 1516 | MovableOnlyInstanceThreeWayCompare> |
| 1517 | set61; |
| 1518 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/100, |
| 1519 | MovableOnlyInstanceThreeWayCompare> |
| 1520 | set100; |
| 1521 | |
| 1522 | // Don't depend on flags for random values because then the expectations will |
| 1523 | // fail if the flags change. |
| 1524 | std::vector<int> values = |
| 1525 | GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23); |
| 1526 | |
| 1527 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3); |
| 1528 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61); |
| 1529 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100); |
| 1530 | if (sizeof(void *) == 8) { |
| 1531 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(), |
| 1532 | BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>()); |
| 1533 | } |
| 1534 | |
| 1535 | // Test key insertion/deletion in random order. |
| 1536 | ExpectOperationCounts(45281, 122560, values, &tracker, &set3); |
| 1537 | ExpectOperationCounts(386718, 119816, values, &tracker, &set61); |
| 1538 | ExpectOperationCounts(586761, 120319, values, &tracker, &set100); |
| 1539 | |
| 1540 | // Test key insertion/deletion in sorted order. |
| 1541 | std::sort(values.begin(), values.end()); |
| 1542 | ExpectOperationCounts(26638, 92134, values, &tracker, &set3); |
| 1543 | ExpectOperationCounts(20208, 87757, values, &tracker, &set61); |
| 1544 | ExpectOperationCounts(20124, 96583, values, &tracker, &set100); |
| 1545 | |
| 1546 | // Test key insertion/deletion in reverse sorted order. |
| 1547 | std::reverse(values.begin(), values.end()); |
| 1548 | ExpectOperationCounts(49951, 109326, values, &tracker, &set3); |
| 1549 | ExpectOperationCounts(338813, 108267, values, &tracker, &set61); |
| 1550 | ExpectOperationCounts(534529, 115280, values, &tracker, &set100); |
| 1551 | } |
| 1552 | |
| 1553 | struct NoDefaultCtor { |
| 1554 | int num; |
| 1555 | explicit NoDefaultCtor(int i) : num(i) {} |
| 1556 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1557 | friend bool operator<(const NoDefaultCtor &a, const NoDefaultCtor &b) { |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1558 | return a.num < b.num; |
| 1559 | } |
| 1560 | }; |
| 1561 | |
| 1562 | TEST(Btree, BtreeMapCanHoldNoDefaultCtorTypes) { |
| 1563 | absl::btree_map<NoDefaultCtor, NoDefaultCtor> m; |
| 1564 | |
| 1565 | for (int i = 1; i <= 99; ++i) { |
| 1566 | SCOPED_TRACE(i); |
| 1567 | EXPECT_TRUE(m.emplace(NoDefaultCtor(i), NoDefaultCtor(100 - i)).second); |
| 1568 | } |
| 1569 | EXPECT_FALSE(m.emplace(NoDefaultCtor(78), NoDefaultCtor(0)).second); |
| 1570 | |
| 1571 | auto iter99 = m.find(NoDefaultCtor(99)); |
| 1572 | ASSERT_NE(iter99, m.end()); |
| 1573 | EXPECT_EQ(iter99->second.num, 1); |
| 1574 | |
| 1575 | auto iter1 = m.find(NoDefaultCtor(1)); |
| 1576 | ASSERT_NE(iter1, m.end()); |
| 1577 | EXPECT_EQ(iter1->second.num, 99); |
| 1578 | |
| 1579 | auto iter50 = m.find(NoDefaultCtor(50)); |
| 1580 | ASSERT_NE(iter50, m.end()); |
| 1581 | EXPECT_EQ(iter50->second.num, 50); |
| 1582 | |
| 1583 | auto iter25 = m.find(NoDefaultCtor(25)); |
| 1584 | ASSERT_NE(iter25, m.end()); |
| 1585 | EXPECT_EQ(iter25->second.num, 75); |
| 1586 | } |
| 1587 | |
| 1588 | TEST(Btree, BtreeMultimapCanHoldNoDefaultCtorTypes) { |
| 1589 | absl::btree_multimap<NoDefaultCtor, NoDefaultCtor> m; |
| 1590 | |
| 1591 | for (int i = 1; i <= 99; ++i) { |
| 1592 | SCOPED_TRACE(i); |
| 1593 | m.emplace(NoDefaultCtor(i), NoDefaultCtor(100 - i)); |
| 1594 | } |
| 1595 | |
| 1596 | auto iter99 = m.find(NoDefaultCtor(99)); |
| 1597 | ASSERT_NE(iter99, m.end()); |
| 1598 | EXPECT_EQ(iter99->second.num, 1); |
| 1599 | |
| 1600 | auto iter1 = m.find(NoDefaultCtor(1)); |
| 1601 | ASSERT_NE(iter1, m.end()); |
| 1602 | EXPECT_EQ(iter1->second.num, 99); |
| 1603 | |
| 1604 | auto iter50 = m.find(NoDefaultCtor(50)); |
| 1605 | ASSERT_NE(iter50, m.end()); |
| 1606 | EXPECT_EQ(iter50->second.num, 50); |
| 1607 | |
| 1608 | auto iter25 = m.find(NoDefaultCtor(25)); |
| 1609 | ASSERT_NE(iter25, m.end()); |
| 1610 | EXPECT_EQ(iter25->second.num, 75); |
| 1611 | } |
| 1612 | |
| 1613 | TEST(Btree, MapAt) { |
| 1614 | absl::btree_map<int, int> map = {{1, 2}, {2, 4}}; |
| 1615 | EXPECT_EQ(map.at(1), 2); |
| 1616 | EXPECT_EQ(map.at(2), 4); |
| 1617 | map.at(2) = 8; |
| 1618 | const absl::btree_map<int, int> &const_map = map; |
| 1619 | EXPECT_EQ(const_map.at(1), 2); |
| 1620 | EXPECT_EQ(const_map.at(2), 8); |
| 1621 | #ifdef ABSL_HAVE_EXCEPTIONS |
| 1622 | EXPECT_THROW(map.at(3), std::out_of_range); |
| 1623 | #else |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1624 | EXPECT_DEATH_IF_SUPPORTED(map.at(3), "absl::btree_map::at"); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1625 | #endif |
| 1626 | } |
| 1627 | |
| 1628 | TEST(Btree, BtreeMultisetEmplace) { |
| 1629 | const int value_to_insert = 123456; |
| 1630 | absl::btree_multiset<int> s; |
| 1631 | auto iter = s.emplace(value_to_insert); |
| 1632 | ASSERT_NE(iter, s.end()); |
| 1633 | EXPECT_EQ(*iter, value_to_insert); |
| 1634 | auto iter2 = s.emplace(value_to_insert); |
| 1635 | EXPECT_NE(iter2, iter); |
| 1636 | ASSERT_NE(iter2, s.end()); |
| 1637 | EXPECT_EQ(*iter2, value_to_insert); |
| 1638 | auto result = s.equal_range(value_to_insert); |
| 1639 | EXPECT_EQ(std::distance(result.first, result.second), 2); |
| 1640 | } |
| 1641 | |
| 1642 | TEST(Btree, BtreeMultisetEmplaceHint) { |
| 1643 | const int value_to_insert = 123456; |
| 1644 | absl::btree_multiset<int> s; |
| 1645 | auto iter = s.emplace(value_to_insert); |
| 1646 | ASSERT_NE(iter, s.end()); |
| 1647 | EXPECT_EQ(*iter, value_to_insert); |
| 1648 | auto emplace_iter = s.emplace_hint(iter, value_to_insert); |
| 1649 | EXPECT_NE(emplace_iter, iter); |
| 1650 | ASSERT_NE(emplace_iter, s.end()); |
| 1651 | EXPECT_EQ(*emplace_iter, value_to_insert); |
| 1652 | } |
| 1653 | |
| 1654 | TEST(Btree, BtreeMultimapEmplace) { |
| 1655 | const int key_to_insert = 123456; |
| 1656 | const char value0[] = "a"; |
| 1657 | absl::btree_multimap<int, std::string> s; |
| 1658 | auto iter = s.emplace(key_to_insert, value0); |
| 1659 | ASSERT_NE(iter, s.end()); |
| 1660 | EXPECT_EQ(iter->first, key_to_insert); |
| 1661 | EXPECT_EQ(iter->second, value0); |
| 1662 | const char value1[] = "b"; |
| 1663 | auto iter2 = s.emplace(key_to_insert, value1); |
| 1664 | EXPECT_NE(iter2, iter); |
| 1665 | ASSERT_NE(iter2, s.end()); |
| 1666 | EXPECT_EQ(iter2->first, key_to_insert); |
| 1667 | EXPECT_EQ(iter2->second, value1); |
| 1668 | auto result = s.equal_range(key_to_insert); |
| 1669 | EXPECT_EQ(std::distance(result.first, result.second), 2); |
| 1670 | } |
| 1671 | |
| 1672 | TEST(Btree, BtreeMultimapEmplaceHint) { |
| 1673 | const int key_to_insert = 123456; |
| 1674 | const char value0[] = "a"; |
| 1675 | absl::btree_multimap<int, std::string> s; |
| 1676 | auto iter = s.emplace(key_to_insert, value0); |
| 1677 | ASSERT_NE(iter, s.end()); |
| 1678 | EXPECT_EQ(iter->first, key_to_insert); |
| 1679 | EXPECT_EQ(iter->second, value0); |
| 1680 | const char value1[] = "b"; |
| 1681 | auto emplace_iter = s.emplace_hint(iter, key_to_insert, value1); |
| 1682 | EXPECT_NE(emplace_iter, iter); |
| 1683 | ASSERT_NE(emplace_iter, s.end()); |
| 1684 | EXPECT_EQ(emplace_iter->first, key_to_insert); |
| 1685 | EXPECT_EQ(emplace_iter->second, value1); |
| 1686 | } |
| 1687 | |
| 1688 | TEST(Btree, ConstIteratorAccessors) { |
| 1689 | absl::btree_set<int> set; |
| 1690 | for (int i = 0; i < 100; ++i) { |
| 1691 | set.insert(i); |
| 1692 | } |
| 1693 | |
| 1694 | auto it = set.cbegin(); |
| 1695 | auto r_it = set.crbegin(); |
| 1696 | for (int i = 0; i < 100; ++i, ++it, ++r_it) { |
| 1697 | ASSERT_EQ(*it, i); |
| 1698 | ASSERT_EQ(*r_it, 99 - i); |
| 1699 | } |
| 1700 | EXPECT_EQ(it, set.cend()); |
| 1701 | EXPECT_EQ(r_it, set.crend()); |
| 1702 | } |
| 1703 | |
| 1704 | TEST(Btree, StrSplitCompatible) { |
| 1705 | const absl::btree_set<std::string> split_set = absl::StrSplit("a,b,c", ','); |
| 1706 | const absl::btree_set<std::string> expected_set = {"a", "b", "c"}; |
| 1707 | |
| 1708 | EXPECT_EQ(split_set, expected_set); |
| 1709 | } |
| 1710 | |
| 1711 | // We can't use EXPECT_EQ/etc. to compare absl::weak_ordering because they |
| 1712 | // convert literal 0 to int and absl::weak_ordering can only be compared with |
| 1713 | // literal 0. Defining this function allows for avoiding ClangTidy warnings. |
| 1714 | bool Identity(const bool b) { return b; } |
| 1715 | |
| 1716 | TEST(Btree, ValueComp) { |
| 1717 | absl::btree_set<int> s; |
| 1718 | EXPECT_TRUE(s.value_comp()(1, 2)); |
| 1719 | EXPECT_FALSE(s.value_comp()(2, 2)); |
| 1720 | EXPECT_FALSE(s.value_comp()(2, 1)); |
| 1721 | |
| 1722 | absl::btree_map<int, int> m1; |
| 1723 | EXPECT_TRUE(m1.value_comp()(std::make_pair(1, 0), std::make_pair(2, 0))); |
| 1724 | EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(2, 0))); |
| 1725 | EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(1, 0))); |
| 1726 | |
| 1727 | absl::btree_map<std::string, int> m2; |
| 1728 | EXPECT_TRUE(Identity( |
| 1729 | m2.value_comp()(std::make_pair("a", 0), std::make_pair("b", 0)) < 0)); |
| 1730 | EXPECT_TRUE(Identity( |
| 1731 | m2.value_comp()(std::make_pair("b", 0), std::make_pair("b", 0)) == 0)); |
| 1732 | EXPECT_TRUE(Identity( |
| 1733 | m2.value_comp()(std::make_pair("b", 0), std::make_pair("a", 0)) > 0)); |
| 1734 | } |
| 1735 | |
| 1736 | TEST(Btree, DefaultConstruction) { |
| 1737 | absl::btree_set<int> s; |
| 1738 | absl::btree_map<int, int> m; |
| 1739 | absl::btree_multiset<int> ms; |
| 1740 | absl::btree_multimap<int, int> mm; |
| 1741 | |
| 1742 | EXPECT_TRUE(s.empty()); |
| 1743 | EXPECT_TRUE(m.empty()); |
| 1744 | EXPECT_TRUE(ms.empty()); |
| 1745 | EXPECT_TRUE(mm.empty()); |
| 1746 | } |
| 1747 | |
| 1748 | TEST(Btree, SwissTableHashable) { |
| 1749 | static constexpr int kValues = 10000; |
| 1750 | std::vector<int> values(kValues); |
| 1751 | std::iota(values.begin(), values.end(), 0); |
| 1752 | std::vector<std::pair<int, int>> map_values; |
| 1753 | for (int v : values) map_values.emplace_back(v, -v); |
| 1754 | |
| 1755 | using set = absl::btree_set<int>; |
| 1756 | EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ |
| 1757 | set{}, |
| 1758 | set{1}, |
| 1759 | set{2}, |
| 1760 | set{1, 2}, |
| 1761 | set{2, 1}, |
| 1762 | set(values.begin(), values.end()), |
| 1763 | set(values.rbegin(), values.rend()), |
| 1764 | })); |
| 1765 | |
| 1766 | using mset = absl::btree_multiset<int>; |
| 1767 | EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ |
| 1768 | mset{}, |
| 1769 | mset{1}, |
| 1770 | mset{1, 1}, |
| 1771 | mset{2}, |
| 1772 | mset{2, 2}, |
| 1773 | mset{1, 2}, |
| 1774 | mset{1, 1, 2}, |
| 1775 | mset{1, 2, 2}, |
| 1776 | mset{1, 1, 2, 2}, |
| 1777 | mset(values.begin(), values.end()), |
| 1778 | mset(values.rbegin(), values.rend()), |
| 1779 | })); |
| 1780 | |
| 1781 | using map = absl::btree_map<int, int>; |
| 1782 | EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ |
| 1783 | map{}, |
| 1784 | map{{1, 0}}, |
| 1785 | map{{1, 1}}, |
| 1786 | map{{2, 0}}, |
| 1787 | map{{2, 2}}, |
| 1788 | map{{1, 0}, {2, 1}}, |
| 1789 | map(map_values.begin(), map_values.end()), |
| 1790 | map(map_values.rbegin(), map_values.rend()), |
| 1791 | })); |
| 1792 | |
| 1793 | using mmap = absl::btree_multimap<int, int>; |
| 1794 | EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ |
| 1795 | mmap{}, |
| 1796 | mmap{{1, 0}}, |
| 1797 | mmap{{1, 1}}, |
| 1798 | mmap{{1, 0}, {1, 1}}, |
| 1799 | mmap{{1, 1}, {1, 0}}, |
| 1800 | mmap{{2, 0}}, |
| 1801 | mmap{{2, 2}}, |
| 1802 | mmap{{1, 0}, {2, 1}}, |
| 1803 | mmap(map_values.begin(), map_values.end()), |
| 1804 | mmap(map_values.rbegin(), map_values.rend()), |
| 1805 | })); |
| 1806 | } |
| 1807 | |
| 1808 | TEST(Btree, ComparableSet) { |
| 1809 | absl::btree_set<int> s1 = {1, 2}; |
| 1810 | absl::btree_set<int> s2 = {2, 3}; |
| 1811 | EXPECT_LT(s1, s2); |
| 1812 | EXPECT_LE(s1, s2); |
| 1813 | EXPECT_LE(s1, s1); |
| 1814 | EXPECT_GT(s2, s1); |
| 1815 | EXPECT_GE(s2, s1); |
| 1816 | EXPECT_GE(s1, s1); |
| 1817 | } |
| 1818 | |
| 1819 | TEST(Btree, ComparableSetsDifferentLength) { |
| 1820 | absl::btree_set<int> s1 = {1, 2}; |
| 1821 | absl::btree_set<int> s2 = {1, 2, 3}; |
| 1822 | EXPECT_LT(s1, s2); |
| 1823 | EXPECT_LE(s1, s2); |
| 1824 | EXPECT_GT(s2, s1); |
| 1825 | EXPECT_GE(s2, s1); |
| 1826 | } |
| 1827 | |
| 1828 | TEST(Btree, ComparableMultiset) { |
| 1829 | absl::btree_multiset<int> s1 = {1, 2}; |
| 1830 | absl::btree_multiset<int> s2 = {2, 3}; |
| 1831 | EXPECT_LT(s1, s2); |
| 1832 | EXPECT_LE(s1, s2); |
| 1833 | EXPECT_LE(s1, s1); |
| 1834 | EXPECT_GT(s2, s1); |
| 1835 | EXPECT_GE(s2, s1); |
| 1836 | EXPECT_GE(s1, s1); |
| 1837 | } |
| 1838 | |
| 1839 | TEST(Btree, ComparableMap) { |
| 1840 | absl::btree_map<int, int> s1 = {{1, 2}}; |
| 1841 | absl::btree_map<int, int> s2 = {{2, 3}}; |
| 1842 | EXPECT_LT(s1, s2); |
| 1843 | EXPECT_LE(s1, s2); |
| 1844 | EXPECT_LE(s1, s1); |
| 1845 | EXPECT_GT(s2, s1); |
| 1846 | EXPECT_GE(s2, s1); |
| 1847 | EXPECT_GE(s1, s1); |
| 1848 | } |
| 1849 | |
| 1850 | TEST(Btree, ComparableMultimap) { |
| 1851 | absl::btree_multimap<int, int> s1 = {{1, 2}}; |
| 1852 | absl::btree_multimap<int, int> s2 = {{2, 3}}; |
| 1853 | EXPECT_LT(s1, s2); |
| 1854 | EXPECT_LE(s1, s2); |
| 1855 | EXPECT_LE(s1, s1); |
| 1856 | EXPECT_GT(s2, s1); |
| 1857 | EXPECT_GE(s2, s1); |
| 1858 | EXPECT_GE(s1, s1); |
| 1859 | } |
| 1860 | |
| 1861 | TEST(Btree, ComparableSetWithCustomComparator) { |
| 1862 | // As specified by |
| 1863 | // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf section |
| 1864 | // [container.requirements.general].12, ordering associative containers always |
| 1865 | // uses default '<' operator |
| 1866 | // - even if otherwise the container uses custom functor. |
| 1867 | absl::btree_set<int, std::greater<int>> s1 = {1, 2}; |
| 1868 | absl::btree_set<int, std::greater<int>> s2 = {2, 3}; |
| 1869 | EXPECT_LT(s1, s2); |
| 1870 | EXPECT_LE(s1, s2); |
| 1871 | EXPECT_LE(s1, s1); |
| 1872 | EXPECT_GT(s2, s1); |
| 1873 | EXPECT_GE(s2, s1); |
| 1874 | EXPECT_GE(s1, s1); |
| 1875 | } |
| 1876 | |
| 1877 | TEST(Btree, EraseReturnsIterator) { |
| 1878 | absl::btree_set<int> set = {1, 2, 3, 4, 5}; |
| 1879 | auto result_it = set.erase(set.begin(), set.find(3)); |
| 1880 | EXPECT_EQ(result_it, set.find(3)); |
| 1881 | result_it = set.erase(set.find(5)); |
| 1882 | EXPECT_EQ(result_it, set.end()); |
| 1883 | } |
| 1884 | |
| 1885 | TEST(Btree, ExtractAndInsertNodeHandleSet) { |
| 1886 | absl::btree_set<int> src1 = {1, 2, 3, 4, 5}; |
| 1887 | auto nh = src1.extract(src1.find(3)); |
| 1888 | EXPECT_THAT(src1, ElementsAre(1, 2, 4, 5)); |
| 1889 | absl::btree_set<int> other; |
| 1890 | absl::btree_set<int>::insert_return_type res = other.insert(std::move(nh)); |
| 1891 | EXPECT_THAT(other, ElementsAre(3)); |
| 1892 | EXPECT_EQ(res.position, other.find(3)); |
| 1893 | EXPECT_TRUE(res.inserted); |
| 1894 | EXPECT_TRUE(res.node.empty()); |
| 1895 | |
| 1896 | absl::btree_set<int> src2 = {3, 4}; |
| 1897 | nh = src2.extract(src2.find(3)); |
| 1898 | EXPECT_THAT(src2, ElementsAre(4)); |
| 1899 | res = other.insert(std::move(nh)); |
| 1900 | EXPECT_THAT(other, ElementsAre(3)); |
| 1901 | EXPECT_EQ(res.position, other.find(3)); |
| 1902 | EXPECT_FALSE(res.inserted); |
| 1903 | ASSERT_FALSE(res.node.empty()); |
| 1904 | EXPECT_EQ(res.node.value(), 3); |
| 1905 | } |
| 1906 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1907 | template <typename Set> |
| 1908 | void TestExtractWithTrackingForSet() { |
| 1909 | InstanceTracker tracker; |
| 1910 | { |
| 1911 | Set s; |
| 1912 | // Add enough elements to make sure we test internal nodes too. |
| 1913 | const size_t kSize = 1000; |
| 1914 | while (s.size() < kSize) { |
| 1915 | s.insert(MovableOnlyInstance(s.size())); |
| 1916 | } |
| 1917 | for (int i = 0; i < kSize; ++i) { |
| 1918 | // Extract with key |
| 1919 | auto nh = s.extract(MovableOnlyInstance(i)); |
| 1920 | EXPECT_EQ(s.size(), kSize - 1); |
| 1921 | EXPECT_EQ(nh.value().value(), i); |
| 1922 | // Insert with node |
| 1923 | s.insert(std::move(nh)); |
| 1924 | EXPECT_EQ(s.size(), kSize); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1925 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 1926 | // Extract with iterator |
| 1927 | auto it = s.find(MovableOnlyInstance(i)); |
| 1928 | nh = s.extract(it); |
| 1929 | EXPECT_EQ(s.size(), kSize - 1); |
| 1930 | EXPECT_EQ(nh.value().value(), i); |
| 1931 | // Insert with node and hint |
| 1932 | s.insert(s.begin(), std::move(nh)); |
| 1933 | EXPECT_EQ(s.size(), kSize); |
| 1934 | } |
| 1935 | } |
| 1936 | EXPECT_EQ(0, tracker.instances()); |
| 1937 | } |
| 1938 | |
| 1939 | template <typename Map> |
| 1940 | void TestExtractWithTrackingForMap() { |
| 1941 | InstanceTracker tracker; |
| 1942 | { |
| 1943 | Map m; |
| 1944 | // Add enough elements to make sure we test internal nodes too. |
| 1945 | const size_t kSize = 1000; |
| 1946 | while (m.size() < kSize) { |
| 1947 | m.insert( |
| 1948 | {CopyableMovableInstance(m.size()), MovableOnlyInstance(m.size())}); |
| 1949 | } |
| 1950 | for (int i = 0; i < kSize; ++i) { |
| 1951 | // Extract with key |
| 1952 | auto nh = m.extract(CopyableMovableInstance(i)); |
| 1953 | EXPECT_EQ(m.size(), kSize - 1); |
| 1954 | EXPECT_EQ(nh.key().value(), i); |
| 1955 | EXPECT_EQ(nh.mapped().value(), i); |
| 1956 | // Insert with node |
| 1957 | m.insert(std::move(nh)); |
| 1958 | EXPECT_EQ(m.size(), kSize); |
| 1959 | |
| 1960 | // Extract with iterator |
| 1961 | auto it = m.find(CopyableMovableInstance(i)); |
| 1962 | nh = m.extract(it); |
| 1963 | EXPECT_EQ(m.size(), kSize - 1); |
| 1964 | EXPECT_EQ(nh.key().value(), i); |
| 1965 | EXPECT_EQ(nh.mapped().value(), i); |
| 1966 | // Insert with node and hint |
| 1967 | m.insert(m.begin(), std::move(nh)); |
| 1968 | EXPECT_EQ(m.size(), kSize); |
| 1969 | } |
| 1970 | } |
| 1971 | EXPECT_EQ(0, tracker.instances()); |
| 1972 | } |
| 1973 | |
| 1974 | TEST(Btree, ExtractTracking) { |
| 1975 | TestExtractWithTrackingForSet<absl::btree_set<MovableOnlyInstance>>(); |
| 1976 | TestExtractWithTrackingForSet<absl::btree_multiset<MovableOnlyInstance>>(); |
| 1977 | TestExtractWithTrackingForMap< |
| 1978 | absl::btree_map<CopyableMovableInstance, MovableOnlyInstance>>(); |
| 1979 | TestExtractWithTrackingForMap< |
| 1980 | absl::btree_multimap<CopyableMovableInstance, MovableOnlyInstance>>(); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1981 | } |
| 1982 | |
| 1983 | TEST(Btree, ExtractAndInsertNodeHandleMultiSet) { |
| 1984 | absl::btree_multiset<int> src1 = {1, 2, 3, 3, 4, 5}; |
| 1985 | auto nh = src1.extract(src1.find(3)); |
| 1986 | EXPECT_THAT(src1, ElementsAre(1, 2, 3, 4, 5)); |
| 1987 | absl::btree_multiset<int> other; |
| 1988 | auto res = other.insert(std::move(nh)); |
| 1989 | EXPECT_THAT(other, ElementsAre(3)); |
| 1990 | EXPECT_EQ(res, other.find(3)); |
| 1991 | |
| 1992 | absl::btree_multiset<int> src2 = {3, 4}; |
| 1993 | nh = src2.extract(src2.find(3)); |
| 1994 | EXPECT_THAT(src2, ElementsAre(4)); |
| 1995 | res = other.insert(std::move(nh)); |
| 1996 | EXPECT_THAT(other, ElementsAre(3, 3)); |
| 1997 | EXPECT_EQ(res, ++other.find(3)); |
| 1998 | } |
| 1999 | |
| 2000 | TEST(Btree, ExtractAndInsertNodeHandleMap) { |
| 2001 | absl::btree_map<int, int> src1 = {{1, 2}, {3, 4}, {5, 6}}; |
| 2002 | auto nh = src1.extract(src1.find(3)); |
| 2003 | EXPECT_THAT(src1, ElementsAre(Pair(1, 2), Pair(5, 6))); |
| 2004 | absl::btree_map<int, int> other; |
| 2005 | absl::btree_map<int, int>::insert_return_type res = |
| 2006 | other.insert(std::move(nh)); |
| 2007 | EXPECT_THAT(other, ElementsAre(Pair(3, 4))); |
| 2008 | EXPECT_EQ(res.position, other.find(3)); |
| 2009 | EXPECT_TRUE(res.inserted); |
| 2010 | EXPECT_TRUE(res.node.empty()); |
| 2011 | |
| 2012 | absl::btree_map<int, int> src2 = {{3, 6}}; |
| 2013 | nh = src2.extract(src2.find(3)); |
| 2014 | EXPECT_TRUE(src2.empty()); |
| 2015 | res = other.insert(std::move(nh)); |
| 2016 | EXPECT_THAT(other, ElementsAre(Pair(3, 4))); |
| 2017 | EXPECT_EQ(res.position, other.find(3)); |
| 2018 | EXPECT_FALSE(res.inserted); |
| 2019 | ASSERT_FALSE(res.node.empty()); |
| 2020 | EXPECT_EQ(res.node.key(), 3); |
| 2021 | EXPECT_EQ(res.node.mapped(), 6); |
| 2022 | } |
| 2023 | |
| 2024 | TEST(Btree, ExtractAndInsertNodeHandleMultiMap) { |
| 2025 | absl::btree_multimap<int, int> src1 = {{1, 2}, {3, 4}, {5, 6}}; |
| 2026 | auto nh = src1.extract(src1.find(3)); |
| 2027 | EXPECT_THAT(src1, ElementsAre(Pair(1, 2), Pair(5, 6))); |
| 2028 | absl::btree_multimap<int, int> other; |
| 2029 | auto res = other.insert(std::move(nh)); |
| 2030 | EXPECT_THAT(other, ElementsAre(Pair(3, 4))); |
| 2031 | EXPECT_EQ(res, other.find(3)); |
| 2032 | |
| 2033 | absl::btree_multimap<int, int> src2 = {{3, 6}}; |
| 2034 | nh = src2.extract(src2.find(3)); |
| 2035 | EXPECT_TRUE(src2.empty()); |
| 2036 | res = other.insert(std::move(nh)); |
| 2037 | EXPECT_THAT(other, ElementsAre(Pair(3, 4), Pair(3, 6))); |
| 2038 | EXPECT_EQ(res, ++other.begin()); |
| 2039 | } |
| 2040 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 2041 | TEST(Btree, ExtractMultiMapEquivalentKeys) { |
| 2042 | // Note: using string keys means a three-way comparator. |
| 2043 | absl::btree_multimap<std::string, int> map; |
| 2044 | for (int i = 0; i < 100; ++i) { |
| 2045 | for (int j = 0; j < 100; ++j) { |
| 2046 | map.insert({absl::StrCat(i), j}); |
| 2047 | } |
| 2048 | } |
| 2049 | |
| 2050 | for (int i = 0; i < 100; ++i) { |
| 2051 | const std::string key = absl::StrCat(i); |
| 2052 | auto node_handle = map.extract(key); |
| 2053 | EXPECT_EQ(node_handle.key(), key); |
| 2054 | EXPECT_EQ(node_handle.mapped(), 0) << i; |
| 2055 | } |
| 2056 | |
| 2057 | for (int i = 0; i < 100; ++i) { |
| 2058 | const std::string key = absl::StrCat(i); |
| 2059 | auto node_handle = map.extract(key); |
| 2060 | EXPECT_EQ(node_handle.key(), key); |
| 2061 | EXPECT_EQ(node_handle.mapped(), 1) << i; |
| 2062 | } |
| 2063 | } |
| 2064 | |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 2065 | // For multisets, insert with hint also affects correctness because we need to |
| 2066 | // insert immediately before the hint if possible. |
| 2067 | struct InsertMultiHintData { |
| 2068 | int key; |
| 2069 | int not_key; |
| 2070 | bool operator==(const InsertMultiHintData other) const { |
| 2071 | return key == other.key && not_key == other.not_key; |
| 2072 | } |
| 2073 | }; |
| 2074 | |
| 2075 | struct InsertMultiHintDataKeyCompare { |
| 2076 | using is_transparent = void; |
| 2077 | bool operator()(const InsertMultiHintData a, |
| 2078 | const InsertMultiHintData b) const { |
| 2079 | return a.key < b.key; |
| 2080 | } |
| 2081 | bool operator()(const int a, const InsertMultiHintData b) const { |
| 2082 | return a < b.key; |
| 2083 | } |
| 2084 | bool operator()(const InsertMultiHintData a, const int b) const { |
| 2085 | return a.key < b; |
| 2086 | } |
| 2087 | }; |
| 2088 | |
| 2089 | TEST(Btree, InsertHintNodeHandle) { |
| 2090 | // For unique sets, insert with hint is just a performance optimization. |
| 2091 | // Test that insert works correctly when the hint is right or wrong. |
| 2092 | { |
| 2093 | absl::btree_set<int> src = {1, 2, 3, 4, 5}; |
| 2094 | auto nh = src.extract(src.find(3)); |
| 2095 | EXPECT_THAT(src, ElementsAre(1, 2, 4, 5)); |
| 2096 | absl::btree_set<int> other = {0, 100}; |
| 2097 | // Test a correct hint. |
| 2098 | auto it = other.insert(other.lower_bound(3), std::move(nh)); |
| 2099 | EXPECT_THAT(other, ElementsAre(0, 3, 100)); |
| 2100 | EXPECT_EQ(it, other.find(3)); |
| 2101 | |
| 2102 | nh = src.extract(src.find(5)); |
| 2103 | // Test an incorrect hint. |
| 2104 | it = other.insert(other.end(), std::move(nh)); |
| 2105 | EXPECT_THAT(other, ElementsAre(0, 3, 5, 100)); |
| 2106 | EXPECT_EQ(it, other.find(5)); |
| 2107 | } |
| 2108 | |
| 2109 | absl::btree_multiset<InsertMultiHintData, InsertMultiHintDataKeyCompare> src = |
| 2110 | {{1, 2}, {3, 4}, {3, 5}}; |
| 2111 | auto nh = src.extract(src.lower_bound(3)); |
| 2112 | EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 4})); |
| 2113 | absl::btree_multiset<InsertMultiHintData, InsertMultiHintDataKeyCompare> |
| 2114 | other = {{3, 1}, {3, 2}, {3, 3}}; |
| 2115 | auto it = other.insert(--other.end(), std::move(nh)); |
| 2116 | EXPECT_THAT( |
| 2117 | other, ElementsAre(InsertMultiHintData{3, 1}, InsertMultiHintData{3, 2}, |
| 2118 | InsertMultiHintData{3, 4}, InsertMultiHintData{3, 3})); |
| 2119 | EXPECT_EQ(it, --(--other.end())); |
| 2120 | |
| 2121 | nh = src.extract(src.find(3)); |
| 2122 | EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 5})); |
| 2123 | it = other.insert(other.begin(), std::move(nh)); |
| 2124 | EXPECT_THAT(other, |
| 2125 | ElementsAre(InsertMultiHintData{3, 5}, InsertMultiHintData{3, 1}, |
| 2126 | InsertMultiHintData{3, 2}, InsertMultiHintData{3, 4}, |
| 2127 | InsertMultiHintData{3, 3})); |
| 2128 | EXPECT_EQ(it, other.begin()); |
| 2129 | } |
| 2130 | |
| 2131 | struct IntCompareToCmp { |
| 2132 | absl::weak_ordering operator()(int a, int b) const { |
| 2133 | if (a < b) return absl::weak_ordering::less; |
| 2134 | if (a > b) return absl::weak_ordering::greater; |
| 2135 | return absl::weak_ordering::equivalent; |
| 2136 | } |
| 2137 | }; |
| 2138 | |
| 2139 | TEST(Btree, MergeIntoUniqueContainers) { |
| 2140 | absl::btree_set<int, IntCompareToCmp> src1 = {1, 2, 3}; |
| 2141 | absl::btree_multiset<int> src2 = {3, 4, 4, 5}; |
| 2142 | absl::btree_set<int> dst; |
| 2143 | |
| 2144 | dst.merge(src1); |
| 2145 | EXPECT_TRUE(src1.empty()); |
| 2146 | EXPECT_THAT(dst, ElementsAre(1, 2, 3)); |
| 2147 | dst.merge(src2); |
| 2148 | EXPECT_THAT(src2, ElementsAre(3, 4)); |
| 2149 | EXPECT_THAT(dst, ElementsAre(1, 2, 3, 4, 5)); |
| 2150 | } |
| 2151 | |
| 2152 | TEST(Btree, MergeIntoUniqueContainersWithCompareTo) { |
| 2153 | absl::btree_set<int, IntCompareToCmp> src1 = {1, 2, 3}; |
| 2154 | absl::btree_multiset<int> src2 = {3, 4, 4, 5}; |
| 2155 | absl::btree_set<int, IntCompareToCmp> dst; |
| 2156 | |
| 2157 | dst.merge(src1); |
| 2158 | EXPECT_TRUE(src1.empty()); |
| 2159 | EXPECT_THAT(dst, ElementsAre(1, 2, 3)); |
| 2160 | dst.merge(src2); |
| 2161 | EXPECT_THAT(src2, ElementsAre(3, 4)); |
| 2162 | EXPECT_THAT(dst, ElementsAre(1, 2, 3, 4, 5)); |
| 2163 | } |
| 2164 | |
| 2165 | TEST(Btree, MergeIntoMultiContainers) { |
| 2166 | absl::btree_set<int, IntCompareToCmp> src1 = {1, 2, 3}; |
| 2167 | absl::btree_multiset<int> src2 = {3, 4, 4, 5}; |
| 2168 | absl::btree_multiset<int> dst; |
| 2169 | |
| 2170 | dst.merge(src1); |
| 2171 | EXPECT_TRUE(src1.empty()); |
| 2172 | EXPECT_THAT(dst, ElementsAre(1, 2, 3)); |
| 2173 | dst.merge(src2); |
| 2174 | EXPECT_TRUE(src2.empty()); |
| 2175 | EXPECT_THAT(dst, ElementsAre(1, 2, 3, 3, 4, 4, 5)); |
| 2176 | } |
| 2177 | |
| 2178 | TEST(Btree, MergeIntoMultiContainersWithCompareTo) { |
| 2179 | absl::btree_set<int, IntCompareToCmp> src1 = {1, 2, 3}; |
| 2180 | absl::btree_multiset<int> src2 = {3, 4, 4, 5}; |
| 2181 | absl::btree_multiset<int, IntCompareToCmp> dst; |
| 2182 | |
| 2183 | dst.merge(src1); |
| 2184 | EXPECT_TRUE(src1.empty()); |
| 2185 | EXPECT_THAT(dst, ElementsAre(1, 2, 3)); |
| 2186 | dst.merge(src2); |
| 2187 | EXPECT_TRUE(src2.empty()); |
| 2188 | EXPECT_THAT(dst, ElementsAre(1, 2, 3, 3, 4, 4, 5)); |
| 2189 | } |
| 2190 | |
| 2191 | TEST(Btree, MergeIntoMultiMapsWithDifferentComparators) { |
| 2192 | absl::btree_map<int, int, IntCompareToCmp> src1 = {{1, 1}, {2, 2}, {3, 3}}; |
| 2193 | absl::btree_multimap<int, int, std::greater<int>> src2 = { |
| 2194 | {5, 5}, {4, 1}, {4, 4}, {3, 2}}; |
| 2195 | absl::btree_multimap<int, int> dst; |
| 2196 | |
| 2197 | dst.merge(src1); |
| 2198 | EXPECT_TRUE(src1.empty()); |
| 2199 | EXPECT_THAT(dst, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3))); |
| 2200 | dst.merge(src2); |
| 2201 | EXPECT_TRUE(src2.empty()); |
| 2202 | EXPECT_THAT(dst, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3), Pair(3, 2), |
| 2203 | Pair(4, 1), Pair(4, 4), Pair(5, 5))); |
| 2204 | } |
| 2205 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 2206 | TEST(Btree, MergeIntoSetMovableOnly) { |
| 2207 | absl::btree_set<MovableOnlyInstance> src; |
| 2208 | src.insert(MovableOnlyInstance(1)); |
| 2209 | absl::btree_multiset<MovableOnlyInstance> dst1; |
| 2210 | dst1.insert(MovableOnlyInstance(2)); |
| 2211 | absl::btree_set<MovableOnlyInstance> dst2; |
| 2212 | |
| 2213 | // Test merge into multiset. |
| 2214 | dst1.merge(src); |
| 2215 | |
| 2216 | EXPECT_TRUE(src.empty()); |
| 2217 | // ElementsAre/ElementsAreArray don't work with move-only types. |
| 2218 | ASSERT_THAT(dst1, SizeIs(2)); |
| 2219 | EXPECT_EQ(*dst1.begin(), MovableOnlyInstance(1)); |
| 2220 | EXPECT_EQ(*std::next(dst1.begin()), MovableOnlyInstance(2)); |
| 2221 | |
| 2222 | // Test merge into set. |
| 2223 | dst2.merge(dst1); |
| 2224 | |
| 2225 | EXPECT_TRUE(dst1.empty()); |
| 2226 | ASSERT_THAT(dst2, SizeIs(2)); |
| 2227 | EXPECT_EQ(*dst2.begin(), MovableOnlyInstance(1)); |
| 2228 | EXPECT_EQ(*std::next(dst2.begin()), MovableOnlyInstance(2)); |
| 2229 | } |
| 2230 | |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 2231 | struct KeyCompareToWeakOrdering { |
| 2232 | template <typename T> |
| 2233 | absl::weak_ordering operator()(const T &a, const T &b) const { |
| 2234 | return a < b ? absl::weak_ordering::less |
| 2235 | : a == b ? absl::weak_ordering::equivalent |
| 2236 | : absl::weak_ordering::greater; |
| 2237 | } |
| 2238 | }; |
| 2239 | |
| 2240 | struct KeyCompareToStrongOrdering { |
| 2241 | template <typename T> |
| 2242 | absl::strong_ordering operator()(const T &a, const T &b) const { |
| 2243 | return a < b ? absl::strong_ordering::less |
| 2244 | : a == b ? absl::strong_ordering::equal |
| 2245 | : absl::strong_ordering::greater; |
| 2246 | } |
| 2247 | }; |
| 2248 | |
| 2249 | TEST(Btree, UserProvidedKeyCompareToComparators) { |
| 2250 | absl::btree_set<int, KeyCompareToWeakOrdering> weak_set = {1, 2, 3}; |
| 2251 | EXPECT_TRUE(weak_set.contains(2)); |
| 2252 | EXPECT_FALSE(weak_set.contains(4)); |
| 2253 | |
| 2254 | absl::btree_set<int, KeyCompareToStrongOrdering> strong_set = {1, 2, 3}; |
| 2255 | EXPECT_TRUE(strong_set.contains(2)); |
| 2256 | EXPECT_FALSE(strong_set.contains(4)); |
| 2257 | } |
| 2258 | |
| 2259 | TEST(Btree, TryEmplaceBasicTest) { |
| 2260 | absl::btree_map<int, std::string> m; |
| 2261 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 2262 | // Should construct a string from the literal. |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 2263 | m.try_emplace(1, "one"); |
| 2264 | EXPECT_EQ(1, m.size()); |
| 2265 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 2266 | // Try other string constructors and const lvalue key. |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 2267 | const int key(42); |
| 2268 | m.try_emplace(key, 3, 'a'); |
| 2269 | m.try_emplace(2, std::string("two")); |
| 2270 | |
| 2271 | EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); |
| 2272 | EXPECT_THAT(m, ElementsAreArray(std::vector<std::pair<int, std::string>>{ |
| 2273 | {1, "one"}, {2, "two"}, {42, "aaa"}})); |
| 2274 | } |
| 2275 | |
| 2276 | TEST(Btree, TryEmplaceWithHintWorks) { |
| 2277 | // Use a counting comparator here to verify that hint is used. |
| 2278 | int calls = 0; |
| 2279 | auto cmp = [&calls](int x, int y) { |
| 2280 | ++calls; |
| 2281 | return x < y; |
| 2282 | }; |
| 2283 | using Cmp = decltype(cmp); |
| 2284 | |
| 2285 | absl::btree_map<int, int, Cmp> m(cmp); |
| 2286 | for (int i = 0; i < 128; ++i) { |
| 2287 | m.emplace(i, i); |
| 2288 | } |
| 2289 | |
| 2290 | // Sanity check for the comparator |
| 2291 | calls = 0; |
| 2292 | m.emplace(127, 127); |
| 2293 | EXPECT_GE(calls, 4); |
| 2294 | |
| 2295 | // Try with begin hint: |
| 2296 | calls = 0; |
| 2297 | auto it = m.try_emplace(m.begin(), -1, -1); |
| 2298 | EXPECT_EQ(129, m.size()); |
| 2299 | EXPECT_EQ(it, m.begin()); |
| 2300 | EXPECT_LE(calls, 2); |
| 2301 | |
| 2302 | // Try with end hint: |
| 2303 | calls = 0; |
| 2304 | std::pair<int, int> pair1024 = {1024, 1024}; |
| 2305 | it = m.try_emplace(m.end(), pair1024.first, pair1024.second); |
| 2306 | EXPECT_EQ(130, m.size()); |
| 2307 | EXPECT_EQ(it, --m.end()); |
| 2308 | EXPECT_LE(calls, 2); |
| 2309 | |
| 2310 | // Try value already present, bad hint; ensure no duplicate added: |
| 2311 | calls = 0; |
| 2312 | it = m.try_emplace(m.end(), 16, 17); |
| 2313 | EXPECT_EQ(130, m.size()); |
| 2314 | EXPECT_GE(calls, 4); |
| 2315 | EXPECT_EQ(it, m.find(16)); |
| 2316 | |
| 2317 | // Try value already present, hint points directly to it: |
| 2318 | calls = 0; |
| 2319 | it = m.try_emplace(it, 16, 17); |
| 2320 | EXPECT_EQ(130, m.size()); |
| 2321 | EXPECT_LE(calls, 2); |
| 2322 | EXPECT_EQ(it, m.find(16)); |
| 2323 | |
| 2324 | m.erase(2); |
| 2325 | EXPECT_EQ(129, m.size()); |
| 2326 | auto hint = m.find(3); |
| 2327 | // Try emplace in the middle of two other elements. |
| 2328 | calls = 0; |
| 2329 | m.try_emplace(hint, 2, 2); |
| 2330 | EXPECT_EQ(130, m.size()); |
| 2331 | EXPECT_LE(calls, 2); |
| 2332 | |
| 2333 | EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); |
| 2334 | } |
| 2335 | |
| 2336 | TEST(Btree, TryEmplaceWithBadHint) { |
| 2337 | absl::btree_map<int, int> m = {{1, 1}, {9, 9}}; |
| 2338 | |
| 2339 | // Bad hint (too small), should still emplace: |
| 2340 | auto it = m.try_emplace(m.begin(), 2, 2); |
| 2341 | EXPECT_EQ(it, ++m.begin()); |
| 2342 | EXPECT_THAT(m, ElementsAreArray( |
| 2343 | std::vector<std::pair<int, int>>{{1, 1}, {2, 2}, {9, 9}})); |
| 2344 | |
| 2345 | // Bad hint, too large this time: |
| 2346 | it = m.try_emplace(++(++m.begin()), 0, 0); |
| 2347 | EXPECT_EQ(it, m.begin()); |
| 2348 | EXPECT_THAT(m, ElementsAreArray(std::vector<std::pair<int, int>>{ |
| 2349 | {0, 0}, {1, 1}, {2, 2}, {9, 9}})); |
| 2350 | } |
| 2351 | |
| 2352 | TEST(Btree, TryEmplaceMaintainsSortedOrder) { |
| 2353 | absl::btree_map<int, std::string> m; |
| 2354 | std::pair<int, std::string> pair5 = {5, "five"}; |
| 2355 | |
| 2356 | // Test both lvalue & rvalue emplace. |
| 2357 | m.try_emplace(10, "ten"); |
| 2358 | m.try_emplace(pair5.first, pair5.second); |
| 2359 | EXPECT_EQ(2, m.size()); |
| 2360 | EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); |
| 2361 | |
| 2362 | int int100{100}; |
| 2363 | m.try_emplace(int100, "hundred"); |
| 2364 | m.try_emplace(1, "one"); |
| 2365 | EXPECT_EQ(4, m.size()); |
| 2366 | EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); |
| 2367 | } |
| 2368 | |
| 2369 | TEST(Btree, TryEmplaceWithHintAndNoValueArgsWorks) { |
| 2370 | absl::btree_map<int, int> m; |
| 2371 | m.try_emplace(m.end(), 1); |
| 2372 | EXPECT_EQ(0, m[1]); |
| 2373 | } |
| 2374 | |
| 2375 | TEST(Btree, TryEmplaceWithHintAndMultipleValueArgsWorks) { |
| 2376 | absl::btree_map<int, std::string> m; |
| 2377 | m.try_emplace(m.end(), 1, 10, 'a'); |
| 2378 | EXPECT_EQ(std::string(10, 'a'), m[1]); |
| 2379 | } |
| 2380 | |
| 2381 | TEST(Btree, MoveAssignmentAllocatorPropagation) { |
| 2382 | InstanceTracker tracker; |
| 2383 | |
| 2384 | int64_t bytes1 = 0, bytes2 = 0; |
| 2385 | PropagatingCountingAlloc<MovableOnlyInstance> allocator1(&bytes1); |
| 2386 | PropagatingCountingAlloc<MovableOnlyInstance> allocator2(&bytes2); |
| 2387 | std::less<MovableOnlyInstance> cmp; |
| 2388 | |
| 2389 | // Test propagating allocator_type. |
| 2390 | { |
| 2391 | absl::btree_set<MovableOnlyInstance, std::less<MovableOnlyInstance>, |
| 2392 | PropagatingCountingAlloc<MovableOnlyInstance>> |
| 2393 | set1(cmp, allocator1), set2(cmp, allocator2); |
| 2394 | |
| 2395 | for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); |
| 2396 | |
| 2397 | tracker.ResetCopiesMovesSwaps(); |
| 2398 | set2 = std::move(set1); |
| 2399 | EXPECT_EQ(tracker.moves(), 0); |
| 2400 | } |
| 2401 | // Test non-propagating allocator_type with equal allocators. |
| 2402 | { |
| 2403 | absl::btree_set<MovableOnlyInstance, std::less<MovableOnlyInstance>, |
| 2404 | CountingAllocator<MovableOnlyInstance>> |
| 2405 | set1(cmp, allocator1), set2(cmp, allocator1); |
| 2406 | |
| 2407 | for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); |
| 2408 | |
| 2409 | tracker.ResetCopiesMovesSwaps(); |
| 2410 | set2 = std::move(set1); |
| 2411 | EXPECT_EQ(tracker.moves(), 0); |
| 2412 | } |
| 2413 | // Test non-propagating allocator_type with different allocators. |
| 2414 | { |
| 2415 | absl::btree_set<MovableOnlyInstance, std::less<MovableOnlyInstance>, |
| 2416 | CountingAllocator<MovableOnlyInstance>> |
| 2417 | set1(cmp, allocator1), set2(cmp, allocator2); |
| 2418 | |
| 2419 | for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); |
| 2420 | |
| 2421 | tracker.ResetCopiesMovesSwaps(); |
| 2422 | set2 = std::move(set1); |
| 2423 | EXPECT_GE(tracker.moves(), 100); |
| 2424 | } |
| 2425 | } |
| 2426 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 2427 | TEST(Btree, EmptyTree) { |
| 2428 | absl::btree_set<int> s; |
| 2429 | EXPECT_TRUE(s.empty()); |
| 2430 | EXPECT_EQ(s.size(), 0); |
| 2431 | EXPECT_GT(s.max_size(), 0); |
| 2432 | } |
| 2433 | |
| 2434 | bool IsEven(int k) { return k % 2 == 0; } |
| 2435 | |
| 2436 | TEST(Btree, EraseIf) { |
| 2437 | // Test that erase_if works with all the container types and supports lambdas. |
| 2438 | { |
| 2439 | absl::btree_set<int> s = {1, 3, 5, 6, 100}; |
| 2440 | erase_if(s, [](int k) { return k > 3; }); |
| 2441 | EXPECT_THAT(s, ElementsAre(1, 3)); |
| 2442 | } |
| 2443 | { |
| 2444 | absl::btree_multiset<int> s = {1, 3, 3, 5, 6, 6, 100}; |
| 2445 | erase_if(s, [](int k) { return k <= 3; }); |
| 2446 | EXPECT_THAT(s, ElementsAre(5, 6, 6, 100)); |
| 2447 | } |
| 2448 | { |
| 2449 | absl::btree_map<int, int> m = {{1, 1}, {3, 3}, {6, 6}, {100, 100}}; |
| 2450 | erase_if(m, [](std::pair<const int, int> kv) { return kv.first > 3; }); |
| 2451 | EXPECT_THAT(m, ElementsAre(Pair(1, 1), Pair(3, 3))); |
| 2452 | } |
| 2453 | { |
| 2454 | absl::btree_multimap<int, int> m = {{1, 1}, {3, 3}, {3, 6}, |
| 2455 | {6, 6}, {6, 7}, {100, 6}}; |
| 2456 | erase_if(m, [](std::pair<const int, int> kv) { return kv.second == 6; }); |
| 2457 | EXPECT_THAT(m, ElementsAre(Pair(1, 1), Pair(3, 3), Pair(6, 7))); |
| 2458 | } |
| 2459 | // Test that erasing all elements from a large set works and test support for |
| 2460 | // function pointers. |
| 2461 | { |
| 2462 | absl::btree_set<int> s; |
| 2463 | for (int i = 0; i < 1000; ++i) s.insert(2 * i); |
| 2464 | erase_if(s, IsEven); |
| 2465 | EXPECT_THAT(s, IsEmpty()); |
| 2466 | } |
| 2467 | // Test that erase_if supports other format of function pointers. |
| 2468 | { |
| 2469 | absl::btree_set<int> s = {1, 3, 5, 6, 100}; |
| 2470 | erase_if(s, &IsEven); |
| 2471 | EXPECT_THAT(s, ElementsAre(1, 3, 5)); |
| 2472 | } |
| 2473 | } |
| 2474 | |
| 2475 | TEST(Btree, InsertOrAssign) { |
| 2476 | absl::btree_map<int, int> m = {{1, 1}, {3, 3}}; |
| 2477 | using value_type = typename decltype(m)::value_type; |
| 2478 | |
| 2479 | auto ret = m.insert_or_assign(4, 4); |
| 2480 | EXPECT_EQ(*ret.first, value_type(4, 4)); |
| 2481 | EXPECT_TRUE(ret.second); |
| 2482 | ret = m.insert_or_assign(3, 100); |
| 2483 | EXPECT_EQ(*ret.first, value_type(3, 100)); |
| 2484 | EXPECT_FALSE(ret.second); |
| 2485 | |
| 2486 | auto hint_ret = m.insert_or_assign(ret.first, 3, 200); |
| 2487 | EXPECT_EQ(*hint_ret, value_type(3, 200)); |
| 2488 | hint_ret = m.insert_or_assign(m.find(1), 0, 1); |
| 2489 | EXPECT_EQ(*hint_ret, value_type(0, 1)); |
| 2490 | // Test with bad hint. |
| 2491 | hint_ret = m.insert_or_assign(m.end(), -1, 1); |
| 2492 | EXPECT_EQ(*hint_ret, value_type(-1, 1)); |
| 2493 | |
| 2494 | EXPECT_THAT(m, ElementsAre(Pair(-1, 1), Pair(0, 1), Pair(1, 1), Pair(3, 200), |
| 2495 | Pair(4, 4))); |
| 2496 | } |
| 2497 | |
| 2498 | TEST(Btree, InsertOrAssignMovableOnly) { |
| 2499 | absl::btree_map<int, MovableOnlyInstance> m; |
| 2500 | using value_type = typename decltype(m)::value_type; |
| 2501 | |
| 2502 | auto ret = m.insert_or_assign(4, MovableOnlyInstance(4)); |
| 2503 | EXPECT_EQ(*ret.first, value_type(4, MovableOnlyInstance(4))); |
| 2504 | EXPECT_TRUE(ret.second); |
| 2505 | ret = m.insert_or_assign(4, MovableOnlyInstance(100)); |
| 2506 | EXPECT_EQ(*ret.first, value_type(4, MovableOnlyInstance(100))); |
| 2507 | EXPECT_FALSE(ret.second); |
| 2508 | |
| 2509 | auto hint_ret = m.insert_or_assign(ret.first, 3, MovableOnlyInstance(200)); |
| 2510 | EXPECT_EQ(*hint_ret, value_type(3, MovableOnlyInstance(200))); |
| 2511 | |
| 2512 | EXPECT_EQ(m.size(), 2); |
| 2513 | } |
| 2514 | |
| 2515 | TEST(Btree, BitfieldArgument) { |
| 2516 | union { |
| 2517 | int n : 1; |
| 2518 | }; |
| 2519 | n = 0; |
| 2520 | absl::btree_map<int, int> m; |
| 2521 | m.erase(n); |
| 2522 | m.count(n); |
| 2523 | m.find(n); |
| 2524 | m.contains(n); |
| 2525 | m.equal_range(n); |
| 2526 | m.insert_or_assign(n, n); |
| 2527 | m.insert_or_assign(m.end(), n, n); |
| 2528 | m.try_emplace(n); |
| 2529 | m.try_emplace(m.end(), n); |
| 2530 | m.at(n); |
| 2531 | m[n]; |
| 2532 | } |
| 2533 | |
| 2534 | TEST(Btree, SetRangeConstructorAndInsertSupportExplicitConversionComparable) { |
| 2535 | const absl::string_view names[] = {"n1", "n2"}; |
| 2536 | |
| 2537 | absl::btree_set<std::string> name_set1{std::begin(names), std::end(names)}; |
| 2538 | EXPECT_THAT(name_set1, ElementsAreArray(names)); |
| 2539 | |
| 2540 | absl::btree_set<std::string> name_set2; |
| 2541 | name_set2.insert(std::begin(names), std::end(names)); |
| 2542 | EXPECT_THAT(name_set2, ElementsAreArray(names)); |
| 2543 | } |
| 2544 | |
| 2545 | // A type that is explicitly convertible from int and counts constructor calls. |
| 2546 | struct ConstructorCounted { |
| 2547 | explicit ConstructorCounted(int i) : i(i) { ++constructor_calls; } |
| 2548 | bool operator==(int other) const { return i == other; } |
| 2549 | |
| 2550 | int i; |
| 2551 | static int constructor_calls; |
| 2552 | }; |
| 2553 | int ConstructorCounted::constructor_calls = 0; |
| 2554 | |
| 2555 | struct ConstructorCountedCompare { |
| 2556 | bool operator()(int a, const ConstructorCounted &b) const { return a < b.i; } |
| 2557 | bool operator()(const ConstructorCounted &a, int b) const { return a.i < b; } |
| 2558 | bool operator()(const ConstructorCounted &a, |
| 2559 | const ConstructorCounted &b) const { |
| 2560 | return a.i < b.i; |
| 2561 | } |
| 2562 | using is_transparent = void; |
| 2563 | }; |
| 2564 | |
| 2565 | TEST(Btree, |
| 2566 | SetRangeConstructorAndInsertExplicitConvComparableLimitConstruction) { |
| 2567 | const int i[] = {0, 1, 1}; |
| 2568 | ConstructorCounted::constructor_calls = 0; |
| 2569 | |
| 2570 | absl::btree_set<ConstructorCounted, ConstructorCountedCompare> set{ |
| 2571 | std::begin(i), std::end(i)}; |
| 2572 | EXPECT_THAT(set, ElementsAre(0, 1)); |
| 2573 | EXPECT_EQ(ConstructorCounted::constructor_calls, 2); |
| 2574 | |
| 2575 | set.insert(std::begin(i), std::end(i)); |
| 2576 | EXPECT_THAT(set, ElementsAre(0, 1)); |
| 2577 | EXPECT_EQ(ConstructorCounted::constructor_calls, 2); |
| 2578 | } |
| 2579 | |
| 2580 | TEST(Btree, |
| 2581 | SetRangeConstructorAndInsertSupportExplicitConversionNonComparable) { |
| 2582 | const int i[] = {0, 1}; |
| 2583 | |
| 2584 | absl::btree_set<std::vector<void *>> s1{std::begin(i), std::end(i)}; |
| 2585 | EXPECT_THAT(s1, ElementsAre(IsEmpty(), ElementsAre(IsNull()))); |
| 2586 | |
| 2587 | absl::btree_set<std::vector<void *>> s2; |
| 2588 | s2.insert(std::begin(i), std::end(i)); |
| 2589 | EXPECT_THAT(s2, ElementsAre(IsEmpty(), ElementsAre(IsNull()))); |
| 2590 | } |
| 2591 | |
| 2592 | // libstdc++ included with GCC 4.9 has a bug in the std::pair constructors that |
| 2593 | // prevents explicit conversions between pair types. |
| 2594 | // We only run this test for the libstdc++ from GCC 7 or newer because we can't |
| 2595 | // reliably check the libstdc++ version prior to that release. |
| 2596 | #if !defined(__GLIBCXX__) || \ |
| 2597 | (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 7) |
| 2598 | TEST(Btree, MapRangeConstructorAndInsertSupportExplicitConversionComparable) { |
| 2599 | const std::pair<absl::string_view, int> names[] = {{"n1", 1}, {"n2", 2}}; |
| 2600 | |
| 2601 | absl::btree_map<std::string, int> name_map1{std::begin(names), |
| 2602 | std::end(names)}; |
| 2603 | EXPECT_THAT(name_map1, ElementsAre(Pair("n1", 1), Pair("n2", 2))); |
| 2604 | |
| 2605 | absl::btree_map<std::string, int> name_map2; |
| 2606 | name_map2.insert(std::begin(names), std::end(names)); |
| 2607 | EXPECT_THAT(name_map2, ElementsAre(Pair("n1", 1), Pair("n2", 2))); |
| 2608 | } |
| 2609 | |
| 2610 | TEST(Btree, |
| 2611 | MapRangeConstructorAndInsertExplicitConvComparableLimitConstruction) { |
| 2612 | const std::pair<int, int> i[] = {{0, 1}, {1, 2}, {1, 3}}; |
| 2613 | ConstructorCounted::constructor_calls = 0; |
| 2614 | |
| 2615 | absl::btree_map<ConstructorCounted, int, ConstructorCountedCompare> map{ |
| 2616 | std::begin(i), std::end(i)}; |
| 2617 | EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2))); |
| 2618 | EXPECT_EQ(ConstructorCounted::constructor_calls, 2); |
| 2619 | |
| 2620 | map.insert(std::begin(i), std::end(i)); |
| 2621 | EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2))); |
| 2622 | EXPECT_EQ(ConstructorCounted::constructor_calls, 2); |
| 2623 | } |
| 2624 | |
| 2625 | TEST(Btree, |
| 2626 | MapRangeConstructorAndInsertSupportExplicitConversionNonComparable) { |
| 2627 | const std::pair<int, int> i[] = {{0, 1}, {1, 2}}; |
| 2628 | |
| 2629 | absl::btree_map<std::vector<void *>, int> m1{std::begin(i), std::end(i)}; |
| 2630 | EXPECT_THAT(m1, |
| 2631 | ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2))); |
| 2632 | |
| 2633 | absl::btree_map<std::vector<void *>, int> m2; |
| 2634 | m2.insert(std::begin(i), std::end(i)); |
| 2635 | EXPECT_THAT(m2, |
| 2636 | ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2))); |
| 2637 | } |
| 2638 | |
| 2639 | TEST(Btree, HeterogeneousTryEmplace) { |
| 2640 | absl::btree_map<std::string, int> m; |
| 2641 | std::string s = "key"; |
| 2642 | absl::string_view sv = s; |
| 2643 | m.try_emplace(sv, 1); |
| 2644 | EXPECT_EQ(m[s], 1); |
| 2645 | |
| 2646 | m.try_emplace(m.end(), sv, 2); |
| 2647 | EXPECT_EQ(m[s], 1); |
| 2648 | } |
| 2649 | |
| 2650 | TEST(Btree, HeterogeneousOperatorMapped) { |
| 2651 | absl::btree_map<std::string, int> m; |
| 2652 | std::string s = "key"; |
| 2653 | absl::string_view sv = s; |
| 2654 | m[sv] = 1; |
| 2655 | EXPECT_EQ(m[s], 1); |
| 2656 | |
| 2657 | m[sv] = 2; |
| 2658 | EXPECT_EQ(m[s], 2); |
| 2659 | } |
| 2660 | |
| 2661 | TEST(Btree, HeterogeneousInsertOrAssign) { |
| 2662 | absl::btree_map<std::string, int> m; |
| 2663 | std::string s = "key"; |
| 2664 | absl::string_view sv = s; |
| 2665 | m.insert_or_assign(sv, 1); |
| 2666 | EXPECT_EQ(m[s], 1); |
| 2667 | |
| 2668 | m.insert_or_assign(m.end(), sv, 2); |
| 2669 | EXPECT_EQ(m[s], 2); |
| 2670 | } |
| 2671 | #endif |
| 2672 | |
| 2673 | // This test requires std::launder for mutable key access in node handles. |
| 2674 | #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 |
| 2675 | TEST(Btree, NodeHandleMutableKeyAccess) { |
| 2676 | { |
| 2677 | absl::btree_map<std::string, std::string> map; |
| 2678 | |
| 2679 | map["key1"] = "mapped"; |
| 2680 | |
| 2681 | auto nh = map.extract(map.begin()); |
| 2682 | nh.key().resize(3); |
| 2683 | map.insert(std::move(nh)); |
| 2684 | |
| 2685 | EXPECT_THAT(map, ElementsAre(Pair("key", "mapped"))); |
| 2686 | } |
| 2687 | // Also for multimap. |
| 2688 | { |
| 2689 | absl::btree_multimap<std::string, std::string> map; |
| 2690 | |
| 2691 | map.emplace("key1", "mapped"); |
| 2692 | |
| 2693 | auto nh = map.extract(map.begin()); |
| 2694 | nh.key().resize(3); |
| 2695 | map.insert(std::move(nh)); |
| 2696 | |
| 2697 | EXPECT_THAT(map, ElementsAre(Pair("key", "mapped"))); |
| 2698 | } |
| 2699 | } |
| 2700 | #endif |
| 2701 | |
| 2702 | struct MultiKey { |
| 2703 | int i1; |
| 2704 | int i2; |
| 2705 | }; |
| 2706 | |
| 2707 | bool operator==(const MultiKey a, const MultiKey b) { |
| 2708 | return a.i1 == b.i1 && a.i2 == b.i2; |
| 2709 | } |
| 2710 | |
| 2711 | // A heterogeneous comparator that has different equivalence classes for |
| 2712 | // different lookup types. |
| 2713 | struct MultiKeyComp { |
| 2714 | using is_transparent = void; |
| 2715 | bool operator()(const MultiKey a, const MultiKey b) const { |
| 2716 | if (a.i1 != b.i1) return a.i1 < b.i1; |
| 2717 | return a.i2 < b.i2; |
| 2718 | } |
| 2719 | bool operator()(const int a, const MultiKey b) const { return a < b.i1; } |
| 2720 | bool operator()(const MultiKey a, const int b) const { return a.i1 < b; } |
| 2721 | }; |
| 2722 | |
| 2723 | // A heterogeneous, three-way comparator that has different equivalence classes |
| 2724 | // for different lookup types. |
| 2725 | struct MultiKeyThreeWayComp { |
| 2726 | using is_transparent = void; |
| 2727 | absl::weak_ordering operator()(const MultiKey a, const MultiKey b) const { |
| 2728 | if (a.i1 < b.i1) return absl::weak_ordering::less; |
| 2729 | if (a.i1 > b.i1) return absl::weak_ordering::greater; |
| 2730 | if (a.i2 < b.i2) return absl::weak_ordering::less; |
| 2731 | if (a.i2 > b.i2) return absl::weak_ordering::greater; |
| 2732 | return absl::weak_ordering::equivalent; |
| 2733 | } |
| 2734 | absl::weak_ordering operator()(const int a, const MultiKey b) const { |
| 2735 | if (a < b.i1) return absl::weak_ordering::less; |
| 2736 | if (a > b.i1) return absl::weak_ordering::greater; |
| 2737 | return absl::weak_ordering::equivalent; |
| 2738 | } |
| 2739 | absl::weak_ordering operator()(const MultiKey a, const int b) const { |
| 2740 | if (a.i1 < b) return absl::weak_ordering::less; |
| 2741 | if (a.i1 > b) return absl::weak_ordering::greater; |
| 2742 | return absl::weak_ordering::equivalent; |
| 2743 | } |
| 2744 | }; |
| 2745 | |
| 2746 | template <typename Compare> |
| 2747 | class BtreeMultiKeyTest : public ::testing::Test {}; |
| 2748 | using MultiKeyComps = ::testing::Types<MultiKeyComp, MultiKeyThreeWayComp>; |
| 2749 | TYPED_TEST_SUITE(BtreeMultiKeyTest, MultiKeyComps); |
| 2750 | |
| 2751 | TYPED_TEST(BtreeMultiKeyTest, EqualRange) { |
| 2752 | absl::btree_set<MultiKey, TypeParam> set; |
| 2753 | for (int i = 0; i < 100; ++i) { |
| 2754 | for (int j = 0; j < 100; ++j) { |
| 2755 | set.insert({i, j}); |
| 2756 | } |
| 2757 | } |
| 2758 | |
| 2759 | for (int i = 0; i < 100; ++i) { |
| 2760 | auto equal_range = set.equal_range(i); |
| 2761 | EXPECT_EQ(equal_range.first->i1, i); |
| 2762 | EXPECT_EQ(equal_range.first->i2, 0) << i; |
| 2763 | EXPECT_EQ(std::distance(equal_range.first, equal_range.second), 100) << i; |
| 2764 | } |
| 2765 | } |
| 2766 | |
| 2767 | TYPED_TEST(BtreeMultiKeyTest, Extract) { |
| 2768 | absl::btree_set<MultiKey, TypeParam> set; |
| 2769 | for (int i = 0; i < 100; ++i) { |
| 2770 | for (int j = 0; j < 100; ++j) { |
| 2771 | set.insert({i, j}); |
| 2772 | } |
| 2773 | } |
| 2774 | |
| 2775 | for (int i = 0; i < 100; ++i) { |
| 2776 | auto node_handle = set.extract(i); |
| 2777 | EXPECT_EQ(node_handle.value().i1, i); |
| 2778 | EXPECT_EQ(node_handle.value().i2, 0) << i; |
| 2779 | } |
| 2780 | |
| 2781 | for (int i = 0; i < 100; ++i) { |
| 2782 | auto node_handle = set.extract(i); |
| 2783 | EXPECT_EQ(node_handle.value().i1, i); |
| 2784 | EXPECT_EQ(node_handle.value().i2, 1) << i; |
| 2785 | } |
| 2786 | } |
| 2787 | |
| 2788 | TYPED_TEST(BtreeMultiKeyTest, Erase) { |
| 2789 | absl::btree_set<MultiKey, TypeParam> set = { |
| 2790 | {1, 1}, {2, 1}, {2, 2}, {3, 1}}; |
| 2791 | EXPECT_EQ(set.erase(2), 2); |
| 2792 | EXPECT_THAT(set, ElementsAre(MultiKey{1, 1}, MultiKey{3, 1})); |
| 2793 | } |
| 2794 | |
| 2795 | TYPED_TEST(BtreeMultiKeyTest, Count) { |
| 2796 | const absl::btree_set<MultiKey, TypeParam> set = { |
| 2797 | {1, 1}, {2, 1}, {2, 2}, {3, 1}}; |
| 2798 | EXPECT_EQ(set.count(2), 2); |
| 2799 | } |
| 2800 | |
| 2801 | TEST(Btree, AllocConstructor) { |
| 2802 | using Alloc = CountingAllocator<int>; |
| 2803 | using Set = absl::btree_set<int, std::less<int>, Alloc>; |
| 2804 | int64_t bytes_used = 0; |
| 2805 | Alloc alloc(&bytes_used); |
| 2806 | Set set(alloc); |
| 2807 | |
| 2808 | set.insert({1, 2, 3}); |
| 2809 | |
| 2810 | EXPECT_THAT(set, ElementsAre(1, 2, 3)); |
| 2811 | EXPECT_GT(bytes_used, set.size() * sizeof(int)); |
| 2812 | } |
| 2813 | |
| 2814 | TEST(Btree, AllocInitializerListConstructor) { |
| 2815 | using Alloc = CountingAllocator<int>; |
| 2816 | using Set = absl::btree_set<int, std::less<int>, Alloc>; |
| 2817 | int64_t bytes_used = 0; |
| 2818 | Alloc alloc(&bytes_used); |
| 2819 | Set set({1, 2, 3}, alloc); |
| 2820 | |
| 2821 | EXPECT_THAT(set, ElementsAre(1, 2, 3)); |
| 2822 | EXPECT_GT(bytes_used, set.size() * sizeof(int)); |
| 2823 | } |
| 2824 | |
| 2825 | TEST(Btree, AllocRangeConstructor) { |
| 2826 | using Alloc = CountingAllocator<int>; |
| 2827 | using Set = absl::btree_set<int, std::less<int>, Alloc>; |
| 2828 | int64_t bytes_used = 0; |
| 2829 | Alloc alloc(&bytes_used); |
| 2830 | std::vector<int> v = {1, 2, 3}; |
| 2831 | Set set(v.begin(), v.end(), alloc); |
| 2832 | |
| 2833 | EXPECT_THAT(set, ElementsAre(1, 2, 3)); |
| 2834 | EXPECT_GT(bytes_used, set.size() * sizeof(int)); |
| 2835 | } |
| 2836 | |
| 2837 | TEST(Btree, AllocCopyConstructor) { |
| 2838 | using Alloc = CountingAllocator<int>; |
| 2839 | using Set = absl::btree_set<int, std::less<int>, Alloc>; |
| 2840 | int64_t bytes_used1 = 0; |
| 2841 | Alloc alloc1(&bytes_used1); |
| 2842 | Set set1(alloc1); |
| 2843 | |
| 2844 | set1.insert({1, 2, 3}); |
| 2845 | |
| 2846 | int64_t bytes_used2 = 0; |
| 2847 | Alloc alloc2(&bytes_used2); |
| 2848 | Set set2(set1, alloc2); |
| 2849 | |
| 2850 | EXPECT_THAT(set1, ElementsAre(1, 2, 3)); |
| 2851 | EXPECT_THAT(set2, ElementsAre(1, 2, 3)); |
| 2852 | EXPECT_GT(bytes_used1, set1.size() * sizeof(int)); |
| 2853 | EXPECT_EQ(bytes_used1, bytes_used2); |
| 2854 | } |
| 2855 | |
| 2856 | TEST(Btree, AllocMoveConstructor_SameAlloc) { |
| 2857 | using Alloc = CountingAllocator<int>; |
| 2858 | using Set = absl::btree_set<int, std::less<int>, Alloc>; |
| 2859 | int64_t bytes_used = 0; |
| 2860 | Alloc alloc(&bytes_used); |
| 2861 | Set set1(alloc); |
| 2862 | |
| 2863 | set1.insert({1, 2, 3}); |
| 2864 | |
| 2865 | const int64_t original_bytes_used = bytes_used; |
| 2866 | EXPECT_GT(original_bytes_used, set1.size() * sizeof(int)); |
| 2867 | |
| 2868 | Set set2(std::move(set1), alloc); |
| 2869 | |
| 2870 | EXPECT_THAT(set2, ElementsAre(1, 2, 3)); |
| 2871 | EXPECT_EQ(bytes_used, original_bytes_used); |
| 2872 | } |
| 2873 | |
| 2874 | TEST(Btree, AllocMoveConstructor_DifferentAlloc) { |
| 2875 | using Alloc = CountingAllocator<int>; |
| 2876 | using Set = absl::btree_set<int, std::less<int>, Alloc>; |
| 2877 | int64_t bytes_used1 = 0; |
| 2878 | Alloc alloc1(&bytes_used1); |
| 2879 | Set set1(alloc1); |
| 2880 | |
| 2881 | set1.insert({1, 2, 3}); |
| 2882 | |
| 2883 | const int64_t original_bytes_used = bytes_used1; |
| 2884 | EXPECT_GT(original_bytes_used, set1.size() * sizeof(int)); |
| 2885 | |
| 2886 | int64_t bytes_used2 = 0; |
| 2887 | Alloc alloc2(&bytes_used2); |
| 2888 | Set set2(std::move(set1), alloc2); |
| 2889 | |
| 2890 | EXPECT_THAT(set2, ElementsAre(1, 2, 3)); |
| 2891 | // We didn't free these bytes allocated by `set1` yet. |
| 2892 | EXPECT_EQ(bytes_used1, original_bytes_used); |
| 2893 | EXPECT_EQ(bytes_used2, original_bytes_used); |
| 2894 | } |
| 2895 | |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 2896 | } // namespace |
| 2897 | } // namespace container_internal |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 2898 | ABSL_NAMESPACE_END |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 2899 | } // namespace absl |