source: mainline/uspace/lib/cpp/include/impl/unordered_map.hpp@ 68cfab1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 68cfab1 was 0893dd23, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: fixed enable_ifs

  • Property mode set to 100644
File size: 38.7 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_UNORDERED_MAP
30#define LIBCPP_UNORDERED_MAP
31
32#include <initializer_list>
33#include <internal/hash_table.hpp>
34#include <functional>
35#include <memory>
36#include <type_traits>
37#include <utility>
38
39namespace std
40{
41 /**
42 * 23.5.4, class template unordered_map:
43 */
44
45 template<
46 class Key, class Value,
47 class Hash = hash<Key>,
48 class Pred = equal_to<Key>,
49 class Alloc = allocator<pair<const Key, Value>>
50 >
51 class unordered_map
52 {
53 public:
54 using key_type = Key;
55 using mapped_type = Value;
56 using value_type = pair<const key_type, mapped_type>;
57 using hasher = Hash;
58 using key_equal = Pred;
59 using allocator_type = Alloc;
60 using pointer = typename allocator_traits<allocator_type>::pointer;
61 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
62 using reference = value_type&;
63 using const_reference = const value_type&;
64 using size_type = size_t;
65 using difference_type = ptrdiff_t;
66
67 using iterator = aux::hash_table_iterator<
68 value_type, reference, pointer, size_type
69 >;
70 using const_iterator = aux::hash_table_const_iterator<
71 value_type, const_reference, const_pointer, size_type
72 >;
73 using local_iterator = aux::hash_table_local_iterator<
74 value_type, reference, pointer
75 >;
76 using const_local_iterator = aux::hash_table_const_local_iterator<
77 value_type, const_reference, const_pointer
78 >;
79
80 unordered_map()
81 : unordered_map{default_bucket_count_}
82 { /* DUMMY BODY */ }
83
84 explicit unordered_map(size_type bucket_count,
85 const hasher& hf = hasher{},
86 const key_equal& eql = key_equal{},
87 const allocator_type& alloc = allocator_type{})
88 : table_{bucket_count, hf, eql}, allocator_{alloc}
89 { /* DUMMY BODY */ }
90
91 template<class InputIterator>
92 unordered_map(InputIterator first, InputIterator last,
93 size_type bucket_count = default_bucket_count_,
94 const hasher& hf = hasher{},
95 const key_equal& eql = key_equal{},
96 const allocator_type& alloc = allocator_type{})
97 : unordered_map{bucket_count, hf, eql, alloc}
98 {
99 insert(first, last);
100 }
101
102 unordered_map(const unordered_map& other)
103 : unordered_map{other, other.allocator_}
104 { /* DUMMY BODY */ }
105
106 unordered_map(unordered_map&& other)
107 : table_{move(other.table_)}, allocator_{move(other.allocator_)}
108 { /* DUMMY BODY */ }
109
110 explicit unordered_map(const allocator_type& alloc)
111 : table_{default_bucket_count_}, allocator_{alloc}
112 { /* DUMMY BODY */ }
113
114 unordered_map(const unordered_map& other, const allocator_type& alloc)
115 : table_{other.table_}, allocator_{alloc}
116 { /* DUMMY BODY */ }
117
118 unordered_map(unordered_map&& other, const allocator_type& alloc)
119 : table_{move(other.table_)}, allocator_{alloc}
120 { /* DUMMY BODY */ }
121
122 unordered_map(initializer_list<value_type> init,
123 size_type bucket_count = default_bucket_count_,
124 const hasher& hf = hasher{},
125 const key_equal& eql = key_equal{},
126 const allocator_type& alloc = allocator_type{})
127 : unordered_map{bucket_count, hf, eql, alloc}
128 {
129 insert(init.begin(), init.end());
130 }
131
132 unordered_map(size_type bucket_count, const allocator_type& alloc)
133 : unordered_map{bucket_count, hasher{}, key_equal{}, alloc}
134 { /* DUMMY BODY */ }
135
136 unordered_map(size_type bucket_count, const hasher& hf, const allocator_type& alloc)
137 : unordered_map{bucket_count, hf, key_equal{}, alloc}
138 { /* DUMMY BODY */ }
139
140 template<class InputIterator>
141 unordered_map(InputIterator first, InputIterator last,
142 size_type bucket_count, const allocator_type& alloc)
143 : unordered_map{first, last, bucket_count, hasher{}, key_equal{}, alloc}
144 { /* DUMMY BODY */ }
145
146 template<class InputIterator>
147 unordered_map(InputIterator first, InputIterator last,
148 size_type bucket_count, const hasher& hf, const allocator_type& alloc)
149 : unordered_map{first, last, bucket_count, hf, key_equal{}, alloc}
150 { /* DUMMY BODY */ }
151
152 unordered_map(initializer_list<value_type> init, size_type bucket_count,
153 const allocator_type& alloc)
154 : unordered_map{init, bucket_count, hasher{}, key_equal{}, alloc}
155 { /* DUMMY BODY */ }
156
157 unordered_map(initializer_list<value_type> init, size_type bucket_count,
158 const hasher& hf, const allocator_type& alloc)
159 : unordered_map{init, bucket_count, hf, key_equal{}, alloc}
160 { /* DUMMY BODY */ }
161
162 ~unordered_map()
163 { /* DUMMY BODY */ }
164
165 unordered_map& operator=(const unordered_map& other)
166 {
167 table_ = other.table_;
168 allocator_ = other.allocator_;
169
170 return *this;
171 }
172
173 unordered_map& operator=(unordered_map&& other)
174 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
175 is_nothrow_move_assignable<hasher>::value &&
176 is_nothrow_move_assignable<key_equal>::value)
177 {
178 table_ = move(other.table_);
179 allocator_ = move(other.allocator_);
180
181 return *this;
182 }
183
184 unordered_map& operator=(initializer_list<value_type>& init)
185 {
186 table_.clear();
187 table_.reserve(init.size());
188
189 insert(init.begin(), init.end());
190
191 return *this;
192 }
193
194 allocator_type get_allocator() const noexcept
195 {
196 return allocator_;
197 }
198
199 bool empty() const noexcept
200 {
201 return table_.empty();
202 }
203
204 size_type size() const noexcept
205 {
206 return table_.size();
207 }
208
209 size_type max_size() const noexcept
210 {
211 return table_.max_size(allocator_);
212 }
213
214 iterator begin() noexcept
215 {
216 return table_.begin();
217 }
218
219 const_iterator begin() const noexcept
220 {
221 return table_.begin();
222 }
223
224 iterator end() noexcept
225 {
226 return table_.end();
227 }
228
229 const_iterator end() const noexcept
230 {
231 return table_.end();
232 }
233
234 const_iterator cbegin() const noexcept
235 {
236 return table_.cbegin();
237 }
238
239 const_iterator cend() const noexcept
240 {
241 return table_.cend();
242 }
243
244 template<class... Args>
245 pair<iterator, bool> emplace(Args&&... args)
246 {
247 return table_.emplace(forward<Args>(args)...);
248 }
249
250 template<class... Args>
251 iterator emplace_hint(const_iterator, Args&&... args)
252 {
253 return emplace(forward<Args>(args)...).first;
254 }
255
256 pair<iterator, bool> insert(const value_type& val)
257 {
258 return table_.insert(val);
259 }
260
261 pair<iterator, bool> insert(value_type&& val)
262 {
263 return table_.insert(forward<value_type>(val));
264 }
265
266 template<class T>
267 pair<iterator, bool> insert(
268 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val)
269 {
270 return emplace(forward<T>(val));
271 }
272
273 iterator insert(const_iterator, const value_type& val)
274 {
275 return insert(val).first;
276 }
277
278 iterator insert(const_iterator, value_type&& val)
279 {
280 return insert(forward<value_type>(val)).first;
281 }
282
283 template<class T>
284 iterator insert(
285 const_iterator hint,
286 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val
287 )
288 {
289 return emplace_hint(hint, forward<T>(val));
290 }
291
292 template<class InputIterator>
293 void insert(InputIterator first, InputIterator last)
294 {
295 while (first != last)
296 insert(*first++);
297 }
298
299 void insert(initializer_list<value_type> init)
300 {
301 insert(init.begin(), init.end());
302 }
303
304 template<class... Args>
305 pair<iterator, bool> try_emplace(const key_type& key, Args&&... args)
306 {
307 /**
308 * Note: If anyone (like me) wonders what is the difference between
309 * emplace and try_emplace, the former always constructs the value
310 * (in order to get the key) and the latter does it only if
311 * an insertion takes place.
312 */
313
314 table_.increment_size();
315
316 auto [bucket, target, idx] = table_.find_insertion_spot(key);
317
318 if (!bucket)
319 return make_pair(end(), false);
320
321 if (target && table_.keys_equal(key, target->value))
322 {
323 table_.decrement_size();
324
325 return make_pair(
326 iterator{
327 table_.table(), idx, table_.bucket_count(),
328 target
329 },
330 false
331 );
332 }
333 else
334 {
335 auto node = new node_type{key, forward<Args>(args)...};
336 bucket->append(node);
337
338 return make_pair(iterator{
339 table_.table(), idx,
340 table_.bucket_count(),
341 node
342 }, true);
343 }
344 }
345
346 template<class... Args>
347 pair<iterator, bool> try_emplace(key_type&& key, Args&&... args)
348 {
349 table_.increment_size();
350
351 auto [bucket, target, idx] = table_.find_insertion_spot(key);
352
353 if (!bucket)
354 return make_pair(end(), false);
355
356 if (target && table_.keys_equal(key, target->value))
357 {
358 table_.decrement_size();
359
360 return make_pair(
361 iterator{
362 table_.table(), idx, table_.bucket_count(),
363 target
364 },
365 false
366 );
367 }
368 else
369 {
370 auto node = new node_type{move(key), forward<Args>(args)...};
371 bucket->append(node);
372
373 return make_pair(iterator{
374 table_.table(), idx,
375 table_.bucket_count(),
376 node
377 }, true);
378 }
379 }
380
381 template<class... Args>
382 iterator try_emplace(const_iterator, const key_type& key, Args&&... args)
383 {
384 return try_emplace(key, forward<Args>(args)...).first;
385 }
386
387 template<class... Args>
388 iterator try_emplace(const_iterator, key_type&& key, Args&&... args)
389 {
390 return try_emplace(move(key), forward<Args>(args)...).first;
391 }
392
393 template<class T>
394 pair<iterator, bool> insert_or_assign(const key_type& key, T&& val)
395 {
396 table_.increment_size();
397
398 auto [bucket, target, idx] = table_.find_insertion_spot(key);
399
400 if (!bucket)
401 return make_pair(end(), false);
402
403 if (target && table_.keys_equal(key, target->value))
404 {
405 table_.decrement_size();
406 target->value.second = forward<T>(val);
407
408 return make_pair(
409 iterator{
410 table_.table(), idx, table_.bucket_count(),
411 target
412 },
413 false
414 );
415 }
416 else
417 {
418 auto node = new node_type{key, forward<T>(val)};
419 bucket->append(node);
420
421 return make_pair(iterator{
422 table_.table(), idx,
423 table_.bucket_count(),
424 node
425 }, true);
426 }
427 }
428
429 template<class T>
430 pair<iterator, bool> insert_or_assign(key_type&& key, T&& val)
431 {
432 table_.increment_size();
433
434 auto [bucket, target, idx] = table_.find_insertion_spot(key);
435
436 if (!bucket)
437 return make_pair(end(), false);
438
439 if (target && table_.keys_equal(key, target->value))
440 {
441 table_.decrement_size();
442 target->value.second = forward<T>(val);
443
444 return make_pair(
445 iterator{
446 table_.table(), idx, table_.bucket_count(),
447 target
448 },
449 false
450 );
451 }
452 else
453 {
454 auto node = new node_type{move(key), forward<T>(val)};
455 bucket->append(node);
456
457 return make_pair(iterator{
458 table_.table(), idx,
459 table_.bucket_count(),
460 node
461 }, true);
462 }
463 }
464
465 template<class T>
466 iterator insert_or_assign(const_iterator, const key_type& key, T&& val)
467 {
468 return insert_or_assign(key, forward<T>(val)).first;
469 }
470
471 template<class T>
472 iterator insert_or_assign(const_iterator, key_type&& key, T&& val)
473 {
474 return insert_or_assign(move(key), forward<T>(val)).first;
475 }
476
477 iterator erase(const_iterator position)
478 {
479 return table_.erase(position);
480 }
481
482 size_type erase(const key_type& key)
483 {
484 return table_.erase(key);
485 }
486
487 iterator erase(const_iterator first, const_iterator last)
488 {
489 while (first != last)
490 first = erase(first);
491
492 return iterator{
493 table_.table(), first.idx(),
494 table_.bucket_count(), table_.head(first.idx())
495 };
496 }
497
498 void clear() noexcept
499 {
500 table_.clear();
501 }
502
503 void swap(unordered_map& other)
504 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
505 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
506 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
507 {
508 table_.swap(other.table_);
509 std::swap(allocator_, other.allocator_);
510 }
511
512 hasher hash_function() const
513 {
514 return table_.hash_function();
515 }
516
517 key_equal key_eq() const
518 {
519 return table_.key_eq();
520 }
521
522 iterator find(const key_type& key)
523 {
524 return table_.find(key);
525 }
526
527 const_iterator find(const key_type& key) const
528 {
529 return table_.find(key);
530 }
531
532 size_type count(const key_type& key) const
533 {
534 return table_.count(key);
535 }
536
537 pair<iterator, iterator> equal_range(const key_type& key)
538 {
539 return table_.equal_range(key);
540 }
541
542 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
543 {
544 return table_.equal_range(key);
545 }
546
547 mapped_type& operator[](const key_type& key)
548 {
549 auto spot = table_.find_insertion_spot(key);
550 auto bucket = get<0>(spot);
551
552 if (bucket->head)
553 {
554 auto head = bucket->head;
555 auto current = bucket->head;
556
557 do
558 {
559 if (table_.keys_equal(key, current->value))
560 return current->value.second;
561 else
562 current = current->next;
563 }
564 while (current != head);
565 }
566
567 auto node = new node_type{key, mapped_type{}};
568 bucket->append(node);
569
570 table_.increment_size();
571 table_.rehash_if_needed();
572 return node->value.second;
573 }
574
575 mapped_type& operator[](key_type&& key)
576 {
577 auto spot = table_.find_insertion_spot(key);
578 auto bucket = get<0>(spot);
579
580 if (bucket->head)
581 {
582 auto head = bucket->head;
583 auto current = bucket->head;
584
585 do
586 {
587 if (table_.keys_equal(key, current->value))
588 return current->value.second;
589 else
590 current = current->next;
591 }
592 while (current != head);
593 }
594
595 auto node = new node_type{move(key), mapped_type{}};
596 bucket->append(node);
597
598 table_.increment_size();
599 table_.rehash_if_needed();
600 return node->value.second;
601 }
602
603 mapped_type& at(const key_type& key)
604 {
605 auto it = find(key);
606
607 // TODO: throw out_of_range if it == end()
608 return it->second;
609 }
610
611 const mapped_type& at(const key_type& key) const
612 {
613 auto it = find(key);
614
615 // TODO: throw out_of_range if it == end()
616 return it->second;
617 }
618
619 size_type bucket_count() const noexcept
620 {
621 return table_.bucket_count();
622 }
623
624 size_type max_bucket_count() const noexcept
625 {
626 return table_.max_bucket_count();
627 }
628
629 size_type bucket_size(size_type idx) const
630 {
631 return table_.bucket_size(idx);
632 }
633
634 size_type bucket(const key_type& key) const
635 {
636 return table_.bucket(key);
637 }
638
639 local_iterator begin(size_type idx)
640 {
641 return table_.begin(idx);
642 }
643
644 const_local_iterator begin(size_type idx) const
645 {
646 return table_.begin(idx);
647 }
648
649 local_iterator end(size_type idx)
650 {
651 return table_.end(idx);
652 }
653
654 const_local_iterator end(size_type idx) const
655 {
656 return table_.end(idx);
657 }
658
659 const_local_iterator cbegin(size_type idx) const
660 {
661 return table_.cbegin(idx);
662 }
663
664 const_local_iterator cend(size_type idx) const
665 {
666 return table_.cend(idx);
667 }
668
669 float load_factor() const noexcept
670 {
671 return table_.load_factor();
672 }
673
674 float max_load_factor() const noexcept
675 {
676 return table_.max_load_factor();
677 }
678
679 void max_load_factor(float factor)
680 {
681 table_.max_load_factor(factor);
682 }
683
684 void rehash(size_type bucket_count)
685 {
686 table_.rehash(bucket_count);
687 }
688
689 void reserve(size_type count)
690 {
691 table_.reserve(count);
692 }
693
694 private:
695 using table_type = aux::hash_table<
696 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
697 hasher, key_equal, allocator_type, size_type,
698 iterator, const_iterator, local_iterator, const_local_iterator,
699 aux::hash_single_policy
700 >;
701 using node_type = typename table_type::node_type;
702
703 table_type table_;
704 allocator_type allocator_;
705
706 static constexpr size_type default_bucket_count_{16};
707
708 template<class K, class V, class H, class P, class A>
709 friend bool operator==(unordered_map<K, V, H, P, A>&,
710 unordered_map<K, V, H, P, A>&);
711 };
712
713 /**
714 * 23.5.5, class template unordered_multimap:
715 */
716
717 template<
718 class Key, class Value,
719 class Hash = hash<Key>,
720 class Pred = equal_to<Key>,
721 class Alloc = allocator<pair<const Key, Value>>
722 >
723 class unordered_multimap
724 {
725 public:
726 using key_type = Key;
727 using mapped_type = Value;
728 using value_type = pair<const key_type, mapped_type>;
729 using hasher = Hash;
730 using key_equal = Pred;
731 using allocator_type = Alloc;
732 using pointer = typename allocator_traits<allocator_type>::pointer;
733 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
734 using reference = value_type&;
735 using const_reference = const value_type&;
736 using size_type = size_t;
737 using difference_type = ptrdiff_t;
738
739 using iterator = aux::hash_table_iterator<
740 value_type, reference, pointer, size_type
741 >;
742 using const_iterator = aux::hash_table_const_iterator<
743 value_type, const_reference, const_pointer, size_type
744 >;
745 using local_iterator = aux::hash_table_local_iterator<
746 value_type, reference, pointer
747 >;
748 using const_local_iterator = aux::hash_table_const_local_iterator<
749 value_type, const_reference, const_pointer
750 >;
751
752 unordered_multimap()
753 : unordered_multimap{default_bucket_count_}
754 { /* DUMMY BODY */ }
755
756 explicit unordered_multimap(size_type bucket_count,
757 const hasher& hf = hasher{},
758 const key_equal& eql = key_equal{},
759 const allocator_type& alloc = allocator_type{})
760 : table_{bucket_count, hf, eql}, allocator_{alloc}
761 { /* DUMMY BODY */ }
762
763 template<class InputIterator>
764 unordered_multimap(InputIterator first, InputIterator last,
765 size_type bucket_count = default_bucket_count_,
766 const hasher& hf = hasher{},
767 const key_equal& eql = key_equal{},
768 const allocator_type& alloc = allocator_type{})
769 : unordered_multimap{bucket_count, hf, eql, alloc}
770 {
771 insert(first, last);
772 }
773
774 unordered_multimap(const unordered_multimap& other)
775 : unordered_multimap{other, other.allocator_}
776 { /* DUMMY BODY */ }
777
778 unordered_multimap(unordered_multimap&& other)
779 : table_{move(other.table_)}, allocator_{move(other.allocator_)}
780 { /* DUMMY BODY */ }
781
782 explicit unordered_multimap(const allocator_type& alloc)
783 : table_{default_bucket_count_}, allocator_{alloc}
784 { /* DUMMY BODY */ }
785
786 unordered_multimap(const unordered_multimap& other, const allocator_type& alloc)
787 : table_{other.table_}, allocator_{alloc}
788 { /* DUMMY BODY */ }
789
790 unordered_multimap(unordered_multimap&& other, const allocator_type& alloc)
791 : table_{move(other.table_)}, allocator_{alloc}
792 { /* DUMMY BODY */ }
793
794 unordered_multimap(initializer_list<value_type> init,
795 size_type bucket_count = default_bucket_count_,
796 const hasher& hf = hasher{},
797 const key_equal& eql = key_equal{},
798 const allocator_type& alloc = allocator_type{})
799 : unordered_multimap{bucket_count, hf, eql, alloc}
800 {
801 insert(init.begin(), init.end());
802 }
803
804 unordered_multimap(size_type bucket_count, const allocator_type& alloc)
805 : unordered_multimap{bucket_count, hasher{}, key_equal{}, alloc}
806 { /* DUMMY BODY */ }
807
808 unordered_multimap(size_type bucket_count, const hasher& hf,
809 const allocator_type& alloc)
810 : unordered_multimap{bucket_count, hf, key_equal{}, alloc}
811 { /* DUMMY BODY */ }
812
813 template<class InputIterator>
814 unordered_multimap(InputIterator first, InputIterator last,
815 size_type bucket_count, const allocator_type& alloc)
816 : unordered_multimap{first, last, bucket_count, hasher{}, key_equal{}, alloc}
817 { /* DUMMY BODY */ }
818
819 template<class InputIterator>
820 unordered_multimap(InputIterator first, InputIterator last,
821 size_type bucket_count, const hasher& hf,
822 const allocator_type& alloc)
823 : unordered_multimap{first, last, bucket_count, hf, key_equal{}, alloc}
824 { /* DUMMY BODY */ }
825
826 unordered_multimap(initializer_list<value_type> init, size_type bucket_count,
827 const allocator_type& alloc)
828 : unordered_multimap{init, bucket_count, hasher{}, key_equal{}, alloc}
829 { /* DUMMY BODY */ }
830
831 unordered_multimap(initializer_list<value_type> init, size_type bucket_count,
832 const hasher& hf, const allocator_type& alloc)
833 : unordered_multimap{init, bucket_count, hf, key_equal{}, alloc}
834 { /* DUMMY BODY */ }
835
836 ~unordered_multimap()
837 { /* DUMMY BODY */ }
838
839 unordered_multimap& operator=(const unordered_multimap& other)
840 {
841 table_ = other.table_;
842 allocator_ = other.allocator_;
843
844 return *this;
845 }
846
847 unordered_multimap& operator=(unordered_multimap&& other)
848 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
849 is_nothrow_move_assignable<hasher>::value &&
850 is_nothrow_move_assignable<key_equal>::value)
851 {
852 table_ = move(other.table_);
853 allocator_ = move(other.allocator_);
854
855 return *this;
856 }
857
858 unordered_multimap& operator=(initializer_list<value_type>& init)
859 {
860 table_.clear();
861 table_.reserve(init.size());
862
863 insert(init.begin(), init.end());
864
865 return *this;
866 }
867
868 allocator_type get_allocator() const noexcept
869 {
870 return allocator_;
871 }
872
873 bool empty() const noexcept
874 {
875 return table_.empty();
876 }
877
878 size_type size() const noexcept
879 {
880 return table_.size();
881 }
882
883 size_type max_size() const noexcept
884 {
885 return table_.max_size(allocator_);
886 }
887
888 iterator begin() noexcept
889 {
890 return table_.begin();
891 }
892
893 const_iterator begin() const noexcept
894 {
895 return table_.begin();
896 }
897
898 iterator end() noexcept
899 {
900 return table_.end();
901 }
902
903 const_iterator end() const noexcept
904 {
905 return table_.end();
906 }
907
908 const_iterator cbegin() const noexcept
909 {
910 return table_.cbegin();
911 }
912
913 const_iterator cend() const noexcept
914 {
915 return table_.cend();
916 }
917
918 template<class... Args>
919 iterator emplace(Args&&... args)
920 {
921 return table_.emplace(forward<Args>(args)...);
922 }
923
924 template<class... Args>
925 iterator emplace_hint(const_iterator, Args&&... args)
926 {
927 return emplace(forward<Args>(args)...);
928 }
929
930 iterator insert(const value_type& val)
931 {
932 return table_.insert(val);
933 }
934
935 iterator insert(value_type&& val)
936 {
937 return table_.insert(forward<value_type>(val));
938 }
939
940 template<class T>
941 iterator insert(
942 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val
943 )
944 {
945 return emplace(forward<T>(val));
946 }
947
948 iterator insert(const_iterator, const value_type& val)
949 {
950 return insert(val);
951 }
952
953 iterator insert(const_iterator, value_type&& val)
954 {
955 return insert(forward<value_type>(val));
956 }
957
958 template<class T>
959 iterator insert(
960 const_iterator hint,
961 enable_if_t<is_constructible_v<value_type, T&&>, T&&> val
962 )
963 {
964 return emplace_hint(hint, forward<T>(val));
965 }
966
967 template<class InputIterator>
968 void insert(InputIterator first, InputIterator last)
969 {
970 while (first != last)
971 insert(*first++);
972 }
973
974 void insert(initializer_list<value_type> init)
975 {
976 insert(init.begin(), init.end());
977 }
978
979 iterator erase(const_iterator position)
980 {
981 return table_.erase(position);
982 }
983
984 size_type erase(const key_type& key)
985 {
986 return table_.erase(key);
987 }
988
989 iterator erase(const_iterator first, const_iterator last)
990 {
991 while (first != last)
992 first = erase(first);
993
994 return iterator{
995 table_.table(), first.idx(),
996 table_.bucket_count(), table_.head(first.idx())
997 };
998 }
999
1000 void clear() noexcept
1001 {
1002 table_.clear();
1003 }
1004
1005 void swap(unordered_multimap& other)
1006 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
1007 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
1008 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
1009 {
1010 table_.swap(other.table_);
1011 std::swap(allocator_, other.allocator_);
1012 }
1013
1014 hasher hash_function() const
1015 {
1016 return table_.hash_function();
1017 }
1018
1019 key_equal key_eq() const
1020 {
1021 return table_.key_eq();
1022 }
1023
1024 iterator find(const key_type& key)
1025 {
1026 return table_.find(key);
1027 }
1028
1029 const_iterator find(const key_type& key) const
1030 {
1031 return table_.find(key);
1032 }
1033
1034 size_type count(const key_type& key) const
1035 {
1036 return table_.count(key);
1037 }
1038
1039 pair<iterator, iterator> equal_range(const key_type& key)
1040 {
1041 return table_.equal_range(key);
1042 }
1043
1044 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
1045 {
1046 return table_.equal_range(key);
1047 }
1048
1049 size_type bucket_count() const noexcept
1050 {
1051 return table_.bucket_count();
1052 }
1053
1054 size_type max_bucket_count() const noexcept
1055 {
1056 return table_.max_bucket_count();
1057 }
1058
1059 size_type bucket_size(size_type idx) const
1060 {
1061 return table_.bucket_size(idx);
1062 }
1063
1064 size_type bucket(const key_type& key) const
1065 {
1066 return table_.bucket(key);
1067 }
1068
1069 local_iterator begin(size_type idx)
1070 {
1071 return table_.begin(idx);
1072 }
1073
1074 const_local_iterator begin(size_type idx) const
1075 {
1076 return table_.begin(idx);
1077 }
1078
1079 local_iterator end(size_type idx)
1080 {
1081 return table_.end(idx);
1082 }
1083
1084 const_local_iterator end(size_type idx) const
1085 {
1086 return table_.end(idx);
1087 }
1088
1089 const_local_iterator cbegin(size_type idx) const
1090 {
1091 return table_.cbegin(idx);
1092 }
1093
1094 const_local_iterator cend(size_type idx) const
1095 {
1096 return table_.cend(idx);
1097 }
1098
1099 float load_factor() const noexcept
1100 {
1101 return table_.load_factor();
1102 }
1103
1104 float max_load_factor() const noexcept
1105 {
1106 return table_.max_load_factor();
1107 }
1108
1109 void max_load_factor(float factor)
1110 {
1111 table_.max_load_factor(factor);
1112 }
1113
1114 void rehash(size_type bucket_count)
1115 {
1116 table_.rehash(bucket_count);
1117 }
1118
1119 void reserve(size_type count)
1120 {
1121 table_.reserve(count);
1122 }
1123
1124 private:
1125 using table_type = aux::hash_table<
1126 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
1127 hasher, key_equal, allocator_type, size_type,
1128 iterator, const_iterator, local_iterator, const_local_iterator,
1129 aux::hash_multi_policy
1130 >;
1131
1132 table_type table_;
1133 allocator_type allocator_;
1134
1135 static constexpr size_type default_bucket_count_{16};
1136
1137 template<class K, class V, class H, class P, class A>
1138 friend bool operator==(unordered_multimap<K, V, H, P, A>&,
1139 unordered_multimap<K, V, H, P, A>&);
1140 };
1141
1142 template<class Key, class Value, class Hash, class Pred, class Alloc>
1143 void swap(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
1144 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
1145 noexcept(noexcept(lhs.swap(rhs)))
1146 {
1147 lhs.swap(rhs);
1148 }
1149
1150 template<class Key, class Value, class Hash, class Pred, class Alloc>
1151 void swap(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
1152 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
1153 noexcept(noexcept(lhs.swap(rhs)))
1154 {
1155 lhs.swap(rhs);
1156 }
1157
1158 template<class Key, class Value, class Hash, class Pred, class Alloc>
1159 bool operator==(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
1160 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
1161 {
1162 return lhs.table_.is_eq_to(rhs.table_);
1163 }
1164
1165 template<class Key, class Value, class Hash, class Pred, class Alloc>
1166 bool operator!=(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
1167 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
1168 {
1169 return !(lhs == rhs);
1170 }
1171
1172 template<class Key, class Value, class Hash, class Pred, class Alloc>
1173 bool operator==(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
1174 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
1175 {
1176 return lhs.table_.is_eq_to(rhs.table_);
1177 }
1178
1179 template<class Key, class Value, class Hash, class Pred, class Alloc>
1180 bool operator!=(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
1181 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
1182 {
1183 return !(lhs == rhs);
1184 }
1185}
1186
1187#endif
Note: See TracBrowser for help on using the repository browser.