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

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

cpp: functions that are implemented in map now properly increase size of the underlying table and rehash if needed

  • Property mode set to 100644
File size: 24.1 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 // TODO: implement
168 return *this;
169 }
170
171 unordered_map& operator=(unordered_map&& other)
172 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
173 is_nothrow_move_assignable<hasher>::value &&
174 is_nothrow_move_assignable<key_equal>::value)
175 {
176 // TODO: implement
177 return *this;
178 }
179
180 unordered_map& operator=(initializer_list<value_type>& init)
181 {
182 table_.clear();
183 table_.reserve(init.size());
184
185 insert(init.begin(), init.end());
186
187 return *this;
188 }
189
190 allocator_type get_allocator() const noexcept
191 {
192 return allocator_;
193 }
194
195 bool empty() const noexcept
196 {
197 return table_.empty();
198 }
199
200 size_type size() const noexcept
201 {
202 return table_.size();
203 }
204
205 size_type max_size() const noexcept
206 {
207 return table_.max_size();
208 }
209
210 iterator begin() noexcept
211 {
212 return table_.begin();
213 }
214
215 const_iterator begin() const noexcept
216 {
217 return table_.begin();
218 }
219
220 iterator end() noexcept
221 {
222 return table_.end();
223 }
224
225 const_iterator end() const noexcept
226 {
227 return table_.end();
228 }
229
230 const_iterator cbegin() const noexcept
231 {
232 return table_.cbegin();
233 }
234
235 const_iterator cend() const noexcept
236 {
237 return table_.cend();
238 }
239
240 template<class... Args>
241 pair<iterator, bool> emplace(Args&&... args)
242 {
243 // TODO: currently there is code repetition in
244 // 3 places, try to find a way to reduce it
245 auto val = value_type{forward<Args>(args)...};
246 auto key = table_.get_key(val);
247 auto spot = table_.find_insertion_spot(key);
248 auto bucket = get<0>(spot);
249 auto idx = get<2>(spot);
250
251 if (bucket->head)
252 {
253 auto head = bucket->head;
254 auto current = bucket->head;
255
256 do
257 {
258 if (table_.keys_equal(key, current->value))
259 {
260 return make_pair(iterator{
261 table_.table(), idx,
262 table_.bucket_count(),
263 current
264 }, false);
265 }
266 else
267 current = current->next;
268 }
269 while (current != head);
270 }
271
272 auto node = new node_type{move(val)};
273 bucket->append(node);
274 table_.increment_size();
275
276 return make_pair(iterator{
277 table_.table(), idx,
278 table_.bucket_count(),
279 node
280 }, true);
281 }
282
283 template<class... Args>
284 iterator emplace_hint(const_iterator, Args&&... args)
285 {
286 return emplace(forward<Args>(args)...).first;
287 }
288
289 pair<iterator, bool> insert(const value_type& val)
290 {
291 auto key = table_.get_key(val);
292 auto spot = table_.find_insertion_spot(key);
293 auto bucket = get<0>(spot);
294 auto idx = get<2>(spot);
295
296 if (bucket->head)
297 {
298 auto head = bucket->head;
299 auto current = bucket->head;
300
301 do
302 {
303 if (table_.keys_equal(key, current->value))
304 {
305 return make_pair(iterator{
306 table_.table(), idx,
307 table_.bucket_count(),
308 current
309 }, false);
310 }
311 else
312 current = current->next;
313 }
314 while (current != head);
315 }
316
317 auto node = new node_type{val};
318 bucket->append(node);
319 table_.increment_size();
320
321 return make_pair(iterator{
322 table_.table(), idx,
323 table_.bucket_count(),
324 node
325 }, true);
326 }
327
328 pair<iterator, bool> insert(value_type&& val)
329 {
330 auto key = table_.get_key(val);
331 auto spot = table_.find_insertion_spot(key);
332 auto bucket = get<0>(spot);
333 auto idx = get<2>(spot);
334
335 if (bucket->head)
336 {
337 auto head = bucket->head;
338 auto current = bucket->head;
339
340 do
341 {
342 if (table_.keys_equal(key, current->value))
343 {
344 return make_pair(iterator{
345 table_.table(), idx,
346 table_.bucket_count(),
347 current
348 }, false);
349 }
350 else
351 current = current->next;
352 }
353 while (current != head);
354 }
355
356 auto node = new node_type{forward<value_type>(val)};
357 bucket->append(node);
358 table_.increment_size();
359 // TODO: problem: rehashing here would invalidate the intel we have...
360
361 return make_pair(iterator{
362 table_.table(), idx,
363 table_.bucket_count(),
364 node
365 }, true);
366 }
367
368 template<
369 class T,
370 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
371 >
372 pair<iterator, bool> insert(T&& val)
373 {
374 return emplace(forward<T>(val));
375 }
376
377 iterator insert(const_iterator, const value_type& val)
378 {
379 return insert(val).first;
380 }
381
382 iterator insert(const_iterator, value_type&& val)
383 {
384 return insert(forward<value_type>(val)).first;
385 }
386
387 template<
388 class T,
389 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
390 >
391 iterator insert(const_iterator hint, T&& val)
392 {
393 return emplace_hint(hint, forward<T>(val));
394 }
395
396 template<class InputIterator>
397 void insert(InputIterator first, InputIterator last)
398 {
399 while (first != last)
400 insert(*first++);
401 }
402
403 void insert(initializer_list<value_type> init)
404 {
405 insert(init.begin(), init.end());
406 }
407
408 template<class... Args>
409 pair<iterator, bool> try_emplace(const key_type& key, Args&&... args)
410 {
411 // TODO: implement
412 }
413
414 template<class... Args>
415 pair<iterator, bool> try_emplace(key_type&& key, Args&&... args)
416 {
417 // TODO: implement
418 }
419
420 template<class... Args>
421 iterator try_emplace(const_iterator hint, const key_type& key, Args&&... args)
422 {
423 // TODO: implement
424 }
425
426 template<class... Args>
427 iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args)
428 {
429 // TODO: implement
430 }
431
432 template<class T>
433 pair<iterator, bool> insert_or_assign(const key_type& key, T&& val)
434 {
435 // TODO: implement
436 }
437
438 template<class T>
439 pair<iterator, bool> insert_or_assign(key_type&& key, T&& val)
440 {
441 // TODO: implement
442 }
443
444 template<class T>
445 iterator insert_or_assign(const_iterator hint, const key_type& key, T&& val)
446 {
447 // TODO: implement
448 }
449
450 template<class T>
451 iterator insert_or_assign(const_iterator hint, key_type&& key, T&& val)
452 {
453 // TODO: implement
454 }
455
456 iterator erase(const_iterator position)
457 {
458 return table_.erase(position);
459 }
460
461 size_type erase(const key_type& key)
462 {
463 return table_.erase(key);
464 }
465
466 iterator erase(const_iterator first, const_iterator last)
467 {
468 while (first != last)
469 first = erase(first);
470
471 return iterator{
472 table_.table(), first.idx(),
473 table_.bucket_count(), table_.head(first.idx())
474 };
475 }
476
477 void clear() noexcept
478 {
479 table_.clear();
480 }
481
482 void swap(unordered_map& other)
483 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
484 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
485 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
486 {
487 table_.swap(other.table_);
488 std::swap(allocator_, other.allocator_);
489 }
490
491 hasher hash_function() const
492 {
493 return table_.hash_function();
494 }
495
496 key_equal key_eq() const
497 {
498 return table_.key_eq();
499 }
500
501 iterator find(const key_type& key)
502 {
503 return table_.find(key);
504 }
505
506 const_iterator find(const key_type& key) const
507 {
508 return table_.find(key);
509 }
510
511 size_type count(const key_type& key) const
512 {
513 return table_.count(key);
514 }
515
516 pair<iterator, iterator> equal_range(const key_type& key)
517 {
518 return table_.equal_range(key);
519 }
520
521 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
522 {
523 return table_.equal_range(key);
524 }
525
526 mapped_type& operator[](const key_type& key)
527 {
528 auto spot = table_.find_insertion_spot(key);
529 auto bucket = get<0>(spot);
530
531 if (bucket->head)
532 {
533 auto head = bucket->head;
534 auto current = bucket->head;
535
536 do
537 {
538 if (table_.keys_equal(key, current->value))
539 return current->value.second;
540 else
541 current = current->next;
542 }
543 while (current != head);
544 }
545
546 auto node = new node_type{key, mapped_type{}};
547 bucket->append(node);
548
549 table_.increment_size();
550 table_.rehash_if_needed();
551 return node->value.second;
552 }
553
554 mapped_type& operator[](key_type&& key)
555 {
556 auto spot = table_.find_insertion_spot(key);
557 auto bucket = get<0>(spot);
558
559 if (bucket->head)
560 {
561 auto head = bucket->head;
562 auto current = bucket->head;
563
564 do
565 {
566 if (table_.keys_equal(key, current->value))
567 return current->value.second;
568 else
569 current = current->next;
570 }
571 while (current != head);
572 }
573
574 auto node = new node_type{move(key), mapped_type{}};
575 bucket->append(node);
576
577 table_.increment_size();
578 table_.rehash_if_needed();
579 return node->value.second;
580 }
581
582 mapped_type& at(const key_type& key)
583 {
584 // TODO: implement
585 }
586
587 const mapped_type& at(const key_type& key) const
588 {
589 // TODO: implement
590 }
591
592 size_type bucket_count() const noexcept
593 {
594 return table_.bucket_count();
595 }
596
597 size_type max_bucket_count() const noexcept
598 {
599 return table_.max_bucket_count();
600 }
601
602 size_type bucket_size(size_type idx) const
603 {
604 return table_.bucket_size(idx);
605 }
606
607 size_type bucket(const key_type& key) const
608 {
609 return table_.bucket(key);
610 }
611
612 local_iterator begin(size_type idx)
613 {
614 return table_.begin(idx);
615 }
616
617 const_local_iterator begin(size_type idx) const
618 {
619 return table_.begin(idx);
620 }
621
622 local_iterator end(size_type idx)
623 {
624 return table_.end(idx);
625 }
626
627 const_local_iterator end(size_type idx) const
628 {
629 return table_.end(idx);
630 }
631
632 const_local_iterator cbegin(size_type idx) const
633 {
634 return table_.cbegin(idx);
635 }
636
637 const_local_iterator cend(size_type idx) const
638 {
639 return table_.cend(idx);
640 }
641
642 float load_factor() const noexcept
643 {
644 return table_.load_factor();
645 }
646
647 float max_load_factor() const noexcept
648 {
649 return table_.max_load_factor();
650 }
651
652 void max_load_factor(float factor)
653 {
654 table_.max_load_factor(factor);
655 }
656
657 void rehash(size_type bucket_count)
658 {
659 table_.rehash(bucket_count);
660 }
661
662 void reserve(size_type count)
663 {
664 table_.reserve(count);
665 }
666
667 private:
668 using table_type = aux::hash_table<
669 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
670 hasher, key_equal, allocator_type, size_type,
671 iterator, const_iterator, local_iterator, const_local_iterator,
672 aux::hash_single_policy
673 >;
674 using node_type = typename table_type::node_type;
675
676 table_type table_;
677 allocator_type allocator_;
678
679 static constexpr size_type default_bucket_count_{16};
680 };
681
682 /**
683 * 23.5.5, class template unordered_multimap:
684 */
685
686 template<
687 class Key, class Value,
688 class Hash = hash<Key>,
689 class Pred = equal_to<Key>,
690 class Alloc = allocator<pair<const Key, Value>>
691 >
692 class unordered_multimap;
693
694 template<class Key, class Value, class Hash, class Pred, class Alloc>
695 void swap(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
696 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
697 noexcept(noexcept(lhs.swap(rhs)))
698 {
699 lhs.swap(rhs);
700 }
701
702 template<class Key, class Value, class Hash, class Pred, class Alloc>
703 void swap(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
704 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
705 noexcept(noexcept(lhs.swap(rhs)))
706 {
707 lhs.swap(rhs);
708 }
709
710 template<class Key, class Value, class Hash, class Pred, class Alloc>
711 bool operator==(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
712 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
713 {
714 // TODO: implement
715 return false;
716 }
717
718 template<class Key, class Value, class Hash, class Pred, class Alloc>
719 bool operator!=(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
720 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
721 {
722 return !(lhs == rhs);
723 }
724
725 template<class Key, class Value, class Hash, class Pred, class Alloc>
726 bool operator==(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
727 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
728 {
729 // TODO: implement
730 return false;
731 }
732
733 template<class Key, class Value, class Hash, class Pred, class Alloc>
734 bool operator!=(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
735 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
736 {
737 return !(lhs == rhs);
738 }
739}
740
741#endif
Note: See TracBrowser for help on using the repository browser.