MSTL 1.4.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
hashtable.hpp
1#ifndef MSTL_CORE_CONTAINER_HASHTABLE_HPP__
2#define MSTL_CORE_CONTAINER_HASHTABLE_HPP__
4#include "vector.hpp"
6
7template <typename Value, typename Key, typename HashFcn,
8 typename ExtractKey, typename EqualKey, typename Alloc>
9class hashtable;
10template <bool IsConst, typename HashTable>
11struct hashtable_iterator;
12
13template <typename T>
14struct hashtable_node {
15private:
16 hashtable_node* next_ = nullptr;
17 T data_{};
18
19 template <typename, typename, typename, typename, typename, typename> friend class hashtable;
20 template <bool, typename> friend struct hashtable_iterator;
21
22public:
23 hashtable_node() = default;
24};
25
26template <bool IsConst, typename HashTable>
27struct hashtable_iterator {
28private:
29 using container_type = HashTable;
30 using iterator = hashtable_iterator<false, container_type>;
31 using const_iterator = hashtable_iterator<true, container_type>;
32
33public:
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;
40
41private:
42 using node_type = hashtable_node<value_type>;
43
44 node_type* cur_ = nullptr;
45 const container_type* ht_ = nullptr;
46 size_type bucket_ = 0;
47
48 template <typename, typename, typename, typename, typename, typename> friend class hashtable;
49 template <bool, typename> friend struct hashtable_iterator;
50
51public:
52 hashtable_iterator() noexcept = default;
53
54 hashtable_iterator(node_type* n, const HashTable* ht, const size_type bucket)
55 : cur_(n), ht_(ht), bucket_(bucket) {}
56
57 hashtable_iterator(const iterator& it)
58 : cur_(it.cur_), ht_(it.ht_), bucket_(it.bucket_) {}
59
60 hashtable_iterator& operator =(const iterator& it) {
61 if(_MSTL addressof(it) == this) return *this;
62 cur_ = it.cur_;
63 ht_ = it.ht_;
64 bucket_ = it.bucket_;
65 return *this;
66 }
67
68 hashtable_iterator(iterator&& it) noexcept
69 : cur_(it.cur_), ht_(it.ht_), bucket_(it.bucket_) {
70 it.cur_ = nullptr;
71 it.ht_ = nullptr;
72 it.bucket_ = -1;
73 }
74
75 hashtable_iterator& operator =(iterator&& it) noexcept {
76 if(_MSTL addressof(it) == this) return *this;
77 cur_ = it.cur_;
78 ht_ = it.ht_;
79 bucket_ = it.bucket_;
80 it.cur_ = nullptr;
81 it.ht_ = nullptr;
82 it.bucket_ = -1;
83 return *this;
84 }
85
86 hashtable_iterator(const const_iterator& it)
87 : cur_(it.cur_), ht_(it.ht_), bucket_(it.bucket_) {}
88
89 hashtable_iterator& operator =(const const_iterator& it) {
90 if(_MSTL addressof(it) == this) return *this;
91 cur_ = it.cur_;
92 ht_ = it.ht_;
93 bucket_ = it.bucket_;
94 return *this;
95 }
96
97 hashtable_iterator(const_iterator&& it)
98 : cur_(it.cur_), ht_(it.ht_), bucket_(it.bucket_) {
99 it.cur_ = nullptr;
100 it.ht_ = nullptr;
101 it.bucket_ = -1;
102 }
103
104 hashtable_iterator& operator =(const_iterator&& it) {
105 if(_MSTL addressof(it) == this) return *this;
106 cur_ = it.cur_;
107 ht_ = it.ht_;
108 bucket_ = it.bucket_;
109 it.cur_ = nullptr;
110 it.ht_ = nullptr;
111 it.bucket_ = -1;
112 return *this;
113 }
114
115 ~hashtable_iterator() = default;
116
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));
121 return cur_->data_;
122 }
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));
127 return &operator*();
128 }
129
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));
134 cur_ = cur_->next_;
135 if (cur_ == nullptr) {
136 while (cur_ == nullptr && ++bucket_ < ht_->buckets_.size()) {
137 cur_ = ht_->buckets_[bucket_];
138 }
139 }
140 return *this;
141 }
142 hashtable_iterator operator ++(int) {
143 iterator tmp = *this;
144 ++*this;
145 return tmp;
146 }
147
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_;
151 }
152 MSTL_NODISCARD bool operator !=(const hashtable_iterator& x) const noexcept {
153 return !(*this == x);
154 }
155
156 MSTL_NODISCARD pointer base() const noexcept {
157 return cur_;
158 }
159};
160
161
163#ifdef MSTL_DATA_BUS_WIDTH_64__
164MSTL_INLINE17 constexpr size_t HASH_PRIME_LIST[] = {
165 101, 173, 263, 397,
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
189};
190#else
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,
197 1610612741
198};
199#endif
200
201MSTL_INLINE17 constexpr size_t HASH_PRIMER_COUNT = extent_v<decltype(HASH_PRIME_LIST)>;
202
204
205
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>;
210
211public:
212 using key_type = Key;
213 using hasher = HashFcn;
214 using key_equal = EqualKey;
215
217
218 using iterator = hashtable_iterator<false, hashtable>;
219 using const_iterator = hashtable_iterator<true, hashtable>;
220
221 using allocator_type = Alloc;
222
223private:
224 vector<node_type*> buckets_{};
225 size_type size_ = 0;
226 hasher hasher_{};
227 key_equal equals_{};
228 ExtractKey extracter_{};
229 compressed_pair<allocator_type, float> pair_{ default_construct_tag{}, 1.0f };
230
231 template <bool, typename>
232 friend struct hashtable_iterator;
233
234private:
235 MSTL_NODISCARD static size_type next_size(const size_type n) noexcept {
236 const size_t* first = _CONSTANTS HASH_PRIME_LIST;
237 const size_t* last = _CONSTANTS HASH_PRIME_LIST + _CONSTANTS HASH_PRIMER_COUNT;
238 const size_t* pos = _MSTL lower_bound(first, last, n);
239 return pos == last ? *(last - 1) : *pos;
240 }
241
242 void initialize_buckets(const size_type n) {
243 const size_type n_buckets = next_size(n);
244 buckets_.assign(n_buckets, nullptr);
245 }
246
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;
251 }
252
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);
256 }
257
258 template <typename... Args>
259 node_type* new_node(Args&&... args) {
260 node_type* n = pair_.get_base().allocate();
261 n->next_ = nullptr;
262 try {
263 _MSTL construct(&n->data_, _MSTL forward<Args>(args)...);
264 } catch (...) {
265 this->delete_node(n);
266 throw_exception(memory_exception("hashtable construct node failed."));
267 }
268 return n;
269 }
270
271 void delete_node(node_type* n) noexcept {
272 _MSTL destroy(&n->data_);
273 pair_.get_base().deallocate(n);
274 }
275
276 void copy_from(const hashtable& ht) {
277 buckets_.clear();
278 buckets_.reserve(ht.buckets_.size());
279 buckets_.insert(buckets_.end(), ht.buckets_.size(), nullptr);
280 try {
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_);
284 buckets_[i] = copy;
285 for (node_type* next = cur->next_; next != nullptr; cur = next, next = cur->next_) {
286 copy->next_ = this->new_node(next->data_);
287 copy = copy->next_;
288 }
289 }
290 }
291 size_ = ht.size_;
292 } catch (...) {
293 clear();
294 throw;
295 }
296 }
297
298 pair<iterator, bool> insert_unique_noresize(node_type* x) {
299 const size_type n = bkt_num(x->data_, buckets_.size());
300
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);
306 *buckets_p = x;
307 return {{x, this, n}, false};
308 }
309 buckets_p = &(*buckets_p)->next_;
310 }
311 x->next_ = nullptr;
312 *buckets_p = x;
313 ++size_;
314 return {iterator{x, this, n}, true};
315 }
316
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];
320
321 node_type* prev = nullptr;
322 node_type* cur = first;
323 while (cur != nullptr && equals_(extracter_(cur->data_), extracter_(x->data_))) {
324 prev = cur;
325 cur = cur->next_;
326 }
327
328 if (prev != nullptr) {
329 prev->next_ = x;
330 x->next_ = cur;
331 } else {
332 x->next_ = first;
333 buckets_[n] = x;
334 }
335
336 ++size_;
337 return {x, this, n};
338 }
339
340 template <typename Iterator,
342 void insert_unique_aux(Iterator first, Iterator last) {
343 for (; first != last; ++first)
344 this->insert_unique(*first);
345 }
346
347 template <typename Iterator, enable_if_t<is_ranges_fwd_iter_v<Iterator>, int> = 0>
348 void insert_unique_aux(Iterator first, Iterator last) {
349 size_type n = _MSTL distance(first, last);
350 rehash(size_ + n);
351 for (; n > 0; --n, ++first) {
352 node_type* tmp = this->new_node(*first);
353 this->insert_unique_noresize(tmp);
354 }
355 }
356
357 template <typename Iterator,
359 void insert_equal_aux(Iterator first, Iterator last) {
360 for (; first != last; ++first)
361 this->insert_equal(*first);
362 }
363
364 template <typename Iterator, enable_if_t<
366 void insert_equal_aux(Iterator first, Iterator last) {
367 size_type n = _MSTL distance(first, last);
368 rehash(size_ + n);
369 for (; n > 0; --n, ++first) {
370 node_type* tmp = this->new_node(*first);
371 this->insert_equal_noresize(tmp);
372 }
373 }
374
375 size_type erase_bucket_to_node(size_type bucket, node_type* last) noexcept {
376 size_type count = 0;
377 node_type* curr = buckets_[bucket];
378 while (curr != nullptr && curr != last) {
379 node_type* next = curr->next_;
380 delete_node(curr);
381 curr = next;
382 --size_;
383 ++count;
384 }
385 buckets_[bucket] = last;
386 return count;
387 }
388
389 size_type erase_bucket_range(size_type bucket,
390 node_type* first, node_type* last) noexcept {
391 size_type count = 0;
392 if (first == nullptr) return 0;
393
394 if (buckets_[bucket] == first) {
395 count += erase_bucket_to_node(bucket, last);
396 } else {
397 node_type* prev = buckets_[bucket];
398 while (prev != nullptr && prev->next_ != first) {
399 prev = prev->next_;
400 }
401 if (prev == nullptr) return 0;
402
403 node_type* curr = first;
404 while (curr != nullptr && curr != last) {
405 node_type* next = curr->next_;
406 prev->next_ = next;
407 delete_node(curr);
408 curr = next;
409 ++count;
410 }
411 }
412 return count;
413 }
414
415 size_type erase_bucket_completely(size_type bucket) noexcept {
416 size_type count = 0;
417 node_type* curr = buckets_[bucket];
418 while (curr != nullptr) {
419 node_type* next = curr->next_;
420 delete_node(curr);
421 curr = next;
422 ++count;
423 }
424 buckets_[bucket] = nullptr;
425 return count;
426 }
427
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);
433 });
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);
436 });
437 if (count_this != count_rh) return false;
438 }
439 return true;
440 }
441
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_);
446
447 for (const_iterator it = begin(); it != end(); ++it) {
448 elements_this.push_back(*it);
449 }
450 for (const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
451 elements_rh.push_back(*it);
452 }
453
454 _MSTL sort(elements_this.begin(), elements_this.end());
455 _MSTL sort(elements_rh.begin(), elements_rh.end());
456
457 return elements_this == elements_rh;
458 }
459
460public:
461 explicit hashtable(const size_type n)
462 : hasher_(HashFcn()), equals_(EqualKey()) {
463 initialize_buckets(n);
464 }
465
466 hashtable(const size_type n, const HashFcn& hf)
467 : hasher_(hf), equals_(EqualKey()) {
468 initialize_buckets(n);
469 }
470 hashtable(const size_type n, const HashFcn& hf, const EqualKey& eql)
471 : hasher_(hf), equals_(eql) {
472 initialize_buckets(n);
473 }
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);
477 }
478
479 hashtable(const hashtable& ht)
480 : hasher_(ht.hasher_), equals_(ht.equals_), extracter_(ht.extracter_), pair_(ht.pair_) {
481 this->copy_from(ht);
482 }
483 hashtable& operator =(const hashtable& ht) {
484 if (_MSTL addressof(ht) == this) return *this;
485 clear();
486 hasher_ = ht.hasher_;
487 equals_ = ht.equals_;
488 extracter_ = ht.extracter_;
489 this->copy_from(ht);
490 return *this;
491 }
492
493 hashtable(hashtable&& ht) noexcept(noexcept(this->swap(ht))) {
494 this->swap(ht);
495 }
496 hashtable& operator =(hashtable&& ht) noexcept(noexcept(this->swap(ht))) {
497 if (_MSTL addressof(ht) == this) return *this;
498 clear();
499 this->swap(ht);
500 return *this;
501 }
502
503 ~hashtable() { clear(); }
504
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);
509 }
510 return end();
511 }
512 MSTL_NODISCARD iterator end() noexcept { return iterator(nullptr, this, -1); }
513
514 MSTL_NODISCARD const_iterator begin() const noexcept { return cbegin(); }
515 MSTL_NODISCARD const_iterator end() const noexcept { return cend(); }
516
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);
521 }
522 return cend();
523 }
524 MSTL_NODISCARD const_iterator cend() const noexcept {
525 return const_iterator(nullptr, this, -1);
526 }
527
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 {
533 return _CONSTANTS HASH_PRIME_LIST[_CONSTANTS HASH_PRIMER_COUNT - 1];
534 }
535 MSTL_NODISCARD size_type bucket(const key_type& key) const noexcept(is_nothrow_hashable_v<key_type>) {
536 return bkt_num_key(key);
537 }
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_)
541 result++;
542 return result;
543 }
544
545 MSTL_NODISCARD allocator_type get_allocator() const noexcept { return allocator_type(); }
546
547 MSTL_NODISCARD hasher hash_func() const noexcept(is_nothrow_copy_constructible_v<hasher>) {
548 return hasher_;
549 }
550 MSTL_NODISCARD key_equal key_eql() const noexcept(is_nothrow_copy_constructible_v<key_equal>) {
551 return equals_;
552 }
553 MSTL_NODISCARD float load_factor() const noexcept {
554 return bucket_count() == 0 ? 0.0f : static_cast<float>(size()) / static_cast<float>(bucket_count());
555 }
556 MSTL_NODISCARD float max_load_factor() const noexcept {
557 return pair_.value;
558 }
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;
562 }
563
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())
567 );
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;
571
572 const size_type n = next_size(target);
573 if (n < target) {
574 throw_exception(value_exception("hashtable size exceeds max count"));
575 }
576
577 vector<node_type*> new_buckets(n, nullptr);
578
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);
584
585 cur->next_ = new_buckets[new_bucket];
586 new_buckets[new_bucket] = cur;
587
588 cur = next;
589 }
590 buckets_[bucket] = nullptr;
591 }
592
593 buckets_.swap(new_buckets);
594 }
595
596 void reserve(const size_type count) {
597 if (count <= size_) return;
598
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"));
602 }
603 rehash(static_cast<size_type>(needed));
604 }
605
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())) {
609 rehash(size_ + 1);
610 }
611 node_type* node = (new_node)(_MSTL forward<Args>(args)...);
612 return (insert_unique_noresize)(node);
613 }
614 template <typename... Args>
615 iterator emplace_equal(Args&&... args) {
616 if (size_ + 1 > static_cast<size_type>(buckets_.size() * max_load_factor())) {
617 rehash(size_ + 1);
618 }
619 node_type* node = (new_node)(_MSTL forward<Args>(args)...);
620 return (insert_equal_noresize)(node);
621 }
622
623 pair<iterator, bool> insert_unique(const value_type& x) {
624 return (emplace_unique)(x);
625 }
626 pair<iterator, bool> insert_unique(value_type&& x) {
627 return (emplace_unique)(_MSTL move(x));
628 }
629 iterator insert_equal(const value_type& x) {
630 return (emplace_equal)(x);
631 }
632 iterator insert_equal(value_type&& x) {
633 return (emplace_equal)(_MSTL move(x));
634 }
635
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);
639 }
640
641 void insert_unique(std::initializer_list<value_type> l) {
642 this->insert_unique(l.begin(), l.end());
643 }
644
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);
648 }
649
650 void insert_equal(std::initializer_list<value_type> l) {
651 this->insert_equal(l.begin(), l.end());
652 }
653
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_;
664 delete_node(next);
665 next = cur->next_;
666 ++erased;
667 --size_;
668 }
669 else {
670 cur = next;
671 next = cur->next_;
672 }
673 }
674 if (equals_(extracter_(first->data_), key)) {
675 buckets_[n] = first->next_;
676 this->delete_node(first);
677 ++erased;
678 --size_;
679 }
680 }
681 return erased;
682 }
683 iterator erase(const iterator& it) noexcept(is_nothrow_hashable_v<key_type>) {
684 if (it.cur_ == nullptr || it.ht_ != this) {
685 return end();
686 }
687
688 const size_type n = it.bucket_;
689 node_type* const p = it.cur_;
690 node_type* next_node = p->next_;
691
692 node_type* prev = nullptr;
693 node_type* curr = buckets_[n];
694 while (curr != nullptr && curr != p) {
695 prev = curr;
696 curr = curr->next_;
697 }
698
699 if (curr == nullptr) return end();
700
701 if (prev == nullptr) {
702 buckets_[n] = next_node;
703 } else {
704 prev->next_ = next_node;
705 }
706
707 this->delete_node(p);
708 --size_;
709
710 if (next_node != nullptr) {
711 return iterator(next_node, this, n);
712 }
713
714 for (size_type bucket = n + 1; bucket < buckets_.size(); ++bucket) {
715 if (buckets_[bucket] != nullptr) {
716 return iterator(buckets_[bucket], this, bucket);
717 }
718 }
719 return end();
720 }
721
722 iterator erase(iterator first, iterator last) noexcept(is_nothrow_hashable_v<key_type>) {
723 if (first == last) {
724 return last;
725 }
726 if (first.ht_ != this || (last.ht_ != this && last != end())) {
727 return end();
728 }
729 size_type count_erased = 0;
730
731 if (first.bucket_ == last.bucket_) {
732 count_erased = erase_bucket_range(first.bucket_, first.cur_, last.cur_);
733 } else {
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);
737 }
738 if (last.bucket_ < buckets_.size()) {
739 count_erased += erase_bucket_range(last.bucket_, buckets_[last.bucket_], last.cur_);
740 }
741 }
742 size_ -= count_erased;
743 return last;
744 }
745
746 const_iterator erase(const const_iterator& it) noexcept(is_nothrow_hashable_v<key_type>) {
747 return this->erase(iterator(it));
748 }
749
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));
752 }
753
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);
760 cur = next;
761 }
762 buckets_[i] = nullptr;
763 }
764 size_ = 0;
765 }
766
767 MSTL_NODISCARD iterator find(const key_type& key) noexcept(is_nothrow_hashable_v<key_type>) {
768 if (buckets_.empty()) return end();
769
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);
774 }
775 }
776 return end();
777 }
778
779 MSTL_NODISCARD const_iterator find(const key_type& key) const noexcept(is_nothrow_hashable_v<key_type>) {
780 if (buckets_.empty()) return cend();
781
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);
786 }
787 }
788 return cend();
789 }
790
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;
797 }
798 return result;
799 }
800 MSTL_NODISCARD bool contains(const key_type& key) const noexcept(is_nothrow_hashable_v<key_type>) {
801 return find(key) != cend();
802 }
803
804 MSTL_NODISCARD pair<iterator, iterator> equal_range(const key_type& key) {
805 if (buckets_.empty()) return {end(), end()};
806
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;
811
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) {
815 first_match = curr;
816 }
817 last_match = curr;
818 } else if (first_match != nullptr) {
819 break;
820 }
821 }
822
823 if (first_match == nullptr) {
824 return {end(), end()};
825 }
826
827 node_type* range_end = (last_match != nullptr) ? last_match->next_ : nullptr;
828 return {
829 iterator(first_match, this, n),
830 iterator(range_end, this, n)
831 };
832 }
833
834 MSTL_NODISCARD pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
835 if (buckets_.empty()) return {cend(), cend()};
836
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;
841
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) {
845 first_match = curr;
846 }
847 last_match = curr;
848 } else if (first_match != nullptr) {
849 break;
850 }
851 }
852
853 if (first_match == nullptr) {
854 return {cend(), cend()};
855 }
856
857 const node_type* range_end = (last_match != nullptr) ? last_match->next_ : nullptr;
858 return {
859 const_iterator(first_match, this, n),
860 const_iterator(range_end, this, n)
861 };
862 }
863
864 void swap(hashtable& ht) noexcept(is_nothrow_swappable_v<HashFcn> && is_nothrow_swappable_v<EqualKey>) {
865 if (_MSTL addressof(ht) == this) return;
866 _MSTL swap(hasher_, ht.hasher_);
867 _MSTL swap(equals_, ht.equals_);
868 _MSTL swap(extracter_, ht.extracter_);
869 buckets_.swap(ht.buckets_);
870 _MSTL swap(size_, ht.size_);
871 pair_.swap(ht.pair_);
872 }
873
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;
878
879 if (size_ < 100) return equal_small(rhs);
880 return equal_large(rhs);
881 }
882
883 MSTL_NODISCARD bool operator <(const hashtable& rhs) const
884 noexcept(noexcept(_MSTL lexicographical_compare(this->cbegin(), this->cend(), rhs.cbegin(), rhs.cend()))) {
885 return _MSTL lexicographical_compare(this->cbegin(), this->cend(), rhs.cbegin(), rhs.cend());
886 }
887};
888
890#endif // MSTL_CORE_CONTAINER_HASHTABLE_HPP__
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
#define MSTL_BUILD_TYPE_ALIAS(TYPE)
快速构建标准类型别名
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排序算法
集合器接口模板
MSTL_NODISCARD constexpr decltype(auto) size() const noexcept(noexcept(derived().size()))
MSTL_NODISCARD constexpr bool empty() const noexcept(noexcept(derived().empty()))