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

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

cpp: added insertion, iterators and some misc operations to aux::hash_table

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