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
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 }
[e9027b5]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 }
[e29ce3d]157 };
158
159 struct hash_multi_policy
160 {
161 // TODO: umultimap/umultiset operations
162
[871cfe0c]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;
[e29ce3d]169
[871cfe0c]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;
[e29ce3d]176
[871cfe0c]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)
[e29ce3d]186 {
[871cfe0c]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)
[e29ce3d]190 }
[e9027b5]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 }
[e29ce3d]197 };
198
[871cfe0c]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
[e9027b5]211 hash_table_const_iterator(const hash_table_bucket<value_type, size_type>* table = nullptr,
[871cfe0c]212 size_type idx = size_type{}, size_type max_idx = size_type{},
[e9027b5]213 const list_node<value_type>* current = nullptr)
[871cfe0c]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 {
[e9027b5]281 return const_cast<list_node<value_type>*>(current_);
[871cfe0c]282 }
283
284 const list_node<value_type>* node() const
285 {
286 return current_;
287 }
288
[e9027b5]289 size_type idx() const
290 {
291 return idx_;
292 }
293
[871cfe0c]294 private:
[e9027b5]295 const hash_table_bucket<value_type, size_type>* table_;
[871cfe0c]296 size_type idx_;
297 size_type max_idx_;
[e9027b5]298 const list_node<value_type>* current_;
[871cfe0c]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
[e9027b5]405 size_type idx() const
406 {
407 return idx_;
408 }
409
[871cfe0c]410 template<class ConstRef, class ConstPtr>
411 operator hash_table_const_iterator<
412 Value, ConstRef, ConstPtr, Size
413 >() const
414 {
[e9027b5]415 return hash_table_const_iterator<value_type, ConstRef, ConstPtr, size_type>{
[871cfe0c]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!
[e9027b5]453 hash_table_const_local_iterator(const list_node<value_type>* head = nullptr,
454 const list_node<value_type>* current = nullptr)
[871cfe0c]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
[e9027b5]490
[871cfe0c]491 list_node<value_type>* node()
492 {
[e9027b5]493 return const_cast<list_node<value_type>*>(current_);
[871cfe0c]494 }
495
496 const list_node<value_type>* node() const
497 {
498 return current_;
499 }
500
501 private:
[e9027b5]502 const list_node<value_type>* head_;
503 const list_node<value_type>* current_;
[871cfe0c]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 {
[e9027b5]583 return hash_table_const_local_iterator<
584 value_type, ConstRef, ConstPtr
585 >{head_, current_};
[871cfe0c]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 }
[e29ce3d]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,
[871cfe0c]612 class LocalIterator, class ConstLocalIterator,
[e29ce3d]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
[871cfe0c]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 */ }
[e29ce3d]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 {
[871cfe0c]660 return iterator{
661 table_, size_type{}, bucket_count_,
662 table_[0].head
663 };
[e29ce3d]664 }
665
666 const_iterator begin() const noexcept
667 {
[871cfe0c]668 return cbegin();
[e29ce3d]669 }
670
671 iterator end() noexcept
672 {
[871cfe0c]673 return iterator{};
[e29ce3d]674 }
675
676 const_iterator end() const noexcept
677 {
[871cfe0c]678 return cend();
[e29ce3d]679 }
680
681 const_iterator cbegin() const noexcept
682 {
[871cfe0c]683 return const_iterator{
684 table_, size_type{}, bucket_count_,
685 table_[0].head
686 };
[e29ce3d]687 }
688
689 const_iterator cend() const noexcept
690 {
[871cfe0c]691 return const_iterator{};
[e29ce3d]692 }
693
694 template<class Allocator, class... Args>
[871cfe0c]695 iterator emplace(Allocator& alloc, Args&&... args)
[e29ce3d]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
[871cfe0c]702 void insert(const hint_type& where, const value_type& val)
[e29ce3d]703 {
[871cfe0c]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_;
[e9027b5]714 // TODO: if we go over max load factor, rehash
[871cfe0c]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_;
[e9027b5]729 // TODO: if we go over max load factor, rehash
[e29ce3d]730 }
731
732 size_type erase(const key_type& key)
733 {
[e9027b5]734 return Policy::erase(*this, key);
[e29ce3d]735 }
736
737 iterator erase(const_iterator it)
738 {
[e9027b5]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;
[e29ce3d]761 }
762
763 void clear() noexcept
764 {
[871cfe0c]765 delete[] table_;
766
767 size_ = size_type{};
768 table_ = new hash_table_bucket<value_type, size_type>[bucket_count_];
[e29ce3d]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 {
[871cfe0c]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_);
[e29ce3d]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 {
[871cfe0c]807 return Policy::count(*this, key);
[e29ce3d]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 {
[871cfe0c]833 return table_[n].size();
[e29ce3d]834 }
835
836 size_type bucket(const key_type& key) const
837 {
[871cfe0c]838 return get_bucket_idx_(key);
[e29ce3d]839 }
840
841 local_iterator begin(size_type n)
842 {
[871cfe0c]843 return local_iterator{table_[n].head, table_[n].head};
[e29ce3d]844 }
845
846 const_local_iterator begin(size_type n) const
847 {
[871cfe0c]848 return cbegin(n);
[e29ce3d]849 }
850
[871cfe0c]851 local_iterator end(size_type n)
[e29ce3d]852 {
[871cfe0c]853 return local_iterator{};
854 }
855
856 const_local_iterator end(size_type n) const
857 {
858 return cend(n);
[e29ce3d]859 }
860
861 const_local_iterator cbegin(size_type n) const
862 {
[871cfe0c]863 return const_local_iterator{table_[n].head, table_[n].head};
[e29ce3d]864 }
865
866 const_local_iterator cend(size_type n) const
867 {
[871cfe0c]868 return const_local_iterator{};
[e29ce3d]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
[871cfe0c]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
[e29ce3d]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
[871cfe0c]905 return false;
[e29ce3d]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
[871cfe0c]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: */
[e29ce3d]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_;
[871cfe0c]936 key_extract key_extractor_;
[e29ce3d]937 float max_load_factor_;
938
[871cfe0c]939 size_type get_bucket_idx_(const key_type& key) const
940 {
941 return hasher_(key) % bucket_count_;
942 }
[e29ce3d]943
[871cfe0c]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;
[e29ce3d]955 };
[871cfe0c]956}
[e29ce3d]957
[871cfe0c]958namespace std
959{
960 template<>
961 struct allocator_traits<aux::key_value_allocator>
[e29ce3d]962 {
[871cfe0c]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 }
[e29ce3d]968 };
969}
970
971#endif
Note: See TracBrowser for help on using the repository browser.