source: mainline/uspace/lib/cpp/include/impl/unordered_map.hpp@ 323ae805

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

cpp: fixed enable_ifs

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