1#ifndef NEFORCE_CORE_CONTAINER_HASHTABLE_HPP__
2#define NEFORCE_CORE_CONTAINER_HASHTABLE_HPP__
16NEFORCE_BEGIN_NAMESPACE__
155template <
typename Value,
typename Key,
typename HashFcn,
typename ExtractKey,
typename EqualKey,
typename Alloc>
167template <
bool IsConst,
typename HashTable>
168struct hashtable_iterator :
iiterator<hashtable_iterator<IsConst, HashTable>> {
176 typename container_type::reference>;
178 typename container_type::pointer>;
183 node_type* current_ =
nullptr;
187 template <
typename,
typename,
typename,
typename,
typename,
typename>
188 friend class hashtable;
191 hashtable_iterator() noexcept = default;
192 ~hashtable_iterator() = default;
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;
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;
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_];
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_;
250 NEFORCE_NODISCARD
const node_type*
base() const noexcept {
return current_; }
266NEFORCE_BEGIN_CONSTANTS__
267#ifdef NEFORCE_ARCH_BITS_64
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};
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};
386NEFORCE_END_CONSTANTS__
402template <
typename Value,
typename Key,
typename HashFcn,
typename ExtractKey,
typename EqualKey,
typename Alloc>
416 using iterator = hashtable_iterator<false, hashtable>;
422 using link_type = node_type*;
428 ExtractKey extracter_{};
429 compressed_pair<allocator_type, float> pair_{default_construct_tag{}, 1.0F};
431 template <
bool,
typename>
432 friend struct hashtable_iterator;
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;
451 void initialize_buckets(
const size_type n) {
452 const size_type n_buckets = next_size(n);
453 buckets_.assign(n_buckets,
nullptr);
466 return hasher_(key) % n;
477 return hashtable::bucket_index_key(extracter_(value), n);
486 template <
typename... Args>
487 link_type new_node(Args&&... args) {
488 link_type n = pair_.get_base().allocate();
493 hashtable::delete_node(n);
494 NEFORCE_THROW_EXCEPTION(memory_exception(
"hashtable construct node failed."));
503 void delete_node(link_type n)
noexcept {
505 pair_.get_base().deallocate(n);
514 buckets_.reserve(other.buckets_.size());
515 buckets_.insert(buckets_.end(), other.buckets_.size(),
nullptr);
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);
521 for (link_type
next = cur->next;
next !=
nullptr; cur =
next,
next = cur->next) {
522 copy->next = hashtable::new_node(
next->data);
539 pair<iterator, bool> insert_unique_noresize(link_type ptr) {
540 const size_type n = hashtable::bucket_index_value(ptr->data, buckets_.size());
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};
549 buckets_ptr = &(*buckets_ptr)->next;
555 return {
iterator{ptr, n,
this},
true};
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];
567 link_type
prev =
nullptr;
568 link_type cur = first;
569 while (cur !=
nullptr && equals_(extracter_(cur->data), extracter_(ptr->data))) {
574 if (
prev !=
nullptr) {
583 return {ptr, n,
this};
592 template <
typename Iterator>
594 for (; first != last; ++first) {
606 template <
typename Iterator>
610 const auto need_buckets =
614 for (; n > 0; --n, ++first) {
615 link_type tmp = hashtable::new_node(*first);
616 hashtable::insert_unique_noresize(tmp);
627 template <
typename Iterator>
629 for (; first != last; ++first) {
641 template <
typename Iterator>
645 const auto need_buckets =
649 for (; n > 0; --n, ++first) {
650 link_type tmp = hashtable::new_node(*first);
651 hashtable::insert_equal_noresize(tmp);
664 link_type curr = buckets_[bucket];
665 while (curr !=
nullptr && curr != last) {
666 link_type
next = curr->next;
667 hashtable::delete_node(curr);
671 buckets_[bucket] = last;
682 size_type erase_bucket_range(
size_type bucket, link_type first, link_type last)
noexcept {
684 if (first ==
nullptr) {
688 if (buckets_[bucket] == first) {
689 count += hashtable::erase_bucket_to_node(bucket, last);
691 link_type
prev = buckets_[bucket];
692 while (
prev !=
nullptr &&
prev->next != first) {
695 if (
prev ==
nullptr) {
699 link_type curr = first;
700 while (curr !=
nullptr && curr != last) {
701 link_type
next = curr->next;
703 hashtable::delete_node(curr);
718 link_type curr = buckets_[bucket];
719 while (curr !=
nullptr) {
720 link_type
next = curr->next;
721 hashtable::delete_node(curr);
725 buckets_[bucket] =
nullptr;
734 bool equal_small(
const hashtable& rhs)
const {
736 const key_type& key = extracter_(*iter);
738 const size_t count_lhs = _NEFORCE
count_if(
739 begin(),
end(), [
this, &key](
const value_type& val) {
return equals_(extracter_(val), key); });
741 return rhs.equals_(rhs.extracter_(val), key);
744 if (count_lhs != count_rhs) {
756 bool equal_large(
const hashtable& rhs)
const {
757 if (size_ != rhs.size_) {
761 vector<const value_type*> ptrs_lhs, ptrs_rhs;
772 auto key_less = [
this](
const value_type* a,
const value_type* b) {
return extracter_(*a) < extracter_(*b); };
774 return rhs.extracter_(*a) < rhs.extracter_(*b);
777 _NEFORCE
sort(ptrs_lhs.
begin(), ptrs_lhs.
end(), key_less);
778 _NEFORCE
sort(ptrs_rhs.
begin(), ptrs_rhs.
end(), rhs_key_less);
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]);
787 if (!equals_(key_l, key_r)) {
792 while (i < n && equals_(extracter_(*ptrs_lhs[i]), key_l)) {
795 while (j < n && rhs.equals_(rhs.extracter_(*ptrs_rhs[j]), key_l)) {
801 if (count_l != count_r) {
805 for (
size_type k = i_start; k < i; ++k) {
808 for (
size_type l = j_start; l < j; ++l) {
809 if (ptrs_rhs[l] && *ptrs_rhs[l] == val) {
810 ptrs_rhs[l] =
nullptr;
820 for (
size_type l = j_start; l < j; ++l) {
821 if (ptrs_rhs[l] !=
nullptr) {
831 return iterator(
const_cast<node_type*
>(iter.base()), iter.bucket(), iter.container());
835 return const_iterator(
const_cast<node_type*
>(iter.base()), iter.bucket(), iter.container());
845 buckets_(next_size(n), nullptr),
855 buckets_(next_size(n), nullptr),
867 buckets_(next_size(n), nullptr),
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),
892 hasher_(other.hasher_),
893 equals_(other.equals_),
894 extracter_(other.extracter_),
896 hashtable::copy_from(other);
909 hasher_ = other.hasher_;
910 equals_ = other.equals_;
911 extracter_ = other.extracter_;
912 hashtable::copy_from(other);
921 buckets_(_NEFORCE
move(other.buckets_)),
923 hasher_(_NEFORCE
move(other.hasher_)),
924 equals_(_NEFORCE
move(other.equals_)),
925 extracter_(_NEFORCE
move(other.extracter_)),
926 pair_(_NEFORCE
move(other.pair_)) {
954 for (
size_type n = 0; n < buckets_.size(); ++n) {
955 if (buckets_[n] !=
nullptr) {
956 return iterator(buckets_[n], n,
this);
985 for (
size_type n = 0; n < buckets_.size(); ++n) {
986 if (buckets_[n] !=
nullptr) {
1015 NEFORCE_NODISCARD
bool empty() const noexcept {
return size_ == 0; }
1028 return constants::HASH_PRIME_LIST[constants::HASH_PRIMER_COUNT - 1];
1037 return hashtable::bucket_index_key(key);
1047 for (link_type cur = buckets_[index]; cur !=
nullptr; cur = cur->next) {
1084 NEFORCE_DEBUG_VERIFY(lf > 0,
"hashtable load factor invalid.");
1093 const auto min_buckets_for_size =
1095 const size_type target = _NEFORCE
max(new_size, min_buckets_for_size);
1096 const size_type old_size = buckets_.size();
1098 if (target <= old_size) {
1102 const size_type n = hashtable::next_size(target);
1104 NEFORCE_THROW_EXCEPTION(
value_exception(
"hashtable size exceeds max count"));
1109 for (
size_type bucket = 0; bucket < old_size; ++bucket) {
1110 link_type cur = buckets_[bucket];
1111 while (cur !=
nullptr) {
1113 const size_type new_bucket = hashtable::bucket_index_value(cur->
data, n);
1115 cur->
next = new_buckets[new_bucket];
1116 new_buckets[new_bucket] = cur;
1120 buckets_[bucket] =
nullptr;
1123 buckets_.swap(new_buckets);
1140 NEFORCE_THROW_EXCEPTION(
value_exception(
"hashtable size exceeds max count"));
1151 template <
typename... Args>
1156 const link_type node = hashtable::new_node(_NEFORCE
forward<Args>(args)...);
1157 return hashtable::insert_unique_noresize(node);
1166 template <
typename... Args>
1171 const link_type node = hashtable::new_node(_NEFORCE
forward<Args>(args)...);
1172 return hashtable::insert_equal_noresize(node);
1209 template <
typename Iterator>
1211 hashtable::insert_unique_aux(first, last);
1229 template <
typename Iterator>
1231 hashtable::insert_equal_aux(first, last);
1247 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1248 link_type first = buckets_[n];
1251 if (first !=
nullptr) {
1252 link_type cur = first;
1255 while (
next !=
nullptr) {
1256 if (equals_(extracter_(
next->data), key)) {
1258 hashtable::delete_node(
next);
1268 if (equals_(extracter_(first->
data), key)) {
1269 buckets_[n] = first->
next;
1270 hashtable::delete_node(first);
1285 if (position.current_ ==
nullptr || position.container_ !=
this) {
1290 link_type
const p = position.current_;
1291 link_type next_node = p->
next;
1293 link_type
prev =
nullptr;
1294 link_type curr = buckets_[n];
1295 while (curr !=
nullptr && curr != p) {
1300 if (curr ==
nullptr) {
1304 if (
prev ==
nullptr) {
1305 buckets_[n] = next_node;
1307 prev->next = next_node;
1310 hashtable::delete_node(p);
1313 if (next_node !=
nullptr) {
1314 return iterator(next_node, n,
this);
1317 for (
size_type bucket = n + 1; bucket < buckets_.size(); ++bucket) {
1318 if (buckets_[bucket] !=
nullptr) {
1319 return iterator(buckets_[bucket], bucket,
this);
1332 if (first == last) {
1336 if (first.container_ !=
this || (last.container_ !=
this && last !=
end())) {
1342 if (first.bucket_ == last.bucket_) {
1343 count_erased = hashtable::erase_bucket_range(first.bucket_, first.current_, last.current_);
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);
1349 if (last.bucket_ < buckets_.size()) {
1350 count_erased += hashtable::erase_bucket_range(last.bucket_, buckets_[last.bucket_], last.current_);
1353 size_ -= count_erased;
1363 return hashtable::to_const_iterator(
hashtable::erase(hashtable::to_iterator(position)));
1373 return hashtable::to_const_iterator(
1374 hashtable::erase(hashtable::to_iterator(first), hashtable::to_iterator(last)));
1381 for (
size_type i = 0; i < buckets_.size(); ++i) {
1382 link_type cur = buckets_[i];
1383 while (cur !=
nullptr) {
1385 hashtable::delete_node(cur);
1388 buckets_[i] =
nullptr;
1399 if (buckets_.empty()) {
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)) {
1418 if (buckets_.empty()) {
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)) {
1437 if (buckets_.empty()) {
1440 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1442 for (link_type cur = buckets_[n]; cur !=
nullptr; cur = cur->next) {
1443 if (equals_(extracter_(cur->data), key)) {
1465 if (buckets_.empty()) {
1469 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1471 link_type first = buckets_[n];
1472 while (first && !equals_(extracter_(first->
data), key)) {
1473 first = first->
next;
1476 if (first ==
nullptr) {
1480 link_type last = first;
1481 while (last && equals_(extracter_(last->data), key)) {
1486 if (last !=
nullptr) {
1487 second_it =
iterator(last, n,
this);
1490 while (next_bucket < buckets_.size() && buckets_[next_bucket] ==
nullptr) {
1493 if (next_bucket < buckets_.size()) {
1494 second_it =
iterator(buckets_[next_bucket], next_bucket,
this);
1500 return {
iterator(first, n,
this), second_it};
1509 if (buckets_.empty()) {
1513 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1515 link_type first = buckets_[n];
1516 while (first && !equals_(extracter_(first->
data), key)) {
1517 first = first->
next;
1520 if (first ==
nullptr) {
1524 link_type last = first;
1525 while (last && equals_(extracter_(last->data), key)) {
1530 if (last !=
nullptr) {
1534 while (next_bucket < buckets_.size() && buckets_[next_bucket] ==
nullptr) {
1537 if (next_bucket < buckets_.size()) {
1538 second_it =
const_iterator(buckets_[next_bucket], next_bucket,
this);
1553 if (_NEFORCE
addressof(other) ==
this) {
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_);
1570 if (size_ != rhs.size_) {
1581 return hashtable::equal_small(rhs);
1583 return hashtable::equal_large(rhs);
1600NEFORCE_END_NAMESPACE__
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
常量指针类型
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
获取最大负载因子
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)
构造函数,指定哈希函数和相等比较函数
const_iterator cbegin() const noexcept
获取常量起始迭代器
size_type bucket_size(size_type index) const noexcept
获取指定桶的大小
hashtable_iterator< false, hashtable > iterator
迭代器类型
const_iterator cend() const noexcept
获取常量结束迭代器
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
获取常量起始迭代器
iterator insert_equal(value_type &&value)
移动插入元素(允许重复键版本)
iterator end() noexcept
获取结束迭代器
void reserve(const size_type n)
预留空间
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
向上取整
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
获取底层指针
size_type bucket() const noexcept
hashtable_node() noexcept(is_nothrow_default_constructible_v< T >)
默认构造函数