source: mainline/uspace/lib/cpp/include/impl/unordered_map.hpp@ 04fa158

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

cpp: removed no unneeded type alias

  • 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<
267 class T,
268 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
269 >
270 pair<iterator, bool> insert(T&& val)
271 {
272 return emplace(forward<T>(val));
273 }
274
275 iterator insert(const_iterator, const value_type& val)
276 {
277 return insert(val).first;
278 }
279
280 iterator insert(const_iterator, value_type&& val)
281 {
282 return insert(forward<value_type>(val)).first;
283 }
284
285 template<
286 class T,
287 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
288 >
289 iterator insert(const_iterator hint, T&& val)
290 {
291 return emplace_hint(hint, forward<T>(val));
292 }
293
294 template<class InputIterator>
295 void insert(InputIterator first, InputIterator last)
296 {
297 while (first != last)
298 insert(*first++);
299 }
300
301 void insert(initializer_list<value_type> init)
302 {
303 insert(init.begin(), init.end());
304 }
305
306 template<class... Args>
307 pair<iterator, bool> try_emplace(const key_type& key, Args&&... args)
308 {
309 /**
310 * Note: If anyone (like me) wonders what is the difference between
311 * emplace and try_emplace, the former always constructs the value
312 * (in order to get the key) and the latter does it only if
313 * an insertion takes place.
314 */
315
316 table_.increment_size();
317
318 auto [bucket, target, idx] = table_.find_insertion_spot(key);
319
320 if (!bucket)
321 return make_pair(end(), false);
322
323 if (target && table_.keys_equal(key, target->value))
324 {
325 table_.decrement_size();
326
327 return make_pair(
328 iterator{
329 table_.table(), idx, table_.bucket_count(),
330 target
331 },
332 false
333 );
334 }
335 else
336 {
337 auto node = new node_type{key, forward<Args>(args)...};
338 bucket->append(node);
339
340 return make_pair(iterator{
341 table_.table(), idx,
342 table_.bucket_count(),
343 node
344 }, true);
345 }
346 }
347
348 template<class... Args>
349 pair<iterator, bool> try_emplace(key_type&& key, Args&&... args)
350 {
351 table_.increment_size();
352
353 auto [bucket, target, idx] = table_.find_insertion_spot(key);
354
355 if (!bucket)
356 return make_pair(end(), false);
357
358 if (target && table_.keys_equal(key, target->value))
359 {
360 table_.decrement_size();
361
362 return make_pair(
363 iterator{
364 table_.table(), idx, table_.bucket_count(),
365 target
366 },
367 false
368 );
369 }
370 else
371 {
372 auto node = new node_type{move(key), forward<Args>(args)...};
373 bucket->append(node);
374
375 return make_pair(iterator{
376 table_.table(), idx,
377 table_.bucket_count(),
378 node
379 }, true);
380 }
381 }
382
383 template<class... Args>
384 iterator try_emplace(const_iterator, const key_type& key, Args&&... args)
385 {
386 return try_emplace(key, forward<Args>(args)...).first;
387 }
388
389 template<class... Args>
390 iterator try_emplace(const_iterator, key_type&& key, Args&&... args)
391 {
392 return try_emplace(move(key), forward<Args>(args)...).first;
393 }
394
395 template<class T>
396 pair<iterator, bool> insert_or_assign(const key_type& key, T&& val)
397 {
398 table_.increment_size();
399
400 auto [bucket, target, idx] = table_.find_insertion_spot(key);
401
402 if (!bucket)
403 return make_pair(end(), false);
404
405 if (target && table_.keys_equal(key, target->value))
406 {
407 table_.decrement_size();
408 target->value.second = forward<T>(val);
409
410 return make_pair(
411 iterator{
412 table_.table(), idx, table_.bucket_count(),
413 target
414 },
415 false
416 );
417 }
418 else
419 {
420 auto node = new node_type{key, forward<T>(val)};
421 bucket->append(node);
422
423 return make_pair(iterator{
424 table_.table(), idx,
425 table_.bucket_count(),
426 node
427 }, true);
428 }
429 }
430
431 template<class T>
432 pair<iterator, bool> insert_or_assign(key_type&& key, T&& val)
433 {
434 table_.increment_size();
435
436 auto [bucket, target, idx] = table_.find_insertion_spot(key);
437
438 if (!bucket)
439 return make_pair(end(), false);
440
441 if (target && table_.keys_equal(key, target->value))
442 {
443 table_.decrement_size();
444 target->value.second = forward<T>(val);
445
446 return make_pair(
447 iterator{
448 table_.table(), idx, table_.bucket_count(),
449 target
450 },
451 false
452 );
453 }
454 else
455 {
456 auto node = new node_type{move(key), forward<T>(val)};
457 bucket->append(node);
458
459 return make_pair(iterator{
460 table_.table(), idx,
461 table_.bucket_count(),
462 node
463 }, true);
464 }
465 }
466
467 template<class T>
468 iterator insert_or_assign(const_iterator, const key_type& key, T&& val)
469 {
470 return insert_or_assign(key, forward<T>(val)).first;
471 }
472
473 template<class T>
474 iterator insert_or_assign(const_iterator, key_type&& key, T&& val)
475 {
476 return insert_or_assign(move(key), forward<T>(val)).first;
477 }
478
479 iterator erase(const_iterator position)
480 {
481 return table_.erase(position);
482 }
483
484 size_type erase(const key_type& key)
485 {
486 return table_.erase(key);
487 }
488
489 iterator erase(const_iterator first, const_iterator last)
490 {
491 while (first != last)
492 first = erase(first);
493
494 return iterator{
495 table_.table(), first.idx(),
496 table_.bucket_count(), table_.head(first.idx())
497 };
498 }
499
500 void clear() noexcept
501 {
502 table_.clear();
503 }
504
505 void swap(unordered_map& other)
506 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
507 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
508 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
509 {
510 table_.swap(other.table_);
511 std::swap(allocator_, other.allocator_);
512 }
513
514 hasher hash_function() const
515 {
516 return table_.hash_function();
517 }
518
519 key_equal key_eq() const
520 {
521 return table_.key_eq();
522 }
523
524 iterator find(const key_type& key)
525 {
526 return table_.find(key);
527 }
528
529 const_iterator find(const key_type& key) const
530 {
531 return table_.find(key);
532 }
533
534 size_type count(const key_type& key) const
535 {
536 return table_.count(key);
537 }
538
539 pair<iterator, iterator> equal_range(const key_type& key)
540 {
541 return table_.equal_range(key);
542 }
543
544 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
545 {
546 return table_.equal_range(key);
547 }
548
549 mapped_type& operator[](const key_type& key)
550 {
551 auto spot = table_.find_insertion_spot(key);
552 auto bucket = get<0>(spot);
553
554 if (bucket->head)
555 {
556 auto head = bucket->head;
557 auto current = bucket->head;
558
559 do
560 {
561 if (table_.keys_equal(key, current->value))
562 return current->value.second;
563 else
564 current = current->next;
565 }
566 while (current != head);
567 }
568
569 auto node = new node_type{key, mapped_type{}};
570 bucket->append(node);
571
572 table_.increment_size();
573 table_.rehash_if_needed();
574 return node->value.second;
575 }
576
577 mapped_type& operator[](key_type&& key)
578 {
579 auto spot = table_.find_insertion_spot(key);
580 auto bucket = get<0>(spot);
581
582 if (bucket->head)
583 {
584 auto head = bucket->head;
585 auto current = bucket->head;
586
587 do
588 {
589 if (table_.keys_equal(key, current->value))
590 return current->value.second;
591 else
592 current = current->next;
593 }
594 while (current != head);
595 }
596
597 auto node = new node_type{move(key), mapped_type{}};
598 bucket->append(node);
599
600 table_.increment_size();
601 table_.rehash_if_needed();
602 return node->value.second;
603 }
604
605 mapped_type& at(const key_type& key)
606 {
607 auto it = find(key);
608
609 // TODO: throw out_of_range if it == end()
610 return it->second;
611 }
612
613 const mapped_type& at(const key_type& key) const
614 {
615 auto it = find(key);
616
617 // TODO: throw out_of_range if it == end()
618 return it->second;
619 }
620
621 size_type bucket_count() const noexcept
622 {
623 return table_.bucket_count();
624 }
625
626 size_type max_bucket_count() const noexcept
627 {
628 return table_.max_bucket_count();
629 }
630
631 size_type bucket_size(size_type idx) const
632 {
633 return table_.bucket_size(idx);
634 }
635
636 size_type bucket(const key_type& key) const
637 {
638 return table_.bucket(key);
639 }
640
641 local_iterator begin(size_type idx)
642 {
643 return table_.begin(idx);
644 }
645
646 const_local_iterator begin(size_type idx) const
647 {
648 return table_.begin(idx);
649 }
650
651 local_iterator end(size_type idx)
652 {
653 return table_.end(idx);
654 }
655
656 const_local_iterator end(size_type idx) const
657 {
658 return table_.end(idx);
659 }
660
661 const_local_iterator cbegin(size_type idx) const
662 {
663 return table_.cbegin(idx);
664 }
665
666 const_local_iterator cend(size_type idx) const
667 {
668 return table_.cend(idx);
669 }
670
671 float load_factor() const noexcept
672 {
673 return table_.load_factor();
674 }
675
676 float max_load_factor() const noexcept
677 {
678 return table_.max_load_factor();
679 }
680
681 void max_load_factor(float factor)
682 {
683 table_.max_load_factor(factor);
684 }
685
686 void rehash(size_type bucket_count)
687 {
688 table_.rehash(bucket_count);
689 }
690
691 void reserve(size_type count)
692 {
693 table_.reserve(count);
694 }
695
696 private:
697 using table_type = aux::hash_table<
698 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
699 hasher, key_equal, allocator_type, size_type,
700 iterator, const_iterator, local_iterator, const_local_iterator,
701 aux::hash_single_policy
702 >;
703 using node_type = typename table_type::node_type;
704
705 table_type table_;
706 allocator_type allocator_;
707
708 static constexpr size_type default_bucket_count_{16};
709
710 template<class K, class V, class H, class P, class A>
711 friend bool operator==(unordered_map<K, V, H, P, A>&,
712 unordered_map<K, V, H, P, A>&);
713 };
714
715 /**
716 * 23.5.5, class template unordered_multimap:
717 */
718
719 template<
720 class Key, class Value,
721 class Hash = hash<Key>,
722 class Pred = equal_to<Key>,
723 class Alloc = allocator<pair<const Key, Value>>
724 >
725 class unordered_multimap
726 {
727 public:
728 using key_type = Key;
729 using mapped_type = Value;
730 using value_type = pair<const key_type, mapped_type>;
731 using hasher = Hash;
732 using key_equal = Pred;
733 using allocator_type = Alloc;
734 using pointer = typename allocator_traits<allocator_type>::pointer;
735 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
736 using reference = value_type&;
737 using const_reference = const value_type&;
738 using size_type = size_t;
739 using difference_type = ptrdiff_t;
740
741 using iterator = aux::hash_table_iterator<
742 value_type, reference, pointer, size_type
743 >;
744 using const_iterator = aux::hash_table_const_iterator<
745 value_type, const_reference, const_pointer, size_type
746 >;
747 using local_iterator = aux::hash_table_local_iterator<
748 value_type, reference, pointer
749 >;
750 using const_local_iterator = aux::hash_table_const_local_iterator<
751 value_type, const_reference, const_pointer
752 >;
753
754 unordered_multimap()
755 : unordered_multimap{default_bucket_count_}
756 { /* DUMMY BODY */ }
757
758 explicit unordered_multimap(size_type bucket_count,
759 const hasher& hf = hasher{},
760 const key_equal& eql = key_equal{},
761 const allocator_type& alloc = allocator_type{})
762 : table_{bucket_count, hf, eql}, allocator_{alloc}
763 { /* DUMMY BODY */ }
764
765 template<class InputIterator>
766 unordered_multimap(InputIterator first, InputIterator last,
767 size_type bucket_count = default_bucket_count_,
768 const hasher& hf = hasher{},
769 const key_equal& eql = key_equal{},
770 const allocator_type& alloc = allocator_type{})
771 : unordered_multimap{bucket_count, hf, eql, alloc}
772 {
773 insert(first, last);
774 }
775
776 unordered_multimap(const unordered_multimap& other)
777 : unordered_multimap{other, other.allocator_}
778 { /* DUMMY BODY */ }
779
780 unordered_multimap(unordered_multimap&& other)
781 : table_{move(other.table_)}, allocator_{move(other.allocator_)}
782 { /* DUMMY BODY */ }
783
784 explicit unordered_multimap(const allocator_type& alloc)
785 : table_{default_bucket_count_}, allocator_{alloc}
786 { /* DUMMY BODY */ }
787
788 unordered_multimap(const unordered_multimap& other, const allocator_type& alloc)
789 : table_{other.table_}, allocator_{alloc}
790 { /* DUMMY BODY */ }
791
792 unordered_multimap(unordered_multimap&& other, const allocator_type& alloc)
793 : table_{move(other.table_)}, allocator_{alloc}
794 { /* DUMMY BODY */ }
795
796 unordered_multimap(initializer_list<value_type> init,
797 size_type bucket_count = default_bucket_count_,
798 const hasher& hf = hasher{},
799 const key_equal& eql = key_equal{},
800 const allocator_type& alloc = allocator_type{})
801 : unordered_multimap{bucket_count, hf, eql, alloc}
802 {
803 insert(init.begin(), init.end());
804 }
805
806 unordered_multimap(size_type bucket_count, const allocator_type& alloc)
807 : unordered_multimap{bucket_count, hasher{}, key_equal{}, alloc}
808 { /* DUMMY BODY */ }
809
810 unordered_multimap(size_type bucket_count, const hasher& hf, const allocator_type& alloc)
811 : unordered_multimap{bucket_count, hf, key_equal{}, alloc}
812 { /* DUMMY BODY */ }
813
814 template<class InputIterator>
815 unordered_multimap(InputIterator first, InputIterator last,
816 size_type bucket_count, const allocator_type& alloc)
817 : unordered_multimap{first, last, bucket_count, hasher{}, key_equal{}, alloc}
818 { /* DUMMY BODY */ }
819
820 template<class InputIterator>
821 unordered_multimap(InputIterator first, InputIterator last,
822 size_type bucket_count, const hasher& hf, 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 pair<iterator, bool> 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)...).first;
928 }
929
930 pair<iterator, bool> insert(const value_type& val)
931 {
932 return table_.insert(val);
933 }
934
935 pair<iterator, bool> insert(value_type&& val)
936 {
937 return table_.insert(forward<value_type>(val));
938 }
939
940 template<
941 class T,
942 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
943 >
944 pair<iterator, bool> insert(T&& val)
945 {
946 return emplace(forward<T>(val));
947 }
948
949 iterator insert(const_iterator, const value_type& val)
950 {
951 return insert(val).first;
952 }
953
954 iterator insert(const_iterator, value_type&& val)
955 {
956 return insert(forward<value_type>(val)).first;
957 }
958
959 template<
960 class T,
961 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
962 >
963 iterator insert(const_iterator hint, T&& val)
964 {
965 return emplace_hint(hint, forward<T>(val));
966 }
967
968 template<class InputIterator>
969 void insert(InputIterator first, InputIterator last)
970 {
971 while (first != last)
972 insert(*first++);
973 }
974
975 void insert(initializer_list<value_type> init)
976 {
977 insert(init.begin(), init.end());
978 }
979
980 iterator erase(const_iterator position)
981 {
982 return table_.erase(position);
983 }
984
985 size_type erase(const key_type& key)
986 {
987 return table_.erase(key);
988 }
989
990 iterator erase(const_iterator first, const_iterator last)
991 {
992 while (first != last)
993 first = erase(first);
994
995 return iterator{
996 table_.table(), first.idx(),
997 table_.bucket_count(), table_.head(first.idx())
998 };
999 }
1000
1001 void clear() noexcept
1002 {
1003 table_.clear();
1004 }
1005
1006 void swap(unordered_multimap& other)
1007 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
1008 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
1009 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
1010 {
1011 table_.swap(other.table_);
1012 std::swap(allocator_, other.allocator_);
1013 }
1014
1015 hasher hash_function() const
1016 {
1017 return table_.hash_function();
1018 }
1019
1020 key_equal key_eq() const
1021 {
1022 return table_.key_eq();
1023 }
1024
1025 iterator find(const key_type& key)
1026 {
1027 return table_.find(key);
1028 }
1029
1030 const_iterator find(const key_type& key) const
1031 {
1032 return table_.find(key);
1033 }
1034
1035 size_type count(const key_type& key) const
1036 {
1037 return table_.count(key);
1038 }
1039
1040 pair<iterator, iterator> equal_range(const key_type& key)
1041 {
1042 return table_.equal_range(key);
1043 }
1044
1045 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
1046 {
1047 return table_.equal_range(key);
1048 }
1049
1050 size_type bucket_count() const noexcept
1051 {
1052 return table_.bucket_count();
1053 }
1054
1055 size_type max_bucket_count() const noexcept
1056 {
1057 return table_.max_bucket_count();
1058 }
1059
1060 size_type bucket_size(size_type idx) const
1061 {
1062 return table_.bucket_size(idx);
1063 }
1064
1065 size_type bucket(const key_type& key) const
1066 {
1067 return table_.bucket(key);
1068 }
1069
1070 local_iterator begin(size_type idx)
1071 {
1072 return table_.begin(idx);
1073 }
1074
1075 const_local_iterator begin(size_type idx) const
1076 {
1077 return table_.begin(idx);
1078 }
1079
1080 local_iterator end(size_type idx)
1081 {
1082 return table_.end(idx);
1083 }
1084
1085 const_local_iterator end(size_type idx) const
1086 {
1087 return table_.end(idx);
1088 }
1089
1090 const_local_iterator cbegin(size_type idx) const
1091 {
1092 return table_.cbegin(idx);
1093 }
1094
1095 const_local_iterator cend(size_type idx) const
1096 {
1097 return table_.cend(idx);
1098 }
1099
1100 float load_factor() const noexcept
1101 {
1102 return table_.load_factor();
1103 }
1104
1105 float max_load_factor() const noexcept
1106 {
1107 return table_.max_load_factor();
1108 }
1109
1110 void max_load_factor(float factor)
1111 {
1112 table_.max_load_factor(factor);
1113 }
1114
1115 void rehash(size_type bucket_count)
1116 {
1117 table_.rehash(bucket_count);
1118 }
1119
1120 void reserve(size_type count)
1121 {
1122 table_.reserve(count);
1123 }
1124
1125 private:
1126 using table_type = aux::hash_table<
1127 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
1128 hasher, key_equal, allocator_type, size_type,
1129 iterator, const_iterator, local_iterator, const_local_iterator,
1130 aux::hash_multi_policy
1131 >;
1132
1133 table_type table_;
1134 allocator_type allocator_;
1135
1136 static constexpr size_type default_bucket_count_{16};
1137
1138 template<class K, class V, class H, class P, class A>
1139 friend bool operator==(unordered_multimap<K, V, H, P, A>&,
1140 unordered_multimap<K, V, H, P, A>&);
1141 };
1142
1143 template<class Key, class Value, class Hash, class Pred, class Alloc>
1144 void swap(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
1145 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
1146 noexcept(noexcept(lhs.swap(rhs)))
1147 {
1148 lhs.swap(rhs);
1149 }
1150
1151 template<class Key, class Value, class Hash, class Pred, class Alloc>
1152 void swap(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
1153 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
1154 noexcept(noexcept(lhs.swap(rhs)))
1155 {
1156 lhs.swap(rhs);
1157 }
1158
1159 template<class Key, class Value, class Hash, class Pred, class Alloc>
1160 bool operator==(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
1161 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
1162 {
1163 return lhs.table_.is_eq_to(rhs.table_);
1164 }
1165
1166 template<class Key, class Value, class Hash, class Pred, class Alloc>
1167 bool operator!=(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
1168 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
1169 {
1170 return !(lhs == rhs);
1171 }
1172
1173 template<class Key, class Value, class Hash, class Pred, class Alloc>
1174 bool operator==(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
1175 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
1176 {
1177 return lhs.table_.is_eq_to(rhs.table_);
1178 }
1179
1180 template<class Key, class Value, class Hash, class Pred, class Alloc>
1181 bool operator!=(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
1182 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
1183 {
1184 return !(lhs == rhs);
1185 }
1186}
1187
1188#endif
Note: See TracBrowser for help on using the repository browser.