1#ifndef MSTL_CORE_CONTAINER_HASHTABLE_HPP__
2#define MSTL_CORE_CONTAINER_HASHTABLE_HPP__
7template <
typename Value,
typename Key,
typename HashFcn,
8 typename ExtractKey,
typename EqualKey,
typename Alloc>
10template <
bool IsConst,
typename HashTable>
11struct hashtable_iterator;
14struct hashtable_node {
16 hashtable_node* next_ =
nullptr;
19 template <
typename,
typename,
typename,
typename,
typename,
typename>
friend class hashtable;
20 template <
bool,
typename>
friend struct hashtable_iterator;
23 hashtable_node() =
default;
26template <
bool IsConst,
typename HashTable>
27struct hashtable_iterator {
29 using container_type = HashTable;
30 using iterator = hashtable_iterator<false, container_type>;
31 using const_iterator = hashtable_iterator<true, container_type>;
34 using iterator_category = forward_iterator_tag;
35 using value_type =
typename container_type::value_type;
38 using difference_type =
typename container_type::difference_type;
39 using size_type =
typename container_type::size_type;
42 using node_type = hashtable_node<value_type>;
44 node_type* cur_ =
nullptr;
45 const container_type* ht_ =
nullptr;
46 size_type bucket_ = 0;
48 template <
typename,
typename,
typename,
typename,
typename,
typename>
friend class hashtable;
49 template <
bool,
typename>
friend struct hashtable_iterator;
52 hashtable_iterator() noexcept = default;
54 hashtable_iterator(node_type* n, const HashTable* ht, const size_type bucket)
55 : cur_(n), ht_(ht), bucket_(bucket) {}
57 hashtable_iterator(
const iterator& it)
58 : cur_(it.cur_), ht_(it.ht_), bucket_(it.bucket_) {}
60 hashtable_iterator& operator =(
const iterator& it) {
68 hashtable_iterator(iterator&& it) noexcept
69 : cur_(it.cur_), ht_(it.ht_), bucket_(it.bucket_) {
75 hashtable_iterator& operator =(iterator&& it)
noexcept {
86 hashtable_iterator(
const const_iterator& it)
87 : cur_(it.cur_), ht_(it.ht_), bucket_(it.bucket_) {}
89 hashtable_iterator& operator =(
const const_iterator& it) {
97 hashtable_iterator(const_iterator&& it)
98 : cur_(it.cur_), ht_(it.ht_), bucket_(it.bucket_) {
104 hashtable_iterator& operator =(const_iterator&& it) {
108 bucket_ = it.bucket_;
115 ~hashtable_iterator() =
default;
117 MSTL_NODISCARD reference operator *() const noexcept {
118 MSTL_DEBUG_VERIFY(cur_ && ht_, __MSTL_DEBUG_MESG_OPERATE_NULLPTR(hashtable_iterator, __MSTL_DEBUG_TAG_DEREFERENCE));
119 MSTL_DEBUG_VERIFY(bucket_ < ht_->buckets_.size() && 0 <= bucket_,
120 __MSTL_DEBUG_MESG_OUT_OF_RANGE(hashtable_iterator, __MSTL_DEBUG_TAG_DEREFERENCE));
123 MSTL_NODISCARD pointer operator ->() const noexcept {
124 MSTL_DEBUG_VERIFY(cur_ && ht_, __MSTL_DEBUG_MESG_OPERATE_NULLPTR(hashtable_iterator, __MSTL_DEBUG_TAG_DEREFERENCE));
125 MSTL_DEBUG_VERIFY(bucket_ < ht_->buckets_.size() && 0 <= bucket_,
126 __MSTL_DEBUG_MESG_OUT_OF_RANGE(hashtable_iterator, __MSTL_DEBUG_TAG_DEREFERENCE));
130 hashtable_iterator& operator ++() {
131 MSTL_DEBUG_VERIFY(cur_ && ht_, __MSTL_DEBUG_MESG_OPERATE_NULLPTR(hashtable_iterator, __MSTL_DEBUG_TAG_INCREMENT));
132 MSTL_DEBUG_VERIFY(bucket_ < ht_->buckets_.size() && !(bucket_ + 1 == ht_->buckets_.size() && cur_->next_ !=
nullptr),
133 __MSTL_DEBUG_MESG_OUT_OF_RANGE(hashtable_iterator, __MSTL_DEBUG_TAG_INCREMENT));
135 if (cur_ ==
nullptr) {
136 while (cur_ ==
nullptr && ++bucket_ < ht_->buckets_.size()) {
137 cur_ = ht_->buckets_[bucket_];
142 hashtable_iterator operator ++(
int) {
143 iterator tmp = *
this;
148 MSTL_NODISCARD
bool operator ==(
const hashtable_iterator& x)
const noexcept {
149 MSTL_DEBUG_VERIFY(ht_ == x.ht_, __MSTL_DEBUG_MESG_CONTAINER_INCOMPATIBLE(hashtable_iterator));
150 return cur_ == x.cur_;
152 MSTL_NODISCARD
bool operator !=(
const hashtable_iterator& x)
const noexcept {
153 return !(*
this == x);
156 MSTL_NODISCARD pointer base() const noexcept {
163#ifdef MSTL_DATA_BUS_WIDTH_64__
164MSTL_INLINE17
constexpr size_t HASH_PRIME_LIST[] = {
166 599, 907, 1361, 2053,
167 3083, 4637, 6959, 10453,
168 15683, 23531, 35311, 52967,
169 79451, 119179, 178781, 268189,
170 402299, 603457, 905189, 1357787,
171 2036687, 3055043, 4582577, 6873871,
172 10310819, 15466229, 23199347, 34799021,
173 52198537, 78297827, 117446801, 176170229,
174 264255353, 396383041, 594574583, 891861923,
175 1337792887, 2006689337, 3010034021u, 4515051137ull,
176 6772576709ull, 10158865069ull, 15238297621ull, 22857446471ull,
177 34286169707ull, 51429254599ull, 77143881917ull, 115715822899ull,
178 173573734363ull, 260360601547ull, 390540902329ull, 585811353559ull,
179 878717030339ull, 1318075545511ull, 1977113318311ull, 2965669977497ull,
180 4448504966249ull, 6672757449409ull, 10009136174239ull, 15013704261371ull,
181 22520556392057ull, 33780834588157ull, 50671251882247ull, 76006877823377ull,
182 114010316735089ull, 171015475102649ull, 256523212653977ull, 384784818980971ull,
183 577177228471507ull, 865765842707309ull, 1298648764060979ull, 1947973146091477ull,
184 2921959719137273ull, 4382939578705967ull, 6574409368058969ull, 9861614052088471ull,
185 14792421078132871ull, 22188631617199337ull, 33282947425799017ull, 49924421138698549ull,
186 74886631708047827ull, 112329947562071807ull, 168494921343107851ull, 252742382014661767ull,
187 379113573021992729ull, 568670359532989111ull, 853005539299483657ull, 1279508308949225477ull,
188 1919262463423838231ull, 2878893695135757317ull, 4318340542703636011ull, 6477510814055453699ull
191MSTL_INLINE17
constexpr size_t HASH_PRIME_LIST[] = {
192 53, 97, 193, 389, 769,
193 1543, 3079, 6151, 12289, 24593,
194 49157, 98317, 196613, 393241, 786433,
195 1572869, 3145739, 6291469, 12582917, 25165843,
196 50331653, 100663319, 201326611, 402653189, 805306457,
201MSTL_INLINE17
constexpr size_t HASH_PRIMER_COUNT = extent_v<
decltype(HASH_PRIME_LIST)>;
206template <
typename Value,
typename Key,
typename HashFcn,
207 typename ExtractKey,
typename EqualKey,
typename Alloc>
208class hashtable :
public icollector<hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>> {
209 using node_type = hashtable_node<Value>;
212 using key_type = Key;
213 using hasher = HashFcn;
214 using key_equal = EqualKey;
218 using iterator = hashtable_iterator<false, hashtable>;
219 using const_iterator = hashtable_iterator<true, hashtable>;
221 using allocator_type = Alloc;
224 vector<node_type*> buckets_{};
228 ExtractKey extracter_{};
229 compressed_pair<allocator_type, float> pair_{ default_construct_tag{}, 1.0f };
231 template <
bool,
typename>
232 friend struct hashtable_iterator;
235 MSTL_NODISCARD
static size_type next_size(
const size_type n)
noexcept {
236 const size_t* first =
_CONSTANTS HASH_PRIME_LIST;
239 return pos == last ? *(last - 1) : *pos;
242 void initialize_buckets(
const size_type n) {
243 const size_type n_buckets = next_size(n);
244 buckets_.assign(n_buckets,
nullptr);
247 size_type bkt_num_key(
const key_type& key,
const size_t n)
const
248 noexcept(is_nothrow_hashable_v<key_type>) {
249 if (n == 0)
return 0;
250 return hasher_(key) % n;
253 size_type bkt_num(
const value_type& obj,
const size_t n)
const
254 noexcept(is_nothrow_hashable_v<key_type>) {
255 return this->bkt_num_key(extracter_(obj), n);
258 template <
typename... Args>
259 node_type* new_node(Args&&... args) {
260 node_type* n = pair_.get_base().allocate();
265 this->delete_node(n);
266 throw_exception(memory_exception(
"hashtable construct node failed."));
271 void delete_node(node_type* n)
noexcept {
273 pair_.get_base().deallocate(n);
276 void copy_from(
const hashtable& ht) {
278 buckets_.reserve(ht.buckets_.size());
279 buckets_.insert(buckets_.end(), ht.buckets_.size(),
nullptr);
281 for (size_type i = 0; i < ht.buckets_.size(); ++i) {
282 if (
const node_type* cur = ht.buckets_[i]) {
283 node_type*
copy = this->new_node(cur->data_);
285 for (node_type*
next = cur->next_;
next !=
nullptr; cur =
next,
next = cur->next_) {
286 copy->next_ = this->new_node(
next->data_);
298 pair<iterator, bool> insert_unique_noresize(node_type* x) {
299 const size_type n = bkt_num(x->data_, buckets_.size());
301 node_type** buckets_p = &buckets_[n];
302 while (*buckets_p !=
nullptr) {
303 if (equals_(extracter_((*buckets_p)->data_), extracter_(x->data_))) {
304 x->next_ = (*buckets_p)->next_;
305 delete_node(*buckets_p);
307 return {{x,
this, n},
false};
309 buckets_p = &(*buckets_p)->next_;
314 return {iterator{x,
this, n},
true};
317 iterator insert_equal_noresize(node_type* x) {
318 const size_type n = bkt_num(x->data_, buckets_.size());
319 node_type* first = buckets_[n];
321 node_type*
prev =
nullptr;
322 node_type* cur = first;
323 while (cur !=
nullptr && equals_(extracter_(cur->data_), extracter_(x->data_))) {
328 if (
prev !=
nullptr) {
340 template <
typename Iterator,
342 void insert_unique_aux(Iterator first, Iterator last) {
343 for (; first != last; ++first)
344 this->insert_unique(*first);
347 template <
typename Iterator, enable_if_t<is_ranges_fwd_iter_v<Iterator>,
int> = 0>
348 void insert_unique_aux(Iterator first, Iterator last) {
351 for (; n > 0; --n, ++first) {
352 node_type* tmp = this->new_node(*first);
353 this->insert_unique_noresize(tmp);
357 template <
typename Iterator,
359 void insert_equal_aux(Iterator first, Iterator last) {
360 for (; first != last; ++first)
361 this->insert_equal(*first);
366 void insert_equal_aux(Iterator first, Iterator last) {
369 for (; n > 0; --n, ++first) {
370 node_type* tmp = this->new_node(*first);
371 this->insert_equal_noresize(tmp);
375 size_type erase_bucket_to_node(size_type bucket, node_type* last)
noexcept {
377 node_type* curr = buckets_[bucket];
378 while (curr !=
nullptr && curr != last) {
379 node_type*
next = curr->next_;
385 buckets_[bucket] = last;
389 size_type erase_bucket_range(size_type bucket,
390 node_type* first, node_type* last)
noexcept {
392 if (first ==
nullptr)
return 0;
394 if (buckets_[bucket] == first) {
395 count += erase_bucket_to_node(bucket, last);
397 node_type*
prev = buckets_[bucket];
398 while (
prev !=
nullptr &&
prev->next_ != first) {
401 if (
prev ==
nullptr)
return 0;
403 node_type* curr = first;
404 while (curr !=
nullptr && curr != last) {
405 node_type*
next = curr->next_;
415 size_type erase_bucket_completely(size_type bucket)
noexcept {
417 node_type* curr = buckets_[bucket];
418 while (curr !=
nullptr) {
419 node_type*
next = curr->next_;
424 buckets_[bucket] =
nullptr;
428 bool equal_small(
const hashtable& rhs)
const {
429 for (const_iterator it1 = begin(); it1 != end(); ++it1) {
430 const key_type& key = extracter_(*it1);
431 const size_t count_this =
_MSTL count_if(begin(), end(), [&](
const value_type& val) {
432 return equals_(extracter_(val), key);
434 const size_t count_rh =
_MSTL count_if(rhs.begin(), rhs.end(), [&](
const value_type& val) {
435 return rhs.equals_(rhs.extracter_(val), key);
437 if (count_this != count_rh)
return false;
442 bool equal_large(
const hashtable& rhs)
const {
443 vector<value_type> elements_this, elements_rh;
444 elements_this.reserve(size_);
445 elements_rh.reserve(size_);
447 for (const_iterator it = begin(); it != end(); ++it) {
448 elements_this.push_back(*it);
450 for (const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
451 elements_rh.push_back(*it);
454 _MSTL sort(elements_this.begin(), elements_this.end());
455 _MSTL sort(elements_rh.begin(), elements_rh.end());
457 return elements_this == elements_rh;
461 explicit hashtable(
const size_type n)
462 : hasher_(HashFcn()), equals_(EqualKey()) {
463 initialize_buckets(n);
466 hashtable(
const size_type n,
const HashFcn& hf)
467 : hasher_(hf), equals_(EqualKey()) {
468 initialize_buckets(n);
470 hashtable(
const size_type n,
const HashFcn& hf,
const EqualKey& eql)
471 : hasher_(hf), equals_(eql) {
472 initialize_buckets(n);
474 hashtable(
const size_type n,
const HashFcn& hf,
const EqualKey& eql,
const ExtractKey& ext)
475 : hasher_(hf), equals_(eql), extracter_(ext) {
476 initialize_buckets(n);
479 hashtable(
const hashtable& ht)
480 : hasher_(ht.hasher_), equals_(ht.equals_), extracter_(ht.extracter_), pair_(ht.pair_) {
483 hashtable& operator =(
const hashtable& ht) {
486 hasher_ = ht.hasher_;
487 equals_ = ht.equals_;
488 extracter_ = ht.extracter_;
493 hashtable(hashtable&& ht)
noexcept(
noexcept(this->
swap(ht))) {
496 hashtable& operator =(hashtable&& ht)
noexcept(
noexcept(this->
swap(ht))) {
503 ~hashtable() { clear(); }
505 MSTL_NODISCARD iterator begin() noexcept {
506 for (size_type n = 0; n < buckets_.size(); ++n) {
507 if (buckets_[n] !=
nullptr)
508 return iterator(buckets_[n],
this, n);
512 MSTL_NODISCARD iterator end() noexcept {
return iterator(
nullptr,
this, -1); }
514 MSTL_NODISCARD const_iterator begin() const noexcept {
return cbegin(); }
515 MSTL_NODISCARD const_iterator end() const noexcept {
return cend(); }
517 MSTL_NODISCARD const_iterator cbegin() const noexcept {
518 for (size_type n = 0; n < buckets_.size(); ++n) {
519 if (buckets_[n] !=
nullptr)
520 return const_iterator(buckets_[n],
this, n);
524 MSTL_NODISCARD const_iterator cend() const noexcept {
525 return const_iterator(
nullptr,
this, -1);
528 MSTL_NODISCARD size_type
size() const noexcept {
return size_; }
529 MSTL_NODISCARD size_type max_size() noexcept {
return static_cast<size_type
>(-1); }
530 MSTL_NODISCARD
bool empty() const noexcept {
return size_ == 0; }
531 MSTL_NODISCARD size_type bucket_count() const noexcept {
return buckets_.size(); }
532 MSTL_NODISCARD
static size_type max_bucket_count() noexcept {
535 MSTL_NODISCARD size_type bucket(
const key_type& key)
const noexcept(is_nothrow_hashable_v<key_type>) {
536 return bkt_num_key(key);
538 MSTL_NODISCARD size_type bucket_size(size_type bucket)
const noexcept {
539 size_type result = 0;
540 for (node_type* cur = buckets_[bucket]; cur !=
nullptr; cur = cur->next_)
545 MSTL_NODISCARD allocator_type get_allocator() const noexcept {
return allocator_type(); }
547 MSTL_NODISCARD hasher hash_func() const noexcept(is_nothrow_copy_constructible_v<hasher>) {
550 MSTL_NODISCARD key_equal key_eql() const noexcept(is_nothrow_copy_constructible_v<key_equal>) {
553 MSTL_NODISCARD
float load_factor() const noexcept {
554 return bucket_count() == 0 ? 0.0f :
static_cast<float>(
size()) /
static_cast<float>(bucket_count());
556 MSTL_NODISCARD
float max_load_factor() const noexcept {
559 void max_load_factor(
float new_max)
noexcept {
560 MSTL_DEBUG_VERIFY(new_max > 0,
"hashtable load factor invalid.");
561 pair_.value = new_max;
564 void rehash(
const size_type new_size) {
565 const auto min_buckets_for_size =
static_cast<size_type
>(
566 _MSTL ceil(
static_cast<double>(size_) / max_load_factor())
568 const size_type target =
_MSTL max(new_size, min_buckets_for_size);
569 const size_type old_size = buckets_.size();
570 if (target <= old_size)
return;
572 const size_type n = next_size(target);
574 throw_exception(value_exception(
"hashtable size exceeds max count"));
577 vector<node_type*> new_buckets(n,
nullptr);
579 for (size_type bucket = 0; bucket < old_size; ++bucket) {
580 node_type* cur = buckets_[bucket];
581 while (cur !=
nullptr) {
582 node_type*
next = cur->next_;
583 const size_type new_bucket = bkt_num(cur->data_, n);
585 cur->next_ = new_buckets[new_bucket];
586 new_buckets[new_bucket] = cur;
590 buckets_[bucket] =
nullptr;
593 buckets_.swap(new_buckets);
596 void reserve(
const size_type count) {
597 if (count <= size_)
return;
599 const float needed =
static_cast<float>(count) / max_load_factor();
600 if (needed >
static_cast<float>(max_bucket_count())) {
601 throw_exception(value_exception(
"hashtable size exceeds max count"));
603 rehash(
static_cast<size_type
>(needed));
606 template <
typename... Args>
607 pair<iterator, bool> emplace_unique(Args&&... args) {
608 if (size_ + 1 >
static_cast<size_type
>(buckets_.size() * max_load_factor())) {
612 return (insert_unique_noresize)(node);
614 template <
typename... Args>
615 iterator emplace_equal(Args&&... args) {
616 if (size_ + 1 >
static_cast<size_type
>(buckets_.size() * max_load_factor())) {
620 return (insert_equal_noresize)(node);
623 pair<iterator, bool> insert_unique(
const value_type& x) {
624 return (emplace_unique)(x);
626 pair<iterator, bool> insert_unique(value_type&& x) {
629 iterator insert_equal(
const value_type& x) {
630 return (emplace_equal)(x);
632 iterator insert_equal(value_type&& x) {
636 template <
typename Iterator, enable_if_t<is_iter_v<Iterator>,
int> = 0>
637 void insert_unique(Iterator first, Iterator last) {
638 this->insert_unique_aux(first, last);
641 void insert_unique(std::initializer_list<value_type> l) {
642 this->insert_unique(l.begin(), l.end());
645 template <
typename Iterator, enable_if_t<is_iter_v<Iterator>,
int> = 0>
646 void insert_equal(Iterator first, Iterator last) {
647 this->insert_equal_aux(first, last);
650 void insert_equal(std::initializer_list<value_type> l) {
651 this->insert_equal(l.begin(), l.end());
654 size_type erase(
const key_type& key)
noexcept(is_nothrow_hashable_v<key_type>) {
655 const size_type n = this->bkt_num_key(key, buckets_.size());
656 node_type* first = buckets_[n];
657 size_type erased = 0;
658 if (first !=
nullptr) {
659 node_type* cur = first;
660 node_type*
next = cur->next_;
661 while (
next !=
nullptr) {
662 if (equals_(extracter_(
next->data_), key)) {
663 cur->next_ =
next->next_;
674 if (equals_(extracter_(first->data_), key)) {
675 buckets_[n] = first->next_;
676 this->delete_node(first);
683 iterator erase(
const iterator& it)
noexcept(is_nothrow_hashable_v<key_type>) {
684 if (it.cur_ ==
nullptr || it.ht_ !=
this) {
688 const size_type n = it.bucket_;
689 node_type*
const p = it.cur_;
690 node_type* next_node = p->next_;
692 node_type*
prev =
nullptr;
693 node_type* curr = buckets_[n];
694 while (curr !=
nullptr && curr != p) {
699 if (curr ==
nullptr)
return end();
701 if (
prev ==
nullptr) {
702 buckets_[n] = next_node;
704 prev->next_ = next_node;
707 this->delete_node(p);
710 if (next_node !=
nullptr) {
711 return iterator(next_node,
this, n);
714 for (size_type bucket = n + 1; bucket < buckets_.size(); ++bucket) {
715 if (buckets_[bucket] !=
nullptr) {
716 return iterator(buckets_[bucket],
this, bucket);
722 iterator erase(iterator first, iterator last)
noexcept(is_nothrow_hashable_v<key_type>) {
726 if (first.ht_ !=
this || (last.ht_ !=
this && last != end())) {
729 size_type count_erased = 0;
731 if (first.bucket_ == last.bucket_) {
732 count_erased = erase_bucket_range(first.bucket_, first.cur_, last.cur_);
734 count_erased += erase_bucket_range(first.bucket_, first.cur_,
nullptr);
735 for (size_type bucket = first.bucket_ + 1; bucket < last.bucket_; ++bucket) {
736 count_erased += erase_bucket_completely(bucket);
738 if (last.bucket_ < buckets_.size()) {
739 count_erased += erase_bucket_range(last.bucket_, buckets_[last.bucket_], last.cur_);
742 size_ -= count_erased;
746 const_iterator erase(
const const_iterator& it)
noexcept(is_nothrow_hashable_v<key_type>) {
747 return this->erase(iterator(it));
750 const_iterator erase(const_iterator first, const_iterator last)
noexcept(is_nothrow_hashable_v<key_type>) {
751 return this->erase(iterator(first), iterator(last));
754 void clear() noexcept {
755 for (size_type i = 0; i < buckets_.size(); ++i) {
756 node_type* cur = buckets_[i];
757 while (cur !=
nullptr) {
758 node_type*
next = cur->next_;
759 this->delete_node(cur);
762 buckets_[i] =
nullptr;
767 MSTL_NODISCARD iterator find(
const key_type& key)
noexcept(is_nothrow_hashable_v<key_type>) {
768 if (buckets_.empty())
return end();
770 size_type n = this->bkt_num_key(key, buckets_.size());
771 for (node_type* first = buckets_[n]; first !=
nullptr; first = first->next_) {
772 if (equals_(extracter_(first->data_), key)) {
773 return iterator(first,
this, n);
779 MSTL_NODISCARD const_iterator find(
const key_type& key)
const noexcept(is_nothrow_hashable_v<key_type>) {
780 if (buckets_.empty())
return cend();
782 size_type n = this->bkt_num_key(key, buckets_.size());
783 for (node_type* first = buckets_[n]; first !=
nullptr; first = first->next_) {
784 if (equals_(extracter_(first->data_), key)) {
785 return const_iterator(first,
this, n);
791 MSTL_NODISCARD size_type count(
const key_type& key)
const noexcept(is_nothrow_hashable_v<key_type>) {
792 if (buckets_.empty())
return 0;
793 const size_type n = this->bkt_num_key(key, buckets_.size());
794 size_type result = 0;
795 for (
const node_type* cur = buckets_[n]; cur !=
nullptr; cur = cur->next_) {
796 if (equals_(extracter_(cur->data_), key)) ++result;
800 MSTL_NODISCARD
bool contains(
const key_type& key)
const noexcept(is_nothrow_hashable_v<key_type>) {
801 return find(key) != cend();
804 MSTL_NODISCARD pair<iterator, iterator> equal_range(
const key_type& key) {
805 if (buckets_.empty())
return {end(), end()};
807 const size_type n = this->bkt_num_key(key, buckets_.size());
808 node_type* first_match =
nullptr;
809 node_type* last_match =
nullptr;
810 node_type*
prev =
nullptr;
812 for (node_type* curr = buckets_[n]; curr !=
nullptr;
prev = curr, curr = curr->next_) {
813 if (equals_(extracter_(curr->data_), key)) {
814 if (first_match ==
nullptr) {
818 }
else if (first_match !=
nullptr) {
823 if (first_match ==
nullptr) {
824 return {end(), end()};
827 node_type* range_end = (last_match !=
nullptr) ? last_match->next_ : nullptr;
829 iterator(first_match,
this, n),
830 iterator(range_end,
this, n)
834 MSTL_NODISCARD pair<const_iterator, const_iterator> equal_range(
const key_type& key)
const {
835 if (buckets_.empty())
return {cend(), cend()};
837 const size_type n = this->bkt_num_key(key, buckets_.size());
838 const node_type* first_match =
nullptr;
839 const node_type* last_match =
nullptr;
840 const node_type*
prev =
nullptr;
842 for (
const node_type* curr = buckets_[n]; curr !=
nullptr;
prev = curr, curr = curr->next_) {
843 if (equals_(extracter_(curr->data_), key)) {
844 if (first_match ==
nullptr) {
848 }
else if (first_match !=
nullptr) {
853 if (first_match ==
nullptr) {
854 return {cend(), cend()};
857 const node_type* range_end = (last_match !=
nullptr) ? last_match->next_ : nullptr;
859 const_iterator(first_match,
this, n),
860 const_iterator(range_end,
this, n)
864 void swap(hashtable& ht)
noexcept(is_nothrow_swappable_v<HashFcn> && is_nothrow_swappable_v<EqualKey>) {
869 buckets_.swap(ht.buckets_);
871 pair_.swap(ht.pair_);
874 MSTL_NODISCARD
bool operator ==(
const hashtable& rhs)
const {
875 if (size_ != rhs.size_)
return false;
876 if (size_ == 0)
return true;
877 if (
this == &rhs)
return true;
879 if (size_ < 100)
return equal_small(rhs);
880 return equal_large(rhs);
883 MSTL_NODISCARD
bool operator <(
const hashtable& rhs)
const
MSTL_NODISCARD constexpr T * addressof(T &x) noexcept
获取对象的地址
MSTL_NODISCARD constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
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)))
返回两个值中的较大者
MSTL_NODISCARD 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)
统计范围内满足二元谓词的元素数量
MSTL_CONSTEXPR20 enable_if_t< is_constructible_v< T, Args... >, void * > construct(T *ptr, Args &&... args) noexcept(is_nothrow_constructible_v< T, Args... >)
在指定内存位置构造对象
MSTL_CONSTEXPR20 void destroy(T *pointer) noexcept(is_nothrow_destructible_v< T >)
销毁单个对象
MSTL_INLINE17 constexpr bool is_ranges_fwd_iter_v
检查是否为范围前向迭代器
constexpr Iterator prev(Iterator iter, iter_difference_t< Iterator > n=-1)
获取迭代器的前一个位置
constexpr Iterator next(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的后一个位置
constexpr iter_difference_t< Iterator > distance(Iterator first, Iterator last)
计算两个迭代器之间的距离
MSTL_CONST_FUNCTION MSTL_CONSTEXPR14 decimal_t ceil(const decimal_t x) noexcept
向上取整
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_CONSTANTS__
结束constants命名空间
#define _CONSTANTS
constants命名空间前缀
#define MSTL_BEGIN_CONSTANTS__
开始constants命名空间
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result)
移动范围元素
constexpr Iterator2 copy(Iterator1 first, Iterator1 last, Iterator2 result)
复制范围元素
void sort(Iterator first, Iterator last, Compare comp)
标准排序
void swap()=delete
删除无参数的swap重载
typename conditional< Test, T1, T2 >::type conditional_t
conditional的便捷别名
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
MSTL_NODISCARD constexpr decltype(auto) size() const noexcept(noexcept(derived().size()))
MSTL_NODISCARD constexpr bool empty() const noexcept(noexcept(derived().empty()))