source: mainline/uspace/lib/cpp/include/internal/hash_table.hpp@ e9027b5

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

cpp: fixed some iterator constness issues, added erase to hash_table

  • Property mode set to 100644
File size: 29.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_INTERNAL_HASH_TABLE
30#define LIBCPP_INTERNAL_HASH_TABLE
31
32#include <cstdlib>
33#include <internal/list.hpp>
34#include <iterator>
35#include <memory>
36#include <tuple>
37#include <utility>
38
39namespace std::aux
40{
41 /**
42 * To save code, we're going to implement one hash table
43 * for both unordered_map and unordered_set. To do this,
44 * we create one inner hash table that is oblivious to its
45 * held type (and uses a key extractor to get the key from it)
46 * and two proxies that either use plain Key type or a pair
47 * of a key and a value.
48 * Note: I am aware the naming is very unimaginative here,
49 * not my strong side :)
50 */
51
52 template<class Key, class Value>
53 struct key_value_key_extractor
54 {
55 Key& operator()(pair<Key, Value>& p) const noexcept
56 {
57 return p.first;
58 }
59 };
60
61 template<class Key>
62 struct key_no_value_key_extractor
63 {
64 Key& operator()(Key& k) const noexcept
65 {
66 return k;
67 }
68 };
69
70 struct key_value_allocator
71 { /* DUMMY BODY */ };
72
73 template<class Value, class Size>
74 struct hash_table_bucket
75 {
76 /**
77 * Note: We use a doubly linked list because
78 * we need to use hints, which point to the
79 * element after the hinted spot.
80 */
81
82 list_node<Value>* head;
83
84 Size size() const noexcept
85 {
86 // TODO: implement
87 }
88
89 void append(list_node<Value>* node)
90 {
91 if (!head)
92 head = node;
93 else
94 head->append(node);
95 }
96
97 ~hash_table_bucket()
98 {
99 // TODO: deallocate the entire list
100 }
101 };
102
103 struct hash_single_policy
104 {
105 // TODO: umap/uset operations
106
107 template<class Table, class Key>
108 static typename Table::size_type count(const Table& table, const Key& key)
109 {
110 return table.find(key) == table.end() ? 0 : 1;
111 }
112
113 template<class Table, class Key>
114 static typename Table::hint_type find_insertion_spot(const Table& table, const Key& key)
115 {
116 auto idx = table.get_bucket_idx_(key);
117 return make_tuple(
118 &table.table_[idx],
119 table.table_[idx].head,
120 idx
121 );
122 }
123
124 template<class Table, class Key>
125 static typename Table::size_type erase(Table& table, const Key& key)
126 {
127 auto idx = table.get_bucket_idx_(key);
128 auto head = table.table_[idx].head;
129 auto current = head;
130
131 do
132 {
133 if (table.key_eq_(key, table.key_extractor_(current->value)))
134 {
135 --table.size_;
136
137 if (current == head)
138 {
139 if (current->next != head)
140 table.table_[idx].head = current->next;
141 else
142 table.table_[idx].head = nullptr;
143 }
144
145 current->unlink();
146 delete current;
147
148 return 1;
149 }
150 else
151 current = current->next;
152 }
153 while (current != head);
154
155 return 0;
156 }
157 };
158
159 struct hash_multi_policy
160 {
161 // TODO: umultimap/umultiset operations
162
163 template<class Table, class Key>
164 static typename Table::size_type count(const Table& table, const Key& key)
165 {
166 auto head = table.table_[get_bucket_idx_(key)].head;
167 if (!head)
168 return 0;
169
170 auto current = head;
171 typename Table::size_type res = 0;
172 do
173 {
174 if (table.key_eq_(key, table.key_extractor_(current->value)))
175 ++res;
176
177 current = current->next;
178 }
179 while (current != head);
180
181 return res;
182 }
183
184 template<class Table, class Key>
185 static typename Table::hint_type find_insertion_spot(const Table& table, const Key& key)
186 {
187 // TODO: find the right bucket, in that, find the right
188 // link (if key is already in it, place the new copy
189 // next to it, otherwise just return head)
190 }
191
192 template<class Table, class Key>
193 static typename Table::size_type erase(Table& table, const Key& key)
194 {
195 // TODO: erase all items with given key
196 }
197 };
198
199 template<class Value, class ConstReference, class ConstPointer, class Size>
200 class hash_table_const_iterator
201 {
202 public:
203 using value_type = Value;
204 using size_type = Size;
205 using const_reference = ConstReference;
206 using const_pointer = ConstPointer;
207 using difference_type = ptrdiff_t;
208
209 using iterator_category = forward_iterator_tag;
210
211 hash_table_const_iterator(const hash_table_bucket<value_type, size_type>* table = nullptr,
212 size_type idx = size_type{}, size_type max_idx = size_type{},
213 const list_node<value_type>* current = nullptr)
214 : table_{table}, idx_{idx}, max_idx_{max_idx}, current_{current}
215 { /* DUMMY BODY */ }
216
217 hash_table_const_iterator(const hash_table_const_iterator&) = default;
218 hash_table_const_iterator& operator=(const hash_table_const_iterator&) = default;
219
220 const_reference operator*() const
221 {
222 return current_->value;
223 }
224
225 const_pointer operator->() const
226 {
227 return &current_->value;
228 }
229
230 hash_table_const_iterator& operator++()
231 {
232 current_ = current_->next;
233 if (current_ == table_[idx_].head)
234 {
235 if (idx_ < max_idx_)
236 {
237 while (!table_[++idx_].head)
238 { /* DUMMY BODY */ }
239
240 if (idx_ < max_idx_)
241 current_ = table_[idx_].head;
242 else
243 current_ = nullptr;
244 }
245 else
246 current_ = nullptr;
247 }
248
249 return *this;
250 }
251
252 hash_table_const_iterator operator++(int)
253 {
254 auto tmp_current = current_;
255 auto tmp_idx = idx_;
256
257 current_ = current_->next;
258 if (current_ == table_[idx_].head)
259 {
260 if (idx_ < max_idx_)
261 {
262 while (!table_[++idx_].head)
263 { /* DUMMY BODY */ }
264
265 if (idx_ < max_idx_)
266 current_ = table_[idx_].head;
267 else
268 current_ = nullptr;
269 }
270 else
271 current_ = nullptr;
272 }
273
274 return hash_table_const_iterator{
275 table_, tmp_idx, max_idx_, tmp_current
276 };
277 }
278
279 list_node<value_type>* node()
280 {
281 return const_cast<list_node<value_type>*>(current_);
282 }
283
284 const list_node<value_type>* node() const
285 {
286 return current_;
287 }
288
289 size_type idx() const
290 {
291 return idx_;
292 }
293
294 private:
295 const hash_table_bucket<value_type, size_type>* table_;
296 size_type idx_;
297 size_type max_idx_;
298 const list_node<value_type>* current_;
299 };
300
301 template<class Value, class ConstRef, class ConstPtr, class Size>
302 bool operator==(const hash_table_const_iterator<Value, ConstRef, ConstPtr, Size>& lhs,
303 const hash_table_const_iterator<Value, ConstRef, ConstPtr, Size>& rhs)
304 {
305 return lhs.node() == rhs.node();
306 }
307
308 template<class Value, class ConstRef, class ConstPtr, class Size>
309 bool operator!=(const hash_table_const_iterator<Value, ConstRef, ConstPtr, Size>& lhs,
310 const hash_table_const_iterator<Value, ConstRef, ConstPtr, Size>& rhs)
311 {
312 return !(lhs == rhs);
313 }
314
315 template<class Value, class Reference, class Pointer, class Size>
316 class hash_table_iterator
317 {
318 public:
319 using value_type = Value;
320 using size_type = Size;
321 using reference = Reference;
322 using pointer = Pointer;
323 using difference_type = ptrdiff_t;
324
325 using iterator_category = forward_iterator_tag;
326
327 hash_table_iterator(hash_table_bucket<value_type, size_type>* table = nullptr,
328 size_type idx = size_type{}, size_type max_idx = size_type{},
329 list_node<value_type>* current = nullptr)
330 : table_{table}, idx_{idx}, max_idx_{max_idx}, current_{current}
331 { /* DUMMY BODY */ }
332
333 hash_table_iterator(const hash_table_iterator&) = default;
334 hash_table_iterator& operator=(const hash_table_iterator&) = default;
335
336 reference operator*()
337 {
338 return current_->value;
339 }
340
341 pointer operator->()
342 {
343 return &current_->value;
344 }
345
346 hash_table_iterator& operator++()
347 {
348 current_ = current_->next;
349 if (current_ == table_[idx_].head)
350 {
351 if (idx_ < max_idx_)
352 {
353 while (!table_[++idx_].head)
354 { /* DUMMY BODY */ }
355
356 if (idx_ < max_idx_)
357 current_ = table_[idx_].head;
358 else
359 current_ = nullptr;
360 }
361 else
362 current_ = nullptr;
363 }
364
365 return *this;
366 }
367
368 hash_table_iterator operator++(int)
369 {
370 auto tmp_current = current_;
371 auto tmp_idx = idx_;
372
373 current_ = current_->next;
374 if (current_ == table_[idx_].head)
375 {
376 if (idx_ < max_idx_)
377 {
378 while (!table_[++idx_].head)
379 { /* DUMMY BODY */ }
380
381 if (idx_ < max_idx_)
382 current_ = table_[idx_].head;
383 else
384 current_ = nullptr;
385 }
386 else
387 current_ = nullptr;
388 }
389
390 return hash_table_iterator{
391 table_, tmp_idx, max_idx_, tmp_current
392 };
393 }
394
395 list_node<value_type>* node()
396 {
397 return current_;
398 }
399
400 const list_node<value_type>* node() const
401 {
402 return current_;
403 }
404
405 size_type idx() const
406 {
407 return idx_;
408 }
409
410 template<class ConstRef, class ConstPtr>
411 operator hash_table_const_iterator<
412 Value, ConstRef, ConstPtr, Size
413 >() const
414 {
415 return hash_table_const_iterator<value_type, ConstRef, ConstPtr, size_type>{
416 table_, idx_, max_idx_, current_
417 };
418 }
419
420 private:
421 hash_table_bucket<value_type, size_type>* table_;
422 size_type idx_;
423 size_type max_idx_;
424 list_node<value_type>* current_;
425 };
426
427 template<class Value, class Ref, class Ptr, class Size>
428 bool operator==(const hash_table_iterator<Value, Ref, Ptr, Size>& lhs,
429 const hash_table_iterator<Value, Ref, Ptr, Size>& rhs)
430 {
431 return lhs.node() == rhs.node();
432 }
433
434 template<class Value, class Ref, class Ptr, class Size>
435 bool operator!=(const hash_table_iterator<Value, Ref, Ptr, Size>& lhs,
436 const hash_table_iterator<Value, Ref, Ptr, Size>& rhs)
437 {
438 return !(lhs == rhs);
439 }
440
441 template<class Value, class ConstReference, class ConstPointer>
442 class hash_table_const_local_iterator
443 {
444 public:
445 using value_type = Value;
446 using const_reference = ConstReference;
447 using const_pointer = ConstPointer;
448 using difference_type = ptrdiff_t;
449
450 using iterator_category = forward_iterator_tag;
451
452 // TODO: requirement for forward iterator is default constructibility, fix others!
453 hash_table_const_local_iterator(const list_node<value_type>* head = nullptr,
454 const list_node<value_type>* current = nullptr)
455 : head_{head}, current_{current}
456 { /* DUMMY BODY */ }
457
458 hash_table_const_local_iterator(const hash_table_const_local_iterator&) = default;
459 hash_table_const_local_iterator& operator=(const hash_table_const_local_iterator&) = default;
460
461 const_reference operator*() const
462 {
463 return current_->value;
464 }
465
466 const_pointer operator->() const
467 {
468 return &current_->value;
469 }
470
471 hash_table_const_local_iterator& operator++()
472 {
473 current_ = current_->next;
474 if (current_ == head_)
475 current_ = nullptr;
476
477 return *this;
478 }
479
480 hash_table_const_local_iterator operator++(int)
481 {
482 auto tmp = current_;
483 current_ = current_->next;
484 if (current_ == head_)
485 current_ = nullptr;
486
487 return hash_table_const_local_iterator{head_, tmp};
488 }
489
490
491 list_node<value_type>* node()
492 {
493 return const_cast<list_node<value_type>*>(current_);
494 }
495
496 const list_node<value_type>* node() const
497 {
498 return current_;
499 }
500
501 private:
502 const list_node<value_type>* head_;
503 const list_node<value_type>* current_;
504 };
505
506 template<class Value, class ConstRef, class ConstPtr>
507 bool operator==(const hash_table_const_local_iterator<Value, ConstRef, ConstPtr>& lhs,
508 const hash_table_const_local_iterator<Value, ConstRef, ConstPtr>& rhs)
509 {
510 return lhs.node() == rhs.node();
511 }
512
513 template<class Value, class ConstRef, class ConstPtr>
514 bool operator!=(const hash_table_const_local_iterator<Value, ConstRef, ConstPtr>& lhs,
515 const hash_table_const_local_iterator<Value, ConstRef, ConstPtr>& rhs)
516 {
517 return !(lhs == rhs);
518 }
519
520 template<class Value, class Reference, class Pointer>
521 class hash_table_local_iterator
522 {
523 public:
524 using value_type = Value;
525 using reference = Reference;
526 using pointer = Pointer;
527 using difference_type = ptrdiff_t;
528
529 using iterator_category = forward_iterator_tag;
530
531 hash_table_local_iterator(list_node<value_type>* head = nullptr,
532 list_node<value_type>* current = nullptr)
533 : head_{head}, current_{current}
534 { /* DUMMY BODY */ }
535
536 hash_table_local_iterator(const hash_table_local_iterator&) = default;
537 hash_table_local_iterator& operator=(const hash_table_local_iterator&) = default;
538
539 reference operator*()
540 {
541 return current_->value;
542 }
543
544 pointer operator->()
545 {
546 return &current_->value;
547 }
548
549 hash_table_local_iterator& operator++()
550 {
551 current_ = current_->next;
552 if (current_ == head_)
553 current_ = nullptr;
554
555 return *this;
556 }
557
558 hash_table_local_iterator operator++(int)
559 {
560 auto tmp = current_;
561 current_ = current_->next;
562 if (current_ == head_)
563 current_ = nullptr;
564
565 return hash_table_local_iterator{head_, tmp};
566 }
567
568 list_node<value_type>* node()
569 {
570 return current_;
571 }
572
573 const list_node<value_type>* node() const
574 {
575 return current_;
576 }
577
578 template<class ConstRef, class ConstPtr>
579 operator hash_table_const_local_iterator<
580 Value, ConstRef, ConstPtr
581 >() const
582 {
583 return hash_table_const_local_iterator<
584 value_type, ConstRef, ConstPtr
585 >{head_, current_};
586 }
587
588 private:
589 list_node<value_type>* head_;
590 list_node<value_type>* current_;
591 };
592
593 template<class Value, class Ref, class Ptr>
594 bool operator==(const hash_table_local_iterator<Value, Ref, Ptr>& lhs,
595 const hash_table_local_iterator<Value, Ref, Ptr>& rhs)
596 {
597 return lhs.node() == rhs.node();
598 }
599
600 template<class Value, class Ref, class Ptr>
601 bool operator!=(const hash_table_local_iterator<Value, Ref, Ptr>& lhs,
602 const hash_table_local_iterator<Value, Ref, Ptr>& rhs)
603 {
604 return !(lhs == rhs);
605 }
606
607 template<
608 class Value, class Key, class KeyExtractor,
609 class Hasher, class KeyEq,
610 class Alloc, class Size,
611 class Iterator, class ConstIterator,
612 class LocalIterator, class ConstLocalIterator,
613 class Policy
614 >
615 class hash_table
616 {
617 public:
618 using value_type = Value;
619 using key_type = Key;
620 using size_type = Size;
621 using allocator_type = Alloc;
622 using key_equal = KeyEq;
623 using hasher = Hasher;
624 using key_extract = KeyExtractor;
625
626 using iterator = Iterator;
627 using const_iterator = ConstIterator;
628 using local_iterator = LocalIterator;
629 using const_local_iterator = ConstLocalIterator;
630
631 using hint_type = tuple<
632 hash_table_bucket<value_type, size_type>*,
633 list_node<value_type>*, size_type
634 >;
635
636 hash_table(size_type buckets, float max_load_factor = 1.f)
637 : table_{new hash_table_bucket<value_type, size_type>[buckets]},
638 bucket_count_{buckets}, size_{}, hasher_{}, key_eq_{},
639 key_extractor_{}, max_load_factor_{max_load_factor}
640 { /* DUMMY BODY */ }
641
642 bool empty() const noexcept
643 {
644 return size_ == 0;
645 }
646
647 size_type size() const noexcept
648 {
649 return size_;
650 }
651
652 template<class Allocator>
653 size_type max_size(Allocator& alloc)
654 {
655 return allocator_traits<Allocator>::max_size(alloc);
656 }
657
658 iterator begin() noexcept
659 {
660 return iterator{
661 table_, size_type{}, bucket_count_,
662 table_[0].head
663 };
664 }
665
666 const_iterator begin() const noexcept
667 {
668 return cbegin();
669 }
670
671 iterator end() noexcept
672 {
673 return iterator{};
674 }
675
676 const_iterator end() const noexcept
677 {
678 return cend();
679 }
680
681 const_iterator cbegin() const noexcept
682 {
683 return const_iterator{
684 table_, size_type{}, bucket_count_,
685 table_[0].head
686 };
687 }
688
689 const_iterator cend() const noexcept
690 {
691 return const_iterator{};
692 }
693
694 template<class Allocator, class... Args>
695 iterator emplace(Allocator& alloc, Args&&... args)
696 {
697 // TODO: use allocator traits of allocator_type but pass alloc!
698 // TODO: also, try_emplace should be one level above (we don't know
699 // keys)
700 }
701
702 void insert(const hint_type& where, const value_type& val)
703 {
704 if (!hint_ok_(where))
705 return;
706
707 auto node = new list_node<value_type>{val};
708 if (get<1>(where) == nullptr) // Append here will create a new head.
709 get<0>(where)->append(node);
710 else // Prepending before an exact position is common in the standard.
711 get<1>(where)->prepend(node);
712
713 ++size_;
714 // TODO: if we go over max load factor, rehash
715 }
716
717 void insert(const hint_type& where, value_type&& val)
718 {
719 if (!hint_ok_(where))
720 return;
721
722 auto node = new list_node<value_type>{forward<value_type>(val)};
723 if (get<1>(where) == nullptr)
724 get<0>(where)->append(node);
725 else
726 get<1>(where)->prepend(node);
727
728 ++size_;
729 // TODO: if we go over max load factor, rehash
730 }
731
732 size_type erase(const key_type& key)
733 {
734 return Policy::erase(*this, key);
735 }
736
737 iterator erase(const_iterator it)
738 {
739 auto node = it.node();
740 auto idx = it.idx();
741
742 /**
743 * Note: This way we will continue on the next bucket
744 * if this is the last element in its bucket.
745 */
746 iterator res{table_, idx, size_, node};
747 ++res;
748
749 if (table_[idx].head == node)
750 {
751 if (node->next != node)
752 table_[idx].head = node->next;
753 else
754 table_[idx].head = nullptr;
755 }
756
757 node->unlink();
758 delete node;
759
760 return res;
761 }
762
763 void clear() noexcept
764 {
765 delete[] table_;
766
767 size_ = size_type{};
768 table_ = new hash_table_bucket<value_type, size_type>[bucket_count_];
769 }
770
771 template<class Allocator>
772 void swap(hash_table& other)
773 noexcept(allocator_traits<Allocator>::is_always_equal::value &&
774 noexcept(swap(declval<Hasher&>(), declval<Hasher&>())) &&
775 noexcept(swap(declval<KeyEq&>(), declval<KeyEq&>())))
776 {
777 std::swap(table_, other.table_);
778 std::swap(bucket_count_, other.bucket_count_);
779 std::swap(size_, other.size_);
780 std::swap(hasher_, other.hasher_);
781 std::swap(key_eq_, other.key_eq_);
782 std::swap(max_load_factor_, other.max_load_factor_);
783 }
784
785 hasher hash_function() const
786 {
787 return hasher_;
788 }
789
790 key_equal key_eq() const
791 {
792 return key_eq_;
793 }
794
795 iterator find(const key_type& key)
796 {
797 // TODO: implement
798 }
799
800 const_iterator find(const key_type& key) const
801 {
802 // TODO: implement
803 }
804
805 size_type count(const key_type& key) const
806 {
807 return Policy::count(*this, key);
808 }
809
810 pair<iterator, iterator> equal_range(const key_type& key)
811 {
812 // TODO: implement
813 }
814
815 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
816 {
817 // TODO: implement
818 }
819
820 size_type bucket_count() const noexcept
821 {
822 return bucket_count_;
823 }
824
825 size_type max_bucket_count() const noexcept
826 {
827 // TODO: implement
828 return 0;
829 }
830
831 size_type bucket_size(size_type n) const
832 {
833 return table_[n].size();
834 }
835
836 size_type bucket(const key_type& key) const
837 {
838 return get_bucket_idx_(key);
839 }
840
841 local_iterator begin(size_type n)
842 {
843 return local_iterator{table_[n].head, table_[n].head};
844 }
845
846 const_local_iterator begin(size_type n) const
847 {
848 return cbegin(n);
849 }
850
851 local_iterator end(size_type n)
852 {
853 return local_iterator{};
854 }
855
856 const_local_iterator end(size_type n) const
857 {
858 return cend(n);
859 }
860
861 const_local_iterator cbegin(size_type n) const
862 {
863 return const_local_iterator{table_[n].head, table_[n].head};
864 }
865
866 const_local_iterator cend(size_type n) const
867 {
868 return const_local_iterator{};
869 }
870
871 float load_factor() const noexcept
872 {
873 return size_ / static_cast<float>(bucket_count_);
874 }
875
876 float max_load_factor() const noexcept
877 {
878 return max_load_factor_;
879 }
880
881 void max_load_factor(float factor)
882 {
883 /**
884 * Note: According to the standard, this function
885 * can have no effect.
886 */
887 }
888
889 void rehash(size_type n)
890 {
891 // TODO: implement
892 // TODO: exception thrown in rehash means the rehash
893 // has no effect, so we create a new table, insert in it
894 // and then swap
895 }
896
897 void reserve(size_type n)
898 {
899 // TODO: implement
900 }
901
902 bool is_eq_to(hash_table& other)
903 {
904 // TODO: implement
905 return false;
906 }
907
908 ~hash_table()
909 {
910 // Lists are deleted in ~hash_table_bucket.
911 delete[] table_;
912 }
913
914 void set_hint(const_iterator hint)
915 {
916 // TODO: hint_ should be a ptr and we extract it here,
917 // then set it to nullptr after each operation
918 }
919
920 hint_type find_insertion_spot(const key_type& key)
921 {
922 return Policy::find_insertion_spot(*this, key);
923 }
924
925 hint_type find_insertion_spot(key_type&& key)
926 {
927 return Policy::find_insertion_spot(*this, key);
928 }
929
930 /* private: */
931 hash_table_bucket<value_type, size_type>* table_;
932 size_type bucket_count_;
933 size_type size_;
934 hasher hasher_;
935 key_equal key_eq_;
936 key_extract key_extractor_;
937 float max_load_factor_;
938
939 size_type get_bucket_idx_(const key_type& key) const
940 {
941 return hasher_(key) % bucket_count_;
942 }
943
944 bool hint_ok_(const hint_type& hint)
945 {
946 // TODO: pass this to the policy, because the multi policy
947 // will need to check if a similar key is close,
948 // that is something like:
949 // return get<1>(hint)->prev->key == key || !bucket.contains(key)
950 return get<0>(hint) != nullptr && get<2>(hint) < bucket_count_;
951 }
952
953 // Praise C++11 for this.
954 friend Policy;
955 };
956}
957
958namespace std
959{
960 template<>
961 struct allocator_traits<aux::key_value_allocator>
962 {
963 template<class Alloc, class Key, class Value, class... Args>
964 static void construct(Alloc& alloc, pair<Key, Value>* ptr, Args&&... args)
965 {
966 alloc.construct(&ptr->second, forward<Args>(args)...);
967 }
968 };
969}
970
971#endif
Note: See TracBrowser for help on using the repository browser.