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> |
| 18 | #include <map> |
| 19 | #include <memory> |
| 20 | #include <stdexcept> |
| 21 | #include <string> |
| 22 | #include <type_traits> |
| 23 | #include <utility> |
| 24 | |
| 25 | #include "gmock/gmock.h" |
| 26 | #include "gtest/gtest.h" |
| 27 | #include "absl/base/internal/raw_logging.h" |
| 28 | #include "absl/base/macros.h" |
| 29 | #include "absl/container/btree_map.h" |
| 30 | #include "absl/container/btree_set.h" |
| 31 | #include "absl/container/internal/counting_allocator.h" |
| 32 | #include "absl/container/internal/test_instance_tracker.h" |
| 33 | #include "absl/flags/flag.h" |
| 34 | #include "absl/hash/hash_testing.h" |
| 35 | #include "absl/memory/memory.h" |
| 36 | #include "absl/meta/type_traits.h" |
| 37 | #include "absl/strings/str_cat.h" |
| 38 | #include "absl/strings/str_split.h" |
| 39 | #include "absl/strings/string_view.h" |
| 40 | #include "absl/types/compare.h" |
| 41 | |
| 42 | ABSL_FLAG(int, test_values, 10000, "The number of values to use for tests"); |
| 43 | |
| 44 | namespace absl { |
| 45 | namespace container_internal { |
| 46 | namespace { |
| 47 | |
| 48 | using ::absl::test_internal::InstanceTracker; |
| 49 | using ::absl::test_internal::MovableOnlyInstance; |
| 50 | using ::testing::ElementsAre; |
| 51 | using ::testing::ElementsAreArray; |
| 52 | using ::testing::Pair; |
| 53 | |
| 54 | template <typename T, typename U> |
| 55 | void CheckPairEquals(const T &x, const U &y) { |
| 56 | ABSL_INTERNAL_CHECK(x == y, "Values are unequal."); |
| 57 | } |
| 58 | |
| 59 | template <typename T, typename U, typename V, typename W> |
| 60 | void CheckPairEquals(const std::pair<T, U> &x, const std::pair<V, W> &y) { |
| 61 | CheckPairEquals(x.first, y.first); |
| 62 | CheckPairEquals(x.second, y.second); |
| 63 | } |
| 64 | } // namespace |
| 65 | |
| 66 | // The base class for a sorted associative container checker. TreeType is the |
| 67 | // container type to check and CheckerType is the container type to check |
| 68 | // against. TreeType is expected to be btree_{set,map,multiset,multimap} and |
| 69 | // CheckerType is expected to be {set,map,multiset,multimap}. |
| 70 | template <typename TreeType, typename CheckerType> |
| 71 | class base_checker { |
| 72 | public: |
| 73 | using key_type = typename TreeType::key_type; |
| 74 | using value_type = typename TreeType::value_type; |
| 75 | using key_compare = typename TreeType::key_compare; |
| 76 | using pointer = typename TreeType::pointer; |
| 77 | using const_pointer = typename TreeType::const_pointer; |
| 78 | using reference = typename TreeType::reference; |
| 79 | using const_reference = typename TreeType::const_reference; |
| 80 | using size_type = typename TreeType::size_type; |
| 81 | using difference_type = typename TreeType::difference_type; |
| 82 | using iterator = typename TreeType::iterator; |
| 83 | using const_iterator = typename TreeType::const_iterator; |
| 84 | using reverse_iterator = typename TreeType::reverse_iterator; |
| 85 | using const_reverse_iterator = typename TreeType::const_reverse_iterator; |
| 86 | |
| 87 | public: |
| 88 | base_checker() : const_tree_(tree_) {} |
| 89 | base_checker(const base_checker &x) |
| 90 | : tree_(x.tree_), const_tree_(tree_), checker_(x.checker_) {} |
| 91 | template <typename InputIterator> |
| 92 | base_checker(InputIterator b, InputIterator e) |
| 93 | : tree_(b, e), const_tree_(tree_), checker_(b, e) {} |
| 94 | |
| 95 | iterator begin() { return tree_.begin(); } |
| 96 | const_iterator begin() const { return tree_.begin(); } |
| 97 | iterator end() { return tree_.end(); } |
| 98 | const_iterator end() const { return tree_.end(); } |
| 99 | reverse_iterator rbegin() { return tree_.rbegin(); } |
| 100 | const_reverse_iterator rbegin() const { return tree_.rbegin(); } |
| 101 | reverse_iterator rend() { return tree_.rend(); } |
| 102 | const_reverse_iterator rend() const { return tree_.rend(); } |
| 103 | |
| 104 | template <typename IterType, typename CheckerIterType> |
| 105 | IterType iter_check(IterType tree_iter, CheckerIterType checker_iter) const { |
| 106 | if (tree_iter == tree_.end()) { |
| 107 | ABSL_INTERNAL_CHECK(checker_iter == checker_.end(), |
| 108 | "Checker iterator not at end."); |
| 109 | } else { |
| 110 | CheckPairEquals(*tree_iter, *checker_iter); |
| 111 | } |
| 112 | return tree_iter; |
| 113 | } |
| 114 | template <typename IterType, typename CheckerIterType> |
| 115 | IterType riter_check(IterType tree_iter, CheckerIterType checker_iter) const { |
| 116 | if (tree_iter == tree_.rend()) { |
| 117 | ABSL_INTERNAL_CHECK(checker_iter == checker_.rend(), |
| 118 | "Checker iterator not at rend."); |
| 119 | } else { |
| 120 | CheckPairEquals(*tree_iter, *checker_iter); |
| 121 | } |
| 122 | return tree_iter; |
| 123 | } |
| 124 | void value_check(const value_type &x) { |
| 125 | typename KeyOfValue<typename TreeType::key_type, |
| 126 | typename TreeType::value_type>::type key_of_value; |
| 127 | const key_type &key = key_of_value(x); |
| 128 | CheckPairEquals(*find(key), x); |
| 129 | lower_bound(key); |
| 130 | upper_bound(key); |
| 131 | equal_range(key); |
| 132 | contains(key); |
| 133 | count(key); |
| 134 | } |
| 135 | void erase_check(const key_type &key) { |
| 136 | EXPECT_FALSE(tree_.contains(key)); |
| 137 | EXPECT_EQ(tree_.find(key), const_tree_.end()); |
| 138 | EXPECT_FALSE(const_tree_.contains(key)); |
| 139 | EXPECT_EQ(const_tree_.find(key), tree_.end()); |
| 140 | EXPECT_EQ(tree_.equal_range(key).first, |
| 141 | const_tree_.equal_range(key).second); |
| 142 | } |
| 143 | |
| 144 | iterator lower_bound(const key_type &key) { |
| 145 | return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); |
| 146 | } |
| 147 | const_iterator lower_bound(const key_type &key) const { |
| 148 | return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); |
| 149 | } |
| 150 | iterator upper_bound(const key_type &key) { |
| 151 | return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); |
| 152 | } |
| 153 | const_iterator upper_bound(const key_type &key) const { |
| 154 | return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); |
| 155 | } |
| 156 | std::pair<iterator, iterator> equal_range(const key_type &key) { |
| 157 | std::pair<typename CheckerType::iterator, typename CheckerType::iterator> |
| 158 | checker_res = checker_.equal_range(key); |
| 159 | std::pair<iterator, iterator> tree_res = tree_.equal_range(key); |
| 160 | iter_check(tree_res.first, checker_res.first); |
| 161 | iter_check(tree_res.second, checker_res.second); |
| 162 | return tree_res; |
| 163 | } |
| 164 | std::pair<const_iterator, const_iterator> equal_range( |
| 165 | const key_type &key) const { |
| 166 | std::pair<typename CheckerType::const_iterator, |
| 167 | typename CheckerType::const_iterator> |
| 168 | checker_res = checker_.equal_range(key); |
| 169 | std::pair<const_iterator, const_iterator> tree_res = tree_.equal_range(key); |
| 170 | iter_check(tree_res.first, checker_res.first); |
| 171 | iter_check(tree_res.second, checker_res.second); |
| 172 | return tree_res; |
| 173 | } |
| 174 | iterator find(const key_type &key) { |
| 175 | return iter_check(tree_.find(key), checker_.find(key)); |
| 176 | } |
| 177 | const_iterator find(const key_type &key) const { |
| 178 | return iter_check(tree_.find(key), checker_.find(key)); |
| 179 | } |
| 180 | bool contains(const key_type &key) const { |
| 181 | return find(key) != end(); |
| 182 | } |
| 183 | size_type count(const key_type &key) const { |
| 184 | size_type res = checker_.count(key); |
| 185 | EXPECT_EQ(res, tree_.count(key)); |
| 186 | return res; |
| 187 | } |
| 188 | |
| 189 | base_checker &operator=(const base_checker &x) { |
| 190 | tree_ = x.tree_; |
| 191 | checker_ = x.checker_; |
| 192 | return *this; |
| 193 | } |
| 194 | |
| 195 | int erase(const key_type &key) { |
| 196 | int size = tree_.size(); |
| 197 | int res = checker_.erase(key); |
| 198 | EXPECT_EQ(res, tree_.count(key)); |
| 199 | EXPECT_EQ(res, tree_.erase(key)); |
| 200 | EXPECT_EQ(tree_.count(key), 0); |
| 201 | EXPECT_EQ(tree_.size(), size - res); |
| 202 | erase_check(key); |
| 203 | return res; |
| 204 | } |
| 205 | iterator erase(iterator iter) { |
| 206 | key_type key = iter.key(); |
| 207 | int size = tree_.size(); |
| 208 | int count = tree_.count(key); |
| 209 | auto checker_iter = checker_.lower_bound(key); |
| 210 | for (iterator tmp(tree_.lower_bound(key)); tmp != iter; ++tmp) { |
| 211 | ++checker_iter; |
| 212 | } |
| 213 | auto checker_next = checker_iter; |
| 214 | ++checker_next; |
| 215 | checker_.erase(checker_iter); |
| 216 | iter = tree_.erase(iter); |
| 217 | EXPECT_EQ(tree_.size(), checker_.size()); |
| 218 | EXPECT_EQ(tree_.size(), size - 1); |
| 219 | EXPECT_EQ(tree_.count(key), count - 1); |
| 220 | if (count == 1) { |
| 221 | erase_check(key); |
| 222 | } |
| 223 | return iter_check(iter, checker_next); |
| 224 | } |
| 225 | |
| 226 | void erase(iterator begin, iterator end) { |
| 227 | int size = tree_.size(); |
| 228 | int count = std::distance(begin, end); |
| 229 | auto checker_begin = checker_.lower_bound(begin.key()); |
| 230 | for (iterator tmp(tree_.lower_bound(begin.key())); tmp != begin; ++tmp) { |
| 231 | ++checker_begin; |
| 232 | } |
| 233 | auto checker_end = |
| 234 | end == tree_.end() ? checker_.end() : checker_.lower_bound(end.key()); |
| 235 | if (end != tree_.end()) { |
| 236 | for (iterator tmp(tree_.lower_bound(end.key())); tmp != end; ++tmp) { |
| 237 | ++checker_end; |
| 238 | } |
| 239 | } |
| 240 | checker_.erase(checker_begin, checker_end); |
| 241 | tree_.erase(begin, end); |
| 242 | EXPECT_EQ(tree_.size(), checker_.size()); |
| 243 | EXPECT_EQ(tree_.size(), size - count); |
| 244 | } |
| 245 | |
| 246 | void clear() { |
| 247 | tree_.clear(); |
| 248 | checker_.clear(); |
| 249 | } |
| 250 | void swap(base_checker &x) { |
| 251 | tree_.swap(x.tree_); |
| 252 | checker_.swap(x.checker_); |
| 253 | } |
| 254 | |
| 255 | void verify() const { |
| 256 | tree_.verify(); |
| 257 | EXPECT_EQ(tree_.size(), checker_.size()); |
| 258 | |
| 259 | // Move through the forward iterators using increment. |
| 260 | auto checker_iter = checker_.begin(); |
| 261 | const_iterator tree_iter(tree_.begin()); |
| 262 | for (; tree_iter != tree_.end(); ++tree_iter, ++checker_iter) { |
| 263 | CheckPairEquals(*tree_iter, *checker_iter); |
| 264 | } |
| 265 | |
| 266 | // Move through the forward iterators using decrement. |
| 267 | for (int n = tree_.size() - 1; n >= 0; --n) { |
| 268 | iter_check(tree_iter, checker_iter); |
| 269 | --tree_iter; |
| 270 | --checker_iter; |
| 271 | } |
| 272 | EXPECT_EQ(tree_iter, tree_.begin()); |
| 273 | EXPECT_EQ(checker_iter, checker_.begin()); |
| 274 | |
| 275 | // Move through the reverse iterators using increment. |
| 276 | auto checker_riter = checker_.rbegin(); |
| 277 | const_reverse_iterator tree_riter(tree_.rbegin()); |
| 278 | for (; tree_riter != tree_.rend(); ++tree_riter, ++checker_riter) { |
| 279 | CheckPairEquals(*tree_riter, *checker_riter); |
| 280 | } |
| 281 | |
| 282 | // Move through the reverse iterators using decrement. |
| 283 | for (int n = tree_.size() - 1; n >= 0; --n) { |
| 284 | riter_check(tree_riter, checker_riter); |
| 285 | --tree_riter; |
| 286 | --checker_riter; |
| 287 | } |
| 288 | EXPECT_EQ(tree_riter, tree_.rbegin()); |
| 289 | EXPECT_EQ(checker_riter, checker_.rbegin()); |
| 290 | } |
| 291 | |
| 292 | const TreeType &tree() const { return tree_; } |
| 293 | |
| 294 | size_type size() const { |
| 295 | EXPECT_EQ(tree_.size(), checker_.size()); |
| 296 | return tree_.size(); |
| 297 | } |
| 298 | size_type max_size() const { return tree_.max_size(); } |
| 299 | bool empty() const { |
| 300 | EXPECT_EQ(tree_.empty(), checker_.empty()); |
| 301 | return tree_.empty(); |
| 302 | } |
| 303 | |
| 304 | protected: |
| 305 | TreeType tree_; |
| 306 | const TreeType &const_tree_; |
| 307 | CheckerType checker_; |
| 308 | }; |
| 309 | |
| 310 | namespace { |
| 311 | // A checker for unique sorted associative containers. TreeType is expected to |
| 312 | // be btree_{set,map} and CheckerType is expected to be {set,map}. |
| 313 | template <typename TreeType, typename CheckerType> |
| 314 | class unique_checker : public base_checker<TreeType, CheckerType> { |
| 315 | using super_type = base_checker<TreeType, CheckerType>; |
| 316 | |
| 317 | public: |
| 318 | using iterator = typename super_type::iterator; |
| 319 | using value_type = typename super_type::value_type; |
| 320 | |
| 321 | public: |
| 322 | unique_checker() : super_type() {} |
| 323 | unique_checker(const unique_checker &x) : super_type(x) {} |
| 324 | template <class InputIterator> |
| 325 | unique_checker(InputIterator b, InputIterator e) : super_type(b, e) {} |
| 326 | unique_checker& operator=(const unique_checker&) = default; |
| 327 | |
| 328 | // Insertion routines. |
| 329 | std::pair<iterator, bool> insert(const value_type &x) { |
| 330 | int size = this->tree_.size(); |
| 331 | std::pair<typename CheckerType::iterator, bool> checker_res = |
| 332 | this->checker_.insert(x); |
| 333 | std::pair<iterator, bool> tree_res = this->tree_.insert(x); |
| 334 | CheckPairEquals(*tree_res.first, *checker_res.first); |
| 335 | EXPECT_EQ(tree_res.second, checker_res.second); |
| 336 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); |
| 337 | EXPECT_EQ(this->tree_.size(), size + tree_res.second); |
| 338 | return tree_res; |
| 339 | } |
| 340 | iterator insert(iterator position, const value_type &x) { |
| 341 | int size = this->tree_.size(); |
| 342 | std::pair<typename CheckerType::iterator, bool> checker_res = |
| 343 | this->checker_.insert(x); |
| 344 | iterator tree_res = this->tree_.insert(position, x); |
| 345 | CheckPairEquals(*tree_res, *checker_res.first); |
| 346 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); |
| 347 | EXPECT_EQ(this->tree_.size(), size + checker_res.second); |
| 348 | return tree_res; |
| 349 | } |
| 350 | template <typename InputIterator> |
| 351 | void insert(InputIterator b, InputIterator e) { |
| 352 | for (; b != e; ++b) { |
| 353 | insert(*b); |
| 354 | } |
| 355 | } |
| 356 | }; |
| 357 | |
| 358 | // A checker for multiple sorted associative containers. TreeType is expected |
| 359 | // to be btree_{multiset,multimap} and CheckerType is expected to be |
| 360 | // {multiset,multimap}. |
| 361 | template <typename TreeType, typename CheckerType> |
| 362 | class multi_checker : public base_checker<TreeType, CheckerType> { |
| 363 | using super_type = base_checker<TreeType, CheckerType>; |
| 364 | |
| 365 | public: |
| 366 | using iterator = typename super_type::iterator; |
| 367 | using value_type = typename super_type::value_type; |
| 368 | |
| 369 | public: |
| 370 | multi_checker() : super_type() {} |
| 371 | multi_checker(const multi_checker &x) : super_type(x) {} |
| 372 | template <class InputIterator> |
| 373 | multi_checker(InputIterator b, InputIterator e) : super_type(b, e) {} |
| 374 | multi_checker& operator=(const multi_checker&) = default; |
| 375 | |
| 376 | // Insertion routines. |
| 377 | iterator insert(const value_type &x) { |
| 378 | int size = this->tree_.size(); |
| 379 | auto checker_res = this->checker_.insert(x); |
| 380 | iterator tree_res = this->tree_.insert(x); |
| 381 | CheckPairEquals(*tree_res, *checker_res); |
| 382 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); |
| 383 | EXPECT_EQ(this->tree_.size(), size + 1); |
| 384 | return tree_res; |
| 385 | } |
| 386 | iterator insert(iterator position, const value_type &x) { |
| 387 | int size = this->tree_.size(); |
| 388 | auto checker_res = this->checker_.insert(x); |
| 389 | iterator tree_res = this->tree_.insert(position, x); |
| 390 | CheckPairEquals(*tree_res, *checker_res); |
| 391 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); |
| 392 | EXPECT_EQ(this->tree_.size(), size + 1); |
| 393 | return tree_res; |
| 394 | } |
| 395 | template <typename InputIterator> |
| 396 | void insert(InputIterator b, InputIterator e) { |
| 397 | for (; b != e; ++b) { |
| 398 | insert(*b); |
| 399 | } |
| 400 | } |
| 401 | }; |
| 402 | |
| 403 | template <typename T, typename V> |
| 404 | void DoTest(const char *name, T *b, const std::vector<V> &values) { |
| 405 | typename KeyOfValue<typename T::key_type, V>::type key_of_value; |
| 406 | |
| 407 | T &mutable_b = *b; |
| 408 | const T &const_b = *b; |
| 409 | |
| 410 | // Test insert. |
| 411 | for (int i = 0; i < values.size(); ++i) { |
| 412 | mutable_b.insert(values[i]); |
| 413 | mutable_b.value_check(values[i]); |
| 414 | } |
| 415 | ASSERT_EQ(mutable_b.size(), values.size()); |
| 416 | |
| 417 | const_b.verify(); |
| 418 | |
| 419 | // Test copy constructor. |
| 420 | T b_copy(const_b); |
| 421 | EXPECT_EQ(b_copy.size(), const_b.size()); |
| 422 | for (int i = 0; i < values.size(); ++i) { |
| 423 | CheckPairEquals(*b_copy.find(key_of_value(values[i])), values[i]); |
| 424 | } |
| 425 | |
| 426 | // Test range constructor. |
| 427 | T b_range(const_b.begin(), const_b.end()); |
| 428 | EXPECT_EQ(b_range.size(), const_b.size()); |
| 429 | for (int i = 0; i < values.size(); ++i) { |
| 430 | CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); |
| 431 | } |
| 432 | |
| 433 | // Test range insertion for values that already exist. |
| 434 | b_range.insert(b_copy.begin(), b_copy.end()); |
| 435 | b_range.verify(); |
| 436 | |
| 437 | // Test range insertion for new values. |
| 438 | b_range.clear(); |
| 439 | b_range.insert(b_copy.begin(), b_copy.end()); |
| 440 | EXPECT_EQ(b_range.size(), b_copy.size()); |
| 441 | for (int i = 0; i < values.size(); ++i) { |
| 442 | CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); |
| 443 | } |
| 444 | |
| 445 | // Test assignment to self. Nothing should change. |
| 446 | b_range.operator=(b_range); |
| 447 | EXPECT_EQ(b_range.size(), b_copy.size()); |
| 448 | |
| 449 | // Test assignment of new values. |
| 450 | b_range.clear(); |
| 451 | b_range = b_copy; |
| 452 | EXPECT_EQ(b_range.size(), b_copy.size()); |
| 453 | |
| 454 | // Test swap. |
| 455 | b_range.clear(); |
| 456 | b_range.swap(b_copy); |
| 457 | EXPECT_EQ(b_copy.size(), 0); |
| 458 | EXPECT_EQ(b_range.size(), const_b.size()); |
| 459 | for (int i = 0; i < values.size(); ++i) { |
| 460 | CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); |
| 461 | } |
| 462 | b_range.swap(b_copy); |
| 463 | |
| 464 | // Test non-member function swap. |
| 465 | swap(b_range, b_copy); |
| 466 | EXPECT_EQ(b_copy.size(), 0); |
| 467 | EXPECT_EQ(b_range.size(), const_b.size()); |
| 468 | for (int i = 0; i < values.size(); ++i) { |
| 469 | CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); |
| 470 | } |
| 471 | swap(b_range, b_copy); |
| 472 | |
| 473 | // Test erase via values. |
| 474 | for (int i = 0; i < values.size(); ++i) { |
| 475 | mutable_b.erase(key_of_value(values[i])); |
| 476 | // Erasing a non-existent key should have no effect. |
| 477 | ASSERT_EQ(mutable_b.erase(key_of_value(values[i])), 0); |
| 478 | } |
| 479 | |
| 480 | const_b.verify(); |
| 481 | EXPECT_EQ(const_b.size(), 0); |
| 482 | |
| 483 | // Test erase via iterators. |
| 484 | mutable_b = b_copy; |
| 485 | for (int i = 0; i < values.size(); ++i) { |
| 486 | mutable_b.erase(mutable_b.find(key_of_value(values[i]))); |
| 487 | } |
| 488 | |
| 489 | const_b.verify(); |
| 490 | EXPECT_EQ(const_b.size(), 0); |
| 491 | |
| 492 | // Test insert with hint. |
| 493 | for (int i = 0; i < values.size(); i++) { |
| 494 | mutable_b.insert(mutable_b.upper_bound(key_of_value(values[i])), values[i]); |
| 495 | } |
| 496 | |
| 497 | const_b.verify(); |
| 498 | |
| 499 | // Test range erase. |
| 500 | mutable_b.erase(mutable_b.begin(), mutable_b.end()); |
| 501 | EXPECT_EQ(mutable_b.size(), 0); |
| 502 | const_b.verify(); |
| 503 | |
| 504 | // First half. |
| 505 | mutable_b = b_copy; |
| 506 | typename T::iterator mutable_iter_end = mutable_b.begin(); |
| 507 | for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end; |
| 508 | mutable_b.erase(mutable_b.begin(), mutable_iter_end); |
| 509 | EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2); |
| 510 | const_b.verify(); |
| 511 | |
| 512 | // Second half. |
| 513 | mutable_b = b_copy; |
| 514 | typename T::iterator mutable_iter_begin = mutable_b.begin(); |
| 515 | for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin; |
| 516 | mutable_b.erase(mutable_iter_begin, mutable_b.end()); |
| 517 | EXPECT_EQ(mutable_b.size(), values.size() / 2); |
| 518 | const_b.verify(); |
| 519 | |
| 520 | // Second quarter. |
| 521 | mutable_b = b_copy; |
| 522 | mutable_iter_begin = mutable_b.begin(); |
| 523 | for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_begin; |
| 524 | mutable_iter_end = mutable_iter_begin; |
| 525 | for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end; |
| 526 | mutable_b.erase(mutable_iter_begin, mutable_iter_end); |
| 527 | EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4); |
| 528 | const_b.verify(); |
| 529 | |
| 530 | mutable_b.clear(); |
| 531 | } |
| 532 | |
| 533 | template <typename T> |
| 534 | void ConstTest() { |
| 535 | using value_type = typename T::value_type; |
| 536 | typename KeyOfValue<typename T::key_type, value_type>::type key_of_value; |
| 537 | |
| 538 | T mutable_b; |
| 539 | const T &const_b = mutable_b; |
| 540 | |
| 541 | // Insert a single value into the container and test looking it up. |
| 542 | value_type value = Generator<value_type>(2)(2); |
| 543 | mutable_b.insert(value); |
| 544 | EXPECT_TRUE(mutable_b.contains(key_of_value(value))); |
| 545 | EXPECT_NE(mutable_b.find(key_of_value(value)), const_b.end()); |
| 546 | EXPECT_TRUE(const_b.contains(key_of_value(value))); |
| 547 | EXPECT_NE(const_b.find(key_of_value(value)), mutable_b.end()); |
| 548 | EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value); |
| 549 | EXPECT_EQ(const_b.upper_bound(key_of_value(value)), const_b.end()); |
| 550 | EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value); |
| 551 | |
| 552 | // We can only create a non-const iterator from a non-const container. |
| 553 | typename T::iterator mutable_iter(mutable_b.begin()); |
| 554 | EXPECT_EQ(mutable_iter, const_b.begin()); |
| 555 | EXPECT_NE(mutable_iter, const_b.end()); |
| 556 | EXPECT_EQ(const_b.begin(), mutable_iter); |
| 557 | EXPECT_NE(const_b.end(), mutable_iter); |
| 558 | typename T::reverse_iterator mutable_riter(mutable_b.rbegin()); |
| 559 | EXPECT_EQ(mutable_riter, const_b.rbegin()); |
| 560 | EXPECT_NE(mutable_riter, const_b.rend()); |
| 561 | EXPECT_EQ(const_b.rbegin(), mutable_riter); |
| 562 | EXPECT_NE(const_b.rend(), mutable_riter); |
| 563 | |
| 564 | // We can create a const iterator from a non-const iterator. |
| 565 | typename T::const_iterator const_iter(mutable_iter); |
| 566 | EXPECT_EQ(const_iter, mutable_b.begin()); |
| 567 | EXPECT_NE(const_iter, mutable_b.end()); |
| 568 | EXPECT_EQ(mutable_b.begin(), const_iter); |
| 569 | EXPECT_NE(mutable_b.end(), const_iter); |
| 570 | typename T::const_reverse_iterator const_riter(mutable_riter); |
| 571 | EXPECT_EQ(const_riter, mutable_b.rbegin()); |
| 572 | EXPECT_NE(const_riter, mutable_b.rend()); |
| 573 | EXPECT_EQ(mutable_b.rbegin(), const_riter); |
| 574 | EXPECT_NE(mutable_b.rend(), const_riter); |
| 575 | |
| 576 | // Make sure various methods can be invoked on a const container. |
| 577 | const_b.verify(); |
| 578 | ASSERT_TRUE(!const_b.empty()); |
| 579 | EXPECT_EQ(const_b.size(), 1); |
| 580 | EXPECT_GT(const_b.max_size(), 0); |
| 581 | EXPECT_TRUE(const_b.contains(key_of_value(value))); |
| 582 | EXPECT_EQ(const_b.count(key_of_value(value)), 1); |
| 583 | } |
| 584 | |
| 585 | template <typename T, typename C> |
| 586 | void BtreeTest() { |
| 587 | ConstTest<T>(); |
| 588 | |
| 589 | using V = typename remove_pair_const<typename T::value_type>::type; |
| 590 | const std::vector<V> random_values = GenerateValuesWithSeed<V>( |
| 591 | absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), |
| 592 | testing::GTEST_FLAG(random_seed)); |
| 593 | |
| 594 | unique_checker<T, C> container; |
| 595 | |
| 596 | // Test key insertion/deletion in sorted order. |
| 597 | std::vector<V> sorted_values(random_values); |
| 598 | std::sort(sorted_values.begin(), sorted_values.end()); |
| 599 | DoTest("sorted: ", &container, sorted_values); |
| 600 | |
| 601 | // Test key insertion/deletion in reverse sorted order. |
| 602 | std::reverse(sorted_values.begin(), sorted_values.end()); |
| 603 | DoTest("rsorted: ", &container, sorted_values); |
| 604 | |
| 605 | // Test key insertion/deletion in random order. |
| 606 | DoTest("random: ", &container, random_values); |
| 607 | } |
| 608 | |
| 609 | template <typename T, typename C> |
| 610 | void BtreeMultiTest() { |
| 611 | ConstTest<T>(); |
| 612 | |
| 613 | using V = typename remove_pair_const<typename T::value_type>::type; |
| 614 | const std::vector<V> random_values = GenerateValuesWithSeed<V>( |
| 615 | absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), |
| 616 | testing::GTEST_FLAG(random_seed)); |
| 617 | |
| 618 | multi_checker<T, C> container; |
| 619 | |
| 620 | // Test keys in sorted order. |
| 621 | std::vector<V> sorted_values(random_values); |
| 622 | std::sort(sorted_values.begin(), sorted_values.end()); |
| 623 | DoTest("sorted: ", &container, sorted_values); |
| 624 | |
| 625 | // Test keys in reverse sorted order. |
| 626 | std::reverse(sorted_values.begin(), sorted_values.end()); |
| 627 | DoTest("rsorted: ", &container, sorted_values); |
| 628 | |
| 629 | // Test keys in random order. |
| 630 | DoTest("random: ", &container, random_values); |
| 631 | |
| 632 | // Test keys in random order w/ duplicates. |
| 633 | std::vector<V> duplicate_values(random_values); |
| 634 | duplicate_values.insert(duplicate_values.end(), random_values.begin(), |
| 635 | random_values.end()); |
| 636 | DoTest("duplicates:", &container, duplicate_values); |
| 637 | |
| 638 | // Test all identical keys. |
| 639 | std::vector<V> identical_values(100); |
| 640 | std::fill(identical_values.begin(), identical_values.end(), |
| 641 | Generator<V>(2)(2)); |
| 642 | DoTest("identical: ", &container, identical_values); |
| 643 | } |
| 644 | |
| 645 | template <typename T> |
| 646 | struct PropagatingCountingAlloc : public CountingAllocator<T> { |
| 647 | using propagate_on_container_copy_assignment = std::true_type; |
| 648 | using propagate_on_container_move_assignment = std::true_type; |
| 649 | using propagate_on_container_swap = std::true_type; |
| 650 | |
| 651 | using Base = CountingAllocator<T>; |
| 652 | using Base::Base; |
| 653 | |
| 654 | template <typename U> |
| 655 | explicit PropagatingCountingAlloc(const PropagatingCountingAlloc<U> &other) |
| 656 | : Base(other.bytes_used_) {} |
| 657 | |
| 658 | template <typename U> |
| 659 | struct rebind { |
| 660 | using other = PropagatingCountingAlloc<U>; |
| 661 | }; |
| 662 | }; |
| 663 | |
| 664 | template <typename T> |
| 665 | void BtreeAllocatorTest() { |
| 666 | using value_type = typename T::value_type; |
| 667 | |
| 668 | int64_t bytes1 = 0, bytes2 = 0; |
| 669 | PropagatingCountingAlloc<T> allocator1(&bytes1); |
| 670 | PropagatingCountingAlloc<T> allocator2(&bytes2); |
| 671 | Generator<value_type> generator(1000); |
| 672 | |
| 673 | // Test that we allocate properly aligned memory. If we don't, then Layout |
| 674 | // will assert fail. |
| 675 | auto unused1 = allocator1.allocate(1); |
| 676 | auto unused2 = allocator2.allocate(1); |
| 677 | |
| 678 | // Test copy assignment |
| 679 | { |
| 680 | T b1(typename T::key_compare(), allocator1); |
| 681 | T b2(typename T::key_compare(), allocator2); |
| 682 | |
| 683 | int64_t original_bytes1 = bytes1; |
| 684 | b1.insert(generator(0)); |
| 685 | EXPECT_GT(bytes1, original_bytes1); |
| 686 | |
| 687 | // This should propagate the allocator. |
| 688 | b1 = b2; |
| 689 | EXPECT_EQ(b1.size(), 0); |
| 690 | EXPECT_EQ(b2.size(), 0); |
| 691 | EXPECT_EQ(bytes1, original_bytes1); |
| 692 | |
| 693 | for (int i = 1; i < 1000; i++) { |
| 694 | b1.insert(generator(i)); |
| 695 | } |
| 696 | |
| 697 | // We should have allocated out of allocator2. |
| 698 | EXPECT_GT(bytes2, bytes1); |
| 699 | } |
| 700 | |
| 701 | // Test move assignment |
| 702 | { |
| 703 | T b1(typename T::key_compare(), allocator1); |
| 704 | T b2(typename T::key_compare(), allocator2); |
| 705 | |
| 706 | int64_t original_bytes1 = bytes1; |
| 707 | b1.insert(generator(0)); |
| 708 | EXPECT_GT(bytes1, original_bytes1); |
| 709 | |
| 710 | // This should propagate the allocator. |
| 711 | b1 = std::move(b2); |
| 712 | EXPECT_EQ(b1.size(), 0); |
| 713 | EXPECT_EQ(bytes1, original_bytes1); |
| 714 | |
| 715 | for (int i = 1; i < 1000; i++) { |
| 716 | b1.insert(generator(i)); |
| 717 | } |
| 718 | |
| 719 | // We should have allocated out of allocator2. |
| 720 | EXPECT_GT(bytes2, bytes1); |
| 721 | } |
| 722 | |
| 723 | // Test swap |
| 724 | { |
| 725 | T b1(typename T::key_compare(), allocator1); |
| 726 | T b2(typename T::key_compare(), allocator2); |
| 727 | |
| 728 | int64_t original_bytes1 = bytes1; |
| 729 | b1.insert(generator(0)); |
| 730 | EXPECT_GT(bytes1, original_bytes1); |
| 731 | |
| 732 | // This should swap the allocators. |
| 733 | swap(b1, b2); |
| 734 | EXPECT_EQ(b1.size(), 0); |
| 735 | EXPECT_EQ(b2.size(), 1); |
| 736 | EXPECT_GT(bytes1, original_bytes1); |
| 737 | |
| 738 | for (int i = 1; i < 1000; i++) { |
| 739 | b1.insert(generator(i)); |
| 740 | } |
| 741 | |
| 742 | // We should have allocated out of allocator2. |
| 743 | EXPECT_GT(bytes2, bytes1); |
| 744 | } |
| 745 | |
| 746 | allocator1.deallocate(unused1, 1); |
| 747 | allocator2.deallocate(unused2, 1); |
| 748 | } |
| 749 | |
| 750 | template <typename T> |
| 751 | void BtreeMapTest() { |
| 752 | using value_type = typename T::value_type; |
| 753 | using mapped_type = typename T::mapped_type; |
| 754 | |
| 755 | mapped_type m = Generator<mapped_type>(0)(0); |
| 756 | (void)m; |
| 757 | |
| 758 | T b; |
| 759 | |
| 760 | // Verify we can insert using operator[]. |
| 761 | for (int i = 0; i < 1000; i++) { |
| 762 | value_type v = Generator<value_type>(1000)(i); |
| 763 | b[v.first] = v.second; |
| 764 | } |
| 765 | EXPECT_EQ(b.size(), 1000); |
| 766 | |
| 767 | // Test whether we can use the "->" operator on iterators and |
| 768 | // reverse_iterators. This stresses the btree_map_params::pair_pointer |
| 769 | // mechanism. |
| 770 | EXPECT_EQ(b.begin()->first, Generator<value_type>(1000)(0).first); |
| 771 | EXPECT_EQ(b.begin()->second, Generator<value_type>(1000)(0).second); |
| 772 | EXPECT_EQ(b.rbegin()->first, Generator<value_type>(1000)(999).first); |
| 773 | EXPECT_EQ(b.rbegin()->second, Generator<value_type>(1000)(999).second); |
| 774 | } |
| 775 | |
| 776 | template <typename T> |
| 777 | void BtreeMultiMapTest() { |
| 778 | using mapped_type = typename T::mapped_type; |
| 779 | mapped_type m = Generator<mapped_type>(0)(0); |
| 780 | (void)m; |
| 781 | } |
| 782 | |
| 783 | template <typename K, int N = 256> |
| 784 | void SetTest() { |
| 785 | EXPECT_EQ( |
| 786 | sizeof(absl::btree_set<K>), |
| 787 | 2 * sizeof(void *) + sizeof(typename absl::btree_set<K>::size_type)); |
| 788 | using BtreeSet = absl::btree_set<K>; |
| 789 | using CountingBtreeSet = |
| 790 | absl::btree_set<K, std::less<K>, PropagatingCountingAlloc<K>>; |
| 791 | BtreeTest<BtreeSet, std::set<K>>(); |
| 792 | BtreeAllocatorTest<CountingBtreeSet>(); |
| 793 | } |
| 794 | |
| 795 | template <typename K, int N = 256> |
| 796 | void MapTest() { |
| 797 | EXPECT_EQ( |
| 798 | sizeof(absl::btree_map<K, K>), |
| 799 | 2 * sizeof(void *) + sizeof(typename absl::btree_map<K, K>::size_type)); |
| 800 | using BtreeMap = absl::btree_map<K, K>; |
| 801 | using CountingBtreeMap = |
| 802 | absl::btree_map<K, K, std::less<K>, |
| 803 | PropagatingCountingAlloc<std::pair<const K, K>>>; |
| 804 | BtreeTest<BtreeMap, std::map<K, K>>(); |
| 805 | BtreeAllocatorTest<CountingBtreeMap>(); |
| 806 | BtreeMapTest<BtreeMap>(); |
| 807 | } |
| 808 | |
| 809 | TEST(Btree, set_int32) { SetTest<int32_t>(); } |
| 810 | TEST(Btree, set_int64) { SetTest<int64_t>(); } |
| 811 | TEST(Btree, set_string) { SetTest<std::string>(); } |
| 812 | TEST(Btree, set_pair) { SetTest<std::pair<int, int>>(); } |
| 813 | TEST(Btree, map_int32) { MapTest<int32_t>(); } |
| 814 | TEST(Btree, map_int64) { MapTest<int64_t>(); } |
| 815 | TEST(Btree, map_string) { MapTest<std::string>(); } |
| 816 | TEST(Btree, map_pair) { MapTest<std::pair<int, int>>(); } |
| 817 | |
| 818 | template <typename K, int N = 256> |
| 819 | void MultiSetTest() { |
| 820 | EXPECT_EQ( |
| 821 | sizeof(absl::btree_multiset<K>), |
| 822 | 2 * sizeof(void *) + sizeof(typename absl::btree_multiset<K>::size_type)); |
| 823 | using BtreeMSet = absl::btree_multiset<K>; |
| 824 | using CountingBtreeMSet = |
| 825 | absl::btree_multiset<K, std::less<K>, PropagatingCountingAlloc<K>>; |
| 826 | BtreeMultiTest<BtreeMSet, std::multiset<K>>(); |
| 827 | BtreeAllocatorTest<CountingBtreeMSet>(); |
| 828 | } |
| 829 | |
| 830 | template <typename K, int N = 256> |
| 831 | void MultiMapTest() { |
| 832 | EXPECT_EQ(sizeof(absl::btree_multimap<K, K>), |
| 833 | 2 * sizeof(void *) + |
| 834 | sizeof(typename absl::btree_multimap<K, K>::size_type)); |
| 835 | using BtreeMMap = absl::btree_multimap<K, K>; |
| 836 | using CountingBtreeMMap = |
| 837 | absl::btree_multimap<K, K, std::less<K>, |
| 838 | PropagatingCountingAlloc<std::pair<const K, K>>>; |
| 839 | BtreeMultiTest<BtreeMMap, std::multimap<K, K>>(); |
| 840 | BtreeMultiMapTest<BtreeMMap>(); |
| 841 | BtreeAllocatorTest<CountingBtreeMMap>(); |
| 842 | } |
| 843 | |
| 844 | TEST(Btree, multiset_int32) { MultiSetTest<int32_t>(); } |
| 845 | TEST(Btree, multiset_int64) { MultiSetTest<int64_t>(); } |
| 846 | TEST(Btree, multiset_string) { MultiSetTest<std::string>(); } |
| 847 | TEST(Btree, multiset_pair) { MultiSetTest<std::pair<int, int>>(); } |
| 848 | TEST(Btree, multimap_int32) { MultiMapTest<int32_t>(); } |
| 849 | TEST(Btree, multimap_int64) { MultiMapTest<int64_t>(); } |
| 850 | TEST(Btree, multimap_string) { MultiMapTest<std::string>(); } |
| 851 | TEST(Btree, multimap_pair) { MultiMapTest<std::pair<int, int>>(); } |
| 852 | |
| 853 | struct CompareIntToString { |
| 854 | bool operator()(const std::string &a, const std::string &b) const { |
| 855 | return a < b; |
| 856 | } |
| 857 | bool operator()(const std::string &a, int b) const { |
| 858 | return a < absl::StrCat(b); |
| 859 | } |
| 860 | bool operator()(int a, const std::string &b) const { |
| 861 | return absl::StrCat(a) < b; |
| 862 | } |
| 863 | using is_transparent = void; |
| 864 | }; |
| 865 | |
| 866 | struct NonTransparentCompare { |
| 867 | template <typename T, typename U> |
| 868 | bool operator()(const T& t, const U& u) const { |
| 869 | // Treating all comparators as transparent can cause inefficiencies (see |
| 870 | // N3657 C++ proposal). Test that for comparators without 'is_transparent' |
| 871 | // alias (like this one), we do not attempt heterogeneous lookup. |
| 872 | EXPECT_TRUE((std::is_same<T, U>())); |
| 873 | return t < u; |
| 874 | } |
| 875 | }; |
| 876 | |
| 877 | template <typename T> |
| 878 | bool CanEraseWithEmptyBrace(T t, decltype(t.erase({})) *) { |
| 879 | return true; |
| 880 | } |
| 881 | |
| 882 | template <typename T> |
| 883 | bool CanEraseWithEmptyBrace(T, ...) { |
| 884 | return false; |
| 885 | } |
| 886 | |
| 887 | template <typename T> |
| 888 | void TestHeterogeneous(T table) { |
| 889 | auto lb = table.lower_bound("3"); |
| 890 | EXPECT_EQ(lb, table.lower_bound(3)); |
| 891 | EXPECT_NE(lb, table.lower_bound(4)); |
| 892 | EXPECT_EQ(lb, table.lower_bound({"3"})); |
| 893 | EXPECT_NE(lb, table.lower_bound({})); |
| 894 | |
| 895 | auto ub = table.upper_bound("3"); |
| 896 | EXPECT_EQ(ub, table.upper_bound(3)); |
| 897 | EXPECT_NE(ub, table.upper_bound(5)); |
| 898 | EXPECT_EQ(ub, table.upper_bound({"3"})); |
| 899 | EXPECT_NE(ub, table.upper_bound({})); |
| 900 | |
| 901 | auto er = table.equal_range("3"); |
| 902 | EXPECT_EQ(er, table.equal_range(3)); |
| 903 | EXPECT_NE(er, table.equal_range(4)); |
| 904 | EXPECT_EQ(er, table.equal_range({"3"})); |
| 905 | EXPECT_NE(er, table.equal_range({})); |
| 906 | |
| 907 | auto it = table.find("3"); |
| 908 | EXPECT_EQ(it, table.find(3)); |
| 909 | EXPECT_NE(it, table.find(4)); |
| 910 | EXPECT_EQ(it, table.find({"3"})); |
| 911 | EXPECT_NE(it, table.find({})); |
| 912 | |
| 913 | EXPECT_TRUE(table.contains(3)); |
| 914 | EXPECT_FALSE(table.contains(4)); |
| 915 | EXPECT_TRUE(table.count({"3"})); |
| 916 | EXPECT_FALSE(table.contains({})); |
| 917 | |
| 918 | EXPECT_EQ(1, table.count(3)); |
| 919 | EXPECT_EQ(0, table.count(4)); |
| 920 | EXPECT_EQ(1, table.count({"3"})); |
| 921 | EXPECT_EQ(0, table.count({})); |
| 922 | |
| 923 | auto copy = table; |
| 924 | copy.erase(3); |
| 925 | EXPECT_EQ(table.size() - 1, copy.size()); |
| 926 | copy.erase(4); |
| 927 | EXPECT_EQ(table.size() - 1, copy.size()); |
| 928 | copy.erase({"5"}); |
| 929 | EXPECT_EQ(table.size() - 2, copy.size()); |
| 930 | EXPECT_FALSE(CanEraseWithEmptyBrace(table, nullptr)); |
| 931 | |
| 932 | // Also run it with const T&. |
| 933 | if (std::is_class<T>()) TestHeterogeneous<const T &>(table); |
| 934 | } |
| 935 | |
| 936 | TEST(Btree, HeterogeneousLookup) { |
| 937 | TestHeterogeneous(btree_set<std::string, CompareIntToString>{"1", "3", "5"}); |
| 938 | TestHeterogeneous(btree_map<std::string, int, CompareIntToString>{ |
| 939 | {"1", 1}, {"3", 3}, {"5", 5}}); |
| 940 | TestHeterogeneous( |
| 941 | btree_multiset<std::string, CompareIntToString>{"1", "3", "5"}); |
| 942 | TestHeterogeneous(btree_multimap<std::string, int, CompareIntToString>{ |
| 943 | {"1", 1}, {"3", 3}, {"5", 5}}); |
| 944 | |
| 945 | // Only maps have .at() |
| 946 | btree_map<std::string, int, CompareIntToString> map{ |
| 947 | {"", -1}, {"1", 1}, {"3", 3}, {"5", 5}}; |
| 948 | EXPECT_EQ(1, map.at(1)); |
| 949 | EXPECT_EQ(3, map.at({"3"})); |
| 950 | EXPECT_EQ(-1, map.at({})); |
| 951 | const auto &cmap = map; |
| 952 | EXPECT_EQ(1, cmap.at(1)); |
| 953 | EXPECT_EQ(3, cmap.at({"3"})); |
| 954 | EXPECT_EQ(-1, cmap.at({})); |
| 955 | } |
| 956 | |
| 957 | TEST(Btree, NoHeterogeneousLookupWithoutAlias) { |
| 958 | using StringSet = absl::btree_set<std::string, NonTransparentCompare>; |
| 959 | StringSet s; |
| 960 | ASSERT_TRUE(s.insert("hello").second); |
| 961 | ASSERT_TRUE(s.insert("world").second); |
| 962 | EXPECT_TRUE(s.end() == s.find("blah")); |
| 963 | EXPECT_TRUE(s.begin() == s.lower_bound("hello")); |
| 964 | EXPECT_EQ(1, s.count("world")); |
| 965 | EXPECT_TRUE(s.contains("hello")); |
| 966 | EXPECT_TRUE(s.contains("world")); |
| 967 | EXPECT_FALSE(s.contains("blah")); |
| 968 | |
| 969 | using StringMultiSet = |
| 970 | absl::btree_multiset<std::string, NonTransparentCompare>; |
| 971 | StringMultiSet ms; |
| 972 | ms.insert("hello"); |
| 973 | ms.insert("world"); |
| 974 | ms.insert("world"); |
| 975 | EXPECT_TRUE(ms.end() == ms.find("blah")); |
| 976 | EXPECT_TRUE(ms.begin() == ms.lower_bound("hello")); |
| 977 | EXPECT_EQ(2, ms.count("world")); |
| 978 | EXPECT_TRUE(ms.contains("hello")); |
| 979 | EXPECT_TRUE(ms.contains("world")); |
| 980 | EXPECT_FALSE(ms.contains("blah")); |
| 981 | } |
| 982 | |
| 983 | TEST(Btree, DefaultTransparent) { |
| 984 | { |
| 985 | // `int` does not have a default transparent comparator. |
| 986 | // The input value is converted to key_type. |
| 987 | btree_set<int> s = {1}; |
| 988 | double d = 1.1; |
| 989 | EXPECT_EQ(s.begin(), s.find(d)); |
| 990 | EXPECT_TRUE(s.contains(d)); |
| 991 | } |
| 992 | |
| 993 | { |
| 994 | // `std::string` has heterogeneous support. |
| 995 | btree_set<std::string> s = {"A"}; |
| 996 | EXPECT_EQ(s.begin(), s.find(absl::string_view("A"))); |
| 997 | EXPECT_TRUE(s.contains(absl::string_view("A"))); |
| 998 | } |
| 999 | } |
| 1000 | |
| 1001 | class StringLike { |
| 1002 | public: |
| 1003 | StringLike() = default; |
| 1004 | |
| 1005 | StringLike(const char* s) : s_(s) { // NOLINT |
| 1006 | ++constructor_calls_; |
| 1007 | } |
| 1008 | |
| 1009 | bool operator<(const StringLike& a) const { |
| 1010 | return s_ < a.s_; |
| 1011 | } |
| 1012 | |
| 1013 | static void clear_constructor_call_count() { |
| 1014 | constructor_calls_ = 0; |
| 1015 | } |
| 1016 | |
| 1017 | static int constructor_calls() { |
| 1018 | return constructor_calls_; |
| 1019 | } |
| 1020 | |
| 1021 | private: |
| 1022 | static int constructor_calls_; |
| 1023 | std::string s_; |
| 1024 | }; |
| 1025 | |
| 1026 | int StringLike::constructor_calls_ = 0; |
| 1027 | |
| 1028 | TEST(Btree, HeterogeneousLookupDoesntDegradePerformance) { |
| 1029 | using StringSet = absl::btree_set<StringLike>; |
| 1030 | StringSet s; |
| 1031 | for (int i = 0; i < 100; ++i) { |
| 1032 | ASSERT_TRUE(s.insert(absl::StrCat(i).c_str()).second); |
| 1033 | } |
| 1034 | StringLike::clear_constructor_call_count(); |
| 1035 | s.find("50"); |
| 1036 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1037 | |
| 1038 | StringLike::clear_constructor_call_count(); |
| 1039 | s.contains("50"); |
| 1040 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1041 | |
| 1042 | StringLike::clear_constructor_call_count(); |
| 1043 | s.count("50"); |
| 1044 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1045 | |
| 1046 | StringLike::clear_constructor_call_count(); |
| 1047 | s.lower_bound("50"); |
| 1048 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1049 | |
| 1050 | StringLike::clear_constructor_call_count(); |
| 1051 | s.upper_bound("50"); |
| 1052 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1053 | |
| 1054 | StringLike::clear_constructor_call_count(); |
| 1055 | s.equal_range("50"); |
| 1056 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1057 | |
| 1058 | StringLike::clear_constructor_call_count(); |
| 1059 | s.erase("50"); |
| 1060 | ASSERT_EQ(1, StringLike::constructor_calls()); |
| 1061 | } |
| 1062 | |
| 1063 | // Verify that swapping btrees swaps the key comparison functors and that we can |
| 1064 | // use non-default constructible comparators. |
| 1065 | struct SubstringLess { |
| 1066 | SubstringLess() = delete; |
| 1067 | explicit SubstringLess(int length) : n(length) {} |
| 1068 | bool operator()(const std::string &a, const std::string &b) const { |
| 1069 | return absl::string_view(a).substr(0, n) < |
| 1070 | absl::string_view(b).substr(0, n); |
| 1071 | } |
| 1072 | int n; |
| 1073 | }; |
| 1074 | |
| 1075 | TEST(Btree, SwapKeyCompare) { |
| 1076 | using SubstringSet = absl::btree_set<std::string, SubstringLess>; |
| 1077 | SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type()); |
| 1078 | SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type()); |
| 1079 | |
| 1080 | ASSERT_TRUE(s1.insert("a").second); |
| 1081 | ASSERT_FALSE(s1.insert("aa").second); |
| 1082 | |
| 1083 | ASSERT_TRUE(s2.insert("a").second); |
| 1084 | ASSERT_TRUE(s2.insert("aa").second); |
| 1085 | ASSERT_FALSE(s2.insert("aaa").second); |
| 1086 | |
| 1087 | swap(s1, s2); |
| 1088 | |
| 1089 | ASSERT_TRUE(s1.insert("b").second); |
| 1090 | ASSERT_TRUE(s1.insert("bb").second); |
| 1091 | ASSERT_FALSE(s1.insert("bbb").second); |
| 1092 | |
| 1093 | ASSERT_TRUE(s2.insert("b").second); |
| 1094 | ASSERT_FALSE(s2.insert("bb").second); |
| 1095 | } |
| 1096 | |
| 1097 | TEST(Btree, UpperBoundRegression) { |
| 1098 | // Regress a bug where upper_bound would default-construct a new key_compare |
| 1099 | // instead of copying the existing one. |
| 1100 | using SubstringSet = absl::btree_set<std::string, SubstringLess>; |
| 1101 | SubstringSet my_set(SubstringLess(3)); |
| 1102 | my_set.insert("aab"); |
| 1103 | my_set.insert("abb"); |
| 1104 | // We call upper_bound("aaa"). If this correctly uses the length 3 |
| 1105 | // comparator, aaa < aab < abb, so we should get aab as the result. |
| 1106 | // If it instead uses the default-constructed length 2 comparator, |
| 1107 | // aa == aa < ab, so we'll get abb as our result. |
| 1108 | SubstringSet::iterator it = my_set.upper_bound("aaa"); |
| 1109 | ASSERT_TRUE(it != my_set.end()); |
| 1110 | EXPECT_EQ("aab", *it); |
| 1111 | } |
| 1112 | |
| 1113 | TEST(Btree, Comparison) { |
| 1114 | const int kSetSize = 1201; |
| 1115 | absl::btree_set<int64_t> my_set; |
| 1116 | for (int i = 0; i < kSetSize; ++i) { |
| 1117 | my_set.insert(i); |
| 1118 | } |
| 1119 | absl::btree_set<int64_t> my_set_copy(my_set); |
| 1120 | EXPECT_TRUE(my_set_copy == my_set); |
| 1121 | EXPECT_TRUE(my_set == my_set_copy); |
| 1122 | EXPECT_FALSE(my_set_copy != my_set); |
| 1123 | EXPECT_FALSE(my_set != my_set_copy); |
| 1124 | |
| 1125 | my_set.insert(kSetSize); |
| 1126 | EXPECT_FALSE(my_set_copy == my_set); |
| 1127 | EXPECT_FALSE(my_set == my_set_copy); |
| 1128 | EXPECT_TRUE(my_set_copy != my_set); |
| 1129 | EXPECT_TRUE(my_set != my_set_copy); |
| 1130 | |
| 1131 | my_set.erase(kSetSize - 1); |
| 1132 | EXPECT_FALSE(my_set_copy == my_set); |
| 1133 | EXPECT_FALSE(my_set == my_set_copy); |
| 1134 | EXPECT_TRUE(my_set_copy != my_set); |
| 1135 | EXPECT_TRUE(my_set != my_set_copy); |
| 1136 | |
| 1137 | absl::btree_map<std::string, int64_t> my_map; |
| 1138 | for (int i = 0; i < kSetSize; ++i) { |
| 1139 | my_map[std::string(i, 'a')] = i; |
| 1140 | } |
| 1141 | absl::btree_map<std::string, int64_t> my_map_copy(my_map); |
| 1142 | EXPECT_TRUE(my_map_copy == my_map); |
| 1143 | EXPECT_TRUE(my_map == my_map_copy); |
| 1144 | EXPECT_FALSE(my_map_copy != my_map); |
| 1145 | EXPECT_FALSE(my_map != my_map_copy); |
| 1146 | |
| 1147 | ++my_map_copy[std::string(7, 'a')]; |
| 1148 | EXPECT_FALSE(my_map_copy == my_map); |
| 1149 | EXPECT_FALSE(my_map == my_map_copy); |
| 1150 | EXPECT_TRUE(my_map_copy != my_map); |
| 1151 | EXPECT_TRUE(my_map != my_map_copy); |
| 1152 | |
| 1153 | my_map_copy = my_map; |
| 1154 | my_map["hello"] = kSetSize; |
| 1155 | EXPECT_FALSE(my_map_copy == my_map); |
| 1156 | EXPECT_FALSE(my_map == my_map_copy); |
| 1157 | EXPECT_TRUE(my_map_copy != my_map); |
| 1158 | EXPECT_TRUE(my_map != my_map_copy); |
| 1159 | |
| 1160 | my_map.erase(std::string(kSetSize - 1, 'a')); |
| 1161 | EXPECT_FALSE(my_map_copy == my_map); |
| 1162 | EXPECT_FALSE(my_map == my_map_copy); |
| 1163 | EXPECT_TRUE(my_map_copy != my_map); |
| 1164 | EXPECT_TRUE(my_map != my_map_copy); |
| 1165 | } |
| 1166 | |
| 1167 | TEST(Btree, RangeCtorSanity) { |
| 1168 | std::vector<int> ivec; |
| 1169 | ivec.push_back(1); |
| 1170 | std::map<int, int> imap; |
| 1171 | imap.insert(std::make_pair(1, 2)); |
| 1172 | absl::btree_multiset<int> tmset(ivec.begin(), ivec.end()); |
| 1173 | absl::btree_multimap<int, int> tmmap(imap.begin(), imap.end()); |
| 1174 | absl::btree_set<int> tset(ivec.begin(), ivec.end()); |
| 1175 | absl::btree_map<int, int> tmap(imap.begin(), imap.end()); |
| 1176 | EXPECT_EQ(1, tmset.size()); |
| 1177 | EXPECT_EQ(1, tmmap.size()); |
| 1178 | EXPECT_EQ(1, tset.size()); |
| 1179 | EXPECT_EQ(1, tmap.size()); |
| 1180 | } |
| 1181 | |
| 1182 | TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) { |
| 1183 | absl::btree_map<std::string, std::unique_ptr<std::string>> m; |
| 1184 | |
| 1185 | std::unique_ptr<std::string> &v = m["A"]; |
| 1186 | EXPECT_TRUE(v == nullptr); |
| 1187 | v.reset(new std::string("X")); |
| 1188 | |
| 1189 | auto iter = m.find("A"); |
| 1190 | EXPECT_EQ("X", *iter->second); |
| 1191 | } |
| 1192 | |
| 1193 | TEST(Btree, InitializerListConstructor) { |
| 1194 | absl::btree_set<std::string> set({"a", "b"}); |
| 1195 | EXPECT_EQ(set.count("a"), 1); |
| 1196 | EXPECT_EQ(set.count("b"), 1); |
| 1197 | |
| 1198 | absl::btree_multiset<int> mset({1, 1, 4}); |
| 1199 | EXPECT_EQ(mset.count(1), 2); |
| 1200 | EXPECT_EQ(mset.count(4), 1); |
| 1201 | |
| 1202 | absl::btree_map<int, int> map({{1, 5}, {2, 10}}); |
| 1203 | EXPECT_EQ(map[1], 5); |
| 1204 | EXPECT_EQ(map[2], 10); |
| 1205 | |
| 1206 | absl::btree_multimap<int, int> mmap({{1, 5}, {1, 10}}); |
| 1207 | auto range = mmap.equal_range(1); |
| 1208 | auto it = range.first; |
| 1209 | ASSERT_NE(it, range.second); |
| 1210 | EXPECT_EQ(it->second, 5); |
| 1211 | ASSERT_NE(++it, range.second); |
| 1212 | EXPECT_EQ(it->second, 10); |
| 1213 | EXPECT_EQ(++it, range.second); |
| 1214 | } |
| 1215 | |
| 1216 | TEST(Btree, InitializerListInsert) { |
| 1217 | absl::btree_set<std::string> set; |
| 1218 | set.insert({"a", "b"}); |
| 1219 | EXPECT_EQ(set.count("a"), 1); |
| 1220 | EXPECT_EQ(set.count("b"), 1); |
| 1221 | |
| 1222 | absl::btree_multiset<int> mset; |
| 1223 | mset.insert({1, 1, 4}); |
| 1224 | EXPECT_EQ(mset.count(1), 2); |
| 1225 | EXPECT_EQ(mset.count(4), 1); |
| 1226 | |
| 1227 | absl::btree_map<int, int> map; |
| 1228 | map.insert({{1, 5}, {2, 10}}); |
| 1229 | // Test that inserting one element using an initializer list also works. |
| 1230 | map.insert({3, 15}); |
| 1231 | EXPECT_EQ(map[1], 5); |
| 1232 | EXPECT_EQ(map[2], 10); |
| 1233 | EXPECT_EQ(map[3], 15); |
| 1234 | |
| 1235 | absl::btree_multimap<int, int> mmap; |
| 1236 | mmap.insert({{1, 5}, {1, 10}}); |
| 1237 | auto range = mmap.equal_range(1); |
| 1238 | auto it = range.first; |
| 1239 | ASSERT_NE(it, range.second); |
| 1240 | EXPECT_EQ(it->second, 5); |
| 1241 | ASSERT_NE(++it, range.second); |
| 1242 | EXPECT_EQ(it->second, 10); |
| 1243 | EXPECT_EQ(++it, range.second); |
| 1244 | } |
| 1245 | |
| 1246 | template <typename Compare, typename K> |
| 1247 | void AssertKeyCompareToAdapted() { |
| 1248 | using Adapted = typename key_compare_to_adapter<Compare>::type; |
| 1249 | static_assert(!std::is_same<Adapted, Compare>::value, |
| 1250 | "key_compare_to_adapter should have adapted this comparator."); |
| 1251 | static_assert( |
| 1252 | std::is_same<absl::weak_ordering, |
| 1253 | absl::result_of_t<Adapted(const K &, const K &)>>::value, |
| 1254 | "Adapted comparator should be a key-compare-to comparator."); |
| 1255 | } |
| 1256 | template <typename Compare, typename K> |
| 1257 | void AssertKeyCompareToNotAdapted() { |
| 1258 | using Unadapted = typename key_compare_to_adapter<Compare>::type; |
| 1259 | static_assert( |
| 1260 | std::is_same<Unadapted, Compare>::value, |
| 1261 | "key_compare_to_adapter shouldn't have adapted this comparator."); |
| 1262 | static_assert( |
| 1263 | std::is_same<bool, |
| 1264 | absl::result_of_t<Unadapted(const K &, const K &)>>::value, |
| 1265 | "Un-adapted comparator should return bool."); |
| 1266 | } |
| 1267 | |
| 1268 | TEST(Btree, KeyCompareToAdapter) { |
| 1269 | AssertKeyCompareToAdapted<std::less<std::string>, std::string>(); |
| 1270 | AssertKeyCompareToAdapted<std::greater<std::string>, std::string>(); |
| 1271 | AssertKeyCompareToAdapted<std::less<absl::string_view>, absl::string_view>(); |
| 1272 | AssertKeyCompareToAdapted<std::greater<absl::string_view>, |
| 1273 | absl::string_view>(); |
| 1274 | AssertKeyCompareToNotAdapted<std::less<int>, int>(); |
| 1275 | AssertKeyCompareToNotAdapted<std::greater<int>, int>(); |
| 1276 | } |
| 1277 | |
| 1278 | TEST(Btree, RValueInsert) { |
| 1279 | InstanceTracker tracker; |
| 1280 | |
| 1281 | absl::btree_set<MovableOnlyInstance> set; |
| 1282 | set.insert(MovableOnlyInstance(1)); |
| 1283 | set.insert(MovableOnlyInstance(3)); |
| 1284 | MovableOnlyInstance two(2); |
| 1285 | set.insert(set.find(MovableOnlyInstance(3)), std::move(two)); |
| 1286 | auto it = set.find(MovableOnlyInstance(2)); |
| 1287 | ASSERT_NE(it, set.end()); |
| 1288 | ASSERT_NE(++it, set.end()); |
| 1289 | EXPECT_EQ(it->value(), 3); |
| 1290 | |
| 1291 | absl::btree_multiset<MovableOnlyInstance> mset; |
| 1292 | MovableOnlyInstance zero(0); |
| 1293 | MovableOnlyInstance zero2(0); |
| 1294 | mset.insert(std::move(zero)); |
| 1295 | mset.insert(mset.find(MovableOnlyInstance(0)), std::move(zero2)); |
| 1296 | EXPECT_EQ(mset.count(MovableOnlyInstance(0)), 2); |
| 1297 | |
| 1298 | absl::btree_map<int, MovableOnlyInstance> map; |
| 1299 | std::pair<const int, MovableOnlyInstance> p1 = {1, MovableOnlyInstance(5)}; |
| 1300 | std::pair<const int, MovableOnlyInstance> p2 = {2, MovableOnlyInstance(10)}; |
| 1301 | std::pair<const int, MovableOnlyInstance> p3 = {3, MovableOnlyInstance(15)}; |
| 1302 | map.insert(std::move(p1)); |
| 1303 | map.insert(std::move(p3)); |
| 1304 | map.insert(map.find(3), std::move(p2)); |
| 1305 | ASSERT_NE(map.find(2), map.end()); |
| 1306 | EXPECT_EQ(map.find(2)->second.value(), 10); |
| 1307 | |
| 1308 | absl::btree_multimap<int, MovableOnlyInstance> mmap; |
| 1309 | std::pair<const int, MovableOnlyInstance> p4 = {1, MovableOnlyInstance(5)}; |
| 1310 | std::pair<const int, MovableOnlyInstance> p5 = {1, MovableOnlyInstance(10)}; |
| 1311 | mmap.insert(std::move(p4)); |
| 1312 | mmap.insert(mmap.find(1), std::move(p5)); |
| 1313 | auto range = mmap.equal_range(1); |
| 1314 | auto it1 = range.first; |
| 1315 | ASSERT_NE(it1, range.second); |
| 1316 | EXPECT_EQ(it1->second.value(), 10); |
| 1317 | ASSERT_NE(++it1, range.second); |
| 1318 | EXPECT_EQ(it1->second.value(), 5); |
| 1319 | EXPECT_EQ(++it1, range.second); |
| 1320 | |
| 1321 | EXPECT_EQ(tracker.copies(), 0); |
| 1322 | EXPECT_EQ(tracker.swaps(), 0); |
| 1323 | } |
| 1324 | |
| 1325 | } // namespace |
| 1326 | |
| 1327 | class BtreeNodePeer { |
| 1328 | public: |
| 1329 | // Yields the size of a leaf node with a specific number of values. |
| 1330 | template <typename ValueType> |
| 1331 | constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) { |
| 1332 | return btree_node< |
| 1333 | set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>, |
| 1334 | /*TargetNodeSize=*/256, // This parameter isn't used here. |
| 1335 | /*Multi=*/false>>::SizeWithNValues(target_values_per_node); |
| 1336 | } |
| 1337 | |
| 1338 | // Yields the number of values in a (non-root) leaf node for this set. |
| 1339 | template <typename Set> |
| 1340 | constexpr static size_t GetNumValuesPerNode() { |
| 1341 | return btree_node<typename Set::params_type>::kNodeValues; |
| 1342 | } |
| 1343 | }; |
| 1344 | |
| 1345 | namespace { |
| 1346 | |
| 1347 | // A btree set with a specific number of values per node. |
| 1348 | template <typename Key, int TargetValuesPerNode, typename Cmp = std::less<Key>> |
| 1349 | class SizedBtreeSet |
| 1350 | : public btree_set_container<btree< |
| 1351 | set_params<Key, Cmp, std::allocator<Key>, |
| 1352 | BtreeNodePeer::GetTargetNodeSize<Key>(TargetValuesPerNode), |
| 1353 | /*Multi=*/false>>> { |
| 1354 | using Base = typename SizedBtreeSet::btree_set_container; |
| 1355 | |
| 1356 | public: |
| 1357 | SizedBtreeSet() {} |
| 1358 | using Base::Base; |
| 1359 | }; |
| 1360 | |
| 1361 | template <typename Set> |
| 1362 | void ExpectOperationCounts(const int expected_moves, |
| 1363 | const int expected_comparisons, |
| 1364 | const std::vector<int> &values, |
| 1365 | InstanceTracker *tracker, Set *set) { |
| 1366 | for (const int v : values) set->insert(MovableOnlyInstance(v)); |
| 1367 | set->clear(); |
| 1368 | EXPECT_EQ(tracker->moves(), expected_moves); |
| 1369 | EXPECT_EQ(tracker->comparisons(), expected_comparisons); |
| 1370 | EXPECT_EQ(tracker->copies(), 0); |
| 1371 | EXPECT_EQ(tracker->swaps(), 0); |
| 1372 | tracker->ResetCopiesMovesSwaps(); |
| 1373 | } |
| 1374 | |
| 1375 | // Note: when the values in this test change, it is expected to have an impact |
| 1376 | // on performance. |
| 1377 | TEST(Btree, MovesComparisonsCopiesSwapsTracking) { |
| 1378 | InstanceTracker tracker; |
| 1379 | // Note: this is minimum number of values per node. |
| 1380 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3> set3; |
| 1381 | // Note: this is the default number of values per node for a set of int32s |
| 1382 | // (with 64-bit pointers). |
| 1383 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61> set61; |
| 1384 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/100> set100; |
| 1385 | |
| 1386 | // Don't depend on flags for random values because then the expectations will |
| 1387 | // fail if the flags change. |
| 1388 | std::vector<int> values = |
| 1389 | GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23); |
| 1390 | |
| 1391 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3); |
| 1392 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61); |
| 1393 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100); |
| 1394 | if (sizeof(void *) == 8) { |
| 1395 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(), |
| 1396 | BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>()); |
| 1397 | } |
| 1398 | |
| 1399 | // Test key insertion/deletion in random order. |
| 1400 | ExpectOperationCounts(45281, 132551, values, &tracker, &set3); |
| 1401 | ExpectOperationCounts(386718, 129807, values, &tracker, &set61); |
| 1402 | ExpectOperationCounts(586761, 130310, values, &tracker, &set100); |
| 1403 | |
| 1404 | // Test key insertion/deletion in sorted order. |
| 1405 | std::sort(values.begin(), values.end()); |
| 1406 | ExpectOperationCounts(26638, 92134, values, &tracker, &set3); |
| 1407 | ExpectOperationCounts(20208, 87757, values, &tracker, &set61); |
| 1408 | ExpectOperationCounts(20124, 96583, values, &tracker, &set100); |
| 1409 | |
| 1410 | // Test key insertion/deletion in reverse sorted order. |
| 1411 | std::reverse(values.begin(), values.end()); |
| 1412 | ExpectOperationCounts(49951, 119325, values, &tracker, &set3); |
| 1413 | ExpectOperationCounts(338813, 118266, values, &tracker, &set61); |
| 1414 | ExpectOperationCounts(534529, 125279, values, &tracker, &set100); |
| 1415 | } |
| 1416 | |
| 1417 | struct MovableOnlyInstanceThreeWayCompare { |
| 1418 | absl::weak_ordering operator()(const MovableOnlyInstance &a, |
| 1419 | const MovableOnlyInstance &b) const { |
| 1420 | return a.compare(b); |
| 1421 | } |
| 1422 | }; |
| 1423 | |
| 1424 | // Note: when the values in this test change, it is expected to have an impact |
| 1425 | // on performance. |
| 1426 | TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) { |
| 1427 | InstanceTracker tracker; |
| 1428 | // Note: this is minimum number of values per node. |
| 1429 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3, |
| 1430 | MovableOnlyInstanceThreeWayCompare> |
| 1431 | set3; |
| 1432 | // Note: this is the default number of values per node for a set of int32s |
| 1433 | // (with 64-bit pointers). |
| 1434 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61, |
| 1435 | MovableOnlyInstanceThreeWayCompare> |
| 1436 | set61; |
| 1437 | SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/100, |
| 1438 | MovableOnlyInstanceThreeWayCompare> |
| 1439 | set100; |
| 1440 | |
| 1441 | // Don't depend on flags for random values because then the expectations will |
| 1442 | // fail if the flags change. |
| 1443 | std::vector<int> values = |
| 1444 | GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23); |
| 1445 | |
| 1446 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3); |
| 1447 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61); |
| 1448 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100); |
| 1449 | if (sizeof(void *) == 8) { |
| 1450 | EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(), |
| 1451 | BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>()); |
| 1452 | } |
| 1453 | |
| 1454 | // Test key insertion/deletion in random order. |
| 1455 | ExpectOperationCounts(45281, 122560, values, &tracker, &set3); |
| 1456 | ExpectOperationCounts(386718, 119816, values, &tracker, &set61); |
| 1457 | ExpectOperationCounts(586761, 120319, values, &tracker, &set100); |
| 1458 | |
| 1459 | // Test key insertion/deletion in sorted order. |
| 1460 | std::sort(values.begin(), values.end()); |
| 1461 | ExpectOperationCounts(26638, 92134, values, &tracker, &set3); |
| 1462 | ExpectOperationCounts(20208, 87757, values, &tracker, &set61); |
| 1463 | ExpectOperationCounts(20124, 96583, values, &tracker, &set100); |
| 1464 | |
| 1465 | // Test key insertion/deletion in reverse sorted order. |
| 1466 | std::reverse(values.begin(), values.end()); |
| 1467 | ExpectOperationCounts(49951, 109326, values, &tracker, &set3); |
| 1468 | ExpectOperationCounts(338813, 108267, values, &tracker, &set61); |
| 1469 | ExpectOperationCounts(534529, 115280, values, &tracker, &set100); |
| 1470 | } |
| 1471 | |
| 1472 | struct NoDefaultCtor { |
| 1473 | int num; |
| 1474 | explicit NoDefaultCtor(int i) : num(i) {} |
| 1475 | |
| 1476 | friend bool operator<(const NoDefaultCtor& a, const NoDefaultCtor& b) { |
| 1477 | return a.num < b.num; |
| 1478 | } |
| 1479 | }; |
| 1480 | |
| 1481 | TEST(Btree, BtreeMapCanHoldNoDefaultCtorTypes) { |
| 1482 | absl::btree_map<NoDefaultCtor, NoDefaultCtor> m; |
| 1483 | |
| 1484 | for (int i = 1; i <= 99; ++i) { |
| 1485 | SCOPED_TRACE(i); |
| 1486 | EXPECT_TRUE(m.emplace(NoDefaultCtor(i), NoDefaultCtor(100 - i)).second); |
| 1487 | } |
| 1488 | EXPECT_FALSE(m.emplace(NoDefaultCtor(78), NoDefaultCtor(0)).second); |
| 1489 | |
| 1490 | auto iter99 = m.find(NoDefaultCtor(99)); |
| 1491 | ASSERT_NE(iter99, m.end()); |
| 1492 | EXPECT_EQ(iter99->second.num, 1); |
| 1493 | |
| 1494 | auto iter1 = m.find(NoDefaultCtor(1)); |
| 1495 | ASSERT_NE(iter1, m.end()); |
| 1496 | EXPECT_EQ(iter1->second.num, 99); |
| 1497 | |
| 1498 | auto iter50 = m.find(NoDefaultCtor(50)); |
| 1499 | ASSERT_NE(iter50, m.end()); |
| 1500 | EXPECT_EQ(iter50->second.num, 50); |
| 1501 | |
| 1502 | auto iter25 = m.find(NoDefaultCtor(25)); |
| 1503 | ASSERT_NE(iter25, m.end()); |
| 1504 | EXPECT_EQ(iter25->second.num, 75); |
| 1505 | } |
| 1506 | |
| 1507 | TEST(Btree, BtreeMultimapCanHoldNoDefaultCtorTypes) { |
| 1508 | absl::btree_multimap<NoDefaultCtor, NoDefaultCtor> m; |
| 1509 | |
| 1510 | for (int i = 1; i <= 99; ++i) { |
| 1511 | SCOPED_TRACE(i); |
| 1512 | m.emplace(NoDefaultCtor(i), NoDefaultCtor(100 - i)); |
| 1513 | } |
| 1514 | |
| 1515 | auto iter99 = m.find(NoDefaultCtor(99)); |
| 1516 | ASSERT_NE(iter99, m.end()); |
| 1517 | EXPECT_EQ(iter99->second.num, 1); |
| 1518 | |
| 1519 | auto iter1 = m.find(NoDefaultCtor(1)); |
| 1520 | ASSERT_NE(iter1, m.end()); |
| 1521 | EXPECT_EQ(iter1->second.num, 99); |
| 1522 | |
| 1523 | auto iter50 = m.find(NoDefaultCtor(50)); |
| 1524 | ASSERT_NE(iter50, m.end()); |
| 1525 | EXPECT_EQ(iter50->second.num, 50); |
| 1526 | |
| 1527 | auto iter25 = m.find(NoDefaultCtor(25)); |
| 1528 | ASSERT_NE(iter25, m.end()); |
| 1529 | EXPECT_EQ(iter25->second.num, 75); |
| 1530 | } |
| 1531 | |
| 1532 | TEST(Btree, MapAt) { |
| 1533 | absl::btree_map<int, int> map = {{1, 2}, {2, 4}}; |
| 1534 | EXPECT_EQ(map.at(1), 2); |
| 1535 | EXPECT_EQ(map.at(2), 4); |
| 1536 | map.at(2) = 8; |
| 1537 | const absl::btree_map<int, int> &const_map = map; |
| 1538 | EXPECT_EQ(const_map.at(1), 2); |
| 1539 | EXPECT_EQ(const_map.at(2), 8); |
| 1540 | #ifdef ABSL_HAVE_EXCEPTIONS |
| 1541 | EXPECT_THROW(map.at(3), std::out_of_range); |
| 1542 | #else |
| 1543 | EXPECT_DEATH(map.at(3), "absl::btree_map::at"); |
| 1544 | #endif |
| 1545 | } |
| 1546 | |
| 1547 | TEST(Btree, BtreeMultisetEmplace) { |
| 1548 | const int value_to_insert = 123456; |
| 1549 | absl::btree_multiset<int> s; |
| 1550 | auto iter = s.emplace(value_to_insert); |
| 1551 | ASSERT_NE(iter, s.end()); |
| 1552 | EXPECT_EQ(*iter, value_to_insert); |
| 1553 | auto iter2 = s.emplace(value_to_insert); |
| 1554 | EXPECT_NE(iter2, iter); |
| 1555 | ASSERT_NE(iter2, s.end()); |
| 1556 | EXPECT_EQ(*iter2, value_to_insert); |
| 1557 | auto result = s.equal_range(value_to_insert); |
| 1558 | EXPECT_EQ(std::distance(result.first, result.second), 2); |
| 1559 | } |
| 1560 | |
| 1561 | TEST(Btree, BtreeMultisetEmplaceHint) { |
| 1562 | const int value_to_insert = 123456; |
| 1563 | absl::btree_multiset<int> s; |
| 1564 | auto iter = s.emplace(value_to_insert); |
| 1565 | ASSERT_NE(iter, s.end()); |
| 1566 | EXPECT_EQ(*iter, value_to_insert); |
| 1567 | auto emplace_iter = s.emplace_hint(iter, value_to_insert); |
| 1568 | EXPECT_NE(emplace_iter, iter); |
| 1569 | ASSERT_NE(emplace_iter, s.end()); |
| 1570 | EXPECT_EQ(*emplace_iter, value_to_insert); |
| 1571 | } |
| 1572 | |
| 1573 | TEST(Btree, BtreeMultimapEmplace) { |
| 1574 | const int key_to_insert = 123456; |
| 1575 | const char value0[] = "a"; |
| 1576 | absl::btree_multimap<int, std::string> s; |
| 1577 | auto iter = s.emplace(key_to_insert, value0); |
| 1578 | ASSERT_NE(iter, s.end()); |
| 1579 | EXPECT_EQ(iter->first, key_to_insert); |
| 1580 | EXPECT_EQ(iter->second, value0); |
| 1581 | const char value1[] = "b"; |
| 1582 | auto iter2 = s.emplace(key_to_insert, value1); |
| 1583 | EXPECT_NE(iter2, iter); |
| 1584 | ASSERT_NE(iter2, s.end()); |
| 1585 | EXPECT_EQ(iter2->first, key_to_insert); |
| 1586 | EXPECT_EQ(iter2->second, value1); |
| 1587 | auto result = s.equal_range(key_to_insert); |
| 1588 | EXPECT_EQ(std::distance(result.first, result.second), 2); |
| 1589 | } |
| 1590 | |
| 1591 | TEST(Btree, BtreeMultimapEmplaceHint) { |
| 1592 | const int key_to_insert = 123456; |
| 1593 | const char value0[] = "a"; |
| 1594 | absl::btree_multimap<int, std::string> s; |
| 1595 | auto iter = s.emplace(key_to_insert, value0); |
| 1596 | ASSERT_NE(iter, s.end()); |
| 1597 | EXPECT_EQ(iter->first, key_to_insert); |
| 1598 | EXPECT_EQ(iter->second, value0); |
| 1599 | const char value1[] = "b"; |
| 1600 | auto emplace_iter = s.emplace_hint(iter, key_to_insert, value1); |
| 1601 | EXPECT_NE(emplace_iter, iter); |
| 1602 | ASSERT_NE(emplace_iter, s.end()); |
| 1603 | EXPECT_EQ(emplace_iter->first, key_to_insert); |
| 1604 | EXPECT_EQ(emplace_iter->second, value1); |
| 1605 | } |
| 1606 | |
| 1607 | TEST(Btree, ConstIteratorAccessors) { |
| 1608 | absl::btree_set<int> set; |
| 1609 | for (int i = 0; i < 100; ++i) { |
| 1610 | set.insert(i); |
| 1611 | } |
| 1612 | |
| 1613 | auto it = set.cbegin(); |
| 1614 | auto r_it = set.crbegin(); |
| 1615 | for (int i = 0; i < 100; ++i, ++it, ++r_it) { |
| 1616 | ASSERT_EQ(*it, i); |
| 1617 | ASSERT_EQ(*r_it, 99 - i); |
| 1618 | } |
| 1619 | EXPECT_EQ(it, set.cend()); |
| 1620 | EXPECT_EQ(r_it, set.crend()); |
| 1621 | } |
| 1622 | |
| 1623 | TEST(Btree, StrSplitCompatible) { |
| 1624 | const absl::btree_set<std::string> split_set = absl::StrSplit("a,b,c", ','); |
| 1625 | const absl::btree_set<std::string> expected_set = {"a", "b", "c"}; |
| 1626 | |
| 1627 | EXPECT_EQ(split_set, expected_set); |
| 1628 | } |
| 1629 | |
| 1630 | // We can't use EXPECT_EQ/etc. to compare absl::weak_ordering because they |
| 1631 | // convert literal 0 to int and absl::weak_ordering can only be compared with |
| 1632 | // literal 0. Defining this function allows for avoiding ClangTidy warnings. |
| 1633 | bool Identity(const bool b) { return b; } |
| 1634 | |
| 1635 | TEST(Btree, ValueComp) { |
| 1636 | absl::btree_set<int> s; |
| 1637 | EXPECT_TRUE(s.value_comp()(1, 2)); |
| 1638 | EXPECT_FALSE(s.value_comp()(2, 2)); |
| 1639 | EXPECT_FALSE(s.value_comp()(2, 1)); |
| 1640 | |
| 1641 | absl::btree_map<int, int> m1; |
| 1642 | EXPECT_TRUE(m1.value_comp()(std::make_pair(1, 0), std::make_pair(2, 0))); |
| 1643 | EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(2, 0))); |
| 1644 | EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(1, 0))); |
| 1645 | |
| 1646 | absl::btree_map<std::string, int> m2; |
| 1647 | EXPECT_TRUE(Identity( |
| 1648 | m2.value_comp()(std::make_pair("a", 0), std::make_pair("b", 0)) < 0)); |
| 1649 | EXPECT_TRUE(Identity( |
| 1650 | m2.value_comp()(std::make_pair("b", 0), std::make_pair("b", 0)) == 0)); |
| 1651 | EXPECT_TRUE(Identity( |
| 1652 | m2.value_comp()(std::make_pair("b", 0), std::make_pair("a", 0)) > 0)); |
| 1653 | } |
| 1654 | |
| 1655 | TEST(Btree, DefaultConstruction) { |
| 1656 | absl::btree_set<int> s; |
| 1657 | absl::btree_map<int, int> m; |
| 1658 | absl::btree_multiset<int> ms; |
| 1659 | absl::btree_multimap<int, int> mm; |
| 1660 | |
| 1661 | EXPECT_TRUE(s.empty()); |
| 1662 | EXPECT_TRUE(m.empty()); |
| 1663 | EXPECT_TRUE(ms.empty()); |
| 1664 | EXPECT_TRUE(mm.empty()); |
| 1665 | } |
| 1666 | |
| 1667 | TEST(Btree, SwissTableHashable) { |
| 1668 | static constexpr int kValues = 10000; |
| 1669 | std::vector<int> values(kValues); |
| 1670 | std::iota(values.begin(), values.end(), 0); |
| 1671 | std::vector<std::pair<int, int>> map_values; |
| 1672 | for (int v : values) map_values.emplace_back(v, -v); |
| 1673 | |
| 1674 | using set = absl::btree_set<int>; |
| 1675 | EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ |
| 1676 | set{}, |
| 1677 | set{1}, |
| 1678 | set{2}, |
| 1679 | set{1, 2}, |
| 1680 | set{2, 1}, |
| 1681 | set(values.begin(), values.end()), |
| 1682 | set(values.rbegin(), values.rend()), |
| 1683 | })); |
| 1684 | |
| 1685 | using mset = absl::btree_multiset<int>; |
| 1686 | EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ |
| 1687 | mset{}, |
| 1688 | mset{1}, |
| 1689 | mset{1, 1}, |
| 1690 | mset{2}, |
| 1691 | mset{2, 2}, |
| 1692 | mset{1, 2}, |
| 1693 | mset{1, 1, 2}, |
| 1694 | mset{1, 2, 2}, |
| 1695 | mset{1, 1, 2, 2}, |
| 1696 | mset(values.begin(), values.end()), |
| 1697 | mset(values.rbegin(), values.rend()), |
| 1698 | })); |
| 1699 | |
| 1700 | using map = absl::btree_map<int, int>; |
| 1701 | EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ |
| 1702 | map{}, |
| 1703 | map{{1, 0}}, |
| 1704 | map{{1, 1}}, |
| 1705 | map{{2, 0}}, |
| 1706 | map{{2, 2}}, |
| 1707 | map{{1, 0}, {2, 1}}, |
| 1708 | map(map_values.begin(), map_values.end()), |
| 1709 | map(map_values.rbegin(), map_values.rend()), |
| 1710 | })); |
| 1711 | |
| 1712 | using mmap = absl::btree_multimap<int, int>; |
| 1713 | EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ |
| 1714 | mmap{}, |
| 1715 | mmap{{1, 0}}, |
| 1716 | mmap{{1, 1}}, |
| 1717 | mmap{{1, 0}, {1, 1}}, |
| 1718 | mmap{{1, 1}, {1, 0}}, |
| 1719 | mmap{{2, 0}}, |
| 1720 | mmap{{2, 2}}, |
| 1721 | mmap{{1, 0}, {2, 1}}, |
| 1722 | mmap(map_values.begin(), map_values.end()), |
| 1723 | mmap(map_values.rbegin(), map_values.rend()), |
| 1724 | })); |
| 1725 | } |
| 1726 | |
| 1727 | TEST(Btree, ComparableSet) { |
| 1728 | absl::btree_set<int> s1 = {1, 2}; |
| 1729 | absl::btree_set<int> s2 = {2, 3}; |
| 1730 | EXPECT_LT(s1, s2); |
| 1731 | EXPECT_LE(s1, s2); |
| 1732 | EXPECT_LE(s1, s1); |
| 1733 | EXPECT_GT(s2, s1); |
| 1734 | EXPECT_GE(s2, s1); |
| 1735 | EXPECT_GE(s1, s1); |
| 1736 | } |
| 1737 | |
| 1738 | TEST(Btree, ComparableSetsDifferentLength) { |
| 1739 | absl::btree_set<int> s1 = {1, 2}; |
| 1740 | absl::btree_set<int> s2 = {1, 2, 3}; |
| 1741 | EXPECT_LT(s1, s2); |
| 1742 | EXPECT_LE(s1, s2); |
| 1743 | EXPECT_GT(s2, s1); |
| 1744 | EXPECT_GE(s2, s1); |
| 1745 | } |
| 1746 | |
| 1747 | TEST(Btree, ComparableMultiset) { |
| 1748 | absl::btree_multiset<int> s1 = {1, 2}; |
| 1749 | absl::btree_multiset<int> s2 = {2, 3}; |
| 1750 | EXPECT_LT(s1, s2); |
| 1751 | EXPECT_LE(s1, s2); |
| 1752 | EXPECT_LE(s1, s1); |
| 1753 | EXPECT_GT(s2, s1); |
| 1754 | EXPECT_GE(s2, s1); |
| 1755 | EXPECT_GE(s1, s1); |
| 1756 | } |
| 1757 | |
| 1758 | TEST(Btree, ComparableMap) { |
| 1759 | absl::btree_map<int, int> s1 = {{1, 2}}; |
| 1760 | absl::btree_map<int, int> s2 = {{2, 3}}; |
| 1761 | EXPECT_LT(s1, s2); |
| 1762 | EXPECT_LE(s1, s2); |
| 1763 | EXPECT_LE(s1, s1); |
| 1764 | EXPECT_GT(s2, s1); |
| 1765 | EXPECT_GE(s2, s1); |
| 1766 | EXPECT_GE(s1, s1); |
| 1767 | } |
| 1768 | |
| 1769 | TEST(Btree, ComparableMultimap) { |
| 1770 | absl::btree_multimap<int, int> s1 = {{1, 2}}; |
| 1771 | absl::btree_multimap<int, int> s2 = {{2, 3}}; |
| 1772 | EXPECT_LT(s1, s2); |
| 1773 | EXPECT_LE(s1, s2); |
| 1774 | EXPECT_LE(s1, s1); |
| 1775 | EXPECT_GT(s2, s1); |
| 1776 | EXPECT_GE(s2, s1); |
| 1777 | EXPECT_GE(s1, s1); |
| 1778 | } |
| 1779 | |
| 1780 | TEST(Btree, ComparableSetWithCustomComparator) { |
| 1781 | // As specified by |
| 1782 | // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf section |
| 1783 | // [container.requirements.general].12, ordering associative containers always |
| 1784 | // uses default '<' operator |
| 1785 | // - even if otherwise the container uses custom functor. |
| 1786 | absl::btree_set<int, std::greater<int>> s1 = {1, 2}; |
| 1787 | absl::btree_set<int, std::greater<int>> s2 = {2, 3}; |
| 1788 | EXPECT_LT(s1, s2); |
| 1789 | EXPECT_LE(s1, s2); |
| 1790 | EXPECT_LE(s1, s1); |
| 1791 | EXPECT_GT(s2, s1); |
| 1792 | EXPECT_GE(s2, s1); |
| 1793 | EXPECT_GE(s1, s1); |
| 1794 | } |
| 1795 | |
| 1796 | TEST(Btree, EraseReturnsIterator) { |
| 1797 | absl::btree_set<int> set = {1, 2, 3, 4, 5}; |
| 1798 | auto result_it = set.erase(set.begin(), set.find(3)); |
| 1799 | EXPECT_EQ(result_it, set.find(3)); |
| 1800 | result_it = set.erase(set.find(5)); |
| 1801 | EXPECT_EQ(result_it, set.end()); |
| 1802 | } |
| 1803 | |
| 1804 | TEST(Btree, ExtractAndInsertNodeHandleSet) { |
| 1805 | absl::btree_set<int> src1 = {1, 2, 3, 4, 5}; |
| 1806 | auto nh = src1.extract(src1.find(3)); |
| 1807 | EXPECT_THAT(src1, ElementsAre(1, 2, 4, 5)); |
| 1808 | absl::btree_set<int> other; |
| 1809 | absl::btree_set<int>::insert_return_type res = other.insert(std::move(nh)); |
| 1810 | EXPECT_THAT(other, ElementsAre(3)); |
| 1811 | EXPECT_EQ(res.position, other.find(3)); |
| 1812 | EXPECT_TRUE(res.inserted); |
| 1813 | EXPECT_TRUE(res.node.empty()); |
| 1814 | |
| 1815 | absl::btree_set<int> src2 = {3, 4}; |
| 1816 | nh = src2.extract(src2.find(3)); |
| 1817 | EXPECT_THAT(src2, ElementsAre(4)); |
| 1818 | res = other.insert(std::move(nh)); |
| 1819 | EXPECT_THAT(other, ElementsAre(3)); |
| 1820 | EXPECT_EQ(res.position, other.find(3)); |
| 1821 | EXPECT_FALSE(res.inserted); |
| 1822 | ASSERT_FALSE(res.node.empty()); |
| 1823 | EXPECT_EQ(res.node.value(), 3); |
| 1824 | } |
| 1825 | |
| 1826 | struct Deref { |
| 1827 | bool operator()(const std::unique_ptr<int> &lhs, |
| 1828 | const std::unique_ptr<int> &rhs) const { |
| 1829 | return *lhs < *rhs; |
| 1830 | } |
| 1831 | }; |
| 1832 | |
| 1833 | TEST(Btree, ExtractWithUniquePtr) { |
| 1834 | absl::btree_set<std::unique_ptr<int>, Deref> s; |
| 1835 | s.insert(absl::make_unique<int>(1)); |
| 1836 | s.insert(absl::make_unique<int>(2)); |
| 1837 | s.insert(absl::make_unique<int>(3)); |
| 1838 | s.insert(absl::make_unique<int>(4)); |
| 1839 | s.insert(absl::make_unique<int>(5)); |
| 1840 | auto nh = s.extract(s.find(absl::make_unique<int>(3))); |
| 1841 | EXPECT_EQ(s.size(), 4); |
| 1842 | EXPECT_EQ(*nh.value(), 3); |
| 1843 | s.insert(std::move(nh)); |
| 1844 | EXPECT_EQ(s.size(), 5); |
| 1845 | } |
| 1846 | |
| 1847 | TEST(Btree, ExtractAndInsertNodeHandleMultiSet) { |
| 1848 | absl::btree_multiset<int> src1 = {1, 2, 3, 3, 4, 5}; |
| 1849 | auto nh = src1.extract(src1.find(3)); |
| 1850 | EXPECT_THAT(src1, ElementsAre(1, 2, 3, 4, 5)); |
| 1851 | absl::btree_multiset<int> other; |
| 1852 | auto res = other.insert(std::move(nh)); |
| 1853 | EXPECT_THAT(other, ElementsAre(3)); |
| 1854 | EXPECT_EQ(res, other.find(3)); |
| 1855 | |
| 1856 | absl::btree_multiset<int> src2 = {3, 4}; |
| 1857 | nh = src2.extract(src2.find(3)); |
| 1858 | EXPECT_THAT(src2, ElementsAre(4)); |
| 1859 | res = other.insert(std::move(nh)); |
| 1860 | EXPECT_THAT(other, ElementsAre(3, 3)); |
| 1861 | EXPECT_EQ(res, ++other.find(3)); |
| 1862 | } |
| 1863 | |
| 1864 | TEST(Btree, ExtractAndInsertNodeHandleMap) { |
| 1865 | absl::btree_map<int, int> src1 = {{1, 2}, {3, 4}, {5, 6}}; |
| 1866 | auto nh = src1.extract(src1.find(3)); |
| 1867 | EXPECT_THAT(src1, ElementsAre(Pair(1, 2), Pair(5, 6))); |
| 1868 | absl::btree_map<int, int> other; |
| 1869 | absl::btree_map<int, int>::insert_return_type res = |
| 1870 | other.insert(std::move(nh)); |
| 1871 | EXPECT_THAT(other, ElementsAre(Pair(3, 4))); |
| 1872 | EXPECT_EQ(res.position, other.find(3)); |
| 1873 | EXPECT_TRUE(res.inserted); |
| 1874 | EXPECT_TRUE(res.node.empty()); |
| 1875 | |
| 1876 | absl::btree_map<int, int> src2 = {{3, 6}}; |
| 1877 | nh = src2.extract(src2.find(3)); |
| 1878 | EXPECT_TRUE(src2.empty()); |
| 1879 | res = other.insert(std::move(nh)); |
| 1880 | EXPECT_THAT(other, ElementsAre(Pair(3, 4))); |
| 1881 | EXPECT_EQ(res.position, other.find(3)); |
| 1882 | EXPECT_FALSE(res.inserted); |
| 1883 | ASSERT_FALSE(res.node.empty()); |
| 1884 | EXPECT_EQ(res.node.key(), 3); |
| 1885 | EXPECT_EQ(res.node.mapped(), 6); |
| 1886 | } |
| 1887 | |
| 1888 | TEST(Btree, ExtractAndInsertNodeHandleMultiMap) { |
| 1889 | absl::btree_multimap<int, int> src1 = {{1, 2}, {3, 4}, {5, 6}}; |
| 1890 | auto nh = src1.extract(src1.find(3)); |
| 1891 | EXPECT_THAT(src1, ElementsAre(Pair(1, 2), Pair(5, 6))); |
| 1892 | absl::btree_multimap<int, int> other; |
| 1893 | auto res = other.insert(std::move(nh)); |
| 1894 | EXPECT_THAT(other, ElementsAre(Pair(3, 4))); |
| 1895 | EXPECT_EQ(res, other.find(3)); |
| 1896 | |
| 1897 | absl::btree_multimap<int, int> src2 = {{3, 6}}; |
| 1898 | nh = src2.extract(src2.find(3)); |
| 1899 | EXPECT_TRUE(src2.empty()); |
| 1900 | res = other.insert(std::move(nh)); |
| 1901 | EXPECT_THAT(other, ElementsAre(Pair(3, 4), Pair(3, 6))); |
| 1902 | EXPECT_EQ(res, ++other.begin()); |
| 1903 | } |
| 1904 | |
| 1905 | // For multisets, insert with hint also affects correctness because we need to |
| 1906 | // insert immediately before the hint if possible. |
| 1907 | struct InsertMultiHintData { |
| 1908 | int key; |
| 1909 | int not_key; |
| 1910 | bool operator==(const InsertMultiHintData other) const { |
| 1911 | return key == other.key && not_key == other.not_key; |
| 1912 | } |
| 1913 | }; |
| 1914 | |
| 1915 | struct InsertMultiHintDataKeyCompare { |
| 1916 | using is_transparent = void; |
| 1917 | bool operator()(const InsertMultiHintData a, |
| 1918 | const InsertMultiHintData b) const { |
| 1919 | return a.key < b.key; |
| 1920 | } |
| 1921 | bool operator()(const int a, const InsertMultiHintData b) const { |
| 1922 | return a < b.key; |
| 1923 | } |
| 1924 | bool operator()(const InsertMultiHintData a, const int b) const { |
| 1925 | return a.key < b; |
| 1926 | } |
| 1927 | }; |
| 1928 | |
| 1929 | TEST(Btree, InsertHintNodeHandle) { |
| 1930 | // For unique sets, insert with hint is just a performance optimization. |
| 1931 | // Test that insert works correctly when the hint is right or wrong. |
| 1932 | { |
| 1933 | absl::btree_set<int> src = {1, 2, 3, 4, 5}; |
| 1934 | auto nh = src.extract(src.find(3)); |
| 1935 | EXPECT_THAT(src, ElementsAre(1, 2, 4, 5)); |
| 1936 | absl::btree_set<int> other = {0, 100}; |
| 1937 | // Test a correct hint. |
| 1938 | auto it = other.insert(other.lower_bound(3), std::move(nh)); |
| 1939 | EXPECT_THAT(other, ElementsAre(0, 3, 100)); |
| 1940 | EXPECT_EQ(it, other.find(3)); |
| 1941 | |
| 1942 | nh = src.extract(src.find(5)); |
| 1943 | // Test an incorrect hint. |
| 1944 | it = other.insert(other.end(), std::move(nh)); |
| 1945 | EXPECT_THAT(other, ElementsAre(0, 3, 5, 100)); |
| 1946 | EXPECT_EQ(it, other.find(5)); |
| 1947 | } |
| 1948 | |
| 1949 | absl::btree_multiset<InsertMultiHintData, InsertMultiHintDataKeyCompare> src = |
| 1950 | {{1, 2}, {3, 4}, {3, 5}}; |
| 1951 | auto nh = src.extract(src.lower_bound(3)); |
| 1952 | EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 4})); |
| 1953 | absl::btree_multiset<InsertMultiHintData, InsertMultiHintDataKeyCompare> |
| 1954 | other = {{3, 1}, {3, 2}, {3, 3}}; |
| 1955 | auto it = other.insert(--other.end(), std::move(nh)); |
| 1956 | EXPECT_THAT( |
| 1957 | other, ElementsAre(InsertMultiHintData{3, 1}, InsertMultiHintData{3, 2}, |
| 1958 | InsertMultiHintData{3, 4}, InsertMultiHintData{3, 3})); |
| 1959 | EXPECT_EQ(it, --(--other.end())); |
| 1960 | |
| 1961 | nh = src.extract(src.find(3)); |
| 1962 | EXPECT_EQ(nh.value(), (InsertMultiHintData{3, 5})); |
| 1963 | it = other.insert(other.begin(), std::move(nh)); |
| 1964 | EXPECT_THAT(other, |
| 1965 | ElementsAre(InsertMultiHintData{3, 5}, InsertMultiHintData{3, 1}, |
| 1966 | InsertMultiHintData{3, 2}, InsertMultiHintData{3, 4}, |
| 1967 | InsertMultiHintData{3, 3})); |
| 1968 | EXPECT_EQ(it, other.begin()); |
| 1969 | } |
| 1970 | |
| 1971 | struct IntCompareToCmp { |
| 1972 | absl::weak_ordering operator()(int a, int b) const { |
| 1973 | if (a < b) return absl::weak_ordering::less; |
| 1974 | if (a > b) return absl::weak_ordering::greater; |
| 1975 | return absl::weak_ordering::equivalent; |
| 1976 | } |
| 1977 | }; |
| 1978 | |
| 1979 | TEST(Btree, MergeIntoUniqueContainers) { |
| 1980 | absl::btree_set<int, IntCompareToCmp> src1 = {1, 2, 3}; |
| 1981 | absl::btree_multiset<int> src2 = {3, 4, 4, 5}; |
| 1982 | absl::btree_set<int> dst; |
| 1983 | |
| 1984 | dst.merge(src1); |
| 1985 | EXPECT_TRUE(src1.empty()); |
| 1986 | EXPECT_THAT(dst, ElementsAre(1, 2, 3)); |
| 1987 | dst.merge(src2); |
| 1988 | EXPECT_THAT(src2, ElementsAre(3, 4)); |
| 1989 | EXPECT_THAT(dst, ElementsAre(1, 2, 3, 4, 5)); |
| 1990 | } |
| 1991 | |
| 1992 | TEST(Btree, MergeIntoUniqueContainersWithCompareTo) { |
| 1993 | absl::btree_set<int, IntCompareToCmp> src1 = {1, 2, 3}; |
| 1994 | absl::btree_multiset<int> src2 = {3, 4, 4, 5}; |
| 1995 | absl::btree_set<int, IntCompareToCmp> dst; |
| 1996 | |
| 1997 | dst.merge(src1); |
| 1998 | EXPECT_TRUE(src1.empty()); |
| 1999 | EXPECT_THAT(dst, ElementsAre(1, 2, 3)); |
| 2000 | dst.merge(src2); |
| 2001 | EXPECT_THAT(src2, ElementsAre(3, 4)); |
| 2002 | EXPECT_THAT(dst, ElementsAre(1, 2, 3, 4, 5)); |
| 2003 | } |
| 2004 | |
| 2005 | TEST(Btree, MergeIntoMultiContainers) { |
| 2006 | absl::btree_set<int, IntCompareToCmp> src1 = {1, 2, 3}; |
| 2007 | absl::btree_multiset<int> src2 = {3, 4, 4, 5}; |
| 2008 | absl::btree_multiset<int> dst; |
| 2009 | |
| 2010 | dst.merge(src1); |
| 2011 | EXPECT_TRUE(src1.empty()); |
| 2012 | EXPECT_THAT(dst, ElementsAre(1, 2, 3)); |
| 2013 | dst.merge(src2); |
| 2014 | EXPECT_TRUE(src2.empty()); |
| 2015 | EXPECT_THAT(dst, ElementsAre(1, 2, 3, 3, 4, 4, 5)); |
| 2016 | } |
| 2017 | |
| 2018 | TEST(Btree, MergeIntoMultiContainersWithCompareTo) { |
| 2019 | absl::btree_set<int, IntCompareToCmp> src1 = {1, 2, 3}; |
| 2020 | absl::btree_multiset<int> src2 = {3, 4, 4, 5}; |
| 2021 | absl::btree_multiset<int, IntCompareToCmp> dst; |
| 2022 | |
| 2023 | dst.merge(src1); |
| 2024 | EXPECT_TRUE(src1.empty()); |
| 2025 | EXPECT_THAT(dst, ElementsAre(1, 2, 3)); |
| 2026 | dst.merge(src2); |
| 2027 | EXPECT_TRUE(src2.empty()); |
| 2028 | EXPECT_THAT(dst, ElementsAre(1, 2, 3, 3, 4, 4, 5)); |
| 2029 | } |
| 2030 | |
| 2031 | TEST(Btree, MergeIntoMultiMapsWithDifferentComparators) { |
| 2032 | absl::btree_map<int, int, IntCompareToCmp> src1 = {{1, 1}, {2, 2}, {3, 3}}; |
| 2033 | absl::btree_multimap<int, int, std::greater<int>> src2 = { |
| 2034 | {5, 5}, {4, 1}, {4, 4}, {3, 2}}; |
| 2035 | absl::btree_multimap<int, int> dst; |
| 2036 | |
| 2037 | dst.merge(src1); |
| 2038 | EXPECT_TRUE(src1.empty()); |
| 2039 | EXPECT_THAT(dst, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3))); |
| 2040 | dst.merge(src2); |
| 2041 | EXPECT_TRUE(src2.empty()); |
| 2042 | EXPECT_THAT(dst, ElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3), Pair(3, 2), |
| 2043 | Pair(4, 1), Pair(4, 4), Pair(5, 5))); |
| 2044 | } |
| 2045 | |
| 2046 | struct KeyCompareToWeakOrdering { |
| 2047 | template <typename T> |
| 2048 | absl::weak_ordering operator()(const T &a, const T &b) const { |
| 2049 | return a < b ? absl::weak_ordering::less |
| 2050 | : a == b ? absl::weak_ordering::equivalent |
| 2051 | : absl::weak_ordering::greater; |
| 2052 | } |
| 2053 | }; |
| 2054 | |
| 2055 | struct KeyCompareToStrongOrdering { |
| 2056 | template <typename T> |
| 2057 | absl::strong_ordering operator()(const T &a, const T &b) const { |
| 2058 | return a < b ? absl::strong_ordering::less |
| 2059 | : a == b ? absl::strong_ordering::equal |
| 2060 | : absl::strong_ordering::greater; |
| 2061 | } |
| 2062 | }; |
| 2063 | |
| 2064 | TEST(Btree, UserProvidedKeyCompareToComparators) { |
| 2065 | absl::btree_set<int, KeyCompareToWeakOrdering> weak_set = {1, 2, 3}; |
| 2066 | EXPECT_TRUE(weak_set.contains(2)); |
| 2067 | EXPECT_FALSE(weak_set.contains(4)); |
| 2068 | |
| 2069 | absl::btree_set<int, KeyCompareToStrongOrdering> strong_set = {1, 2, 3}; |
| 2070 | EXPECT_TRUE(strong_set.contains(2)); |
| 2071 | EXPECT_FALSE(strong_set.contains(4)); |
| 2072 | } |
| 2073 | |
| 2074 | TEST(Btree, TryEmplaceBasicTest) { |
| 2075 | absl::btree_map<int, std::string> m; |
| 2076 | |
| 2077 | // Should construct a std::string from the literal. |
| 2078 | m.try_emplace(1, "one"); |
| 2079 | EXPECT_EQ(1, m.size()); |
| 2080 | |
| 2081 | // Try other std::string constructors and const lvalue key. |
| 2082 | const int key(42); |
| 2083 | m.try_emplace(key, 3, 'a'); |
| 2084 | m.try_emplace(2, std::string("two")); |
| 2085 | |
| 2086 | EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); |
| 2087 | EXPECT_THAT(m, ElementsAreArray(std::vector<std::pair<int, std::string>>{ |
| 2088 | {1, "one"}, {2, "two"}, {42, "aaa"}})); |
| 2089 | } |
| 2090 | |
| 2091 | TEST(Btree, TryEmplaceWithHintWorks) { |
| 2092 | // Use a counting comparator here to verify that hint is used. |
| 2093 | int calls = 0; |
| 2094 | auto cmp = [&calls](int x, int y) { |
| 2095 | ++calls; |
| 2096 | return x < y; |
| 2097 | }; |
| 2098 | using Cmp = decltype(cmp); |
| 2099 | |
| 2100 | absl::btree_map<int, int, Cmp> m(cmp); |
| 2101 | for (int i = 0; i < 128; ++i) { |
| 2102 | m.emplace(i, i); |
| 2103 | } |
| 2104 | |
| 2105 | // Sanity check for the comparator |
| 2106 | calls = 0; |
| 2107 | m.emplace(127, 127); |
| 2108 | EXPECT_GE(calls, 4); |
| 2109 | |
| 2110 | // Try with begin hint: |
| 2111 | calls = 0; |
| 2112 | auto it = m.try_emplace(m.begin(), -1, -1); |
| 2113 | EXPECT_EQ(129, m.size()); |
| 2114 | EXPECT_EQ(it, m.begin()); |
| 2115 | EXPECT_LE(calls, 2); |
| 2116 | |
| 2117 | // Try with end hint: |
| 2118 | calls = 0; |
| 2119 | std::pair<int, int> pair1024 = {1024, 1024}; |
| 2120 | it = m.try_emplace(m.end(), pair1024.first, pair1024.second); |
| 2121 | EXPECT_EQ(130, m.size()); |
| 2122 | EXPECT_EQ(it, --m.end()); |
| 2123 | EXPECT_LE(calls, 2); |
| 2124 | |
| 2125 | // Try value already present, bad hint; ensure no duplicate added: |
| 2126 | calls = 0; |
| 2127 | it = m.try_emplace(m.end(), 16, 17); |
| 2128 | EXPECT_EQ(130, m.size()); |
| 2129 | EXPECT_GE(calls, 4); |
| 2130 | EXPECT_EQ(it, m.find(16)); |
| 2131 | |
| 2132 | // Try value already present, hint points directly to it: |
| 2133 | calls = 0; |
| 2134 | it = m.try_emplace(it, 16, 17); |
| 2135 | EXPECT_EQ(130, m.size()); |
| 2136 | EXPECT_LE(calls, 2); |
| 2137 | EXPECT_EQ(it, m.find(16)); |
| 2138 | |
| 2139 | m.erase(2); |
| 2140 | EXPECT_EQ(129, m.size()); |
| 2141 | auto hint = m.find(3); |
| 2142 | // Try emplace in the middle of two other elements. |
| 2143 | calls = 0; |
| 2144 | m.try_emplace(hint, 2, 2); |
| 2145 | EXPECT_EQ(130, m.size()); |
| 2146 | EXPECT_LE(calls, 2); |
| 2147 | |
| 2148 | EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); |
| 2149 | } |
| 2150 | |
| 2151 | TEST(Btree, TryEmplaceWithBadHint) { |
| 2152 | absl::btree_map<int, int> m = {{1, 1}, {9, 9}}; |
| 2153 | |
| 2154 | // Bad hint (too small), should still emplace: |
| 2155 | auto it = m.try_emplace(m.begin(), 2, 2); |
| 2156 | EXPECT_EQ(it, ++m.begin()); |
| 2157 | EXPECT_THAT(m, ElementsAreArray( |
| 2158 | std::vector<std::pair<int, int>>{{1, 1}, {2, 2}, {9, 9}})); |
| 2159 | |
| 2160 | // Bad hint, too large this time: |
| 2161 | it = m.try_emplace(++(++m.begin()), 0, 0); |
| 2162 | EXPECT_EQ(it, m.begin()); |
| 2163 | EXPECT_THAT(m, ElementsAreArray(std::vector<std::pair<int, int>>{ |
| 2164 | {0, 0}, {1, 1}, {2, 2}, {9, 9}})); |
| 2165 | } |
| 2166 | |
| 2167 | TEST(Btree, TryEmplaceMaintainsSortedOrder) { |
| 2168 | absl::btree_map<int, std::string> m; |
| 2169 | std::pair<int, std::string> pair5 = {5, "five"}; |
| 2170 | |
| 2171 | // Test both lvalue & rvalue emplace. |
| 2172 | m.try_emplace(10, "ten"); |
| 2173 | m.try_emplace(pair5.first, pair5.second); |
| 2174 | EXPECT_EQ(2, m.size()); |
| 2175 | EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); |
| 2176 | |
| 2177 | int int100{100}; |
| 2178 | m.try_emplace(int100, "hundred"); |
| 2179 | m.try_emplace(1, "one"); |
| 2180 | EXPECT_EQ(4, m.size()); |
| 2181 | EXPECT_TRUE(std::is_sorted(m.begin(), m.end())); |
| 2182 | } |
| 2183 | |
| 2184 | TEST(Btree, TryEmplaceWithHintAndNoValueArgsWorks) { |
| 2185 | absl::btree_map<int, int> m; |
| 2186 | m.try_emplace(m.end(), 1); |
| 2187 | EXPECT_EQ(0, m[1]); |
| 2188 | } |
| 2189 | |
| 2190 | TEST(Btree, TryEmplaceWithHintAndMultipleValueArgsWorks) { |
| 2191 | absl::btree_map<int, std::string> m; |
| 2192 | m.try_emplace(m.end(), 1, 10, 'a'); |
| 2193 | EXPECT_EQ(std::string(10, 'a'), m[1]); |
| 2194 | } |
| 2195 | |
| 2196 | TEST(Btree, MoveAssignmentAllocatorPropagation) { |
| 2197 | InstanceTracker tracker; |
| 2198 | |
| 2199 | int64_t bytes1 = 0, bytes2 = 0; |
| 2200 | PropagatingCountingAlloc<MovableOnlyInstance> allocator1(&bytes1); |
| 2201 | PropagatingCountingAlloc<MovableOnlyInstance> allocator2(&bytes2); |
| 2202 | std::less<MovableOnlyInstance> cmp; |
| 2203 | |
| 2204 | // Test propagating allocator_type. |
| 2205 | { |
| 2206 | absl::btree_set<MovableOnlyInstance, std::less<MovableOnlyInstance>, |
| 2207 | PropagatingCountingAlloc<MovableOnlyInstance>> |
| 2208 | set1(cmp, allocator1), set2(cmp, allocator2); |
| 2209 | |
| 2210 | for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); |
| 2211 | |
| 2212 | tracker.ResetCopiesMovesSwaps(); |
| 2213 | set2 = std::move(set1); |
| 2214 | EXPECT_EQ(tracker.moves(), 0); |
| 2215 | } |
| 2216 | // Test non-propagating allocator_type with equal allocators. |
| 2217 | { |
| 2218 | absl::btree_set<MovableOnlyInstance, std::less<MovableOnlyInstance>, |
| 2219 | CountingAllocator<MovableOnlyInstance>> |
| 2220 | set1(cmp, allocator1), set2(cmp, allocator1); |
| 2221 | |
| 2222 | for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); |
| 2223 | |
| 2224 | tracker.ResetCopiesMovesSwaps(); |
| 2225 | set2 = std::move(set1); |
| 2226 | EXPECT_EQ(tracker.moves(), 0); |
| 2227 | } |
| 2228 | // Test non-propagating allocator_type with different allocators. |
| 2229 | { |
| 2230 | absl::btree_set<MovableOnlyInstance, std::less<MovableOnlyInstance>, |
| 2231 | CountingAllocator<MovableOnlyInstance>> |
| 2232 | set1(cmp, allocator1), set2(cmp, allocator2); |
| 2233 | |
| 2234 | for (int i = 0; i < 100; ++i) set1.insert(MovableOnlyInstance(i)); |
| 2235 | |
| 2236 | tracker.ResetCopiesMovesSwaps(); |
| 2237 | set2 = std::move(set1); |
| 2238 | EXPECT_GE(tracker.moves(), 100); |
| 2239 | } |
| 2240 | } |
| 2241 | |
| 2242 | } // namespace |
| 2243 | } // namespace container_internal |
| 2244 | } // namespace absl |