NexusForce 1.0.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
hashtable.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_CONTAINER_HASHTABLE_HPP__
2#define NEFORCE_CORE_CONTAINER_HASHTABLE_HPP__
3
13
16NEFORCE_BEGIN_NAMESPACE__
17
134
142template <typename T>
153
154
155template <typename Value, typename Key, typename HashFcn, typename ExtractKey, typename EqualKey, typename Alloc>
156class hashtable;
157
158
167template <bool IsConst, typename HashTable>
168struct hashtable_iterator : iiterator<hashtable_iterator<IsConst, HashTable>> {
169public:
170 using container_type = HashTable;
171 using value_type = typename container_type::value_type;
172 using size_type = typename container_type::size_type;
173 using difference_type = typename container_type::difference_type;
175 using reference = conditional_t<IsConst, typename container_type::const_reference,
176 typename container_type::reference>;
177 using pointer = conditional_t<IsConst, typename container_type::const_pointer,
178 typename container_type::pointer>;
179
180private:
181 using node_type = hashtable_node<value_type>;
182
183 node_type* current_ = nullptr;
184 size_type bucket_ = 0;
185 const container_type* container_ = nullptr;
186
187 template <typename, typename, typename, typename, typename, typename>
188 friend class hashtable;
189
190public:
191 hashtable_iterator() noexcept = default;
192 ~hashtable_iterator() = default;
193
194 hashtable_iterator(const hashtable_iterator&) noexcept = default;
195 hashtable_iterator& operator=(const hashtable_iterator&) noexcept = default;
196 hashtable_iterator(hashtable_iterator&&) noexcept = default;
197 hashtable_iterator& operator=(hashtable_iterator&&) noexcept = default;
198
205 hashtable_iterator(node_type* ptr, const size_type bucket, const HashTable* ht) :
206 current_(ptr),
207 bucket_(bucket),
208 container_(ht) {}
209
214 NEFORCE_NODISCARD reference dereference() const noexcept {
215 NEFORCE_DEBUG_VERIFY(current_ && container_, "Attempting to dereference on a null pointer");
216 NEFORCE_DEBUG_VERIFY(bucket_ < container_->buckets_.size() && 0 <= bucket_,
217 "Attempting to dereference out of boundary");
218 return current_->data;
219 }
220
226 void increment() noexcept {
227 NEFORCE_DEBUG_VERIFY(current_ && container_, "Attempting to increment a null pointer");
228 current_ = current_->next;
229 if (current_ == nullptr) {
230 while (current_ == nullptr && ++bucket_ < container_->buckets_.size()) {
231 current_ = container_->buckets_[bucket_];
232 }
233 }
234 }
235
241 NEFORCE_NODISCARD bool equal_to(const hashtable_iterator& rhs) const noexcept {
242 NEFORCE_DEBUG_VERIFY(container_ == rhs.container_, "Attempting to equal to a different container");
243 return current_ == rhs.current_;
244 }
245
250 NEFORCE_NODISCARD const node_type* base() const noexcept { return current_; }
251
256 NEFORCE_NODISCARD size_type bucket() const noexcept { return bucket_; }
257
262 NEFORCE_NODISCARD const container_type* container() const noexcept { return container_; }
263};
264
265
266NEFORCE_BEGIN_CONSTANTS__
267#ifdef NEFORCE_ARCH_BITS_64
268
274NEFORCE_INLINE17 constexpr size_t HASH_PRIME_LIST[] = {101,
275 173,
276 263,
277 397,
278 599,
279 907,
280 1361,
281 2053,
282 3083,
283 4637,
284 6959,
285 10453,
286 15683,
287 23531,
288 35311,
289 52967,
290 79451,
291 119179,
292 178781,
293 268189,
294 402299,
295 603457,
296 905189,
297 1357787,
298 2036687,
299 3055043,
300 4582577,
301 6873871,
302 10310819,
303 15466229,
304 23199347,
305 34799021,
306 52198537,
307 78297827,
308 117446801,
309 176170229,
310 264255353,
311 396383041,
312 594574583,
313 891861923,
314 1337792887,
315 2006689337,
316 3010034021U,
317 4515051137ULL,
318 6772576709ULL,
319 10158865069ULL,
320 15238297621ULL,
321 22857446471ULL,
322 34286169707ULL,
323 51429254599ULL,
324 77143881917ULL,
325 115715822899ULL,
326 173573734363ULL,
327 260360601547ULL,
328 390540902329ULL,
329 585811353559ULL,
330 878717030339ULL,
331 1318075545511ULL,
332 1977113318311ULL,
333 2965669977497ULL,
334 4448504966249ULL,
335 6672757449409ULL,
336 10009136174239ULL,
337 15013704261371ULL,
338 22520556392057ULL,
339 33780834588157ULL,
340 50671251882247ULL,
341 76006877823377ULL,
342 114010316735089ULL,
343 171015475102649ULL,
344 256523212653977ULL,
345 384784818980971ULL,
346 577177228471507ULL,
347 865765842707309ULL,
348 1298648764060979ULL,
349 1947973146091477ULL,
350 2921959719137273ULL,
351 4382939578705967ULL,
352 6574409368058969ULL,
353 9861614052088471ULL,
354 14792421078132871ULL,
355 22188631617199337ULL,
356 33282947425799017ULL,
357 49924421138698549ULL,
358 74886631708047827ULL,
359 112329947562071807ULL,
360 168494921343107851ULL,
361 252742382014661767ULL,
362 379113573021992729ULL,
363 568670359532989111ULL,
364 853005539299483657ULL,
365 1279508308949225477ULL,
366 1919262463423838231ULL,
367 2878893695135757317ULL,
368 4318340542703636011ULL,
369 6477510814055453699ULL};
370
371#else
372
376NEFORCE_INLINE17 constexpr size_t HASH_PRIME_LIST[] = {
377 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289,
378 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
379 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741};
380
381#endif
382
384NEFORCE_INLINE17 constexpr size_t HASH_PRIMER_COUNT = extent_v<decltype(HASH_PRIME_LIST)>;
385
386NEFORCE_END_CONSTANTS__
387
388
402template <typename Value, typename Key, typename HashFcn, typename ExtractKey, typename EqualKey, typename Alloc>
403class hashtable : public icollector<hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>> {
404public:
405 using key_type = Key;
406 using hasher = HashFcn;
407 using key_equal = EqualKey;
408
409 using value_type = Value;
410 using pointer = Value*;
411 using reference = Value&;
412 using const_pointer = const Value*;
413 using const_reference = const Value&;
416 using iterator = hashtable_iterator<false, hashtable>;
417 using const_iterator = hashtable_iterator<true, hashtable>;
418 using allocator_type = Alloc;
419
420private:
421 using node_type = hashtable_node<Value>;
422 using link_type = node_type*;
423
424 vector<link_type> buckets_{};
425 size_type size_ = 0;
426 hasher hasher_{};
427 key_equal equals_{};
428 ExtractKey extracter_{};
429 compressed_pair<allocator_type, float> pair_{default_construct_tag{}, 1.0F};
430
431 template <bool, typename>
432 friend struct hashtable_iterator;
433
434private:
440 NEFORCE_NODISCARD static size_type next_size(const size_type n) noexcept {
441 const size_t* first = constants::HASH_PRIME_LIST;
442 const size_t* last = constants::HASH_PRIME_LIST + constants::HASH_PRIMER_COUNT;
443 const size_t* pos = _NEFORCE lower_bound(first, last, n);
444 return pos == last ? *(last - 1) : *pos;
445 }
446
451 void initialize_buckets(const size_type n) {
452 const size_type n_buckets = next_size(n);
453 buckets_.assign(n_buckets, nullptr);
454 }
455
462 size_type bucket_index_key(const key_type& key, const size_t n) const noexcept(is_nothrow_hashable_v<key_type>) {
463 if (n == 0) {
464 return 0;
465 }
466 return hasher_(key) % n;
467 }
468
475 size_type bucket_index_value(const value_type& value, const size_t n) const
477 return hashtable::bucket_index_key(extracter_(value), n);
478 }
479
486 template <typename... Args>
487 link_type new_node(Args&&... args) {
488 link_type n = pair_.get_base().allocate();
489 n->next = nullptr;
490 try {
491 _NEFORCE construct(&n->data, _NEFORCE forward<Args>(args)...);
492 } catch (...) {
493 hashtable::delete_node(n);
494 NEFORCE_THROW_EXCEPTION(memory_exception("hashtable construct node failed."));
495 }
496 return n;
497 }
498
503 void delete_node(link_type n) noexcept {
504 _NEFORCE destroy(&n->data);
505 pair_.get_base().deallocate(n);
506 }
507
512 void copy_from(const hashtable& other) {
513 buckets_.clear();
514 buckets_.reserve(other.buckets_.size());
515 buckets_.insert(buckets_.end(), other.buckets_.size(), nullptr);
516 try {
517 for (size_type i = 0; i < other.buckets_.size(); ++i) {
518 if (link_type cur = other.buckets_[i]) {
519 link_type copy = hashtable::new_node(cur->data);
520 buckets_[i] = copy;
521 for (link_type next = cur->next; next != nullptr; cur = next, next = cur->next) {
522 copy->next = hashtable::new_node(next->data);
523 copy = copy->next;
524 }
525 }
526 }
527 size_ = other.size_;
528 } catch (...) {
529 clear();
530 throw;
531 }
532 }
533
539 pair<iterator, bool> insert_unique_noresize(link_type ptr) {
540 const size_type n = hashtable::bucket_index_value(ptr->data, buckets_.size());
541
542 node_type** buckets_ptr = &buckets_[n];
543 while (*buckets_ptr != nullptr) {
544 if (equals_(extracter_((*buckets_ptr)->data), extracter_(ptr->data))) {
545 link_type existing = *buckets_ptr;
546 hashtable::delete_node(ptr);
547 return {iterator(existing, n, this), false};
548 }
549 buckets_ptr = &(*buckets_ptr)->next;
550 }
551
552 ptr->next = nullptr;
553 *buckets_ptr = ptr;
554 ++size_;
555 return {iterator{ptr, n, this}, true};
556 }
557
563 iterator insert_equal_noresize(link_type ptr) {
564 const size_type n = hashtable::bucket_index_value(ptr->data, buckets_.size());
565 link_type first = buckets_[n];
566
567 link_type prev = nullptr;
568 link_type cur = first;
569 while (cur != nullptr && equals_(extracter_(cur->data), extracter_(ptr->data))) {
570 prev = cur;
571 cur = cur->next;
572 }
573
574 if (prev != nullptr) {
575 prev->next = ptr;
576 ptr->next = cur;
577 } else {
578 ptr->next = first;
579 buckets_[n] = ptr;
580 }
581
582 ++size_;
583 return {ptr, n, this};
584 }
585
592 template <typename Iterator>
593 enable_if_t<!is_ranges_fwd_iter_v<Iterator>> insert_unique_aux(Iterator first, Iterator last) {
594 for (; first != last; ++first) {
596 }
597 return;
598 }
599
606 template <typename Iterator>
607 enable_if_t<is_ranges_fwd_iter_v<Iterator>> insert_unique_aux(Iterator first, Iterator last) {
608 size_type n = _NEFORCE distance(first, last);
609
610 const auto need_buckets =
611 static_cast<size_type>(_NEFORCE ceil(static_cast<double>(size_ + n) / max_load_factor()));
612 rehash(need_buckets);
613
614 for (; n > 0; --n, ++first) {
615 link_type tmp = hashtable::new_node(*first);
616 hashtable::insert_unique_noresize(tmp);
617 }
618 return;
619 }
620
627 template <typename Iterator>
628 enable_if_t<!is_ranges_fwd_iter_v<Iterator>> insert_equal_aux(Iterator first, Iterator last) {
629 for (; first != last; ++first) {
631 }
632 return;
633 }
634
641 template <typename Iterator>
642 enable_if_t<is_ranges_fwd_iter_v<Iterator>> insert_equal_aux(Iterator first, Iterator last) {
643 size_type n = _NEFORCE distance(first, last);
644
645 const auto need_buckets =
646 static_cast<size_type>(_NEFORCE ceil(static_cast<double>(size_ + n) / max_load_factor()));
647 rehash(need_buckets);
648
649 for (; n > 0; --n, ++first) {
650 link_type tmp = hashtable::new_node(*first);
651 hashtable::insert_equal_noresize(tmp);
652 }
653 return;
654 }
655
662 size_type erase_bucket_to_node(size_type bucket, link_type last) noexcept {
663 size_type count = 0;
664 link_type curr = buckets_[bucket];
665 while (curr != nullptr && curr != last) {
666 link_type next = curr->next;
667 hashtable::delete_node(curr);
668 curr = next;
669 ++count;
670 }
671 buckets_[bucket] = last;
672 return count;
673 }
674
682 size_type erase_bucket_range(size_type bucket, link_type first, link_type last) noexcept {
683 size_type count = 0;
684 if (first == nullptr) {
685 return 0;
686 }
687
688 if (buckets_[bucket] == first) {
689 count += hashtable::erase_bucket_to_node(bucket, last);
690 } else {
691 link_type prev = buckets_[bucket];
692 while (prev != nullptr && prev->next != first) {
693 prev = prev->next;
694 }
695 if (prev == nullptr) {
696 return 0;
697 }
698
699 link_type curr = first;
700 while (curr != nullptr && curr != last) {
701 link_type next = curr->next;
702 prev->next = next;
703 hashtable::delete_node(curr);
704 curr = next;
705 ++count;
706 }
707 }
708 return count;
709 }
710
716 size_type erase_bucket_completely(size_type bucket) noexcept {
717 size_type count = 0;
718 link_type curr = buckets_[bucket];
719 while (curr != nullptr) {
720 link_type next = curr->next;
721 hashtable::delete_node(curr);
722 curr = next;
723 ++count;
724 }
725 buckets_[bucket] = nullptr;
726 return count;
727 }
728
734 bool equal_small(const hashtable& rhs) const {
735 for (const_iterator iter = begin(); iter != end(); ++iter) {
736 const key_type& key = extracter_(*iter);
737
738 const size_t count_lhs = _NEFORCE count_if(
739 begin(), end(), [this, &key](const value_type& val) { return equals_(extracter_(val), key); });
740 const size_t count_rhs = _NEFORCE count_if(rhs.begin(), rhs.end(), [&rhs, &key](const value_type& val) {
741 return rhs.equals_(rhs.extracter_(val), key);
742 });
743
744 if (count_lhs != count_rhs) {
745 return false;
746 }
747 }
748 return true;
749 }
750
756 bool equal_large(const hashtable& rhs) const {
757 if (size_ != rhs.size_) {
758 return false;
759 }
760
761 vector<const value_type*> ptrs_lhs, ptrs_rhs;
762 ptrs_lhs.reserve(size_);
763 ptrs_rhs.reserve(size_);
764
765 for (const_iterator it = begin(); it != end(); ++it) {
766 ptrs_lhs.push_back(&(*it));
767 }
768 for (const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
769 ptrs_rhs.push_back(&(*it));
770 }
771
772 auto key_less = [this](const value_type* a, const value_type* b) { return extracter_(*a) < extracter_(*b); };
773 auto rhs_key_less = [&rhs](const value_type* a, const value_type* b) {
774 return rhs.extracter_(*a) < rhs.extracter_(*b);
775 };
776
777 _NEFORCE sort(ptrs_lhs.begin(), ptrs_lhs.end(), key_less);
778 _NEFORCE sort(ptrs_rhs.begin(), ptrs_rhs.end(), rhs_key_less);
779
780 size_type i = 0, j = 0;
781 const size_type n = ptrs_lhs.size();
782
783 while (i < n && j < n) {
784 const key_type& key_l = extracter_(*ptrs_lhs[i]);
785 const key_type& key_r = rhs.extracter_(*ptrs_rhs[j]);
786
787 if (!equals_(key_l, key_r)) {
788 return false;
789 }
790
791 size_type i_start = i, j_start = j;
792 while (i < n && equals_(extracter_(*ptrs_lhs[i]), key_l)) {
793 ++i;
794 }
795 while (j < n && rhs.equals_(rhs.extracter_(*ptrs_rhs[j]), key_l)) {
796 ++j;
797 }
798
799 const size_type count_l = i - i_start;
800 const size_type count_r = j - j_start;
801 if (count_l != count_r) {
802 return false;
803 }
804
805 for (size_type k = i_start; k < i; ++k) {
806 const value_type& val = *ptrs_lhs[k];
807 bool found = false;
808 for (size_type l = j_start; l < j; ++l) {
809 if (ptrs_rhs[l] && *ptrs_rhs[l] == val) {
810 ptrs_rhs[l] = nullptr;
811 found = true;
812 break;
813 }
814 }
815 if (!found) {
816 return false;
817 }
818 }
819
820 for (size_type l = j_start; l < j; ++l) {
821 if (ptrs_rhs[l] != nullptr) {
822 return false;
823 }
824 }
825 }
826
827 return true;
828 }
829
830 static iterator to_iterator(const const_iterator& iter) noexcept {
831 return iterator(const_cast<node_type*>(iter.base()), iter.bucket(), iter.container());
832 }
833
834 static const_iterator to_const_iterator(const iterator& iter) noexcept {
835 return const_iterator(const_cast<node_type*>(iter.base()), iter.bucket(), iter.container());
836 }
837
838public:
844 explicit hashtable(const size_type n, float max_lf = 1.0F) :
845 buckets_(next_size(n), nullptr),
846 pair_(default_construct_tag{}, max_lf) {}
847
854 hashtable(const size_type n, const HashFcn& hf, float max_lf = 1.0F) :
855 buckets_(next_size(n), nullptr),
856 hasher_(hf),
857 pair_(default_construct_tag{}, max_lf) {}
858
866 hashtable(const size_type n, const HashFcn& hf, const EqualKey& eql, float max_lf = 1.0F) :
867 buckets_(next_size(n), nullptr),
868 hasher_(hf),
869 equals_(eql),
870 pair_(default_construct_tag{}, max_lf) {}
871
880 hashtable(const size_type n, const HashFcn& hf, const EqualKey& eql, const ExtractKey& ext, float max_lf = 1.0F) :
881 buckets_(next_size(n), nullptr),
882 hasher_(hf),
883 equals_(eql),
884 extracter_(ext),
885 pair_(default_construct_tag{}, max_lf) {}
886
891 hashtable(const hashtable& other) :
892 hasher_(other.hasher_),
893 equals_(other.equals_),
894 extracter_(other.extracter_),
895 pair_(other.pair_) {
896 hashtable::copy_from(other);
897 }
898
905 if (_NEFORCE addressof(other) == this) {
906 return *this;
907 }
909 hasher_ = other.hasher_;
910 equals_ = other.equals_;
911 extracter_ = other.extracter_;
912 hashtable::copy_from(other);
913 return *this;
914 }
915
920 hashtable(hashtable&& other) noexcept(noexcept(hashtable::swap(other))) :
921 buckets_(_NEFORCE move(other.buckets_)),
922 size_(other.size_),
923 hasher_(_NEFORCE move(other.hasher_)),
924 equals_(_NEFORCE move(other.equals_)),
925 extracter_(_NEFORCE move(other.extracter_)),
926 pair_(_NEFORCE move(other.pair_)) {
927 other.size_ = 0;
928 }
929
935 hashtable& operator=(hashtable&& other) noexcept(noexcept(hashtable::swap(other))) {
936 if (_NEFORCE addressof(other) == this) {
937 return *this;
938 }
939 clear();
940 hashtable::swap(other);
941 return *this;
942 }
943
948
953 NEFORCE_NODISCARD iterator begin() noexcept {
954 for (size_type n = 0; n < buckets_.size(); ++n) {
955 if (buckets_[n] != nullptr) {
956 return iterator(buckets_[n], n, this);
957 }
958 }
959 return end();
960 }
961
966 NEFORCE_NODISCARD iterator end() noexcept { return iterator(nullptr, 0, this); }
967
972 NEFORCE_NODISCARD const_iterator begin() const noexcept { return cbegin(); }
973
978 NEFORCE_NODISCARD const_iterator end() const noexcept { return cend(); }
979
984 NEFORCE_NODISCARD const_iterator cbegin() const noexcept {
985 for (size_type n = 0; n < buckets_.size(); ++n) {
986 if (buckets_[n] != nullptr) {
987 return const_iterator(buckets_[n], n, this);
988 }
989 }
990 return cend();
991 }
992
997 NEFORCE_NODISCARD const_iterator cend() const noexcept { return const_iterator(nullptr, 0, this); }
998
1003 NEFORCE_NODISCARD size_type size() const noexcept { return size_; }
1004
1009 NEFORCE_NODISCARD size_type max_size() const noexcept { return static_cast<size_type>(-1); }
1010
1015 NEFORCE_NODISCARD bool empty() const noexcept { return size_ == 0; }
1016
1021 NEFORCE_NODISCARD size_type buckets_size() const noexcept { return buckets_.size(); }
1022
1027 NEFORCE_NODISCARD static size_type buckets_max_size() noexcept {
1028 return constants::HASH_PRIME_LIST[constants::HASH_PRIMER_COUNT - 1];
1029 }
1030
1036 NEFORCE_NODISCARD size_type bucket_index(const key_type& key) const noexcept(is_nothrow_hashable_v<key_type>) {
1037 return hashtable::bucket_index_key(key);
1038 }
1039
1045 NEFORCE_NODISCARD size_type bucket_size(size_type index) const noexcept {
1046 size_type result = 0;
1047 for (link_type cur = buckets_[index]; cur != nullptr; cur = cur->next) {
1048 result++;
1049 }
1050 return result;
1051 }
1052
1057 NEFORCE_NODISCARD hasher hash_func() const noexcept(is_nothrow_copy_constructible_v<hasher>) { return hasher_; }
1058
1063 NEFORCE_NODISCARD key_equal key_eql() const noexcept(is_nothrow_copy_constructible_v<key_equal>) { return equals_; }
1064
1069 NEFORCE_NODISCARD float load_factor() const noexcept {
1070 return buckets_size() == 0 ? 0.0F : static_cast<float>(size()) / static_cast<float>(buckets_size());
1071 }
1072
1077 NEFORCE_NODISCARD float max_load_factor() const noexcept { return pair_.value; }
1078
1083 void max_load_factor(const float lf) noexcept {
1084 NEFORCE_DEBUG_VERIFY(lf > 0, "hashtable load factor invalid.");
1085 pair_.value = lf;
1086 }
1087
1092 void rehash(const size_type new_size) {
1093 const auto min_buckets_for_size =
1094 static_cast<size_type>(_NEFORCE ceil(static_cast<double>(size_) / max_load_factor()));
1095 const size_type target = _NEFORCE max(new_size, min_buckets_for_size);
1096 const size_type old_size = buckets_.size();
1097
1098 if (target <= old_size) {
1099 return;
1100 }
1101
1102 const size_type n = hashtable::next_size(target);
1103 if (n < target) {
1104 NEFORCE_THROW_EXCEPTION(value_exception("hashtable size exceeds max count"));
1105 }
1106
1107 vector<link_type> new_buckets(n, nullptr);
1108
1109 for (size_type bucket = 0; bucket < old_size; ++bucket) {
1110 link_type cur = buckets_[bucket];
1111 while (cur != nullptr) {
1112 link_type next = cur->next;
1113 const size_type new_bucket = hashtable::bucket_index_value(cur->data, n);
1114
1115 cur->next = new_buckets[new_bucket];
1116 new_buckets[new_bucket] = cur;
1117
1118 cur = next;
1119 }
1120 buckets_[bucket] = nullptr;
1121 }
1122
1123 buckets_.swap(new_buckets);
1124 }
1125
1132 void reserve(const size_type n) {
1133 if (n <= size_) {
1134 return;
1135 }
1136
1137 const auto needed = static_cast<size_type>(_NEFORCE ceil(static_cast<double>(n) / max_load_factor()));
1138
1139 if (needed > static_cast<float>(buckets_max_size())) {
1140 NEFORCE_THROW_EXCEPTION(value_exception("hashtable size exceeds max count"));
1141 }
1142 rehash(static_cast<size_type>(needed));
1143 }
1144
1151 template <typename... Args>
1153 if (size_ + 1 > static_cast<size_type>(buckets_.size() * max_load_factor())) {
1154 rehash(size_ + 1);
1155 }
1156 const link_type node = hashtable::new_node(_NEFORCE forward<Args>(args)...);
1157 return hashtable::insert_unique_noresize(node);
1158 }
1159
1166 template <typename... Args>
1167 iterator emplace_equal(Args&&... args) {
1168 if (size_ + 1 > static_cast<size_type>(buckets_.size() * max_load_factor())) {
1169 rehash(size_ + 1);
1170 }
1171 const link_type node = hashtable::new_node(_NEFORCE forward<Args>(args)...);
1172 return hashtable::insert_equal_noresize(node);
1173 }
1174
1181
1188
1195
1201 iterator insert_equal(value_type&& value) { return hashtable::emplace_equal(_NEFORCE move(value)); }
1202
1209 template <typename Iterator>
1210 enable_if_t<is_iter_v<Iterator>> insert_unique(Iterator first, Iterator last) {
1211 hashtable::insert_unique_aux(first, last);
1212 return;
1213 }
1214
1219 void insert_unique(std::initializer_list<value_type> ilist) {
1220 hashtable::insert_unique(ilist.begin(), ilist.end());
1221 }
1222
1229 template <typename Iterator>
1230 enable_if_t<is_iter_v<Iterator>> insert_equal(Iterator first, Iterator last) {
1231 hashtable::insert_equal_aux(first, last);
1232 return;
1233 }
1234
1239 void insert_equal(std::initializer_list<value_type> ilist) { hashtable::insert_equal(ilist.begin(), ilist.end()); }
1240
1247 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1248 link_type first = buckets_[n];
1249 size_type erased = 0;
1250
1251 if (first != nullptr) {
1252 link_type cur = first;
1253 link_type next = cur->next;
1254
1255 while (next != nullptr) {
1256 if (equals_(extracter_(next->data), key)) {
1257 cur->next = next->next;
1258 hashtable::delete_node(next);
1259 next = cur->next;
1260 ++erased;
1261 --size_;
1262 } else {
1263 cur = next;
1264 next = cur->next;
1265 }
1266 }
1267
1268 if (equals_(extracter_(first->data), key)) {
1269 buckets_[n] = first->next;
1270 hashtable::delete_node(first);
1271 ++erased;
1272 --size_;
1273 }
1274 }
1275
1276 return erased;
1277 }
1278
1285 if (position.current_ == nullptr || position.container_ != this) {
1286 return end();
1287 }
1288
1289 const size_type n = position.bucket_;
1290 link_type const p = position.current_;
1291 link_type next_node = p->next;
1292
1293 link_type prev = nullptr;
1294 link_type curr = buckets_[n];
1295 while (curr != nullptr && curr != p) {
1296 prev = curr;
1297 curr = curr->next;
1298 }
1299
1300 if (curr == nullptr) {
1301 return end();
1302 }
1303
1304 if (prev == nullptr) {
1305 buckets_[n] = next_node;
1306 } else {
1307 prev->next = next_node;
1308 }
1309
1310 hashtable::delete_node(p);
1311 --size_;
1312
1313 if (next_node != nullptr) {
1314 return iterator(next_node, n, this);
1315 }
1316
1317 for (size_type bucket = n + 1; bucket < buckets_.size(); ++bucket) {
1318 if (buckets_[bucket] != nullptr) {
1319 return iterator(buckets_[bucket], bucket, this);
1320 }
1321 }
1322 return end();
1323 }
1324
1332 if (first == last) {
1333 return last;
1334 }
1335
1336 if (first.container_ != this || (last.container_ != this && last != end())) {
1337 return end();
1338 }
1339
1340 size_type count_erased = 0;
1341
1342 if (first.bucket_ == last.bucket_) {
1343 count_erased = hashtable::erase_bucket_range(first.bucket_, first.current_, last.current_);
1344 } else {
1345 count_erased += hashtable::erase_bucket_range(first.bucket_, first.current_, nullptr);
1346 for (size_type bucket = first.bucket_ + 1; bucket < last.bucket_; ++bucket) {
1347 count_erased += hashtable::erase_bucket_completely(bucket);
1348 }
1349 if (last.bucket_ < buckets_.size()) {
1350 count_erased += hashtable::erase_bucket_range(last.bucket_, buckets_[last.bucket_], last.current_);
1351 }
1352 }
1353 size_ -= count_erased;
1354 return last;
1355 }
1356
1363 return hashtable::to_const_iterator(hashtable::erase(hashtable::to_iterator(position)));
1364 }
1365
1373 return hashtable::to_const_iterator(
1374 hashtable::erase(hashtable::to_iterator(first), hashtable::to_iterator(last)));
1375 }
1376
1380 void clear() noexcept {
1381 for (size_type i = 0; i < buckets_.size(); ++i) {
1382 link_type cur = buckets_[i];
1383 while (cur != nullptr) {
1384 link_type next = cur->next;
1385 hashtable::delete_node(cur);
1386 cur = next;
1387 }
1388 buckets_[i] = nullptr;
1389 }
1390 size_ = 0;
1391 }
1392
1398 NEFORCE_NODISCARD iterator find(const key_type& key) noexcept(is_nothrow_hashable_v<key_type>) {
1399 if (buckets_.empty()) {
1400 return end();
1401 }
1402
1403 size_type n = hashtable::bucket_index_key(key, buckets_.size());
1404 for (link_type first = buckets_[n]; first != nullptr; first = first->next) {
1405 if (equals_(extracter_(first->data), key)) {
1406 return iterator(first, n, this);
1407 }
1408 }
1409 return end();
1410 }
1411
1417 NEFORCE_NODISCARD const_iterator find(const key_type& key) const noexcept(is_nothrow_hashable_v<key_type>) {
1418 if (buckets_.empty()) {
1419 return cend();
1420 }
1421
1422 size_type n = hashtable::bucket_index_key(key, buckets_.size());
1423 for (link_type first = buckets_[n]; first != nullptr; first = first->next) {
1424 if (equals_(extracter_(first->data), key)) {
1425 return const_iterator(first, n, this);
1426 }
1427 }
1428 return cend();
1429 }
1430
1436 NEFORCE_NODISCARD size_type count(const key_type& key) const noexcept(is_nothrow_hashable_v<key_type>) {
1437 if (buckets_.empty()) {
1438 return 0;
1439 }
1440 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1441 size_type result = 0;
1442 for (link_type cur = buckets_[n]; cur != nullptr; cur = cur->next) {
1443 if (equals_(extracter_(cur->data), key)) {
1444 ++result;
1445 }
1446 }
1447 return result;
1448 }
1449
1455 NEFORCE_NODISCARD bool contains(const key_type& key) const noexcept(is_nothrow_hashable_v<key_type>) {
1456 return hashtable::find(key) != cend();
1457 }
1458
1464 NEFORCE_NODISCARD pair<iterator, iterator> equal_range(const key_type& key) {
1465 if (buckets_.empty()) {
1466 return {end(), end()};
1467 }
1468
1469 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1470
1471 link_type first = buckets_[n];
1472 while (first && !equals_(extracter_(first->data), key)) {
1473 first = first->next;
1474 }
1475
1476 if (first == nullptr) {
1477 return {end(), end()};
1478 }
1479
1480 link_type last = first;
1481 while (last && equals_(extracter_(last->data), key)) {
1482 last = last->next;
1483 }
1484
1485 iterator second_it;
1486 if (last != nullptr) {
1487 second_it = iterator(last, n, this);
1488 } else {
1489 size_type next_bucket = n + 1;
1490 while (next_bucket < buckets_.size() && buckets_[next_bucket] == nullptr) {
1491 ++next_bucket;
1492 }
1493 if (next_bucket < buckets_.size()) {
1494 second_it = iterator(buckets_[next_bucket], next_bucket, this);
1495 } else {
1496 second_it = end();
1497 }
1498 }
1499
1500 return {iterator(first, n, this), second_it};
1501 }
1502
1508 NEFORCE_NODISCARD pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
1509 if (buckets_.empty()) {
1510 return {cend(), cend()};
1511 }
1512
1513 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1514
1515 link_type first = buckets_[n];
1516 while (first && !equals_(extracter_(first->data), key)) {
1517 first = first->next;
1518 }
1519
1520 if (first == nullptr) {
1521 return {cend(), cend()};
1522 }
1523
1524 link_type last = first;
1525 while (last && equals_(extracter_(last->data), key)) {
1526 last = last->next;
1527 }
1528
1529 const_iterator second_it;
1530 if (last != nullptr) {
1531 second_it = const_iterator(last, n, this);
1532 } else {
1533 size_type next_bucket = n + 1;
1534 while (next_bucket < buckets_.size() && buckets_[next_bucket] == nullptr) {
1535 ++next_bucket;
1536 }
1537 if (next_bucket < buckets_.size()) {
1538 second_it = const_iterator(buckets_[next_bucket], next_bucket, this);
1539 } else {
1540 second_it = cend();
1541 }
1542 }
1543
1544 return {const_iterator(first, n, this), second_it};
1545 }
1546
1553 if (_NEFORCE addressof(other) == this) {
1554 return;
1555 }
1556 _NEFORCE swap(hasher_, other.hasher_);
1557 _NEFORCE swap(equals_, other.equals_);
1558 _NEFORCE swap(extracter_, other.extracter_);
1559 buckets_.swap(other.buckets_);
1560 _NEFORCE swap(size_, other.size_);
1561 pair_.swap(other.pair_);
1562 }
1563
1569 NEFORCE_NODISCARD bool equal_to(const hashtable& rhs) const {
1570 if (size_ != rhs.size_) {
1571 return false;
1572 }
1573 if (size_ == 0) {
1574 return true;
1575 }
1576 if (this == &rhs) {
1577 return true;
1578 }
1579
1580 if (size_ < 100) {
1581 return hashtable::equal_small(rhs);
1582 }
1583 return hashtable::equal_large(rhs);
1584 }
1585
1591 NEFORCE_NODISCARD bool less_than(const hashtable& rhs) const
1592 noexcept(noexcept(_NEFORCE lexicographical_compare(hashtable::cbegin(), hashtable::cend(), rhs.cbegin(),
1593 rhs.cend()))) {
1594 return _NEFORCE lexicographical_compare(hashtable::cbegin(), hashtable::cend(), rhs.cbegin(), rhs.cend());
1595 }
1596};
1597 // HashTable
1599
1600NEFORCE_END_NAMESPACE__
1601#endif // NEFORCE_CORE_CONTAINER_HASHTABLE_HPP__
哈希表容器
pair< iterator, bool > insert_unique(value_type &&value)
移动插入元素(唯一键版本)
iterator insert_equal(const value_type &value)
插入元素(允许重复键版本)
size_type buckets_size() const noexcept
获取桶数量
const Value * const_pointer
常量指针类型
HashFcn hasher
哈希函数类型
pair< iterator, iterator > equal_range(const key_type &key)
获取等于指定键的元素范围
size_type size() const noexcept
获取元素数量
iterator erase(iterator first, iterator last) noexcept(is_nothrow_hashable_v< key_type >)
删除指定范围内的元素
ptrdiff_t difference_type
差值类型
iterator emplace_equal(Args &&... args)
构造元素(允许重复键版本)
key_equal key_eql() const noexcept(is_nothrow_copy_constructible_v< key_equal >)
获取键相等比较函数对象
pair< iterator, bool > emplace_unique(Args &&... args)
构造元素(唯一键版本)
pair< const_iterator, const_iterator > equal_range(const key_type &key) const
获取等于指定键的元素范围(常量版本)
bool contains(const key_type &key) const noexcept(is_nothrow_hashable_v< key_type >)
检查是否包含指定键
float max_load_factor() const noexcept
获取最大负载因子
Value * pointer
指针类型
hashtable(const size_type n, const HashFcn &hf, const EqualKey &eql, const ExtractKey &ext, float max_lf=1.0F)
构造函数,指定所有函数对象
const_iterator find(const key_type &key) const noexcept(is_nothrow_hashable_v< key_type >)
查找具有指定键的元素(常量版本)
hashtable(hashtable &&other) noexcept(noexcept(hashtable::swap(other)))
移动构造函数
hasher hash_func() const noexcept(is_nothrow_copy_constructible_v< hasher >)
获取哈希函数对象
hashtable & operator=(const hashtable &other)
拷贝赋值运算符
bool equal_to(const hashtable &rhs) const
相等比较操作符
iterator erase(const iterator &position) noexcept(is_nothrow_hashable_v< key_type >)
删除指定位置的元素
const Value & const_reference
常量引用类型
hashtable_iterator< true, hashtable > const_iterator
常量迭代器类型
void insert_unique(std::initializer_list< value_type > ilist)
初始化列表插入元素(唯一键版本)
void clear() noexcept
清空哈希表
Alloc allocator_type
分配器类型
hashtable(const hashtable &other)
拷贝构造函数
hashtable(const size_type n, const HashFcn &hf, const EqualKey &eql, float max_lf=1.0F)
构造函数,指定哈希函数和相等比较函数
Value & reference
引用类型
const_iterator cbegin() const noexcept
获取常量起始迭代器
size_type bucket_size(size_type index) const noexcept
获取指定桶的大小
hashtable_iterator< false, hashtable > iterator
迭代器类型
const_iterator cend() const noexcept
获取常量结束迭代器
Value value_type
值类型
size_t size_type
大小类型
enable_if_t< is_iter_v< Iterator > > insert_unique(Iterator first, Iterator last)
范围插入元素(唯一键版本)
size_type erase(const key_type &key) noexcept(is_nothrow_hashable_v< key_type >)
删除所有具有指定键的元素
bool less_than(const hashtable &rhs) const noexcept(noexcept(_NEFORCE lexicographical_compare(hashtable::cbegin(), hashtable::cend(), rhs.cbegin(), rhs.cend())))
小于比较操作符
hashtable & operator=(hashtable &&other) noexcept(noexcept(hashtable::swap(other)))
移动赋值运算符
void max_load_factor(const float lf) noexcept
设置最大负载因子
const_iterator begin() const noexcept
获取常量起始迭代器
~hashtable()
析构函数
iterator insert_equal(value_type &&value)
移动插入元素(允许重复键版本)
iterator end() noexcept
获取结束迭代器
void reserve(const size_type n)
预留空间
Key key_type
键类型
const_iterator erase(const const_iterator &position) noexcept(is_nothrow_hashable_v< key_type >)
删除指定位置的元素(常量迭代器版本)
const_iterator end() const noexcept
获取常量结束迭代器
float load_factor() const noexcept
获取当前负载因子
const_iterator erase(const_iterator first, const_iterator last) noexcept(is_nothrow_hashable_v< key_type >)
删除指定范围内的元素(常量迭代器版本)
size_type max_size() const noexcept
获取最大可能大小
iterator find(const key_type &key) noexcept(is_nothrow_hashable_v< key_type >)
查找具有指定键的元素
EqualKey key_equal
键相等比较函数类型
hashtable(const size_type n, const HashFcn &hf, float max_lf=1.0F)
构造函数,指定哈希函数
pair< iterator, bool > insert_unique(const value_type &value)
插入元素(唯一键版本)
void swap(hashtable &other) noexcept(is_nothrow_swappable_v< HashFcn > &&is_nothrow_swappable_v< EqualKey > &&is_nothrow_swappable_v< allocator_type >)
交换两个哈希表的内容
size_type bucket_index(const key_type &key) const noexcept(is_nothrow_hashable_v< key_type >)
获取键的桶索引
enable_if_t< is_iter_v< Iterator > > insert_equal(Iterator first, Iterator last)
范围插入元素(允许重复键版本)
hashtable(const size_type n, float max_lf=1.0F)
构造函数
void insert_equal(std::initializer_list< value_type > ilist)
初始化列表插入元素(允许重复键版本)
static size_type buckets_max_size() noexcept
获取最大桶数量
iterator begin() noexcept
获取起始迭代器
bool empty() const noexcept
检查是否为空
void rehash(const size_type new_size)
重新哈希,调整桶数量
size_type count(const key_type &key) const noexcept(is_nothrow_hashable_v< key_type >)
统计具有指定键的元素数量
动态大小数组容器
constexpr void reserve(const size_type n)
预留容量
constexpr iterator begin() noexcept
获取起始迭代器
constexpr iterator end() noexcept
获取结束迭代器
constexpr void push_back(const T &value)
在末尾拷贝插入元素
constexpr size_type size() const noexcept
获取当前元素数量
constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr size_t extent_v
extent的便捷变量模板
constexpr Iterator lower_bound(Iterator first, Iterator last, const T &value, Compare comp)
查找有序范围中第一个不小于指定值的元素位置
constexpr const T & max(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(a, b)))
返回两个值中的较大者
constexpr bool lexicographical_compare(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2, Compare comp) noexcept(noexcept(++first1) &&noexcept(++first2) &&noexcept(comp(*first1, *first2)) &&noexcept(first1==last1 &&first2 !=last2))
字典序比较两个范围
constexpr iter_difference_t< Iterator > count_if(Iterator first, Iterator last, const T &value, BinaryPredicate pred)
统计范围内满足二元谓词的元素数量
constexpr bool is_nothrow_hashable_v
is_nothrow_hashable的便捷变量模板
constexpr size_t HASH_PRIMER_COUNT
素数列表长度
NEFORCE_BEGIN_CONSTANTS__ constexpr size_t HASH_PRIME_LIST[]
哈希表素数列表(64位系统)
constexpr void destroy(T *pointer) noexcept(is_nothrow_destructible_v< T >)
销毁单个对象
constexpr T * construct(T *ptr, Args &&... args) noexcept(is_nothrow_constructible_v< T, Args... >)
在指定内存位置构造对象
constexpr Iterator next(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的后一个位置
constexpr iter_difference_t< Iterator > distance(Iterator first, Iterator last)
计算两个迭代器之间的距离
constexpr Iterator prev(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的前一个位置
constexpr decimal_t ceil(const decimal_t x) noexcept
向上取整
uint64_t size_t
无符号大小类型
int64_t ptrdiff_t
指针差类型
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
constexpr Iterator2 copy(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__copy_aux(first, last, result)))
复制范围元素
void sort(Iterator first, Iterator last, Compare comp)
标准排序
void swap()=delete
删除无参数的swap重载
constexpr bool is_nothrow_swappable_v
is_nothrow_swappable的便捷变量模板
constexpr bool is_nothrow_copy_constructible_v
is_nothrow_copy_constructible的便捷变量模板
constexpr bool is_nothrow_default_constructible_v
is_nothrow_default_constructible的便捷变量模板
typename conditional< Test, T1, T2 >::type conditional_t
conditional的便捷别名
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
排序算法
默认构造标签
前向迭代器标签
typename container_type::size_type size_type
大小类型
typename container_type::difference_type difference_type
差值类型
conditional_t< IsConst, typename container_type::const_pointer, typename container_type::pointer > pointer
指针类型
conditional_t< IsConst, typename container_type::const_reference, typename container_type::reference > reference
引用类型
forward_iterator_tag iterator_category
迭代器类别(前向迭代器)
reference dereference() const noexcept
解引用操作
typename container_type::value_type value_type
值类型
bool equal_to(const hashtable_iterator &rhs) const noexcept
相等比较
void increment() noexcept
递增操作
const container_type * container() const noexcept
获取关联容器
HashTable container_type
容器类型
const node_type * base() const noexcept
获取底层指针
哈希表节点
hashtable_node() noexcept(is_nothrow_default_constructible_v< T >)
默认构造函数
集合器接口模板
迭代器接口模板
存储两个值的元组对
变量处理异常
动态大小数组容器