blob: 726861d5bbb1893b2ab9b9a81a15795ccaab0e6c [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// 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#ifndef ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
16#define ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
17
18#include <algorithm>
19#include <initializer_list>
20#include <iterator>
21#include <utility>
22
23#include "absl/base/internal/throw_delegate.h"
24#include "absl/container/internal/btree.h" // IWYU pragma: export
25#include "absl/container/internal/common.h"
26#include "absl/meta/type_traits.h"
27
28namespace absl {
29namespace container_internal {
30
31// A common base class for btree_set, btree_map, btree_multiset, and
32// btree_multimap.
33template <typename Tree>
34class btree_container {
35 using params_type = typename Tree::params_type;
36
37 protected:
38 // Alias used for heterogeneous lookup functions.
39 // `key_arg<K>` evaluates to `K` when the functors are transparent and to
40 // `key_type` otherwise. It permits template argument deduction on `K` for the
41 // transparent case.
42 template <class K>
43 using key_arg =
44 typename KeyArg<IsTransparent<typename Tree::key_compare>::value>::
45 template type<K, typename Tree::key_type>;
46
47 public:
48 using key_type = typename Tree::key_type;
49 using value_type = typename Tree::value_type;
50 using size_type = typename Tree::size_type;
51 using difference_type = typename Tree::difference_type;
52 using key_compare = typename Tree::key_compare;
53 using value_compare = typename Tree::value_compare;
54 using allocator_type = typename Tree::allocator_type;
55 using reference = typename Tree::reference;
56 using const_reference = typename Tree::const_reference;
57 using pointer = typename Tree::pointer;
58 using const_pointer = typename Tree::const_pointer;
59 using iterator = typename Tree::iterator;
60 using const_iterator = typename Tree::const_iterator;
61 using reverse_iterator = typename Tree::reverse_iterator;
62 using const_reverse_iterator = typename Tree::const_reverse_iterator;
63 using node_type = typename Tree::node_handle_type;
64
65 // Constructors/assignments.
66 btree_container() : tree_(key_compare(), allocator_type()) {}
67 explicit btree_container(const key_compare &comp,
68 const allocator_type &alloc = allocator_type())
69 : tree_(comp, alloc) {}
70 btree_container(const btree_container &x) = default;
71 btree_container(btree_container &&x) noexcept = default;
72 btree_container &operator=(const btree_container &x) = default;
73 btree_container &operator=(btree_container &&x) noexcept(
74 std::is_nothrow_move_assignable<Tree>::value) = default;
75
76 // Iterator routines.
77 iterator begin() { return tree_.begin(); }
78 const_iterator begin() const { return tree_.begin(); }
79 const_iterator cbegin() const { return tree_.begin(); }
80 iterator end() { return tree_.end(); }
81 const_iterator end() const { return tree_.end(); }
82 const_iterator cend() const { return tree_.end(); }
83 reverse_iterator rbegin() { return tree_.rbegin(); }
84 const_reverse_iterator rbegin() const { return tree_.rbegin(); }
85 const_reverse_iterator crbegin() const { return tree_.rbegin(); }
86 reverse_iterator rend() { return tree_.rend(); }
87 const_reverse_iterator rend() const { return tree_.rend(); }
88 const_reverse_iterator crend() const { return tree_.rend(); }
89
90 // Lookup routines.
91 template <typename K = key_type>
92 iterator find(const key_arg<K> &key) {
93 return tree_.find(key);
94 }
95 template <typename K = key_type>
96 const_iterator find(const key_arg<K> &key) const {
97 return tree_.find(key);
98 }
99 template <typename K = key_type>
100 bool contains(const key_arg<K> &key) const {
101 return find(key) != end();
102 }
103 template <typename K = key_type>
104 iterator lower_bound(const key_arg<K> &key) {
105 return tree_.lower_bound(key);
106 }
107 template <typename K = key_type>
108 const_iterator lower_bound(const key_arg<K> &key) const {
109 return tree_.lower_bound(key);
110 }
111 template <typename K = key_type>
112 iterator upper_bound(const key_arg<K> &key) {
113 return tree_.upper_bound(key);
114 }
115 template <typename K = key_type>
116 const_iterator upper_bound(const key_arg<K> &key) const {
117 return tree_.upper_bound(key);
118 }
119 template <typename K = key_type>
120 std::pair<iterator, iterator> equal_range(const key_arg<K> &key) {
121 return tree_.equal_range(key);
122 }
123 template <typename K = key_type>
124 std::pair<const_iterator, const_iterator> equal_range(
125 const key_arg<K> &key) const {
126 return tree_.equal_range(key);
127 }
128
129 // Deletion routines. Note that there is also a deletion routine that is
130 // specific to btree_set_container/btree_multiset_container.
131
132 // Erase the specified iterator from the btree. The iterator must be valid
133 // (i.e. not equal to end()). Return an iterator pointing to the node after
134 // the one that was erased (or end() if none exists).
135 iterator erase(const_iterator iter) { return tree_.erase(iterator(iter)); }
136 iterator erase(iterator iter) { return tree_.erase(iter); }
137 iterator erase(const_iterator first, const_iterator last) {
138 return tree_.erase(iterator(first), iterator(last)).second;
139 }
140
141 // Extract routines.
142 node_type extract(iterator position) {
143 // Use Move instead of Transfer, because the rebalancing code expects to
144 // have a valid object to scribble metadata bits on top of.
145 auto node = CommonAccess::Move<node_type>(get_allocator(), position.slot());
146 erase(position);
147 return node;
148 }
149 node_type extract(const_iterator position) {
150 return extract(iterator(position));
151 }
152
153 public:
154 // Utility routines.
155 void clear() { tree_.clear(); }
156 void swap(btree_container &x) { tree_.swap(x.tree_); }
157 void verify() const { tree_.verify(); }
158
159 // Size routines.
160 size_type size() const { return tree_.size(); }
161 size_type max_size() const { return tree_.max_size(); }
162 bool empty() const { return tree_.empty(); }
163
164 friend bool operator==(const btree_container &x, const btree_container &y) {
165 if (x.size() != y.size()) return false;
166 return std::equal(x.begin(), x.end(), y.begin());
167 }
168
169 friend bool operator!=(const btree_container &x, const btree_container &y) {
170 return !(x == y);
171 }
172
173 friend bool operator<(const btree_container &x, const btree_container &y) {
174 return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
175 }
176
177 friend bool operator>(const btree_container &x, const btree_container &y) {
178 return y < x;
179 }
180
181 friend bool operator<=(const btree_container &x, const btree_container &y) {
182 return !(y < x);
183 }
184
185 friend bool operator>=(const btree_container &x, const btree_container &y) {
186 return !(x < y);
187 }
188
189 // The allocator used by the btree.
190 allocator_type get_allocator() const { return tree_.get_allocator(); }
191
192 // The key comparator used by the btree.
193 key_compare key_comp() const { return tree_.key_comp(); }
194 value_compare value_comp() const { return tree_.value_comp(); }
195
196 // Support absl::Hash.
197 template <typename State>
198 friend State AbslHashValue(State h, const btree_container &b) {
199 for (const auto &v : b) {
200 h = State::combine(std::move(h), v);
201 }
202 return State::combine(std::move(h), b.size());
203 }
204
205 protected:
206 Tree tree_;
207};
208
209// A common base class for btree_set and btree_map.
210template <typename Tree>
211class btree_set_container : public btree_container<Tree> {
212 using super_type = btree_container<Tree>;
213 using params_type = typename Tree::params_type;
214 using init_type = typename params_type::init_type;
215 using is_key_compare_to = typename params_type::is_key_compare_to;
216 friend class BtreeNodePeer;
217
218 protected:
219 template <class K>
220 using key_arg = typename super_type::template key_arg<K>;
221
222 public:
223 using key_type = typename Tree::key_type;
224 using value_type = typename Tree::value_type;
225 using size_type = typename Tree::size_type;
226 using key_compare = typename Tree::key_compare;
227 using allocator_type = typename Tree::allocator_type;
228 using iterator = typename Tree::iterator;
229 using const_iterator = typename Tree::const_iterator;
230 using node_type = typename super_type::node_type;
231 using insert_return_type = InsertReturnType<iterator, node_type>;
232
233 // Inherit constructors.
234 using super_type::super_type;
235 btree_set_container() {}
236
237 // Range constructor.
238 template <class InputIterator>
239 btree_set_container(InputIterator b, InputIterator e,
240 const key_compare &comp = key_compare(),
241 const allocator_type &alloc = allocator_type())
242 : super_type(comp, alloc) {
243 insert(b, e);
244 }
245
246 // Initializer list constructor.
247 btree_set_container(std::initializer_list<init_type> init,
248 const key_compare &comp = key_compare(),
249 const allocator_type &alloc = allocator_type())
250 : btree_set_container(init.begin(), init.end(), comp, alloc) {}
251
252 // Lookup routines.
253 template <typename K = key_type>
254 size_type count(const key_arg<K> &key) const {
255 return this->tree_.count_unique(key);
256 }
257
258 // Insertion routines.
259 std::pair<iterator, bool> insert(const value_type &x) {
260 return this->tree_.insert_unique(params_type::key(x), x);
261 }
262 std::pair<iterator, bool> insert(value_type &&x) {
263 return this->tree_.insert_unique(params_type::key(x), std::move(x));
264 }
265 template <typename... Args>
266 std::pair<iterator, bool> emplace(Args &&... args) {
267 init_type v(std::forward<Args>(args)...);
268 return this->tree_.insert_unique(params_type::key(v), std::move(v));
269 }
270 iterator insert(const_iterator position, const value_type &x) {
271 return this->tree_
272 .insert_hint_unique(iterator(position), params_type::key(x), x)
273 .first;
274 }
275 iterator insert(const_iterator position, value_type &&x) {
276 return this->tree_
277 .insert_hint_unique(iterator(position), params_type::key(x),
278 std::move(x))
279 .first;
280 }
281 template <typename... Args>
282 iterator emplace_hint(const_iterator position, Args &&... args) {
283 init_type v(std::forward<Args>(args)...);
284 return this->tree_
285 .insert_hint_unique(iterator(position), params_type::key(v),
286 std::move(v))
287 .first;
288 }
289 template <typename InputIterator>
290 void insert(InputIterator b, InputIterator e) {
291 this->tree_.insert_iterator_unique(b, e);
292 }
293 void insert(std::initializer_list<init_type> init) {
294 this->tree_.insert_iterator_unique(init.begin(), init.end());
295 }
296 insert_return_type insert(node_type &&node) {
297 if (!node) return {this->end(), false, node_type()};
298 std::pair<iterator, bool> res =
299 insert(std::move(params_type::element(CommonAccess::GetSlot(node))));
300 if (res.second) {
301 CommonAccess::Reset(&node);
302 return {res.first, true, node_type()};
303 } else {
304 return {res.first, false, std::move(node)};
305 }
306 }
307 iterator insert(const_iterator hint, node_type &&node) {
308 if (!node) return this->end();
309 std::pair<iterator, bool> res = this->tree_.insert_hint_unique(
310 iterator(hint), params_type::key(CommonAccess::GetSlot(node)),
311 std::move(params_type::element(CommonAccess::GetSlot(node))));
312 if (res.second) CommonAccess::Reset(&node);
313 return res.first;
314 }
315
316 // Deletion routines.
317 template <typename K = key_type>
318 size_type erase(const key_arg<K> &key) {
319 return this->tree_.erase_unique(key);
320 }
321 using super_type::erase;
322
323 // Node extraction routines.
324 template <typename K = key_type>
325 node_type extract(const key_arg<K> &key) {
326 auto it = find(key);
327 return it == this->end() ? node_type() : extract(it);
328 }
329 using super_type::extract;
330
331 // Merge routines.
332 // Moves elements from `src` into `this`. If the element already exists in
333 // `this`, it is left unmodified in `src`.
334 template <
335 typename T,
336 typename absl::enable_if_t<
337 absl::conjunction<
338 std::is_same<value_type, typename T::value_type>,
339 std::is_same<allocator_type, typename T::allocator_type>,
340 std::is_same<typename params_type::is_map_container,
341 typename T::params_type::is_map_container>>::value,
342 int> = 0>
343 void merge(btree_container<T> &src) { // NOLINT
344 for (auto src_it = src.begin(); src_it != src.end();) {
345 if (insert(std::move(*src_it)).second) {
346 src_it = src.erase(src_it);
347 } else {
348 ++src_it;
349 }
350 }
351 }
352
353 template <
354 typename T,
355 typename absl::enable_if_t<
356 absl::conjunction<
357 std::is_same<value_type, typename T::value_type>,
358 std::is_same<allocator_type, typename T::allocator_type>,
359 std::is_same<typename params_type::is_map_container,
360 typename T::params_type::is_map_container>>::value,
361 int> = 0>
362 void merge(btree_container<T> &&src) {
363 merge(src);
364 }
365};
366
367// Base class for btree_map.
368template <typename Tree>
369class btree_map_container : public btree_set_container<Tree> {
370 using super_type = btree_set_container<Tree>;
371 using params_type = typename Tree::params_type;
372
373 protected:
374 template <class K>
375 using key_arg = typename super_type::template key_arg<K>;
376
377 public:
378 using key_type = typename Tree::key_type;
379 using mapped_type = typename params_type::mapped_type;
380 using value_type = typename Tree::value_type;
381 using key_compare = typename Tree::key_compare;
382 using allocator_type = typename Tree::allocator_type;
383 using iterator = typename Tree::iterator;
384 using const_iterator = typename Tree::const_iterator;
385
386 // Inherit constructors.
387 using super_type::super_type;
388 btree_map_container() {}
389
390 // Insertion routines.
391 template <typename... Args>
392 std::pair<iterator, bool> try_emplace(const key_type &k, Args &&... args) {
393 return this->tree_.insert_unique(
394 k, std::piecewise_construct, std::forward_as_tuple(k),
395 std::forward_as_tuple(std::forward<Args>(args)...));
396 }
397 template <typename... Args>
398 std::pair<iterator, bool> try_emplace(key_type &&k, Args &&... args) {
399 // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k`
400 // and then using `k` unsequenced. This is safe because the move is into a
401 // forwarding reference and insert_unique guarantees that `key` is never
402 // referenced after consuming `args`.
403 const key_type& key_ref = k;
404 return this->tree_.insert_unique(
405 key_ref, std::piecewise_construct, std::forward_as_tuple(std::move(k)),
406 std::forward_as_tuple(std::forward<Args>(args)...));
407 }
408 template <typename... Args>
409 iterator try_emplace(const_iterator hint, const key_type &k,
410 Args &&... args) {
411 return this->tree_
412 .insert_hint_unique(iterator(hint), k, std::piecewise_construct,
413 std::forward_as_tuple(k),
414 std::forward_as_tuple(std::forward<Args>(args)...))
415 .first;
416 }
417 template <typename... Args>
418 iterator try_emplace(const_iterator hint, key_type &&k, Args &&... args) {
419 // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k`
420 // and then using `k` unsequenced. This is safe because the move is into a
421 // forwarding reference and insert_hint_unique guarantees that `key` is
422 // never referenced after consuming `args`.
423 const key_type& key_ref = k;
424 return this->tree_
425 .insert_hint_unique(iterator(hint), key_ref, std::piecewise_construct,
426 std::forward_as_tuple(std::move(k)),
427 std::forward_as_tuple(std::forward<Args>(args)...))
428 .first;
429 }
430 mapped_type &operator[](const key_type &k) {
431 return try_emplace(k).first->second;
432 }
433 mapped_type &operator[](key_type &&k) {
434 return try_emplace(std::move(k)).first->second;
435 }
436
437 template <typename K = key_type>
438 mapped_type &at(const key_arg<K> &key) {
439 auto it = this->find(key);
440 if (it == this->end())
441 base_internal::ThrowStdOutOfRange("absl::btree_map::at");
442 return it->second;
443 }
444 template <typename K = key_type>
445 const mapped_type &at(const key_arg<K> &key) const {
446 auto it = this->find(key);
447 if (it == this->end())
448 base_internal::ThrowStdOutOfRange("absl::btree_map::at");
449 return it->second;
450 }
451};
452
453// A common base class for btree_multiset and btree_multimap.
454template <typename Tree>
455class btree_multiset_container : public btree_container<Tree> {
456 using super_type = btree_container<Tree>;
457 using params_type = typename Tree::params_type;
458 using init_type = typename params_type::init_type;
459 using is_key_compare_to = typename params_type::is_key_compare_to;
460
461 template <class K>
462 using key_arg = typename super_type::template key_arg<K>;
463
464 public:
465 using key_type = typename Tree::key_type;
466 using value_type = typename Tree::value_type;
467 using size_type = typename Tree::size_type;
468 using key_compare = typename Tree::key_compare;
469 using allocator_type = typename Tree::allocator_type;
470 using iterator = typename Tree::iterator;
471 using const_iterator = typename Tree::const_iterator;
472 using node_type = typename super_type::node_type;
473
474 // Inherit constructors.
475 using super_type::super_type;
476 btree_multiset_container() {}
477
478 // Range constructor.
479 template <class InputIterator>
480 btree_multiset_container(InputIterator b, InputIterator e,
481 const key_compare &comp = key_compare(),
482 const allocator_type &alloc = allocator_type())
483 : super_type(comp, alloc) {
484 insert(b, e);
485 }
486
487 // Initializer list constructor.
488 btree_multiset_container(std::initializer_list<init_type> init,
489 const key_compare &comp = key_compare(),
490 const allocator_type &alloc = allocator_type())
491 : btree_multiset_container(init.begin(), init.end(), comp, alloc) {}
492
493 // Lookup routines.
494 template <typename K = key_type>
495 size_type count(const key_arg<K> &key) const {
496 return this->tree_.count_multi(key);
497 }
498
499 // Insertion routines.
500 iterator insert(const value_type &x) { return this->tree_.insert_multi(x); }
501 iterator insert(value_type &&x) {
502 return this->tree_.insert_multi(std::move(x));
503 }
504 iterator insert(const_iterator position, const value_type &x) {
505 return this->tree_.insert_hint_multi(iterator(position), x);
506 }
507 iterator insert(const_iterator position, value_type &&x) {
508 return this->tree_.insert_hint_multi(iterator(position), std::move(x));
509 }
510 template <typename InputIterator>
511 void insert(InputIterator b, InputIterator e) {
512 this->tree_.insert_iterator_multi(b, e);
513 }
514 void insert(std::initializer_list<init_type> init) {
515 this->tree_.insert_iterator_multi(init.begin(), init.end());
516 }
517 template <typename... Args>
518 iterator emplace(Args &&... args) {
519 return this->tree_.insert_multi(init_type(std::forward<Args>(args)...));
520 }
521 template <typename... Args>
522 iterator emplace_hint(const_iterator position, Args &&... args) {
523 return this->tree_.insert_hint_multi(
524 iterator(position), init_type(std::forward<Args>(args)...));
525 }
526
527 private:
528 template <typename... Args>
529 iterator insert_node_helper(node_type &&node, Args &&... args) {
530 if (!node) return this->end();
531 iterator res =
532 insert(std::forward<Args>(args)...,
533 std::move(params_type::element(CommonAccess::GetSlot(node))));
534 CommonAccess::Reset(&node);
535 return res;
536 }
537
538 public:
539 iterator insert(node_type &&node) {
540 return insert_node_helper(std::move(node));
541 }
542 iterator insert(const_iterator hint, node_type &&node) {
543 return insert_node_helper(std::move(node), hint);
544 }
545
546 // Deletion routines.
547 template <typename K = key_type>
548 size_type erase(const key_arg<K> &key) {
549 return this->tree_.erase_multi(key);
550 }
551 using super_type::erase;
552
553 // Node extraction routines.
554 template <typename K = key_type>
555 node_type extract(const key_arg<K> &key) {
556 auto it = find(key);
557 return it == this->end() ? node_type() : extract(it);
558 }
559 using super_type::extract;
560
561 // Merge routines.
562 // Moves all elements from `src` into `this`.
563 template <
564 typename T,
565 typename absl::enable_if_t<
566 absl::conjunction<
567 std::is_same<value_type, typename T::value_type>,
568 std::is_same<allocator_type, typename T::allocator_type>,
569 std::is_same<typename params_type::is_map_container,
570 typename T::params_type::is_map_container>>::value,
571 int> = 0>
572 void merge(btree_container<T> &src) { // NOLINT
573 insert(std::make_move_iterator(src.begin()),
574 std::make_move_iterator(src.end()));
575 src.clear();
576 }
577
578 template <
579 typename T,
580 typename absl::enable_if_t<
581 absl::conjunction<
582 std::is_same<value_type, typename T::value_type>,
583 std::is_same<allocator_type, typename T::allocator_type>,
584 std::is_same<typename params_type::is_map_container,
585 typename T::params_type::is_map_container>>::value,
586 int> = 0>
587 void merge(btree_container<T> &&src) {
588 merge(src);
589 }
590};
591
592// A base class for btree_multimap.
593template <typename Tree>
594class btree_multimap_container : public btree_multiset_container<Tree> {
595 using super_type = btree_multiset_container<Tree>;
596 using params_type = typename Tree::params_type;
597
598 public:
599 using mapped_type = typename params_type::mapped_type;
600
601 // Inherit constructors.
602 using super_type::super_type;
603 btree_multimap_container() {}
604};
605
606} // namespace container_internal
607} // namespace absl
608
609#endif // ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_