1#ifndef NEFORCE_CORE_CONTAINER_HASHTABLE_HPP__
2#define NEFORCE_CORE_CONTAINER_HASHTABLE_HPP__
16NEFORCE_BEGIN_NAMESPACE__
44template <
typename Value,
typename Key,
typename HashFcn,
typename ExtractKey,
typename EqualKey,
typename Alloc>
56template <
bool IsConst,
typename HashTable>
57struct hashtable_iterator :
iiterator<hashtable_iterator<IsConst, HashTable>> {
61 using size_type =
typename container_type::size_type;
65 typename container_type::reference>;
67 typename container_type::pointer>;
72 node_type* current_ =
nullptr;
76 template <
typename,
typename,
typename,
typename,
typename,
typename>
77 friend class hashtable;
80 hashtable_iterator() noexcept = default;
81 ~hashtable_iterator() = default;
83 hashtable_iterator(const hashtable_iterator&) noexcept = default;
84 hashtable_iterator& operator=(const hashtable_iterator&) noexcept = default;
85 hashtable_iterator(hashtable_iterator&&) noexcept = default;
86 hashtable_iterator& operator=(hashtable_iterator&&) noexcept = default;
94 hashtable_iterator(node_type* ptr, const
size_type bucket, const HashTable* ht) :
106 "Attempting to dereference out of boundary");
107 return current_->data;
118 !(bucket_ + 1 == container_->buckets_.size() && current_->next !=
nullptr),
119 "Attempting to increment out of boundary");
120 current_ = current_->next;
121 if (current_ ==
nullptr) {
122 while (current_ ==
nullptr && ++bucket_ < container_->buckets_.size()) {
123 current_ = container_->buckets_[bucket_];
133 NEFORCE_NODISCARD
bool equal(
const hashtable_iterator& rhs)
const noexcept {
134 NEFORCE_DEBUG_VERIFY(container_ == rhs.container_,
"Attempting to equal to a different container");
135 return current_ == rhs.current_;
142 NEFORCE_NODISCARD
pointer base() const noexcept {
return current_; }
152NEFORCE_BEGIN_CONSTANTS__
153#ifdef NEFORCE_ARCH_BITS_64
240 14792421078132871ull,
241 22188631617199337ull,
242 33282947425799017ull,
243 49924421138698549ull,
244 74886631708047827ull,
245 112329947562071807ull,
246 168494921343107851ull,
247 252742382014661767ull,
248 379113573021992729ull,
249 568670359532989111ull,
250 853005539299483657ull,
251 1279508308949225477ull,
252 1919262463423838231ull,
253 2878893695135757317ull,
254 4318340542703636011ull,
255 6477510814055453699ull};
263 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289,
264 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
265 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741};
272NEFORCE_END_CONSTANTS__
288template <
typename Value,
typename Key,
typename HashFcn,
typename ExtractKey,
typename EqualKey,
typename Alloc>
302 using iterator = hashtable_iterator<false, hashtable>;
308 using link_type = node_type*;
314 ExtractKey extracter_{};
315 compressed_pair<allocator_type, float> pair_{default_construct_tag{}, 1.0f};
317 template <
bool,
typename>
318 friend struct hashtable_iterator;
327 const size_t* first = constants::HASH_PRIME_LIST;
328 const size_t* last = constants::HASH_PRIME_LIST + constants::HASH_PRIMER_COUNT;
329 const size_t* pos = _NEFORCE
lower_bound(first, last, n);
330 return pos == last ? *(last - 1) : *pos;
337 void initialize_buckets(
const size_type n) {
338 const size_type n_buckets = next_size(n);
339 buckets_.assign(n_buckets,
nullptr);
352 return hasher_(key) % n;
363 return hashtable::bucket_index_key(extracter_(value), n);
372 template <
typename... Args>
373 link_type new_node(Args&&... args) {
374 link_type n = pair_.get_base().allocate();
379 hashtable::delete_node(n);
380 NEFORCE_THROW_EXCEPTION(memory_exception(
"hashtable construct node failed."));
389 void delete_node(link_type n)
noexcept {
391 pair_.get_base().deallocate(n);
400 buckets_.reserve(other.buckets_.size());
401 buckets_.insert(buckets_.end(), other.buckets_.size(),
nullptr);
403 for (
size_type i = 0; i < other.buckets_.size(); ++i) {
404 if (link_type cur = other.buckets_[i]) {
405 link_type
copy = hashtable::new_node(cur->data);
407 for (link_type
next = cur->next;
next !=
nullptr; cur =
next,
next = cur->next) {
408 copy->next = hashtable::new_node(
next->data);
425 pair<iterator, bool> insert_unique_noresize(link_type ptr) {
426 const size_type n = hashtable::bucket_index_value(ptr->data, buckets_.size());
428 node_type** buckets_ptr = &buckets_[n];
429 while (*buckets_ptr !=
nullptr) {
430 if (equals_(extracter_((*buckets_ptr)->data), extracter_(ptr->data))) {
431 ptr->next = (*buckets_ptr)->next;
432 hashtable::delete_node(*buckets_ptr);
434 return {{ptr, n,
this},
false};
436 buckets_ptr = &(*buckets_ptr)->next;
441 return {
iterator{ptr, n,
this},
true};
449 iterator insert_equal_noresize(link_type ptr) {
450 const size_type n = hashtable::bucket_index_value(ptr->data, buckets_.size());
451 link_type first = buckets_[n];
453 link_type
prev =
nullptr;
454 link_type cur = first;
455 while (cur !=
nullptr && equals_(extracter_(cur->data), extracter_(ptr->data))) {
460 if (
prev !=
nullptr) {
469 return {ptr, n,
this};
478 template <
typename Iterator>
480 for (; first != last; ++first) {
492 template <
typename Iterator>
500 for (; n > 0; --n, ++first) {
501 link_type tmp = hashtable::new_node(*first);
502 hashtable::insert_unique_noresize(tmp);
513 template <
typename Iterator>
515 for (; first != last; ++first) {
527 template <
typename Iterator>
535 for (; n > 0; --n, ++first) {
536 link_type tmp = hashtable::new_node(*first);
537 hashtable::insert_equal_noresize(tmp);
550 link_type curr = buckets_[bucket];
551 while (curr !=
nullptr && curr != last) {
552 link_type
next = curr->next;
553 hashtable::delete_node(curr);
558 buckets_[bucket] = last;
569 size_type erase_bucket_range(
size_type bucket, link_type first, link_type last)
noexcept {
571 if (first ==
nullptr) {
575 if (buckets_[bucket] == first) {
576 count += hashtable::erase_bucket_to_node(bucket, last);
578 link_type
prev = buckets_[bucket];
579 while (
prev !=
nullptr &&
prev->next != first) {
582 if (
prev ==
nullptr) {
586 link_type curr = first;
587 while (curr !=
nullptr && curr != last) {
588 link_type
next = curr->next;
590 hashtable::delete_node(curr);
605 link_type curr = buckets_[bucket];
606 while (curr !=
nullptr) {
607 link_type
next = curr->next;
608 hashtable::delete_node(curr);
612 buckets_[bucket] =
nullptr;
621 bool equal_small(
const hashtable& rhs)
const {
623 const key_type& key = extracter_(*iter);
625 const size_t count_lhs = _NEFORCE
count_if(
626 begin(),
end(), [
this, &key](
const value_type& val) {
return equals_(extracter_(val), key); });
628 return rhs.equals_(rhs.extracter_(val), key);
631 if (count_lhs != count_rhs) {
643 bool equal_large(
const hashtable& rhs)
const {
644 vector<value_type> elements_lhs, elements_rhs;
655 _NEFORCE
sort(elements_lhs.
begin(), elements_lhs.
end());
656 _NEFORCE
sort(elements_rhs.
begin(), elements_rhs.
end());
658 return elements_lhs == elements_rhs;
668 buckets_(next_size(n), nullptr),
678 buckets_(next_size(n), nullptr),
690 buckets_(next_size(n), nullptr),
703 hashtable(
const size_type n,
const HashFcn& hf,
const EqualKey& eql,
const ExtractKey& ext,
float max_lf = 1.0f) :
704 buckets_(next_size(n), nullptr),
715 hasher_(other.hasher_),
716 equals_(other.equals_),
717 extracter_(other.extracter_),
719 hashtable::copy_from(other);
732 hasher_ = other.hasher_;
733 equals_ = other.equals_;
734 extracter_ = other.extracter_;
735 hashtable::copy_from(other);
744 buckets_(_NEFORCE
move(other.buckets_)),
746 hasher_(_NEFORCE
move(other.hasher_)),
747 equals_(_NEFORCE
move(other.equals_)),
748 extracter_(_NEFORCE
move(other.extracter_)),
749 pair_(_NEFORCE
move(other.pair_)) {
777 for (
size_type n = 0; n < buckets_.size(); ++n) {
778 if (buckets_[n] !=
nullptr) {
779 return iterator(buckets_[n], n,
this);
808 for (
size_type n = 0; n < buckets_.size(); ++n) {
809 if (buckets_[n] !=
nullptr) {
838 NEFORCE_NODISCARD
bool empty() const noexcept {
return size_ == 0; }
851 return constants::HASH_PRIME_LIST[constants::HASH_PRIMER_COUNT - 1];
860 return hashtable::bucket_index_key(key);
870 for (link_type cur = buckets_[index]; cur !=
nullptr; cur = cur->next) {
916 const auto min_buckets_for_size =
918 const size_type target = _NEFORCE
max(new_size, min_buckets_for_size);
919 const size_type old_size = buckets_.size();
921 if (target <= old_size) {
925 const size_type n = hashtable::next_size(target);
927 NEFORCE_THROW_EXCEPTION(
value_exception(
"hashtable size exceeds max count"));
932 for (
size_type bucket = 0; bucket < old_size; ++bucket) {
933 link_type cur = buckets_[bucket];
934 while (cur !=
nullptr) {
936 const size_type new_bucket = hashtable::bucket_index_value(cur->
data, n);
938 cur->
next = new_buckets[new_bucket];
939 new_buckets[new_bucket] = cur;
943 buckets_[bucket] =
nullptr;
946 buckets_.swap(new_buckets);
963 NEFORCE_THROW_EXCEPTION(
value_exception(
"hashtable size exceeds max count"));
974 template <
typename... Args>
979 const link_type node = hashtable::new_node(_NEFORCE
forward<Args>(args)...);
980 return hashtable::insert_unique_noresize(node);
989 template <
typename... Args>
994 const link_type node = hashtable::new_node(_NEFORCE
forward<Args>(args)...);
995 return hashtable::insert_equal_noresize(node);
1032 template <
typename Iterator>
1034 hashtable::insert_unique_aux(first, last);
1052 template <
typename Iterator>
1054 hashtable::insert_equal_aux(first, last);
1070 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1071 link_type first = buckets_[n];
1074 if (first !=
nullptr) {
1075 link_type cur = first;
1078 while (
next !=
nullptr) {
1079 if (equals_(extracter_(
next->data), key)) {
1081 hashtable::delete_node(
next);
1091 if (equals_(extracter_(first->
data), key)) {
1092 buckets_[n] = first->
next;
1093 hashtable::delete_node(first);
1108 if (position.current_ ==
nullptr || position.container_ !=
this) {
1113 link_type
const p = position.current_;
1114 link_type next_node = p->
next;
1116 link_type
prev =
nullptr;
1117 link_type curr = buckets_[n];
1118 while (curr !=
nullptr && curr != p) {
1123 if (curr ==
nullptr) {
1127 if (
prev ==
nullptr) {
1128 buckets_[n] = next_node;
1130 prev->next = next_node;
1133 hashtable::delete_node(p);
1136 if (next_node !=
nullptr) {
1137 return iterator(next_node, n,
this);
1140 for (
size_type bucket = n + 1; bucket < buckets_.size(); ++bucket) {
1141 if (buckets_[bucket] !=
nullptr) {
1142 return iterator(buckets_[bucket], bucket,
this);
1155 if (first == last) {
1159 if (first.container_ !=
this || (last.container_ !=
this && last !=
end())) {
1165 if (first.bucket_ == last.bucket_) {
1166 count_erased = hashtable::erase_bucket_range(first.bucket_, first.current_, last.current_);
1168 count_erased += hashtable::erase_bucket_range(first.bucket_, first.current_,
nullptr);
1169 for (
size_type bucket = first.bucket_ + 1; bucket < last.bucket_; ++bucket) {
1170 count_erased += hashtable::erase_bucket_completely(bucket);
1172 if (last.bucket_ < buckets_.size()) {
1173 count_erased += hashtable::erase_bucket_range(last.bucket_, buckets_[last.bucket_], last.current_);
1176 size_ -= count_erased;
1203 for (
size_type i = 0; i < buckets_.size(); ++i) {
1204 link_type cur = buckets_[i];
1205 while (cur !=
nullptr) {
1207 hashtable::delete_node(cur);
1210 buckets_[i] =
nullptr;
1221 if (buckets_.empty()) {
1225 size_type n = hashtable::bucket_index_key(key, buckets_.size());
1226 for (link_type first = buckets_[n]; first !=
nullptr; first = first->next) {
1227 if (equals_(extracter_(first->data), key)) {
1240 if (buckets_.empty()) {
1244 size_type n = hashtable::bucket_index_key(key, buckets_.size());
1245 for (link_type first = buckets_[n]; first !=
nullptr; first = first->next) {
1246 if (equals_(extracter_(first->data), key)) {
1259 if (buckets_.empty()) {
1262 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1264 for (link_type cur = buckets_[n]; cur !=
nullptr; cur = cur->next) {
1265 if (equals_(extracter_(cur->data), key)) {
1287 if (buckets_.empty()) {
1291 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1292 link_type first_match =
nullptr;
1293 link_type last_match =
nullptr;
1295 for (link_type curr = buckets_[n]; curr !=
nullptr; curr = curr->next) {
1296 if (equals_(extracter_(curr->data), key)) {
1297 if (first_match ==
nullptr) {
1301 }
else if (first_match !=
nullptr) {
1306 if (first_match ==
nullptr) {
1310 link_type range_end = (last_match !=
nullptr) ? last_match->
next :
nullptr;
1320 if (buckets_.empty()) {
1324 const size_type n = hashtable::bucket_index_key(key, buckets_.size());
1325 const link_type first_match =
nullptr;
1326 const link_type last_match =
nullptr;
1328 for (
const link_type curr = buckets_[n]; curr !=
nullptr; curr = curr->next) {
1329 if (equals_(extracter_(curr->data), key)) {
1330 if (first_match ==
nullptr) {
1334 }
else if (first_match !=
nullptr) {
1339 if (first_match ==
nullptr) {
1343 const link_type range_end = (last_match !=
nullptr) ? last_match->
next :
nullptr;
1353 if (_NEFORCE
addressof(other) ==
this) {
1356 _NEFORCE
swap(hasher_, other.hasher_);
1357 _NEFORCE
swap(equals_, other.equals_);
1358 _NEFORCE
swap(extracter_, other.extracter_);
1359 buckets_.swap(other.buckets_);
1360 _NEFORCE
swap(size_, other.size_);
1361 pair_.swap(other.pair_);
1370 if (size_ != rhs.size_) {
1381 return hashtable::equal_small(rhs);
1383 return hashtable::equal_large(rhs);
1400NEFORCE_END_NAMESPACE__
NEFORCE_NODISCARD bool empty() const noexcept
检查是否为空
NEFORCE_NODISCARD const_iterator cend() const noexcept
获取常量结束迭代器
pair< iterator, bool > insert_unique(value_type &&value)
移动插入元素(唯一键版本)
iterator insert_equal(const value_type &value)
插入元素(允许重复键版本)
hashtable(const size_type n, const HashFcn &hf, const EqualKey &eql, float max_lf=1.0f)
构造函数,指定哈希函数和相等比较函数
hashtable(const size_type n, float max_lf=1.0f)
构造函数
NEFORCE_NODISCARD float load_factor() const noexcept
获取当前负载因子
NEFORCE_NODISCARD bool contains(const key_type &key) const noexcept(is_nothrow_hashable_v< key_type >)
检查是否包含指定键
const Value * const_pointer
常量指针类型
NEFORCE_NODISCARD hasher hash_func() const noexcept(is_nothrow_copy_constructible_v< hasher >)
获取哈希函数对象
NEFORCE_NODISCARD size_type buckets_size() const noexcept
获取桶数量
NEFORCE_NODISCARD iterator find(const key_type &key) noexcept(is_nothrow_hashable_v< key_type >)
查找具有指定键的元素
iterator erase(iterator first, iterator last) noexcept(is_nothrow_hashable_v< key_type >)
删除指定范围内的元素
ptrdiff_t difference_type
差值类型
iterator emplace_equal(Args &&... args)
构造元素(允许重复键版本)
pair< iterator, bool > emplace_unique(Args &&... args)
构造元素(唯一键版本)
hashtable(hashtable &&other) noexcept(noexcept(hashtable::swap(other)))
移动构造函数
NEFORCE_NODISCARD float max_load_factor() const noexcept
获取最大负载因子
NEFORCE_NODISCARD iterator end() noexcept
获取结束迭代器
hashtable & operator=(const hashtable &other)
拷贝赋值运算符
static NEFORCE_NODISCARD size_type buckets_max_size() noexcept
获取最大桶数量
iterator erase(const iterator &position) noexcept(is_nothrow_hashable_v< key_type >)
删除指定位置的元素
const Value & const_reference
常量引用类型
NEFORCE_NODISCARD bool operator==(const hashtable &rhs) const
相等比较操作符
hashtable_iterator< true, hashtable > const_iterator
常量迭代器类型
void insert_unique(std::initializer_list< value_type > ilist)
初始化列表插入元素(唯一键版本)
NEFORCE_NODISCARD const_iterator end() const noexcept
获取常量结束迭代器
NEFORCE_NODISCARD const_iterator cbegin() const noexcept
获取常量起始迭代器
void clear() noexcept
清空哈希表
NEFORCE_NODISCARD size_type bucket_size(size_type index) const noexcept
获取指定桶的大小
Alloc allocator_type
分配器类型
hashtable(const hashtable &other)
拷贝构造函数
hashtable_iterator< false, hashtable > iterator
迭代器类型
NEFORCE_NODISCARD const_iterator begin() const noexcept
获取常量起始迭代器
NEFORCE_NODISCARD size_type count(const key_type &key) const noexcept(is_nothrow_hashable_v< key_type >)
统计具有指定键的元素数量
NEFORCE_NODISCARD bool operator<(const hashtable &rhs) const noexcept(noexcept(_NEFORCE lexicographical_compare(hashtable::cbegin(), hashtable::cend(), rhs.cbegin(), rhs.cend())))
小于比较操作符
NEFORCE_NODISCARD key_equal key_eql() const noexcept(is_nothrow_copy_constructible_v< key_equal >)
获取键相等比较函数对象
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 >)
删除所有具有指定键的元素
hashtable & operator=(hashtable &&other) noexcept(noexcept(hashtable::swap(other)))
移动赋值运算符
void max_load_factor(const float lf) noexcept
设置最大负载因子
iterator insert_equal(value_type &&value)
移动插入元素(允许重复键版本)
hashtable(const size_type n, const HashFcn &hf, float max_lf=1.0f)
构造函数,指定哈希函数
void reserve(const size_type n)
预留空间
NEFORCE_NODISCARD const_iterator find(const key_type &key) const noexcept(is_nothrow_hashable_v< key_type >)
查找具有指定键的元素(常量版本)
const_iterator erase(const const_iterator &position) noexcept(is_nothrow_hashable_v< key_type >)
删除指定位置的元素(常量迭代器版本)
const_iterator erase(const_iterator first, const_iterator last) noexcept(is_nothrow_hashable_v< key_type >)
删除指定范围内的元素(常量迭代器版本)
NEFORCE_NODISCARD pair< iterator, iterator > equal_range(const key_type &key)
获取等于指定键的元素范围
EqualKey key_equal
键相等比较函数类型
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 >)
交换两个哈希表的内容
hashtable(const size_type n, const HashFcn &hf, const EqualKey &eql, const ExtractKey &ext, float max_lf=1.0f)
构造函数,指定所有函数对象
NEFORCE_NODISCARD size_type max_size() const noexcept
获取最大可能大小
enable_if_t< is_iter_v< Iterator > > insert_equal(Iterator first, Iterator last)
范围插入元素(允许重复键版本)
NEFORCE_NODISCARD size_type bucket_index(const key_type &key) const noexcept(is_nothrow_hashable_v< key_type >)
获取键的桶索引
void insert_equal(std::initializer_list< value_type > ilist)
初始化列表插入元素(允许重复键版本)
NEFORCE_NODISCARD pair< const_iterator, const_iterator > equal_range(const key_type &key) const
获取等于指定键的元素范围(常量版本)
NEFORCE_NODISCARD size_type size() const noexcept
获取元素数量
void rehash(const size_type new_size)
重新哈希,调整桶数量
NEFORCE_NODISCARD iterator begin() noexcept
获取起始迭代器
NEFORCE_CONSTEXPR20 void push_back(const T &value)
在末尾拷贝插入元素
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 iterator end() noexcept
获取结束迭代器
NEFORCE_CONSTEXPR20 void reserve(const size_type n)
预留容量
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 iterator begin() noexcept
获取起始迭代器
NEFORCE_NODISCARD constexpr T * addressof(T &x) noexcept
获取对象的地址
NEFORCE_NODISCARD constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
NEFORCE_INLINE17 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)))
返回两个值中的较大者
NEFORCE_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)
统计范围内满足二元谓词的元素数量
#define NEFORCE_DEBUG_VERIFY(CON, MESG)
调试模式断言
NEFORCE_INLINE17 constexpr bool is_nothrow_hashable_v
is_nothrow_hashable的便捷变量模板
NEFORCE_INLINE17 constexpr size_t HASH_PRIMER_COUNT
素数列表长度
NEFORCE_BEGIN_CONSTANTS__ NEFORCE_INLINE17 constexpr size_t HASH_PRIME_LIST[]
哈希表素数列表(32位系统)
NEFORCE_CONSTEXPR20 T * construct(T *ptr, Args &&... args) noexcept(is_nothrow_constructible_v< T, Args... >)
在指定内存位置构造对象
NEFORCE_CONSTEXPR20 void destroy(T *pointer) noexcept(is_nothrow_destructible_v< T >)
销毁单个对象
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)
计算两个迭代器之间的距离
NEFORCE_CONST_FUNCTION NEFORCE_CONSTEXPR14 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重载
NEFORCE_INLINE17 constexpr bool is_nothrow_swappable_v
is_nothrow_swappable的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_nothrow_default_constructible_v
is_nothrow_default_constructible的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_nothrow_copy_constructible_v
is_nothrow_copy_constructible的便捷变量模板
typename conditional< Test, T1, T2 >::type conditional_t
conditional的便捷别名
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
NEFORCE_NODISCARD bool equal(const hashtable_iterator &rhs) const noexcept
相等比较
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
迭代器类别(前向迭代器)
NEFORCE_NODISCARD reference dereference() const noexcept
解引用操作
typename container_type::value_type value_type
值类型
NEFORCE_NODISCARD const container_type * container() const noexcept
获取关联容器
NEFORCE_NODISCARD pointer base() const noexcept
获取底层指针
void increment() noexcept
递增操作
HashTable container_type
容器类型
hashtable_node() noexcept(is_nothrow_default_constructible_v< T >)
默认构造函数