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

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

cpp: removed the allocator trick, map allocator is for the pair, not the value

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