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

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

cpp: added the rest of the basic insert/emplace functions

  • Property mode set to 100644
File size: 23.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 // 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
275 return make_pair(iterator{
276 table_.table(), idx,
277 table_.bucket_count(),
278 node
279 }, true);
280 }
281
282 template<class... Args>
283 iterator emplace_hint(const_iterator, Args&&... args)
284 {
285 return emplace(forward<Args>(args)...).first;
286 }
287
288 pair<iterator, bool> insert(const value_type& val)
289 {
290 auto key = table_.get_key(val);
291 auto spot = table_.find_insertion_spot(key);
292 auto bucket = get<0>(spot);
293 auto idx = get<2>(spot);
294
295 if (bucket->head)
296 {
297 auto head = bucket->head;
298 auto current = bucket->head;
299
300 do
301 {
302 if (table_.keys_equal(key, current->value))
303 {
304 return make_pair(iterator{
305 table_.table(), idx,
306 table_.bucket_count(),
307 current
308 }, false);
309 }
310 else
311 current = current->next;
312 }
313 while (current != head);
314 }
315
316 auto node = new node_type{val};
317 bucket->append(node);
318
319 return make_pair(iterator{
320 table_.table(), idx,
321 table_.bucket_count(),
322 node
323 }, true);
324 }
325
326 pair<iterator, bool> insert(value_type&& val)
327 {
328 auto key = table_.get_key(val);
329 auto spot = table_.find_insertion_spot(key);
330 auto bucket = get<0>(spot);
331 auto idx = get<2>(spot);
332
333 if (bucket->head)
334 {
335 auto head = bucket->head;
336 auto current = bucket->head;
337
338 do
339 {
340 if (table_.keys_equal(key, current->value))
341 {
342 return make_pair(iterator{
343 table_.table(), idx,
344 table_.bucket_count(),
345 current
346 }, false);
347 }
348 else
349 current = current->next;
350 }
351 while (current != head);
352 }
353
354 auto node = new node_type{forward<value_type>(val)};
355 bucket->append(node);
356
357 return make_pair(iterator{
358 table_.table(), idx,
359 table_.bucket_count(),
360 node
361 }, true);
362 }
363
364 template<
365 class T,
366 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
367 >
368 pair<iterator, bool> insert(T&& val)
369 {
370 return emplace(forward<T>(val));
371 }
372
373 iterator insert(const_iterator, const value_type& val)
374 {
375 return insert(val).first;
376 }
377
378 iterator insert(const_iterator, value_type&& val)
379 {
380 return insert(forward<value_type>(val)).first;
381 }
382
383 template<
384 class T,
385 class = enable_if_t<is_constructible_v<value_type, T&&>, void>
386 >
387 iterator insert(const_iterator hint, T&& val)
388 {
389 return emplace_hint(hint, forward<T>(val));
390 }
391
392 template<class InputIterator>
393 void insert(InputIterator first, InputIterator last)
394 {
395 while (first != last)
396 insert(*first++);
397 }
398
399 void insert(initializer_list<value_type> init)
400 {
401 insert(init.begin(), init.end());
402 }
403
404 template<class... Args>
405 pair<iterator, bool> try_emplace(const key_type& key, Args&&... args)
406 {
407 // TODO: implement
408 }
409
410 template<class... Args>
411 pair<iterator, bool> try_emplace(key_type&& key, Args&&... args)
412 {
413 // TODO: implement
414 }
415
416 template<class... Args>
417 iterator try_emplace(const_iterator hint, const key_type& key, Args&&... args)
418 {
419 // TODO: implement
420 }
421
422 template<class... Args>
423 iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args)
424 {
425 // TODO: implement
426 }
427
428 template<class T>
429 pair<iterator, bool> insert_or_assign(const key_type& key, T&& val)
430 {
431 // TODO: implement
432 }
433
434 template<class T>
435 pair<iterator, bool> insert_or_assign(key_type&& key, T&& val)
436 {
437 // TODO: implement
438 }
439
440 template<class T>
441 iterator insert_or_assign(const_iterator hint, const key_type& key, T&& val)
442 {
443 // TODO: implement
444 }
445
446 template<class T>
447 iterator insert_or_assign(const_iterator hint, key_type&& key, T&& val)
448 {
449 // TODO: implement
450 }
451
452 iterator erase(const_iterator position)
453 {
454 return table_.erase(position);
455 }
456
457 size_type erase(const key_type& key)
458 {
459 return table_.erase(key);
460 }
461
462 iterator erase(const_iterator first, const_iterator last)
463 {
464 while (first != last)
465 first = erase(first);
466
467 return iterator{
468 table_.table(), first.idx(),
469 table_.bucket_count(), table_.head(first.idx())
470 };
471 }
472
473 void clear() noexcept
474 {
475 table_.clear();
476 }
477
478 void swap(unordered_map& other)
479 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
480 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
481 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
482 {
483 table_.swap(other.table_);
484 std::swap(allocator_, other.allocator_);
485 }
486
487 hasher hash_function() const
488 {
489 return table_.hash_function();
490 }
491
492 key_equal key_eq() const
493 {
494 return table_.key_eq();
495 }
496
497 iterator find(const key_type& key)
498 {
499 return table_.find(key);
500 }
501
502 const_iterator find(const key_type& key) const
503 {
504 return table_.find(key);
505 }
506
507 size_type count(const key_type& key) const
508 {
509 return table_.count(key);
510 }
511
512 pair<iterator, iterator> equal_range(const key_type& key)
513 {
514 return table_.equal_range(key);
515 }
516
517 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
518 {
519 return table_.equal_range(key);
520 }
521
522 mapped_type& operator[](const key_type& key)
523 {
524 auto spot = table_.find_insertion_spot(key);
525 auto bucket = get<0>(spot);
526
527 if (bucket->head)
528 {
529 auto head = bucket->head;
530 auto current = bucket->head;
531
532 do
533 {
534 if (table_.keys_equal(key, current->value))
535 return current->value.second;
536 else
537 current = current->next;
538 }
539 while (current != head);
540 }
541
542 auto node = new node_type{key, mapped_type{}};
543 bucket->append(node);
544
545 return node->value.second;
546 }
547
548 mapped_type& operator[](key_type&& key)
549 {
550 auto spot = table_.find_insertion_spot(key);
551 auto bucket = get<0>(spot);
552
553 if (bucket->head)
554 {
555 auto head = bucket->head;
556 auto current = bucket->head;
557
558 do
559 {
560 if (table_.keys_equal(key, current->value))
561 return current->value.second;
562 else
563 current = current->next;
564 }
565 while (current != head);
566 }
567
568 auto node = new node_type{move(key), mapped_type{}};
569 bucket->append(node);
570
571 return node->value.second;
572 }
573
574 mapped_type& at(const key_type& key)
575 {
576 // TODO: implement
577 }
578
579 const mapped_type& at(const key_type& key) const
580 {
581 // TODO: implement
582 }
583
584 size_type bucket_count() const noexcept
585 {
586 return table_.bucket_count();
587 }
588
589 size_type max_bucket_count() const noexcept
590 {
591 return table_.max_bucket_count();
592 }
593
594 size_type bucket_size(size_type idx) const
595 {
596 return table_.bucket_size(idx);
597 }
598
599 size_type bucket(const key_type& key) const
600 {
601 return table_.bucket(key);
602 }
603
604 local_iterator begin(size_type idx)
605 {
606 return table_.begin(idx);
607 }
608
609 const_local_iterator begin(size_type idx) const
610 {
611 return table_.begin(idx);
612 }
613
614 local_iterator end(size_type idx)
615 {
616 return table_.end(idx);
617 }
618
619 const_local_iterator end(size_type idx) const
620 {
621 return table_.end(idx);
622 }
623
624 const_local_iterator cbegin(size_type idx) const
625 {
626 return table_.cbegin(idx);
627 }
628
629 const_local_iterator cend(size_type idx) const
630 {
631 return table_.cend(idx);
632 }
633
634 float load_factor() const noexcept
635 {
636 return table_.load_factor();
637 }
638
639 float max_load_factor() const noexcept
640 {
641 return table_.max_load_factor();
642 }
643
644 void max_load_factor(float factor)
645 {
646 table_.max_load_factor(factor);
647 }
648
649 void rehash(size_type bucket_count)
650 {
651 table_.rehash(bucket_count);
652 }
653
654 void reserve(size_type count)
655 {
656 table_.reserve(count);
657 }
658
659 private:
660 using table_type = aux::hash_table<
661 value_type, key_type, aux::key_value_key_extractor<key_type, mapped_type>,
662 hasher, key_equal, allocator_type, size_type,
663 iterator, const_iterator, local_iterator, const_local_iterator,
664 aux::hash_single_policy
665 >;
666 using node_type = typename table_type::node_type;
667
668 table_type table_;
669 allocator_type allocator_;
670
671 static constexpr size_type default_bucket_count_{16};
672 };
673
674 /**
675 * 23.5.5, class template unordered_multimap:
676 */
677
678 template<
679 class Key, class Value,
680 class Hash = hash<Key>,
681 class Pred = equal_to<Key>,
682 class Alloc = allocator<pair<const Key, Value>>
683 >
684 class unordered_multimap;
685
686 template<class Key, class Value, class Hash, class Pred, class Alloc>
687 void swap(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
688 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
689 noexcept(noexcept(lhs.swap(rhs)))
690 {
691 lhs.swap(rhs);
692 }
693
694 template<class Key, class Value, class Hash, class Pred, class Alloc>
695 void swap(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
696 unordered_multimap<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 bool operator==(unordered_map<Key, Value, Hash, Pred, Alloc>& lhs,
704 unordered_map<Key, Value, Hash, Pred, Alloc>& rhs)
705 {
706 // TODO: implement
707 return false;
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 return !(lhs == rhs);
715 }
716
717 template<class Key, class Value, class Hash, class Pred, class Alloc>
718 bool operator==(unordered_multimap<Key, Value, Hash, Pred, Alloc>& lhs,
719 unordered_multimap<Key, Value, Hash, Pred, Alloc>& rhs)
720 {
721 // TODO: implement
722 return false;
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 return !(lhs == rhs);
730 }
731}
732
733#endif
Note: See TracBrowser for help on using the repository browser.