source: mainline/uspace/lib/cpp/include/impl/unordered_map.hpp@ 784c8b6

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

cpp: fixed formatting and fixed insert/emplace return type

  • Property mode set to 100644
File size: 38.8 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,
811 const allocator_type& alloc)
812 : unordered_multimap{bucket_count, hf, key_equal{}, alloc}
813 { /* DUMMY BODY */ }
814
815 template<class InputIterator>
816 unordered_multimap(InputIterator first, InputIterator last,
817 size_type bucket_count, const allocator_type& alloc)
818 : unordered_multimap{first, last, bucket_count, hasher{}, key_equal{}, alloc}
819 { /* DUMMY BODY */ }
820
821 template<class InputIterator>
822 unordered_multimap(InputIterator first, InputIterator last,
823 size_type bucket_count, const hasher& hf,
824 const allocator_type& alloc)
825 : unordered_multimap{first, last, bucket_count, hf, key_equal{}, alloc}
826 { /* DUMMY BODY */ }
827
828 unordered_multimap(initializer_list<value_type> init, size_type bucket_count,
829 const allocator_type& alloc)
830 : unordered_multimap{init, bucket_count, hasher{}, key_equal{}, alloc}
831 { /* DUMMY BODY */ }
832
833 unordered_multimap(initializer_list<value_type> init, size_type bucket_count,
834 const hasher& hf, const allocator_type& alloc)
835 : unordered_multimap{init, bucket_count, hf, key_equal{}, alloc}
836 { /* DUMMY BODY */ }
837
838 ~unordered_multimap()
839 { /* DUMMY BODY */ }
840
841 unordered_multimap& operator=(const unordered_multimap& other)
842 {
843 table_ = other.table_;
844 allocator_ = other.allocator_;
845
846 return *this;
847 }
848
849 unordered_multimap& operator=(unordered_multimap&& other)
850 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
851 is_nothrow_move_assignable<hasher>::value &&
852 is_nothrow_move_assignable<key_equal>::value)
853 {
854 table_ = move(other.table_);
855 allocator_ = move(other.allocator_);
856
857 return *this;
858 }
859
860 unordered_multimap& operator=(initializer_list<value_type>& init)
861 {
862 table_.clear();
863 table_.reserve(init.size());
864
865 insert(init.begin(), init.end());
866
867 return *this;
868 }
869
870 allocator_type get_allocator() const noexcept
871 {
872 return allocator_;
873 }
874
875 bool empty() const noexcept
876 {
877 return table_.empty();
878 }
879
880 size_type size() const noexcept
881 {
882 return table_.size();
883 }
884
885 size_type max_size() const noexcept
886 {
887 return table_.max_size(allocator_);
888 }
889
890 iterator begin() noexcept
891 {
892 return table_.begin();
893 }
894
895 const_iterator begin() const noexcept
896 {
897 return table_.begin();
898 }
899
900 iterator end() noexcept
901 {
902 return table_.end();
903 }
904
905 const_iterator end() const noexcept
906 {
907 return table_.end();
908 }
909
910 const_iterator cbegin() const noexcept
911 {
912 return table_.cbegin();
913 }
914
915 const_iterator cend() const noexcept
916 {
917 return table_.cend();
918 }
919
920 template<class... Args>
921 iterator emplace(Args&&... args)
922 {
923 return table_.emplace(forward<Args>(args)...);
924 }
925
926 template<class... Args>
927 iterator emplace_hint(const_iterator, Args&&... args)
928 {
929 return emplace(forward<Args>(args)...);
930 }
931
932 iterator insert(const value_type& val)
933 {
934 return table_.insert(val);
935 }
936
937 iterator insert(value_type&& val)
938 {
939 return table_.insert(forward<value_type>(val));
940 }
941
942 template<
943 class T,
944 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
945 >
946 iterator insert(T&& val)
947 {
948 return emplace(forward<T>(val));
949 }
950
951 iterator insert(const_iterator, const value_type& val)
952 {
953 return insert(val);
954 }
955
956 iterator insert(const_iterator, value_type&& val)
957 {
958 return insert(forward<value_type>(val));
959 }
960
961 template<
962 class T,
963 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
964 >
965 iterator insert(const_iterator hint, T&& val)
966 {
967 return emplace_hint(hint, forward<T>(val));
968 }
969
970 template<class InputIterator>
971 void insert(InputIterator first, InputIterator last)
972 {
973 while (first != last)
974 insert(*first++);
975 }
976
977 void insert(initializer_list<value_type> init)
978 {
979 insert(init.begin(), init.end());
980 }
981
982 iterator erase(const_iterator position)
983 {
984 return table_.erase(position);
985 }
986
987 size_type erase(const key_type& key)
988 {
989 return table_.erase(key);
990 }
991
992 iterator erase(const_iterator first, const_iterator last)
993 {
994 while (first != last)
995 first = erase(first);
996
997 return iterator{
998 table_.table(), first.idx(),
999 table_.bucket_count(), table_.head(first.idx())
1000 };
1001 }
1002
1003 void clear() noexcept
1004 {
1005 table_.clear();
1006 }
1007
1008 void swap(unordered_multimap& other)
1009 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
1010 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
1011 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
1012 {
1013 table_.swap(other.table_);
1014 std::swap(allocator_, other.allocator_);
1015 }
1016
1017 hasher hash_function() const
1018 {
1019 return table_.hash_function();
1020 }
1021
1022 key_equal key_eq() const
1023 {
1024 return table_.key_eq();
1025 }
1026
1027 iterator find(const key_type& key)
1028 {
1029 return table_.find(key);
1030 }
1031
1032 const_iterator find(const key_type& key) const
1033 {
1034 return table_.find(key);
1035 }
1036
1037 size_type count(const key_type& key) const
1038 {
1039 return table_.count(key);
1040 }
1041
1042 pair<iterator, iterator> equal_range(const key_type& key)
1043 {
1044 return table_.equal_range(key);
1045 }
1046
1047 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
1048 {
1049 return table_.equal_range(key);
1050 }
1051
1052 size_type bucket_count() const noexcept
1053 {
1054 return table_.bucket_count();
1055 }
1056
1057 size_type max_bucket_count() const noexcept
1058 {
1059 return table_.max_bucket_count();
1060 }
1061
1062 size_type bucket_size(size_type idx) const
1063 {
1064 return table_.bucket_size(idx);
1065 }
1066
1067 size_type bucket(const key_type& key) const
1068 {
1069 return table_.bucket(key);
1070 }
1071
1072 local_iterator begin(size_type idx)
1073 {
1074 return table_.begin(idx);
1075 }
1076
1077 const_local_iterator begin(size_type idx) const
1078 {
1079 return table_.begin(idx);
1080 }
1081
1082 local_iterator end(size_type idx)
1083 {
1084 return table_.end(idx);
1085 }
1086
1087 const_local_iterator end(size_type idx) const
1088 {
1089 return table_.end(idx);
1090 }
1091
1092 const_local_iterator cbegin(size_type idx) const
1093 {
1094 return table_.cbegin(idx);
1095 }
1096
1097 const_local_iterator cend(size_type idx) const
1098 {
1099 return table_.cend(idx);
1100 }
1101
1102 float load_factor() const noexcept
1103 {
1104 return table_.load_factor();
1105 }
1106
1107 float max_load_factor() const noexcept
1108 {
1109 return table_.max_load_factor();
1110 }
1111
1112 void max_load_factor(float factor)
1113 {
1114 table_.max_load_factor(factor);
1115 }
1116
1117 void rehash(size_type bucket_count)
1118 {
1119 table_.rehash(bucket_count);
1120 }
1121
1122 void reserve(size_type count)
1123 {
1124 table_.reserve(count);
1125 }
1126
1127 private:
1128 using table_type = aux::hash_table<
1129 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
1130 hasher, key_equal, allocator_type, size_type,
1131 iterator, const_iterator, local_iterator, const_local_iterator,
1132 aux::hash_multi_policy
1133 >;
1134
1135 table_type table_;
1136 allocator_type allocator_;
1137
1138 static constexpr size_type default_bucket_count_{16};
1139
1140 template<class K, class V, class H, class P, class A>
1141 friend bool operator==(unordered_multimap<K, V, H, P, A>&,
1142 unordered_multimap<K, V, H, P, A>&);
1143 };
1144
1145 template<class Key, class Value, class Hash, class Pred, class Alloc>
1146 void swap(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
1147 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
1148 noexcept(noexcept(lhs.swap(rhs)))
1149 {
1150 lhs.swap(rhs);
1151 }
1152
1153 template<class Key, class Value, class Hash, class Pred, class Alloc>
1154 void swap(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
1155 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
1156 noexcept(noexcept(lhs.swap(rhs)))
1157 {
1158 lhs.swap(rhs);
1159 }
1160
1161 template<class Key, class Value, class Hash, class Pred, class Alloc>
1162 bool operator==(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
1163 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
1164 {
1165 return lhs.table_.is_eq_to(rhs.table_);
1166 }
1167
1168 template<class Key, class Value, class Hash, class Pred, class Alloc>
1169 bool operator!=(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
1170 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
1171 {
1172 return !(lhs == rhs);
1173 }
1174
1175 template<class Key, class Value, class Hash, class Pred, class Alloc>
1176 bool operator==(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
1177 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
1178 {
1179 return lhs.table_.is_eq_to(rhs.table_);
1180 }
1181
1182 template<class Key, class Value, class Hash, class Pred, class Alloc>
1183 bool operator!=(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
1184 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
1185 {
1186 return !(lhs == rhs);
1187 }
1188}
1189
1190#endif
Note: See TracBrowser for help on using the repository browser.