Warning, /include/c++/v1/__hash_table is written in an unsupported language. File is not indexed.
0001 // -*- C++ -*-
0002 //===----------------------------------------------------------------------===//
0003 //
0004 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0005 // See https://llvm.org/LICENSE.txt for license information.
0006 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0007 //
0008 //===----------------------------------------------------------------------===//
0009
0010 #ifndef _LIBCPP___HASH_TABLE
0011 #define _LIBCPP___HASH_TABLE
0012
0013 #include <__algorithm/max.h>
0014 #include <__algorithm/min.h>
0015 #include <__assert>
0016 #include <__bit/countl.h>
0017 #include <__config>
0018 #include <__cstddef/ptrdiff_t.h>
0019 #include <__cstddef/size_t.h>
0020 #include <__functional/hash.h>
0021 #include <__iterator/iterator_traits.h>
0022 #include <__math/rounding_functions.h>
0023 #include <__memory/addressof.h>
0024 #include <__memory/allocator_traits.h>
0025 #include <__memory/compressed_pair.h>
0026 #include <__memory/construct_at.h>
0027 #include <__memory/pointer_traits.h>
0028 #include <__memory/swap_allocator.h>
0029 #include <__memory/unique_ptr.h>
0030 #include <__new/launder.h>
0031 #include <__type_traits/can_extract_key.h>
0032 #include <__type_traits/enable_if.h>
0033 #include <__type_traits/invoke.h>
0034 #include <__type_traits/is_const.h>
0035 #include <__type_traits/is_constructible.h>
0036 #include <__type_traits/is_nothrow_assignable.h>
0037 #include <__type_traits/is_nothrow_constructible.h>
0038 #include <__type_traits/is_reference.h>
0039 #include <__type_traits/is_same.h>
0040 #include <__type_traits/is_swappable.h>
0041 #include <__type_traits/remove_const.h>
0042 #include <__type_traits/remove_cvref.h>
0043 #include <__utility/forward.h>
0044 #include <__utility/move.h>
0045 #include <__utility/pair.h>
0046 #include <__utility/swap.h>
0047 #include <limits>
0048
0049 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0050 # pragma GCC system_header
0051 #endif
0052
0053 _LIBCPP_PUSH_MACROS
0054 #include <__undef_macros>
0055
0056 _LIBCPP_BEGIN_NAMESPACE_STD
0057
0058 template <class _Key, class _Tp>
0059 struct __hash_value_type;
0060
0061 template <class _Tp>
0062 struct __is_hash_value_type_imp : false_type {};
0063
0064 template <class _Key, class _Value>
0065 struct __is_hash_value_type_imp<__hash_value_type<_Key, _Value> > : true_type {};
0066
0067 template <class... _Args>
0068 struct __is_hash_value_type : false_type {};
0069
0070 template <class _One>
0071 struct __is_hash_value_type<_One> : __is_hash_value_type_imp<__remove_cvref_t<_One> > {};
0072
0073 _LIBCPP_EXPORTED_FROM_ABI size_t __next_prime(size_t __n);
0074
0075 template <class _NodePtr>
0076 struct __hash_node_base {
0077 typedef typename pointer_traits<_NodePtr>::element_type __node_type;
0078 typedef __hash_node_base __first_node;
0079 typedef __rebind_pointer_t<_NodePtr, __first_node> __node_base_pointer;
0080 typedef _NodePtr __node_pointer;
0081 typedef __node_base_pointer __next_pointer;
0082
0083 // TODO(LLVM 22): Remove this check
0084 #ifndef _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB
0085 static_assert(sizeof(__node_base_pointer) == sizeof(__node_pointer) && _LIBCPP_ALIGNOF(__node_base_pointer) ==
0086 _LIBCPP_ALIGNOF(__node_pointer),
0087 "It looks like you are using std::__hash_table (an implementation detail for the unordered containers) "
0088 "with a fancy pointer type that thas a different representation depending on whether it points to a "
0089 "__hash_table base pointer or a __hash_table node pointer (both of which are implementation details of "
0090 "the standard library). This means that your ABI is being broken between LLVM 19 and LLVM 20. If you "
0091 "don't care about your ABI being broken, define the _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB macro to "
0092 "silence this diagnostic.");
0093 #endif
0094
0095 __next_pointer __next_;
0096
0097 _LIBCPP_HIDE_FROM_ABI __next_pointer __ptr() _NOEXCEPT {
0098 return static_cast<__next_pointer>(pointer_traits<__node_base_pointer>::pointer_to(*this));
0099 }
0100
0101 _LIBCPP_HIDE_FROM_ABI __node_pointer __upcast() _NOEXCEPT {
0102 return static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(*this));
0103 }
0104
0105 _LIBCPP_HIDE_FROM_ABI size_t __hash() const _NOEXCEPT { return static_cast<__node_type const&>(*this).__hash_; }
0106
0107 _LIBCPP_HIDE_FROM_ABI __hash_node_base() _NOEXCEPT : __next_(nullptr) {}
0108 _LIBCPP_HIDE_FROM_ABI explicit __hash_node_base(__next_pointer __next) _NOEXCEPT : __next_(__next) {}
0109 };
0110
0111 template <class _Tp, class _VoidPtr>
0112 struct __hash_node : public __hash_node_base< __rebind_pointer_t<_VoidPtr, __hash_node<_Tp, _VoidPtr> > > {
0113 typedef _Tp __node_value_type;
0114 using _Base _LIBCPP_NODEBUG = __hash_node_base<__rebind_pointer_t<_VoidPtr, __hash_node<_Tp, _VoidPtr> > >;
0115 using __next_pointer _LIBCPP_NODEBUG = typename _Base::__next_pointer;
0116
0117 size_t __hash_;
0118
0119 // We allow starting the lifetime of nodes without initializing the value held by the node,
0120 // since that is handled by the hash table itself in order to be allocator-aware.
0121 #ifndef _LIBCPP_CXX03_LANG
0122
0123 private:
0124 union {
0125 _Tp __value_;
0126 };
0127
0128 public:
0129 _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return __value_; }
0130 #else
0131
0132 private:
0133 _ALIGNAS_TYPE(_Tp) char __buffer_[sizeof(_Tp)];
0134
0135 public:
0136 _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return *std::__launder(reinterpret_cast<_Tp*>(&__buffer_)); }
0137 #endif
0138
0139 _LIBCPP_HIDE_FROM_ABI explicit __hash_node(__next_pointer __next, size_t __hash) : _Base(__next), __hash_(__hash) {}
0140 _LIBCPP_HIDE_FROM_ABI ~__hash_node() {}
0141 };
0142
0143 inline _LIBCPP_HIDE_FROM_ABI bool __is_hash_power2(size_t __bc) { return __bc > 2 && !(__bc & (__bc - 1)); }
0144
0145 inline _LIBCPP_HIDE_FROM_ABI size_t __constrain_hash(size_t __h, size_t __bc) {
0146 return !(__bc & (__bc - 1)) ? __h & (__bc - 1) : (__h < __bc ? __h : __h % __bc);
0147 }
0148
0149 inline _LIBCPP_HIDE_FROM_ABI size_t __next_hash_pow2(size_t __n) {
0150 return __n < 2 ? __n : (size_t(1) << (numeric_limits<size_t>::digits - __libcpp_clz(__n - 1)));
0151 }
0152
0153 template <class _Tp, class _Hash, class _Equal, class _Alloc>
0154 class __hash_table;
0155
0156 template <class _NodePtr>
0157 class _LIBCPP_TEMPLATE_VIS __hash_iterator;
0158 template <class _ConstNodePtr>
0159 class _LIBCPP_TEMPLATE_VIS __hash_const_iterator;
0160 template <class _NodePtr>
0161 class _LIBCPP_TEMPLATE_VIS __hash_local_iterator;
0162 template <class _ConstNodePtr>
0163 class _LIBCPP_TEMPLATE_VIS __hash_const_local_iterator;
0164 template <class _HashIterator>
0165 class _LIBCPP_TEMPLATE_VIS __hash_map_iterator;
0166 template <class _HashIterator>
0167 class _LIBCPP_TEMPLATE_VIS __hash_map_const_iterator;
0168
0169 template <class _Tp>
0170 struct __hash_key_value_types {
0171 static_assert(!is_reference<_Tp>::value && !is_const<_Tp>::value, "");
0172 typedef _Tp key_type;
0173 typedef _Tp __node_value_type;
0174 typedef _Tp __container_value_type;
0175 static const bool __is_map = false;
0176
0177 _LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(_Tp const& __v) { return __v; }
0178 _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __v) { return __v; }
0179 _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) { return std::addressof(__n); }
0180 _LIBCPP_HIDE_FROM_ABI static __container_value_type&& __move(__node_value_type& __v) { return std::move(__v); }
0181 };
0182
0183 template <class _Key, class _Tp>
0184 struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
0185 typedef _Key key_type;
0186 typedef _Tp mapped_type;
0187 typedef __hash_value_type<_Key, _Tp> __node_value_type;
0188 typedef pair<const _Key, _Tp> __container_value_type;
0189 typedef __container_value_type __map_value_type;
0190 static const bool __is_map = true;
0191
0192 _LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(__container_value_type const& __v) { return __v.first; }
0193
0194 template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __node_value_type>::value, int> = 0>
0195 _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) {
0196 return __t.__get_value();
0197 }
0198
0199 template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
0200 _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) {
0201 return __t;
0202 }
0203
0204 _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
0205 return std::addressof(__n.__get_value());
0206 }
0207 _LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
0208 };
0209
0210 template <class _Tp, class _AllocPtr, class _KVTypes = __hash_key_value_types<_Tp>, bool = _KVTypes::__is_map>
0211 struct __hash_map_pointer_types {};
0212
0213 template <class _Tp, class _AllocPtr, class _KVTypes>
0214 struct __hash_map_pointer_types<_Tp, _AllocPtr, _KVTypes, true> {
0215 typedef typename _KVTypes::__map_value_type _Mv;
0216 typedef __rebind_pointer_t<_AllocPtr, _Mv> __map_value_type_pointer;
0217 typedef __rebind_pointer_t<_AllocPtr, const _Mv> __const_map_value_type_pointer;
0218 };
0219
0220 template <class _NodePtr, class _NodeT = typename pointer_traits<_NodePtr>::element_type>
0221 struct __hash_node_types;
0222
0223 template <class _NodePtr, class _Tp, class _VoidPtr>
0224 struct __hash_node_types<_NodePtr, __hash_node<_Tp, _VoidPtr> >
0225 : public __hash_key_value_types<_Tp>,
0226 __hash_map_pointer_types<_Tp, _VoidPtr>
0227
0228 {
0229 typedef __hash_key_value_types<_Tp> __base;
0230
0231 public:
0232 typedef ptrdiff_t difference_type;
0233 typedef size_t size_type;
0234
0235 typedef __rebind_pointer_t<_NodePtr, void> __void_pointer;
0236
0237 typedef typename pointer_traits<_NodePtr>::element_type __node_type;
0238 typedef _NodePtr __node_pointer;
0239
0240 typedef __hash_node_base<__node_pointer> __node_base_type;
0241 typedef __rebind_pointer_t<_NodePtr, __node_base_type> __node_base_pointer;
0242
0243 typedef typename __node_base_type::__next_pointer __next_pointer;
0244
0245 typedef _Tp __node_value_type;
0246 typedef __rebind_pointer_t<_VoidPtr, __node_value_type> __node_value_type_pointer;
0247 typedef __rebind_pointer_t<_VoidPtr, const __node_value_type> __const_node_value_type_pointer;
0248
0249 private:
0250 static_assert(!is_const<__node_type>::value, "_NodePtr should never be a pointer to const");
0251 static_assert(is_same<typename pointer_traits<_VoidPtr>::element_type, void>::value,
0252 "_VoidPtr does not point to unqualified void type");
0253 static_assert(is_same<__rebind_pointer_t<_VoidPtr, __node_type>, _NodePtr>::value,
0254 "_VoidPtr does not rebind to _NodePtr.");
0255 };
0256
0257 template <class _HashIterator>
0258 struct __hash_node_types_from_iterator;
0259 template <class _NodePtr>
0260 struct __hash_node_types_from_iterator<__hash_iterator<_NodePtr> > : __hash_node_types<_NodePtr> {};
0261 template <class _NodePtr>
0262 struct __hash_node_types_from_iterator<__hash_const_iterator<_NodePtr> > : __hash_node_types<_NodePtr> {};
0263 template <class _NodePtr>
0264 struct __hash_node_types_from_iterator<__hash_local_iterator<_NodePtr> > : __hash_node_types<_NodePtr> {};
0265 template <class _NodePtr>
0266 struct __hash_node_types_from_iterator<__hash_const_local_iterator<_NodePtr> > : __hash_node_types<_NodePtr> {};
0267
0268 template <class _NodeValueTp, class _VoidPtr>
0269 struct __make_hash_node_types {
0270 typedef __hash_node<_NodeValueTp, _VoidPtr> _NodeTp;
0271 typedef __rebind_pointer_t<_VoidPtr, _NodeTp> _NodePtr;
0272 typedef __hash_node_types<_NodePtr> type;
0273 };
0274
0275 template <class _NodePtr>
0276 class _LIBCPP_TEMPLATE_VIS __hash_iterator {
0277 typedef __hash_node_types<_NodePtr> _NodeTypes;
0278 typedef _NodePtr __node_pointer;
0279 typedef typename _NodeTypes::__next_pointer __next_pointer;
0280
0281 __next_pointer __node_;
0282
0283 public:
0284 typedef forward_iterator_tag iterator_category;
0285 typedef typename _NodeTypes::__node_value_type value_type;
0286 typedef typename _NodeTypes::difference_type difference_type;
0287 typedef value_type& reference;
0288 typedef typename _NodeTypes::__node_value_type_pointer pointer;
0289
0290 _LIBCPP_HIDE_FROM_ABI __hash_iterator() _NOEXCEPT : __node_(nullptr) {}
0291
0292 _LIBCPP_HIDE_FROM_ABI reference operator*() const {
0293 _LIBCPP_ASSERT_NON_NULL(
0294 __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container iterator");
0295 return __node_->__upcast()->__get_value();
0296 }
0297
0298 _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
0299 _LIBCPP_ASSERT_NON_NULL(
0300 __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container iterator");
0301 return pointer_traits<pointer>::pointer_to(__node_->__upcast()->__get_value());
0302 }
0303
0304 _LIBCPP_HIDE_FROM_ABI __hash_iterator& operator++() {
0305 _LIBCPP_ASSERT_NON_NULL(
0306 __node_ != nullptr, "Attempted to increment a non-incrementable unordered container iterator");
0307 __node_ = __node_->__next_;
0308 return *this;
0309 }
0310
0311 _LIBCPP_HIDE_FROM_ABI __hash_iterator operator++(int) {
0312 __hash_iterator __t(*this);
0313 ++(*this);
0314 return __t;
0315 }
0316
0317 friend _LIBCPP_HIDE_FROM_ABI bool operator==(const __hash_iterator& __x, const __hash_iterator& __y) {
0318 return __x.__node_ == __y.__node_;
0319 }
0320 friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const __hash_iterator& __x, const __hash_iterator& __y) {
0321 return !(__x == __y);
0322 }
0323
0324 private:
0325 _LIBCPP_HIDE_FROM_ABI explicit __hash_iterator(__next_pointer __node) _NOEXCEPT : __node_(__node) {}
0326
0327 template <class, class, class, class>
0328 friend class __hash_table;
0329 template <class>
0330 friend class _LIBCPP_TEMPLATE_VIS __hash_const_iterator;
0331 template <class>
0332 friend class _LIBCPP_TEMPLATE_VIS __hash_map_iterator;
0333 template <class, class, class, class, class>
0334 friend class _LIBCPP_TEMPLATE_VIS unordered_map;
0335 template <class, class, class, class, class>
0336 friend class _LIBCPP_TEMPLATE_VIS unordered_multimap;
0337 };
0338
0339 template <class _NodePtr>
0340 class _LIBCPP_TEMPLATE_VIS __hash_const_iterator {
0341 static_assert(!is_const<typename pointer_traits<_NodePtr>::element_type>::value, "");
0342 typedef __hash_node_types<_NodePtr> _NodeTypes;
0343 typedef _NodePtr __node_pointer;
0344 typedef typename _NodeTypes::__next_pointer __next_pointer;
0345
0346 __next_pointer __node_;
0347
0348 public:
0349 typedef __hash_iterator<_NodePtr> __non_const_iterator;
0350
0351 typedef forward_iterator_tag iterator_category;
0352 typedef typename _NodeTypes::__node_value_type value_type;
0353 typedef typename _NodeTypes::difference_type difference_type;
0354 typedef const value_type& reference;
0355 typedef typename _NodeTypes::__const_node_value_type_pointer pointer;
0356
0357 _LIBCPP_HIDE_FROM_ABI __hash_const_iterator() _NOEXCEPT : __node_(nullptr) {}
0358
0359 _LIBCPP_HIDE_FROM_ABI __hash_const_iterator(const __non_const_iterator& __x) _NOEXCEPT : __node_(__x.__node_) {}
0360
0361 _LIBCPP_HIDE_FROM_ABI reference operator*() const {
0362 _LIBCPP_ASSERT_NON_NULL(
0363 __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container const_iterator");
0364 return __node_->__upcast()->__get_value();
0365 }
0366 _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
0367 _LIBCPP_ASSERT_NON_NULL(
0368 __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container const_iterator");
0369 return pointer_traits<pointer>::pointer_to(__node_->__upcast()->__get_value());
0370 }
0371
0372 _LIBCPP_HIDE_FROM_ABI __hash_const_iterator& operator++() {
0373 _LIBCPP_ASSERT_NON_NULL(
0374 __node_ != nullptr, "Attempted to increment a non-incrementable unordered container const_iterator");
0375 __node_ = __node_->__next_;
0376 return *this;
0377 }
0378
0379 _LIBCPP_HIDE_FROM_ABI __hash_const_iterator operator++(int) {
0380 __hash_const_iterator __t(*this);
0381 ++(*this);
0382 return __t;
0383 }
0384
0385 friend _LIBCPP_HIDE_FROM_ABI bool operator==(const __hash_const_iterator& __x, const __hash_const_iterator& __y) {
0386 return __x.__node_ == __y.__node_;
0387 }
0388 friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const __hash_const_iterator& __x, const __hash_const_iterator& __y) {
0389 return !(__x == __y);
0390 }
0391
0392 private:
0393 _LIBCPP_HIDE_FROM_ABI explicit __hash_const_iterator(__next_pointer __node) _NOEXCEPT : __node_(__node) {}
0394
0395 template <class, class, class, class>
0396 friend class __hash_table;
0397 template <class>
0398 friend class _LIBCPP_TEMPLATE_VIS __hash_map_const_iterator;
0399 template <class, class, class, class, class>
0400 friend class _LIBCPP_TEMPLATE_VIS unordered_map;
0401 template <class, class, class, class, class>
0402 friend class _LIBCPP_TEMPLATE_VIS unordered_multimap;
0403 };
0404
0405 template <class _NodePtr>
0406 class _LIBCPP_TEMPLATE_VIS __hash_local_iterator {
0407 typedef __hash_node_types<_NodePtr> _NodeTypes;
0408 typedef _NodePtr __node_pointer;
0409 typedef typename _NodeTypes::__next_pointer __next_pointer;
0410
0411 __next_pointer __node_;
0412 size_t __bucket_;
0413 size_t __bucket_count_;
0414
0415 public:
0416 typedef forward_iterator_tag iterator_category;
0417 typedef typename _NodeTypes::__node_value_type value_type;
0418 typedef typename _NodeTypes::difference_type difference_type;
0419 typedef value_type& reference;
0420 typedef typename _NodeTypes::__node_value_type_pointer pointer;
0421
0422 _LIBCPP_HIDE_FROM_ABI __hash_local_iterator() _NOEXCEPT : __node_(nullptr) {}
0423
0424 _LIBCPP_HIDE_FROM_ABI reference operator*() const {
0425 _LIBCPP_ASSERT_NON_NULL(
0426 __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container local_iterator");
0427 return __node_->__upcast()->__get_value();
0428 }
0429
0430 _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
0431 _LIBCPP_ASSERT_NON_NULL(
0432 __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container local_iterator");
0433 return pointer_traits<pointer>::pointer_to(__node_->__upcast()->__get_value());
0434 }
0435
0436 _LIBCPP_HIDE_FROM_ABI __hash_local_iterator& operator++() {
0437 _LIBCPP_ASSERT_NON_NULL(
0438 __node_ != nullptr, "Attempted to increment a non-incrementable unordered container local_iterator");
0439 __node_ = __node_->__next_;
0440 if (__node_ != nullptr && std::__constrain_hash(__node_->__hash(), __bucket_count_) != __bucket_)
0441 __node_ = nullptr;
0442 return *this;
0443 }
0444
0445 _LIBCPP_HIDE_FROM_ABI __hash_local_iterator operator++(int) {
0446 __hash_local_iterator __t(*this);
0447 ++(*this);
0448 return __t;
0449 }
0450
0451 friend _LIBCPP_HIDE_FROM_ABI bool operator==(const __hash_local_iterator& __x, const __hash_local_iterator& __y) {
0452 return __x.__node_ == __y.__node_;
0453 }
0454 friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const __hash_local_iterator& __x, const __hash_local_iterator& __y) {
0455 return !(__x == __y);
0456 }
0457
0458 private:
0459 _LIBCPP_HIDE_FROM_ABI explicit __hash_local_iterator(
0460 __next_pointer __node, size_t __bucket, size_t __bucket_count) _NOEXCEPT
0461 : __node_(__node),
0462 __bucket_(__bucket),
0463 __bucket_count_(__bucket_count) {
0464 if (__node_ != nullptr)
0465 __node_ = __node_->__next_;
0466 }
0467
0468 template <class, class, class, class>
0469 friend class __hash_table;
0470 template <class>
0471 friend class _LIBCPP_TEMPLATE_VIS __hash_const_local_iterator;
0472 template <class>
0473 friend class _LIBCPP_TEMPLATE_VIS __hash_map_iterator;
0474 };
0475
0476 template <class _ConstNodePtr>
0477 class _LIBCPP_TEMPLATE_VIS __hash_const_local_iterator {
0478 typedef __hash_node_types<_ConstNodePtr> _NodeTypes;
0479 typedef _ConstNodePtr __node_pointer;
0480 typedef typename _NodeTypes::__next_pointer __next_pointer;
0481
0482 __next_pointer __node_;
0483 size_t __bucket_;
0484 size_t __bucket_count_;
0485
0486 typedef pointer_traits<__node_pointer> __pointer_traits;
0487 typedef typename __pointer_traits::element_type __node;
0488 typedef __remove_const_t<__node> __non_const_node;
0489 typedef __rebind_pointer_t<__node_pointer, __non_const_node> __non_const_node_pointer;
0490
0491 public:
0492 typedef __hash_local_iterator<__non_const_node_pointer> __non_const_iterator;
0493
0494 typedef forward_iterator_tag iterator_category;
0495 typedef typename _NodeTypes::__node_value_type value_type;
0496 typedef typename _NodeTypes::difference_type difference_type;
0497 typedef const value_type& reference;
0498 typedef typename _NodeTypes::__const_node_value_type_pointer pointer;
0499
0500 _LIBCPP_HIDE_FROM_ABI __hash_const_local_iterator() _NOEXCEPT : __node_(nullptr) {}
0501
0502 _LIBCPP_HIDE_FROM_ABI __hash_const_local_iterator(const __non_const_iterator& __x) _NOEXCEPT
0503 : __node_(__x.__node_),
0504 __bucket_(__x.__bucket_),
0505 __bucket_count_(__x.__bucket_count_) {}
0506
0507 _LIBCPP_HIDE_FROM_ABI reference operator*() const {
0508 _LIBCPP_ASSERT_NON_NULL(
0509 __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container const_local_iterator");
0510 return __node_->__upcast()->__get_value();
0511 }
0512
0513 _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
0514 _LIBCPP_ASSERT_NON_NULL(
0515 __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container const_local_iterator");
0516 return pointer_traits<pointer>::pointer_to(__node_->__upcast()->__get_value());
0517 }
0518
0519 _LIBCPP_HIDE_FROM_ABI __hash_const_local_iterator& operator++() {
0520 _LIBCPP_ASSERT_NON_NULL(
0521 __node_ != nullptr, "Attempted to increment a non-incrementable unordered container const_local_iterator");
0522 __node_ = __node_->__next_;
0523 if (__node_ != nullptr && std::__constrain_hash(__node_->__hash(), __bucket_count_) != __bucket_)
0524 __node_ = nullptr;
0525 return *this;
0526 }
0527
0528 _LIBCPP_HIDE_FROM_ABI __hash_const_local_iterator operator++(int) {
0529 __hash_const_local_iterator __t(*this);
0530 ++(*this);
0531 return __t;
0532 }
0533
0534 friend _LIBCPP_HIDE_FROM_ABI bool
0535 operator==(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y) {
0536 return __x.__node_ == __y.__node_;
0537 }
0538 friend _LIBCPP_HIDE_FROM_ABI bool
0539 operator!=(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y) {
0540 return !(__x == __y);
0541 }
0542
0543 private:
0544 _LIBCPP_HIDE_FROM_ABI explicit __hash_const_local_iterator(
0545 __next_pointer __node_ptr, size_t __bucket, size_t __bucket_count) _NOEXCEPT
0546 : __node_(__node_ptr),
0547 __bucket_(__bucket),
0548 __bucket_count_(__bucket_count) {
0549 if (__node_ != nullptr)
0550 __node_ = __node_->__next_;
0551 }
0552
0553 template <class, class, class, class>
0554 friend class __hash_table;
0555 template <class>
0556 friend class _LIBCPP_TEMPLATE_VIS __hash_map_const_iterator;
0557 };
0558
0559 template <class _Alloc>
0560 class __bucket_list_deallocator {
0561 typedef _Alloc allocator_type;
0562 typedef allocator_traits<allocator_type> __alloc_traits;
0563 typedef typename __alloc_traits::size_type size_type;
0564
0565 _LIBCPP_COMPRESSED_PAIR(size_type, __size_, allocator_type, __alloc_);
0566
0567 public:
0568 typedef typename __alloc_traits::pointer pointer;
0569
0570 _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
0571 : __size_(0) {}
0572
0573 _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator(const allocator_type& __a, size_type __size)
0574 _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
0575 : __size_(__size), __alloc_(__a) {}
0576
0577 _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator(__bucket_list_deallocator&& __x)
0578 _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
0579 : __size_(std::move(__x.__size_)), __alloc_(std::move(__x.__alloc_)) {
0580 __x.size() = 0;
0581 }
0582
0583 _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; }
0584 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; }
0585
0586 _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __alloc_; }
0587 _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __alloc_; }
0588
0589 _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT { __alloc_traits::deallocate(__alloc(), __p, size()); }
0590 };
0591
0592 template <class _Alloc>
0593 class __hash_map_node_destructor;
0594
0595 template <class _Alloc>
0596 class __hash_node_destructor {
0597 typedef _Alloc allocator_type;
0598 typedef allocator_traits<allocator_type> __alloc_traits;
0599
0600 public:
0601 typedef typename __alloc_traits::pointer pointer;
0602
0603 private:
0604 typedef __hash_node_types<pointer> _NodeTypes;
0605
0606 allocator_type& __na_;
0607
0608 public:
0609 bool __value_constructed;
0610
0611 _LIBCPP_HIDE_FROM_ABI __hash_node_destructor(__hash_node_destructor const&) = default;
0612 _LIBCPP_HIDE_FROM_ABI __hash_node_destructor& operator=(const __hash_node_destructor&) = delete;
0613
0614 _LIBCPP_HIDE_FROM_ABI explicit __hash_node_destructor(allocator_type& __na, bool __constructed = false) _NOEXCEPT
0615 : __na_(__na),
0616 __value_constructed(__constructed) {}
0617
0618 _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
0619 if (__value_constructed) {
0620 __alloc_traits::destroy(__na_, _NodeTypes::__get_ptr(__p->__get_value()));
0621 std::__destroy_at(std::addressof(*__p));
0622 }
0623 if (__p)
0624 __alloc_traits::deallocate(__na_, __p, 1);
0625 }
0626
0627 template <class>
0628 friend class __hash_map_node_destructor;
0629 };
0630
0631 #if _LIBCPP_STD_VER >= 17
0632 template <class _NodeType, class _Alloc>
0633 struct __generic_container_node_destructor;
0634
0635 template <class _Tp, class _VoidPtr, class _Alloc>
0636 struct __generic_container_node_destructor<__hash_node<_Tp, _VoidPtr>, _Alloc> : __hash_node_destructor<_Alloc> {
0637 using __hash_node_destructor<_Alloc>::__hash_node_destructor;
0638 };
0639 #endif
0640
0641 template <class _Key, class _Hash, class _Equal>
0642 struct __enforce_unordered_container_requirements {
0643 #ifndef _LIBCPP_CXX03_LANG
0644 static_assert(__check_hash_requirements<_Key, _Hash>::value,
0645 "the specified hash does not meet the Hash requirements");
0646 static_assert(is_copy_constructible<_Equal>::value, "the specified comparator is required to be copy constructible");
0647 #endif
0648 typedef int type;
0649 };
0650
0651 template <class _Key, class _Hash, class _Equal>
0652 #ifndef _LIBCPP_CXX03_LANG
0653 _LIBCPP_DIAGNOSE_WARNING(!__is_invocable_v<_Equal const&, _Key const&, _Key const&>,
0654 "the specified comparator type does not provide a viable const call operator")
0655 _LIBCPP_DIAGNOSE_WARNING(!__is_invocable_v<_Hash const&, _Key const&>,
0656 "the specified hash functor does not provide a viable const call operator")
0657 #endif
0658 typename __enforce_unordered_container_requirements<_Key, _Hash, _Equal>::type
0659 __diagnose_unordered_container_requirements(int);
0660
0661 // This dummy overload is used so that the compiler won't emit a spurious
0662 // "no matching function for call to __diagnose_unordered_xxx" diagnostic
0663 // when the overload above causes a hard error.
0664 template <class _Key, class _Hash, class _Equal>
0665 int __diagnose_unordered_container_requirements(void*);
0666
0667 template <class _Tp, class _Hash, class _Equal, class _Alloc>
0668 class __hash_table {
0669 public:
0670 typedef _Tp value_type;
0671 typedef _Hash hasher;
0672 typedef _Equal key_equal;
0673 typedef _Alloc allocator_type;
0674
0675 private:
0676 typedef allocator_traits<allocator_type> __alloc_traits;
0677 typedef typename __make_hash_node_types<value_type, typename __alloc_traits::void_pointer>::type _NodeTypes;
0678
0679 public:
0680 typedef typename _NodeTypes::__node_value_type __node_value_type;
0681 typedef typename _NodeTypes::__container_value_type __container_value_type;
0682 typedef typename _NodeTypes::key_type key_type;
0683 typedef value_type& reference;
0684 typedef const value_type& const_reference;
0685 typedef typename __alloc_traits::pointer pointer;
0686 typedef typename __alloc_traits::const_pointer const_pointer;
0687 #ifndef _LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE
0688 typedef typename __alloc_traits::size_type size_type;
0689 #else
0690 typedef typename _NodeTypes::size_type size_type;
0691 #endif
0692 typedef typename _NodeTypes::difference_type difference_type;
0693
0694 public:
0695 // Create __node
0696
0697 typedef typename _NodeTypes::__node_type __node;
0698 typedef __rebind_alloc<__alloc_traits, __node> __node_allocator;
0699 typedef allocator_traits<__node_allocator> __node_traits;
0700 typedef typename _NodeTypes::__void_pointer __void_pointer;
0701 typedef typename _NodeTypes::__node_pointer __node_pointer;
0702 typedef typename _NodeTypes::__node_pointer __node_const_pointer;
0703 typedef typename _NodeTypes::__node_base_type __first_node;
0704 typedef typename _NodeTypes::__node_base_pointer __node_base_pointer;
0705 typedef typename _NodeTypes::__next_pointer __next_pointer;
0706
0707 private:
0708 // check for sane allocator pointer rebinding semantics. Rebinding the
0709 // allocator for a new pointer type should be exactly the same as rebinding
0710 // the pointer using 'pointer_traits'.
0711 static_assert(is_same<__node_pointer, typename __node_traits::pointer>::value,
0712 "Allocator does not rebind pointers in a sane manner.");
0713 typedef __rebind_alloc<__node_traits, __first_node> __node_base_allocator;
0714 typedef allocator_traits<__node_base_allocator> __node_base_traits;
0715 static_assert(is_same<__node_base_pointer, typename __node_base_traits::pointer>::value,
0716 "Allocator does not rebind pointers in a sane manner.");
0717
0718 private:
0719 typedef __rebind_alloc<__node_traits, __next_pointer> __pointer_allocator;
0720 typedef __bucket_list_deallocator<__pointer_allocator> __bucket_list_deleter;
0721 typedef unique_ptr<__next_pointer[], __bucket_list_deleter> __bucket_list;
0722 typedef allocator_traits<__pointer_allocator> __pointer_alloc_traits;
0723 typedef typename __bucket_list_deleter::pointer __node_pointer_pointer;
0724
0725 // --- Member data begin ---
0726 __bucket_list __bucket_list_;
0727 _LIBCPP_COMPRESSED_PAIR(__first_node, __first_node_, __node_allocator, __node_alloc_);
0728 _LIBCPP_COMPRESSED_PAIR(size_type, __size_, hasher, __hasher_);
0729 _LIBCPP_COMPRESSED_PAIR(float, __max_load_factor_, key_equal, __key_eq_);
0730 // --- Member data end ---
0731
0732 _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; }
0733
0734 public:
0735 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; }
0736
0737 _LIBCPP_HIDE_FROM_ABI hasher& hash_function() _NOEXCEPT { return __hasher_; }
0738 _LIBCPP_HIDE_FROM_ABI const hasher& hash_function() const _NOEXCEPT { return __hasher_; }
0739
0740 _LIBCPP_HIDE_FROM_ABI float& max_load_factor() _NOEXCEPT { return __max_load_factor_; }
0741 _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __max_load_factor_; }
0742
0743 _LIBCPP_HIDE_FROM_ABI key_equal& key_eq() _NOEXCEPT { return __key_eq_; }
0744 _LIBCPP_HIDE_FROM_ABI const key_equal& key_eq() const _NOEXCEPT { return __key_eq_; }
0745
0746 _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __node_alloc_; }
0747 _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __node_alloc_; }
0748
0749 public:
0750 typedef __hash_iterator<__node_pointer> iterator;
0751 typedef __hash_const_iterator<__node_pointer> const_iterator;
0752 typedef __hash_local_iterator<__node_pointer> local_iterator;
0753 typedef __hash_const_local_iterator<__node_pointer> const_local_iterator;
0754
0755 _LIBCPP_HIDE_FROM_ABI __hash_table() _NOEXCEPT_(
0756 is_nothrow_default_constructible<__bucket_list>::value&& is_nothrow_default_constructible<__first_node>::value&&
0757 is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_default_constructible<hasher>::value&&
0758 is_nothrow_default_constructible<key_equal>::value);
0759 _LIBCPP_HIDE_FROM_ABI __hash_table(const hasher& __hf, const key_equal& __eql);
0760 _LIBCPP_HIDE_FROM_ABI __hash_table(const hasher& __hf, const key_equal& __eql, const allocator_type& __a);
0761 _LIBCPP_HIDE_FROM_ABI explicit __hash_table(const allocator_type& __a);
0762 _LIBCPP_HIDE_FROM_ABI __hash_table(const __hash_table& __u);
0763 _LIBCPP_HIDE_FROM_ABI __hash_table(const __hash_table& __u, const allocator_type& __a);
0764 _LIBCPP_HIDE_FROM_ABI __hash_table(__hash_table&& __u) _NOEXCEPT_(
0765 is_nothrow_move_constructible<__bucket_list>::value&& is_nothrow_move_constructible<__first_node>::value&&
0766 is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<hasher>::value&&
0767 is_nothrow_move_constructible<key_equal>::value);
0768 _LIBCPP_HIDE_FROM_ABI __hash_table(__hash_table&& __u, const allocator_type& __a);
0769 _LIBCPP_HIDE_FROM_ABI ~__hash_table();
0770
0771 _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(const __hash_table& __u);
0772 _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(__hash_table&& __u)
0773 _NOEXCEPT_(__node_traits::propagate_on_container_move_assignment::value&&
0774 is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable<hasher>::value&&
0775 is_nothrow_move_assignable<key_equal>::value);
0776 template <class _InputIterator>
0777 _LIBCPP_HIDE_FROM_ABI void __assign_unique(_InputIterator __first, _InputIterator __last);
0778 template <class _InputIterator>
0779 _LIBCPP_HIDE_FROM_ABI void __assign_multi(_InputIterator __first, _InputIterator __last);
0780
0781 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
0782 return std::min<size_type>(__node_traits::max_size(__node_alloc()), numeric_limits<difference_type >::max());
0783 }
0784
0785 private:
0786 _LIBCPP_HIDE_FROM_ABI __next_pointer __node_insert_multi_prepare(size_t __cp_hash, value_type& __cp_val);
0787 _LIBCPP_HIDE_FROM_ABI void __node_insert_multi_perform(__node_pointer __cp, __next_pointer __pn) _NOEXCEPT;
0788
0789 _LIBCPP_HIDE_FROM_ABI __next_pointer __node_insert_unique_prepare(size_t __nd_hash, value_type& __nd_val);
0790 _LIBCPP_HIDE_FROM_ABI void __node_insert_unique_perform(__node_pointer __ptr) _NOEXCEPT;
0791
0792 public:
0793 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __node_insert_unique(__node_pointer __nd);
0794 _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd);
0795 _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(const_iterator __p, __node_pointer __nd);
0796
0797 template <class _Key, class... _Args>
0798 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_key_args(_Key const& __k, _Args&&... __args);
0799
0800 template <class... _Args>
0801 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_impl(_Args&&... __args);
0802
0803 template <class _Pp>
0804 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_Pp&& __x) {
0805 return __emplace_unique_extract_key(std::forward<_Pp>(__x), __can_extract_key<_Pp, key_type>());
0806 }
0807
0808 template <class _First,
0809 class _Second,
0810 __enable_if_t<__can_extract_map_key<_First, key_type, __container_value_type>::value, int> = 0>
0811 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_First&& __f, _Second&& __s) {
0812 return __emplace_unique_key_args(__f, std::forward<_First>(__f), std::forward<_Second>(__s));
0813 }
0814
0815 template <class... _Args>
0816 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_Args&&... __args) {
0817 return __emplace_unique_impl(std::forward<_Args>(__args)...);
0818 }
0819
0820 template <class _Pp>
0821 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_fail_tag) {
0822 return __emplace_unique_impl(std::forward<_Pp>(__x));
0823 }
0824 template <class _Pp>
0825 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_self_tag) {
0826 return __emplace_unique_key_args(__x, std::forward<_Pp>(__x));
0827 }
0828 template <class _Pp>
0829 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_first_tag) {
0830 return __emplace_unique_key_args(__x.first, std::forward<_Pp>(__x));
0831 }
0832
0833 template <class... _Args>
0834 _LIBCPP_HIDE_FROM_ABI iterator __emplace_multi(_Args&&... __args);
0835 template <class... _Args>
0836 _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint_multi(const_iterator __p, _Args&&... __args);
0837
0838 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __insert_unique(__container_value_type&& __x) {
0839 return __emplace_unique_key_args(_NodeTypes::__get_key(__x), std::move(__x));
0840 }
0841
0842 template <class _Pp, __enable_if_t<!__is_same_uncvref<_Pp, __container_value_type>::value, int> = 0>
0843 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __insert_unique(_Pp&& __x) {
0844 return __emplace_unique(std::forward<_Pp>(__x));
0845 }
0846
0847 template <class _Pp>
0848 _LIBCPP_HIDE_FROM_ABI iterator __insert_multi(_Pp&& __x) {
0849 return __emplace_multi(std::forward<_Pp>(__x));
0850 }
0851
0852 template <class _Pp>
0853 _LIBCPP_HIDE_FROM_ABI iterator __insert_multi(const_iterator __p, _Pp&& __x) {
0854 return __emplace_hint_multi(__p, std::forward<_Pp>(__x));
0855 }
0856
0857 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __insert_unique(const __container_value_type& __x) {
0858 return __emplace_unique_key_args(_NodeTypes::__get_key(__x), __x);
0859 }
0860
0861 #if _LIBCPP_STD_VER >= 17
0862 template <class _NodeHandle, class _InsertReturnType>
0863 _LIBCPP_HIDE_FROM_ABI _InsertReturnType __node_handle_insert_unique(_NodeHandle&& __nh);
0864 template <class _NodeHandle>
0865 _LIBCPP_HIDE_FROM_ABI iterator __node_handle_insert_unique(const_iterator __hint, _NodeHandle&& __nh);
0866 template <class _Table>
0867 _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_unique(_Table& __source);
0868
0869 template <class _NodeHandle>
0870 _LIBCPP_HIDE_FROM_ABI iterator __node_handle_insert_multi(_NodeHandle&& __nh);
0871 template <class _NodeHandle>
0872 _LIBCPP_HIDE_FROM_ABI iterator __node_handle_insert_multi(const_iterator __hint, _NodeHandle&& __nh);
0873 template <class _Table>
0874 _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_multi(_Table& __source);
0875
0876 template <class _NodeHandle>
0877 _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(key_type const& __key);
0878 template <class _NodeHandle>
0879 _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(const_iterator __it);
0880 #endif
0881
0882 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT;
0883 _LIBCPP_HIDE_FROM_ABI void __rehash_unique(size_type __n) { __rehash<true>(__n); }
0884 _LIBCPP_HIDE_FROM_ABI void __rehash_multi(size_type __n) { __rehash<false>(__n); }
0885 _LIBCPP_HIDE_FROM_ABI void __reserve_unique(size_type __n) {
0886 __rehash_unique(static_cast<size_type>(__math::ceil(__n / max_load_factor())));
0887 }
0888 _LIBCPP_HIDE_FROM_ABI void __reserve_multi(size_type __n) {
0889 __rehash_multi(static_cast<size_type>(__math::ceil(__n / max_load_factor())));
0890 }
0891
0892 _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __bucket_list_.get_deleter().size(); }
0893
0894 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT;
0895 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT;
0896 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT;
0897 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT;
0898
0899 template <class _Key>
0900 _LIBCPP_HIDE_FROM_ABI size_type bucket(const _Key& __k) const {
0901 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
0902 bucket_count() > 0, "unordered container::bucket(key) called when bucket_count() == 0");
0903 return std::__constrain_hash(hash_function()(__k), bucket_count());
0904 }
0905
0906 template <class _Key>
0907 _LIBCPP_HIDE_FROM_ABI iterator find(const _Key& __x);
0908 template <class _Key>
0909 _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Key& __x) const;
0910
0911 typedef __hash_node_destructor<__node_allocator> _Dp;
0912 typedef unique_ptr<__node, _Dp> __node_holder;
0913
0914 _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p);
0915 _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last);
0916 template <class _Key>
0917 _LIBCPP_HIDE_FROM_ABI size_type __erase_unique(const _Key& __k);
0918 template <class _Key>
0919 _LIBCPP_HIDE_FROM_ABI size_type __erase_multi(const _Key& __k);
0920 _LIBCPP_HIDE_FROM_ABI __node_holder remove(const_iterator __p) _NOEXCEPT;
0921
0922 template <class _Key>
0923 _LIBCPP_HIDE_FROM_ABI size_type __count_unique(const _Key& __k) const;
0924 template <class _Key>
0925 _LIBCPP_HIDE_FROM_ABI size_type __count_multi(const _Key& __k) const;
0926
0927 template <class _Key>
0928 _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> __equal_range_unique(const _Key& __k);
0929 template <class _Key>
0930 _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> __equal_range_unique(const _Key& __k) const;
0931
0932 template <class _Key>
0933 _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> __equal_range_multi(const _Key& __k);
0934 template <class _Key>
0935 _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> __equal_range_multi(const _Key& __k) const;
0936
0937 _LIBCPP_HIDE_FROM_ABI void swap(__hash_table& __u)
0938 #if _LIBCPP_STD_VER <= 11
0939 _NOEXCEPT_(__is_nothrow_swappable_v<hasher>&& __is_nothrow_swappable_v<key_equal> &&
0940 (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value ||
0941 __is_nothrow_swappable_v<__pointer_allocator>) &&
0942 (!__node_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__node_allocator>));
0943 #else
0944 _NOEXCEPT_(__is_nothrow_swappable_v<hasher>&& __is_nothrow_swappable_v<key_equal>);
0945 #endif
0946
0947 _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { return max_size(); }
0948 _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const;
0949 _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT {
0950 size_type __bc = bucket_count();
0951 return __bc != 0 ? (float)size() / __bc : 0.f;
0952 }
0953 _LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) _NOEXCEPT {
0954 // While passing a non-positive load factor is undefined behavior, in practice the result will be benign (the
0955 // call will be equivalent to `max_load_factor(load_factor())`, which is also the case for passing a valid value
0956 // less than the current `load_factor`).
0957 _LIBCPP_ASSERT_PEDANTIC(__mlf > 0, "unordered container::max_load_factor(lf) called with lf <= 0");
0958 max_load_factor() = std::max(__mlf, load_factor());
0959 }
0960
0961 _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) {
0962 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0963 __n < bucket_count(), "unordered container::begin(n) called with n >= bucket_count()");
0964 return local_iterator(__bucket_list_[__n], __n, bucket_count());
0965 }
0966
0967 _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) {
0968 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0969 __n < bucket_count(), "unordered container::end(n) called with n >= bucket_count()");
0970 return local_iterator(nullptr, __n, bucket_count());
0971 }
0972
0973 _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const {
0974 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0975 __n < bucket_count(), "unordered container::cbegin(n) called with n >= bucket_count()");
0976 return const_local_iterator(__bucket_list_[__n], __n, bucket_count());
0977 }
0978
0979 _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const {
0980 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0981 __n < bucket_count(), "unordered container::cend(n) called with n >= bucket_count()");
0982 return const_local_iterator(nullptr, __n, bucket_count());
0983 }
0984
0985 private:
0986 template <bool _UniqueKeys>
0987 _LIBCPP_HIDE_FROM_ABI void __rehash(size_type __n);
0988 template <bool _UniqueKeys>
0989 _LIBCPP_HIDE_FROM_ABI void __do_rehash(size_type __n);
0990
0991 template <class... _Args>
0992 _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node(_Args&&... __args);
0993
0994 template <class _First, class... _Rest>
0995 _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest);
0996
0997 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __hash_table& __u) {
0998 __copy_assign_alloc(__u, integral_constant<bool, __node_traits::propagate_on_container_copy_assignment::value>());
0999 }
1000 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __hash_table& __u, true_type);
1001 _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __hash_table&, false_type) {}
1002
1003 _LIBCPP_HIDE_FROM_ABI void __move_assign(__hash_table& __u, false_type);
1004 _LIBCPP_HIDE_FROM_ABI void __move_assign(__hash_table& __u, true_type)
1005 _NOEXCEPT_(is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable<hasher>::value&&
1006 is_nothrow_move_assignable<key_equal>::value);
1007 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__hash_table& __u) _NOEXCEPT_(
1008 !__node_traits::propagate_on_container_move_assignment::value ||
1009 (is_nothrow_move_assignable<__pointer_allocator>::value && is_nothrow_move_assignable<__node_allocator>::value)) {
1010 __move_assign_alloc(__u, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
1011 }
1012 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__hash_table& __u, true_type) _NOEXCEPT_(
1013 is_nothrow_move_assignable<__pointer_allocator>::value&& is_nothrow_move_assignable<__node_allocator>::value) {
1014 __bucket_list_.get_deleter().__alloc() = std::move(__u.__bucket_list_.get_deleter().__alloc());
1015 __node_alloc() = std::move(__u.__node_alloc());
1016 }
1017 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__hash_table&, false_type) _NOEXCEPT {}
1018
1019 _LIBCPP_HIDE_FROM_ABI void __deallocate_node(__next_pointer __np) _NOEXCEPT;
1020 _LIBCPP_HIDE_FROM_ABI __next_pointer __detach() _NOEXCEPT;
1021
1022 template <class, class, class, class, class>
1023 friend class _LIBCPP_TEMPLATE_VIS unordered_map;
1024 template <class, class, class, class, class>
1025 friend class _LIBCPP_TEMPLATE_VIS unordered_multimap;
1026 };
1027
1028 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1029 inline __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table() _NOEXCEPT_(
1030 is_nothrow_default_constructible<__bucket_list>::value&& is_nothrow_default_constructible<__first_node>::value&&
1031 is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_default_constructible<hasher>::value&&
1032 is_nothrow_default_constructible<key_equal>::value)
1033 : __size_(0), __max_load_factor_(1.0f) {}
1034
1035 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1036 inline __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const hasher& __hf, const key_equal& __eql)
1037 : __bucket_list_(nullptr, __bucket_list_deleter()),
1038 __first_node_(),
1039 __node_alloc_(),
1040 __size_(0),
1041 __hasher_(__hf),
1042 __max_load_factor_(1.0f),
1043 __key_eq_(__eql) {}
1044
1045 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1046 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(
1047 const hasher& __hf, const key_equal& __eql, const allocator_type& __a)
1048 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
1049 __node_alloc_(__node_allocator(__a)),
1050 __size_(0),
1051 __hasher_(__hf),
1052 __max_load_factor_(1.0f),
1053 __key_eq_(__eql) {}
1054
1055 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1056 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const allocator_type& __a)
1057 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
1058 __node_alloc_(__node_allocator(__a)),
1059 __size_(0),
1060 __max_load_factor_(1.0f) {}
1061
1062 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1063 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u)
1064 : __bucket_list_(nullptr,
1065 __bucket_list_deleter(allocator_traits<__pointer_allocator>::select_on_container_copy_construction(
1066 __u.__bucket_list_.get_deleter().__alloc()),
1067 0)),
1068 __node_alloc_(allocator_traits<__node_allocator>::select_on_container_copy_construction(__u.__node_alloc())),
1069 __size_(0),
1070 __hasher_(__u.hash_function()),
1071 __max_load_factor_(__u.__max_load_factor_),
1072 __key_eq_(__u.__key_eq_) {}
1073
1074 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1075 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u, const allocator_type& __a)
1076 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
1077 __node_alloc_(__node_allocator(__a)),
1078 __size_(0),
1079 __hasher_(__u.hash_function()),
1080 __max_load_factor_(__u.__max_load_factor_),
1081 __key_eq_(__u.__key_eq_) {}
1082
1083 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1084 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u) _NOEXCEPT_(
1085 is_nothrow_move_constructible<__bucket_list>::value&& is_nothrow_move_constructible<__first_node>::value&&
1086 is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<hasher>::value&&
1087 is_nothrow_move_constructible<key_equal>::value)
1088 : __bucket_list_(std::move(__u.__bucket_list_)),
1089 __first_node_(std::move(__u.__first_node_)),
1090 __node_alloc_(std::move(__u.__node_alloc_)),
1091 __size_(std::move(__u.__size_)),
1092 __hasher_(std::move(__u.__hasher_)),
1093 __max_load_factor_(__u.__max_load_factor_),
1094 __key_eq_(std::move(__u.__key_eq_)) {
1095 if (size() > 0) {
1096 __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
1097 __u.__first_node_.__next_ = nullptr;
1098 __u.size() = 0;
1099 }
1100 }
1101
1102 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1103 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u, const allocator_type& __a)
1104 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
1105 __node_alloc_(__node_allocator(__a)),
1106 __size_(0),
1107 __hasher_(std::move(__u.__hasher_)),
1108 __max_load_factor_(__u.__max_load_factor_),
1109 __key_eq_(std::move(__u.__key_eq_)) {
1110 if (__a == allocator_type(__u.__node_alloc())) {
1111 __bucket_list_.reset(__u.__bucket_list_.release());
1112 __bucket_list_.get_deleter().size() = __u.__bucket_list_.get_deleter().size();
1113 __u.__bucket_list_.get_deleter().size() = 0;
1114 if (__u.size() > 0) {
1115 __first_node_.__next_ = __u.__first_node_.__next_;
1116 __u.__first_node_.__next_ = nullptr;
1117 __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
1118 size() = __u.size();
1119 __u.size() = 0;
1120 }
1121 }
1122 }
1123
1124 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1125 __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table() {
1126 #if defined(_LIBCPP_CXX03_LANG)
1127 static_assert(is_copy_constructible<key_equal>::value, "Predicate must be copy-constructible.");
1128 static_assert(is_copy_constructible<hasher>::value, "Hasher must be copy-constructible.");
1129 #endif
1130
1131 __deallocate_node(__first_node_.__next_);
1132 }
1133
1134 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1135 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__copy_assign_alloc(const __hash_table& __u, true_type) {
1136 if (__node_alloc() != __u.__node_alloc()) {
1137 clear();
1138 __bucket_list_.reset();
1139 __bucket_list_.get_deleter().size() = 0;
1140 }
1141 __bucket_list_.get_deleter().__alloc() = __u.__bucket_list_.get_deleter().__alloc();
1142 __node_alloc() = __u.__node_alloc();
1143 }
1144
1145 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1146 __hash_table<_Tp, _Hash, _Equal, _Alloc>& __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __u) {
1147 if (this != std::addressof(__u)) {
1148 __copy_assign_alloc(__u);
1149 hash_function() = __u.hash_function();
1150 key_eq() = __u.key_eq();
1151 max_load_factor() = __u.max_load_factor();
1152 __assign_multi(__u.begin(), __u.end());
1153 }
1154 return *this;
1155 }
1156
1157 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1158 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__deallocate_node(__next_pointer __np) _NOEXCEPT {
1159 __node_allocator& __na = __node_alloc();
1160 while (__np != nullptr) {
1161 __next_pointer __next = __np->__next_;
1162 __node_pointer __real_np = __np->__upcast();
1163 __node_traits::destroy(__na, _NodeTypes::__get_ptr(__real_np->__get_value()));
1164 std::__destroy_at(std::addressof(*__real_np));
1165 __node_traits::deallocate(__na, __real_np, 1);
1166 __np = __next;
1167 }
1168 }
1169
1170 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1171 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__next_pointer
1172 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__detach() _NOEXCEPT {
1173 size_type __bc = bucket_count();
1174 for (size_type __i = 0; __i < __bc; ++__i)
1175 __bucket_list_[__i] = nullptr;
1176 size() = 0;
1177 __next_pointer __cache = __first_node_.__next_;
1178 __first_node_.__next_ = nullptr;
1179 return __cache;
1180 }
1181
1182 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1183 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u, true_type)
1184 _NOEXCEPT_(is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable<hasher>::value&&
1185 is_nothrow_move_assignable<key_equal>::value) {
1186 clear();
1187 __bucket_list_.reset(__u.__bucket_list_.release());
1188 __bucket_list_.get_deleter().size() = __u.__bucket_list_.get_deleter().size();
1189 __u.__bucket_list_.get_deleter().size() = 0;
1190 __move_assign_alloc(__u);
1191 size() = __u.size();
1192 hash_function() = std::move(__u.hash_function());
1193 max_load_factor() = __u.max_load_factor();
1194 key_eq() = std::move(__u.key_eq());
1195 __first_node_.__next_ = __u.__first_node_.__next_;
1196 if (size() > 0) {
1197 __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
1198 __u.__first_node_.__next_ = nullptr;
1199 __u.size() = 0;
1200 }
1201 }
1202
1203 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1204 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u, false_type) {
1205 if (__node_alloc() == __u.__node_alloc())
1206 __move_assign(__u, true_type());
1207 else {
1208 hash_function() = std::move(__u.hash_function());
1209 key_eq() = std::move(__u.key_eq());
1210 max_load_factor() = __u.max_load_factor();
1211 if (bucket_count() != 0) {
1212 __next_pointer __cache = __detach();
1213 #if _LIBCPP_HAS_EXCEPTIONS
1214 try {
1215 #endif // _LIBCPP_HAS_EXCEPTIONS
1216 const_iterator __i = __u.begin();
1217 while (__cache != nullptr && __u.size() != 0) {
1218 __cache->__upcast()->__get_value() = std::move(__u.remove(__i++)->__get_value());
1219 __next_pointer __next = __cache->__next_;
1220 __node_insert_multi(__cache->__upcast());
1221 __cache = __next;
1222 }
1223 #if _LIBCPP_HAS_EXCEPTIONS
1224 } catch (...) {
1225 __deallocate_node(__cache);
1226 throw;
1227 }
1228 #endif // _LIBCPP_HAS_EXCEPTIONS
1229 __deallocate_node(__cache);
1230 }
1231 const_iterator __i = __u.begin();
1232 while (__u.size() != 0) {
1233 __node_holder __h = __construct_node(_NodeTypes::__move(__u.remove(__i++)->__get_value()));
1234 __node_insert_multi(__h.get());
1235 __h.release();
1236 }
1237 }
1238 }
1239
1240 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1241 inline __hash_table<_Tp, _Hash, _Equal, _Alloc>&
1242 __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u) _NOEXCEPT_(
1243 __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<__node_allocator>::value&&
1244 is_nothrow_move_assignable<hasher>::value&& is_nothrow_move_assignable<key_equal>::value) {
1245 __move_assign(__u, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
1246 return *this;
1247 }
1248
1249 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1250 template <class _InputIterator>
1251 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __first, _InputIterator __last) {
1252 typedef iterator_traits<_InputIterator> _ITraits;
1253 typedef typename _ITraits::value_type _ItValueType;
1254 static_assert(is_same<_ItValueType, __container_value_type>::value,
1255 "__assign_unique may only be called with the containers value type");
1256
1257 if (bucket_count() != 0) {
1258 __next_pointer __cache = __detach();
1259 #if _LIBCPP_HAS_EXCEPTIONS
1260 try {
1261 #endif // _LIBCPP_HAS_EXCEPTIONS
1262 for (; __cache != nullptr && __first != __last; ++__first) {
1263 __cache->__upcast()->__get_value() = *__first;
1264 __next_pointer __next = __cache->__next_;
1265 __node_insert_unique(__cache->__upcast());
1266 __cache = __next;
1267 }
1268 #if _LIBCPP_HAS_EXCEPTIONS
1269 } catch (...) {
1270 __deallocate_node(__cache);
1271 throw;
1272 }
1273 #endif // _LIBCPP_HAS_EXCEPTIONS
1274 __deallocate_node(__cache);
1275 }
1276 for (; __first != __last; ++__first)
1277 __insert_unique(*__first);
1278 }
1279
1280 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1281 template <class _InputIterator>
1282 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __first, _InputIterator __last) {
1283 typedef iterator_traits<_InputIterator> _ITraits;
1284 typedef typename _ITraits::value_type _ItValueType;
1285 static_assert(
1286 (is_same<_ItValueType, __container_value_type>::value || is_same<_ItValueType, __node_value_type>::value),
1287 "__assign_multi may only be called with the containers value type"
1288 " or the nodes value type");
1289 if (bucket_count() != 0) {
1290 __next_pointer __cache = __detach();
1291 #if _LIBCPP_HAS_EXCEPTIONS
1292 try {
1293 #endif // _LIBCPP_HAS_EXCEPTIONS
1294 for (; __cache != nullptr && __first != __last; ++__first) {
1295 __cache->__upcast()->__get_value() = *__first;
1296 __next_pointer __next = __cache->__next_;
1297 __node_insert_multi(__cache->__upcast());
1298 __cache = __next;
1299 }
1300 #if _LIBCPP_HAS_EXCEPTIONS
1301 } catch (...) {
1302 __deallocate_node(__cache);
1303 throw;
1304 }
1305 #endif // _LIBCPP_HAS_EXCEPTIONS
1306 __deallocate_node(__cache);
1307 }
1308 for (; __first != __last; ++__first)
1309 __insert_multi(_NodeTypes::__get_value(*__first));
1310 }
1311
1312 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1313 inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1314 __hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() _NOEXCEPT {
1315 return iterator(__first_node_.__next_);
1316 }
1317
1318 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1319 inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1320 __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() _NOEXCEPT {
1321 return iterator(nullptr);
1322 }
1323
1324 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1325 inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
1326 __hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() const _NOEXCEPT {
1327 return const_iterator(__first_node_.__next_);
1328 }
1329
1330 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1331 inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
1332 __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const _NOEXCEPT {
1333 return const_iterator(nullptr);
1334 }
1335
1336 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1337 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::clear() _NOEXCEPT {
1338 if (size() > 0) {
1339 __deallocate_node(__first_node_.__next_);
1340 __first_node_.__next_ = nullptr;
1341 size_type __bc = bucket_count();
1342 for (size_type __i = 0; __i < __bc; ++__i)
1343 __bucket_list_[__i] = nullptr;
1344 size() = 0;
1345 }
1346 }
1347
1348 // Prepare the container for an insertion of the value __value with the hash
1349 // __hash. This does a lookup into the container to see if __value is already
1350 // present, and performs a rehash if necessary. Returns a pointer to the
1351 // existing element if it exists, otherwise nullptr.
1352 //
1353 // Note that this function does forward exceptions if key_eq() throws, and never
1354 // mutates __value or actually inserts into the map.
1355 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1356 _LIBCPP_HIDE_FROM_ABI typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__next_pointer
1357 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique_prepare(size_t __hash, value_type& __value) {
1358 size_type __bc = bucket_count();
1359
1360 if (__bc != 0) {
1361 size_t __chash = std::__constrain_hash(__hash, __bc);
1362 __next_pointer __ndptr = __bucket_list_[__chash];
1363 if (__ndptr != nullptr) {
1364 for (__ndptr = __ndptr->__next_;
1365 __ndptr != nullptr &&
1366 (__ndptr->__hash() == __hash || std::__constrain_hash(__ndptr->__hash(), __bc) == __chash);
1367 __ndptr = __ndptr->__next_) {
1368 if ((__ndptr->__hash() == __hash) && key_eq()(__ndptr->__upcast()->__get_value(), __value))
1369 return __ndptr;
1370 }
1371 }
1372 }
1373 if (size() + 1 > __bc * max_load_factor() || __bc == 0) {
1374 __rehash_unique(std::max<size_type>(
1375 2 * __bc + !std::__is_hash_power2(__bc), size_type(__math::ceil(float(size() + 1) / max_load_factor()))));
1376 }
1377 return nullptr;
1378 }
1379
1380 // Insert the node __nd into the container by pushing it into the right bucket,
1381 // and updating size(). Assumes that __nd->__hash is up-to-date, and that
1382 // rehashing has already occurred and that no element with the same key exists
1383 // in the map.
1384 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1385 _LIBCPP_HIDE_FROM_ABI void
1386 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique_perform(__node_pointer __nd) _NOEXCEPT {
1387 size_type __bc = bucket_count();
1388 size_t __chash = std::__constrain_hash(__nd->__hash(), __bc);
1389 // insert_after __bucket_list_[__chash], or __first_node if bucket is null
1390 __next_pointer __pn = __bucket_list_[__chash];
1391 if (__pn == nullptr) {
1392 __pn = __first_node_.__ptr();
1393 __nd->__next_ = __pn->__next_;
1394 __pn->__next_ = __nd->__ptr();
1395 // fix up __bucket_list_
1396 __bucket_list_[__chash] = __pn;
1397 if (__nd->__next_ != nullptr)
1398 __bucket_list_[std::__constrain_hash(__nd->__next_->__hash(), __bc)] = __nd->__ptr();
1399 } else {
1400 __nd->__next_ = __pn->__next_;
1401 __pn->__next_ = __nd->__ptr();
1402 }
1403 ++size();
1404 }
1405
1406 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1407 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1408 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique(__node_pointer __nd) {
1409 __nd->__hash_ = hash_function()(__nd->__get_value());
1410 __next_pointer __existing_node = __node_insert_unique_prepare(__nd->__hash(), __nd->__get_value());
1411
1412 // Insert the node, unless it already exists in the container.
1413 bool __inserted = false;
1414 if (__existing_node == nullptr) {
1415 __node_insert_unique_perform(__nd);
1416 __existing_node = __nd->__ptr();
1417 __inserted = true;
1418 }
1419 return pair<iterator, bool>(iterator(__existing_node), __inserted);
1420 }
1421
1422 // Prepare the container for an insertion of the value __cp_val with the hash
1423 // __cp_hash. This does a lookup into the container to see if __cp_value is
1424 // already present, and performs a rehash if necessary. Returns a pointer to the
1425 // last occurrence of __cp_val in the map.
1426 //
1427 // Note that this function does forward exceptions if key_eq() throws, and never
1428 // mutates __value or actually inserts into the map.
1429 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1430 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__next_pointer
1431 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi_prepare(size_t __cp_hash, value_type& __cp_val) {
1432 size_type __bc = bucket_count();
1433 if (size() + 1 > __bc * max_load_factor() || __bc == 0) {
1434 __rehash_multi(std::max<size_type>(
1435 2 * __bc + !std::__is_hash_power2(__bc), size_type(__math::ceil(float(size() + 1) / max_load_factor()))));
1436 __bc = bucket_count();
1437 }
1438 size_t __chash = std::__constrain_hash(__cp_hash, __bc);
1439 __next_pointer __pn = __bucket_list_[__chash];
1440 if (__pn != nullptr) {
1441 for (bool __found = false;
1442 __pn->__next_ != nullptr && std::__constrain_hash(__pn->__next_->__hash(), __bc) == __chash;
1443 __pn = __pn->__next_) {
1444 // __found key_eq() action
1445 // false false loop
1446 // true true loop
1447 // false true set __found to true
1448 // true false break
1449 if (__found !=
1450 (__pn->__next_->__hash() == __cp_hash && key_eq()(__pn->__next_->__upcast()->__get_value(), __cp_val))) {
1451 if (!__found)
1452 __found = true;
1453 else
1454 break;
1455 }
1456 }
1457 }
1458 return __pn;
1459 }
1460
1461 // Insert the node __cp into the container after __pn (which is the last node in
1462 // the bucket that compares equal to __cp). Rehashing, and checking for
1463 // uniqueness has already been performed (in __node_insert_multi_prepare), so
1464 // all we need to do is update the bucket and size(). Assumes that __cp->__hash
1465 // is up-to-date.
1466 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1467 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi_perform(
1468 __node_pointer __cp, __next_pointer __pn) _NOEXCEPT {
1469 size_type __bc = bucket_count();
1470 size_t __chash = std::__constrain_hash(__cp->__hash_, __bc);
1471 if (__pn == nullptr) {
1472 __pn = __first_node_.__ptr();
1473 __cp->__next_ = __pn->__next_;
1474 __pn->__next_ = __cp->__ptr();
1475 // fix up __bucket_list_
1476 __bucket_list_[__chash] = __pn;
1477 if (__cp->__next_ != nullptr)
1478 __bucket_list_[std::__constrain_hash(__cp->__next_->__hash(), __bc)] = __cp->__ptr();
1479 } else {
1480 __cp->__next_ = __pn->__next_;
1481 __pn->__next_ = __cp->__ptr();
1482 if (__cp->__next_ != nullptr) {
1483 size_t __nhash = std::__constrain_hash(__cp->__next_->__hash(), __bc);
1484 if (__nhash != __chash)
1485 __bucket_list_[__nhash] = __cp->__ptr();
1486 }
1487 }
1488 ++size();
1489 }
1490
1491 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1492 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1493 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(__node_pointer __cp) {
1494 __cp->__hash_ = hash_function()(__cp->__get_value());
1495 __next_pointer __pn = __node_insert_multi_prepare(__cp->__hash(), __cp->__get_value());
1496 __node_insert_multi_perform(__cp, __pn);
1497
1498 return iterator(__cp->__ptr());
1499 }
1500
1501 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1502 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1503 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(const_iterator __p, __node_pointer __cp) {
1504 if (__p != end() && key_eq()(*__p, __cp->__get_value())) {
1505 __next_pointer __np = __p.__node_;
1506 __cp->__hash_ = __np->__hash();
1507 size_type __bc = bucket_count();
1508 if (size() + 1 > __bc * max_load_factor() || __bc == 0) {
1509 __rehash_multi(std::max<size_type>(
1510 2 * __bc + !std::__is_hash_power2(__bc), size_type(__math::ceil(float(size() + 1) / max_load_factor()))));
1511 __bc = bucket_count();
1512 }
1513 size_t __chash = std::__constrain_hash(__cp->__hash_, __bc);
1514 __next_pointer __pp = __bucket_list_[__chash];
1515 while (__pp->__next_ != __np)
1516 __pp = __pp->__next_;
1517 __cp->__next_ = __np;
1518 __pp->__next_ = static_cast<__next_pointer>(__cp);
1519 ++size();
1520 return iterator(static_cast<__next_pointer>(__cp));
1521 }
1522 return __node_insert_multi(__cp);
1523 }
1524
1525 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1526 template <class _Key, class... _Args>
1527 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1528 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const& __k, _Args&&... __args) {
1529 size_t __hash = hash_function()(__k);
1530 size_type __bc = bucket_count();
1531 bool __inserted = false;
1532 __next_pointer __nd;
1533 size_t __chash;
1534 if (__bc != 0) {
1535 __chash = std::__constrain_hash(__hash, __bc);
1536 __nd = __bucket_list_[__chash];
1537 if (__nd != nullptr) {
1538 for (__nd = __nd->__next_;
1539 __nd != nullptr && (__nd->__hash() == __hash || std::__constrain_hash(__nd->__hash(), __bc) == __chash);
1540 __nd = __nd->__next_) {
1541 if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __k))
1542 goto __done;
1543 }
1544 }
1545 }
1546 {
1547 __node_holder __h = __construct_node_hash(__hash, std::forward<_Args>(__args)...);
1548 if (size() + 1 > __bc * max_load_factor() || __bc == 0) {
1549 __rehash_unique(std::max<size_type>(
1550 2 * __bc + !std::__is_hash_power2(__bc), size_type(__math::ceil(float(size() + 1) / max_load_factor()))));
1551 __bc = bucket_count();
1552 __chash = std::__constrain_hash(__hash, __bc);
1553 }
1554 // insert_after __bucket_list_[__chash], or __first_node if bucket is null
1555 __next_pointer __pn = __bucket_list_[__chash];
1556 if (__pn == nullptr) {
1557 __pn = __first_node_.__ptr();
1558 __h->__next_ = __pn->__next_;
1559 __pn->__next_ = __h.get()->__ptr();
1560 // fix up __bucket_list_
1561 __bucket_list_[__chash] = __pn;
1562 if (__h->__next_ != nullptr)
1563 __bucket_list_[std::__constrain_hash(__h->__next_->__hash(), __bc)] = __h.get()->__ptr();
1564 } else {
1565 __h->__next_ = __pn->__next_;
1566 __pn->__next_ = static_cast<__next_pointer>(__h.get());
1567 }
1568 __nd = static_cast<__next_pointer>(__h.release());
1569 // increment size
1570 ++size();
1571 __inserted = true;
1572 }
1573 __done:
1574 return pair<iterator, bool>(iterator(__nd), __inserted);
1575 }
1576
1577 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1578 template <class... _Args>
1579 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1580 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_impl(_Args&&... __args) {
1581 __node_holder __h = __construct_node(std::forward<_Args>(__args)...);
1582 pair<iterator, bool> __r = __node_insert_unique(__h.get());
1583 if (__r.second)
1584 __h.release();
1585 return __r;
1586 }
1587
1588 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1589 template <class... _Args>
1590 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1591 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_multi(_Args&&... __args) {
1592 __node_holder __h = __construct_node(std::forward<_Args>(__args)...);
1593 iterator __r = __node_insert_multi(__h.get());
1594 __h.release();
1595 return __r;
1596 }
1597
1598 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1599 template <class... _Args>
1600 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1601 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_hint_multi(const_iterator __p, _Args&&... __args) {
1602 __node_holder __h = __construct_node(std::forward<_Args>(__args)...);
1603 iterator __r = __node_insert_multi(__p, __h.get());
1604 __h.release();
1605 return __r;
1606 }
1607
1608 #if _LIBCPP_STD_VER >= 17
1609 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1610 template <class _NodeHandle, class _InsertReturnType>
1611 _LIBCPP_HIDE_FROM_ABI _InsertReturnType
1612 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_unique(_NodeHandle&& __nh) {
1613 if (__nh.empty())
1614 return _InsertReturnType{end(), false, _NodeHandle()};
1615 pair<iterator, bool> __result = __node_insert_unique(__nh.__ptr_);
1616 if (__result.second)
1617 __nh.__release_ptr();
1618 return _InsertReturnType{__result.first, __result.second, std::move(__nh)};
1619 }
1620
1621 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1622 template <class _NodeHandle>
1623 _LIBCPP_HIDE_FROM_ABI typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1624 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_unique(const_iterator, _NodeHandle&& __nh) {
1625 if (__nh.empty())
1626 return end();
1627 pair<iterator, bool> __result = __node_insert_unique(__nh.__ptr_);
1628 if (__result.second)
1629 __nh.__release_ptr();
1630 return __result.first;
1631 }
1632
1633 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1634 template <class _NodeHandle>
1635 _LIBCPP_HIDE_FROM_ABI _NodeHandle
1636 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_extract(key_type const& __key) {
1637 iterator __i = find(__key);
1638 if (__i == end())
1639 return _NodeHandle();
1640 return __node_handle_extract<_NodeHandle>(__i);
1641 }
1642
1643 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1644 template <class _NodeHandle>
1645 _LIBCPP_HIDE_FROM_ABI _NodeHandle __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_extract(const_iterator __p) {
1646 allocator_type __alloc(__node_alloc());
1647 return _NodeHandle(remove(__p).release(), __alloc);
1648 }
1649
1650 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1651 template <class _Table>
1652 _LIBCPP_HIDE_FROM_ABI void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_merge_unique(_Table& __source) {
1653 static_assert(is_same<__node, typename _Table::__node>::value, "");
1654
1655 for (typename _Table::iterator __it = __source.begin(); __it != __source.end();) {
1656 __node_pointer __src_ptr = __it.__node_->__upcast();
1657 size_t __hash = hash_function()(__src_ptr->__get_value());
1658 __next_pointer __existing_node = __node_insert_unique_prepare(__hash, __src_ptr->__get_value());
1659 auto __prev_iter = __it++;
1660 if (__existing_node == nullptr) {
1661 (void)__source.remove(__prev_iter).release();
1662 __src_ptr->__hash_ = __hash;
1663 __node_insert_unique_perform(__src_ptr);
1664 }
1665 }
1666 }
1667
1668 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1669 template <class _NodeHandle>
1670 _LIBCPP_HIDE_FROM_ABI typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1671 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_multi(_NodeHandle&& __nh) {
1672 if (__nh.empty())
1673 return end();
1674 iterator __result = __node_insert_multi(__nh.__ptr_);
1675 __nh.__release_ptr();
1676 return __result;
1677 }
1678
1679 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1680 template <class _NodeHandle>
1681 _LIBCPP_HIDE_FROM_ABI typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1682 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_multi(const_iterator __hint, _NodeHandle&& __nh) {
1683 if (__nh.empty())
1684 return end();
1685 iterator __result = __node_insert_multi(__hint, __nh.__ptr_);
1686 __nh.__release_ptr();
1687 return __result;
1688 }
1689
1690 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1691 template <class _Table>
1692 _LIBCPP_HIDE_FROM_ABI void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_merge_multi(_Table& __source) {
1693 static_assert(is_same<typename _Table::__node, __node>::value, "");
1694
1695 for (typename _Table::iterator __it = __source.begin(); __it != __source.end();) {
1696 __node_pointer __src_ptr = __it.__node_->__upcast();
1697 size_t __src_hash = hash_function()(__src_ptr->__get_value());
1698 __next_pointer __pn = __node_insert_multi_prepare(__src_hash, __src_ptr->__get_value());
1699 (void)__source.remove(__it++).release();
1700 __src_ptr->__hash_ = __src_hash;
1701 __node_insert_multi_perform(__src_ptr, __pn);
1702 }
1703 }
1704 #endif // _LIBCPP_STD_VER >= 17
1705
1706 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1707 template <bool _UniqueKeys>
1708 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __n) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK {
1709 if (__n == 1)
1710 __n = 2;
1711 else if (__n & (__n - 1))
1712 __n = std::__next_prime(__n);
1713 size_type __bc = bucket_count();
1714 if (__n > __bc)
1715 __do_rehash<_UniqueKeys>(__n);
1716 else if (__n < __bc) {
1717 __n = std::max<size_type>(
1718 __n,
1719 std::__is_hash_power2(__bc) ? std::__next_hash_pow2(size_t(__math::ceil(float(size()) / max_load_factor())))
1720 : std::__next_prime(size_t(__math::ceil(float(size()) / max_load_factor()))));
1721 if (__n < __bc)
1722 __do_rehash<_UniqueKeys>(__n);
1723 }
1724 }
1725
1726 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1727 template <bool _UniqueKeys>
1728 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc) {
1729 __pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc();
1730 __bucket_list_.reset(__nbc > 0 ? __pointer_alloc_traits::allocate(__npa, __nbc) : nullptr);
1731 __bucket_list_.get_deleter().size() = __nbc;
1732 if (__nbc > 0) {
1733 for (size_type __i = 0; __i < __nbc; ++__i)
1734 __bucket_list_[__i] = nullptr;
1735 __next_pointer __pp = __first_node_.__ptr();
1736 __next_pointer __cp = __pp->__next_;
1737 if (__cp != nullptr) {
1738 size_type __chash = std::__constrain_hash(__cp->__hash(), __nbc);
1739 __bucket_list_[__chash] = __pp;
1740 size_type __phash = __chash;
1741 for (__pp = __cp, void(), __cp = __cp->__next_; __cp != nullptr; __cp = __pp->__next_) {
1742 __chash = std::__constrain_hash(__cp->__hash(), __nbc);
1743 if (__chash == __phash)
1744 __pp = __cp;
1745 else {
1746 if (__bucket_list_[__chash] == nullptr) {
1747 __bucket_list_[__chash] = __pp;
1748 __pp = __cp;
1749 __phash = __chash;
1750 } else {
1751 __next_pointer __np = __cp;
1752 if _LIBCPP_CONSTEXPR_SINCE_CXX17 (!_UniqueKeys) {
1753 for (; __np->__next_ != nullptr &&
1754 key_eq()(__cp->__upcast()->__get_value(), __np->__next_->__upcast()->__get_value());
1755 __np = __np->__next_)
1756 ;
1757 }
1758 __pp->__next_ = __np->__next_;
1759 __np->__next_ = __bucket_list_[__chash]->__next_;
1760 __bucket_list_[__chash]->__next_ = __cp;
1761 }
1762 }
1763 }
1764 }
1765 }
1766 }
1767
1768 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1769 template <class _Key>
1770 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1771 __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) {
1772 size_t __hash = hash_function()(__k);
1773 size_type __bc = bucket_count();
1774 if (__bc != 0) {
1775 size_t __chash = std::__constrain_hash(__hash, __bc);
1776 __next_pointer __nd = __bucket_list_[__chash];
1777 if (__nd != nullptr) {
1778 for (__nd = __nd->__next_;
1779 __nd != nullptr && (__nd->__hash() == __hash || std::__constrain_hash(__nd->__hash(), __bc) == __chash);
1780 __nd = __nd->__next_) {
1781 if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __k))
1782 return iterator(__nd);
1783 }
1784 }
1785 }
1786 return end();
1787 }
1788
1789 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1790 template <class _Key>
1791 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
1792 __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) const {
1793 size_t __hash = hash_function()(__k);
1794 size_type __bc = bucket_count();
1795 if (__bc != 0) {
1796 size_t __chash = std::__constrain_hash(__hash, __bc);
1797 __next_pointer __nd = __bucket_list_[__chash];
1798 if (__nd != nullptr) {
1799 for (__nd = __nd->__next_;
1800 __nd != nullptr && (__hash == __nd->__hash() || std::__constrain_hash(__nd->__hash(), __bc) == __chash);
1801 __nd = __nd->__next_) {
1802 if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __k))
1803 return const_iterator(__nd);
1804 }
1805 }
1806 }
1807 return end();
1808 }
1809
1810 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1811 template <class... _Args>
1812 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1813 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&&... __args) {
1814 static_assert(!__is_hash_value_type<_Args...>::value, "Construct cannot be called with a hash value type");
1815 __node_allocator& __na = __node_alloc();
1816 __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
1817
1818 // Begin the lifetime of the node itself. Note that this doesn't begin the lifetime of the value
1819 // held inside the node, since we need to use the allocator's construct() method for that.
1820 //
1821 // We don't use the allocator's construct() method to construct the node itself since the
1822 // Cpp17FooInsertable named requirements don't require the allocator's construct() method
1823 // to work on anything other than the value_type.
1824 std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ 0);
1825
1826 // Now construct the value_type using the allocator's construct() method.
1827 __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__get_value()), std::forward<_Args>(__args)...);
1828 __h.get_deleter().__value_constructed = true;
1829
1830 __h->__hash_ = hash_function()(__h->__get_value());
1831 return __h;
1832 }
1833
1834 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1835 template <class _First, class... _Rest>
1836 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1837 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest) {
1838 static_assert(!__is_hash_value_type<_First, _Rest...>::value, "Construct cannot be called with a hash value type");
1839 __node_allocator& __na = __node_alloc();
1840 __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
1841 std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ __hash);
1842 __node_traits::construct(
1843 __na, _NodeTypes::__get_ptr(__h->__get_value()), std::forward<_First>(__f), std::forward<_Rest>(__rest)...);
1844 __h.get_deleter().__value_constructed = true;
1845 return __h;
1846 }
1847
1848 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1849 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1850 __hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __p) {
1851 __next_pointer __np = __p.__node_;
1852 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1853 __p != end(), "unordered container::erase(iterator) called with a non-dereferenceable iterator");
1854 iterator __r(__np);
1855 ++__r;
1856 remove(__p);
1857 return __r;
1858 }
1859
1860 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1861 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1862 __hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __first, const_iterator __last) {
1863 for (const_iterator __p = __first; __first != __last; __p = __first) {
1864 ++__first;
1865 erase(__p);
1866 }
1867 __next_pointer __np = __last.__node_;
1868 return iterator(__np);
1869 }
1870
1871 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1872 template <class _Key>
1873 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1874 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__erase_unique(const _Key& __k) {
1875 iterator __i = find(__k);
1876 if (__i == end())
1877 return 0;
1878 erase(__i);
1879 return 1;
1880 }
1881
1882 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1883 template <class _Key>
1884 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1885 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__erase_multi(const _Key& __k) {
1886 size_type __r = 0;
1887 iterator __i = find(__k);
1888 if (__i != end()) {
1889 iterator __e = end();
1890 do {
1891 erase(__i++);
1892 ++__r;
1893 } while (__i != __e && key_eq()(*__i, __k));
1894 }
1895 return __r;
1896 }
1897
1898 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1899 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1900 __hash_table<_Tp, _Hash, _Equal, _Alloc>::remove(const_iterator __p) _NOEXCEPT {
1901 // current node
1902 __next_pointer __cn = __p.__node_;
1903 size_type __bc = bucket_count();
1904 size_t __chash = std::__constrain_hash(__cn->__hash(), __bc);
1905 // find previous node
1906 __next_pointer __pn = __bucket_list_[__chash];
1907 for (; __pn->__next_ != __cn; __pn = __pn->__next_)
1908 ;
1909 // Fix up __bucket_list_
1910 // if __pn is not in same bucket (before begin is not in same bucket) &&
1911 // if __cn->__next_ is not in same bucket (nullptr is not in same bucket)
1912 if (__pn == __first_node_.__ptr() || std::__constrain_hash(__pn->__hash(), __bc) != __chash) {
1913 if (__cn->__next_ == nullptr || std::__constrain_hash(__cn->__next_->__hash(), __bc) != __chash)
1914 __bucket_list_[__chash] = nullptr;
1915 }
1916 // if __cn->__next_ is not in same bucket (nullptr is in same bucket)
1917 if (__cn->__next_ != nullptr) {
1918 size_t __nhash = std::__constrain_hash(__cn->__next_->__hash(), __bc);
1919 if (__nhash != __chash)
1920 __bucket_list_[__nhash] = __pn;
1921 }
1922 // remove __cn
1923 __pn->__next_ = __cn->__next_;
1924 __cn->__next_ = nullptr;
1925 --size();
1926 return __node_holder(__cn->__upcast(), _Dp(__node_alloc(), true));
1927 }
1928
1929 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1930 template <class _Key>
1931 inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1932 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__count_unique(const _Key& __k) const {
1933 return static_cast<size_type>(find(__k) != end());
1934 }
1935
1936 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1937 template <class _Key>
1938 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1939 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__count_multi(const _Key& __k) const {
1940 size_type __r = 0;
1941 const_iterator __i = find(__k);
1942 if (__i != end()) {
1943 const_iterator __e = end();
1944 do {
1945 ++__i;
1946 ++__r;
1947 } while (__i != __e && key_eq()(*__i, __k));
1948 }
1949 return __r;
1950 }
1951
1952 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1953 template <class _Key>
1954 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator,
1955 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator>
1956 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_unique(const _Key& __k) {
1957 iterator __i = find(__k);
1958 iterator __j = __i;
1959 if (__i != end())
1960 ++__j;
1961 return pair<iterator, iterator>(__i, __j);
1962 }
1963
1964 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1965 template <class _Key>
1966 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator,
1967 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator>
1968 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_unique(const _Key& __k) const {
1969 const_iterator __i = find(__k);
1970 const_iterator __j = __i;
1971 if (__i != end())
1972 ++__j;
1973 return pair<const_iterator, const_iterator>(__i, __j);
1974 }
1975
1976 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1977 template <class _Key>
1978 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator,
1979 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator>
1980 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_multi(const _Key& __k) {
1981 iterator __i = find(__k);
1982 iterator __j = __i;
1983 if (__i != end()) {
1984 iterator __e = end();
1985 do {
1986 ++__j;
1987 } while (__j != __e && key_eq()(*__j, __k));
1988 }
1989 return pair<iterator, iterator>(__i, __j);
1990 }
1991
1992 template <class _Tp, class _Hash, class _Equal, class _Alloc>
1993 template <class _Key>
1994 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator,
1995 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator>
1996 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_multi(const _Key& __k) const {
1997 const_iterator __i = find(__k);
1998 const_iterator __j = __i;
1999 if (__i != end()) {
2000 const_iterator __e = end();
2001 do {
2002 ++__j;
2003 } while (__j != __e && key_eq()(*__j, __k));
2004 }
2005 return pair<const_iterator, const_iterator>(__i, __j);
2006 }
2007
2008 template <class _Tp, class _Hash, class _Equal, class _Alloc>
2009 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
2010 #if _LIBCPP_STD_VER <= 11
2011 _NOEXCEPT_(__is_nothrow_swappable_v<hasher>&& __is_nothrow_swappable_v<key_equal> &&
2012 (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value ||
2013 __is_nothrow_swappable_v<__pointer_allocator>) &&
2014 (!__node_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__node_allocator>))
2015 #else
2016 _NOEXCEPT_(__is_nothrow_swappable_v<hasher>&& __is_nothrow_swappable_v<key_equal>)
2017 #endif
2018 {
2019 _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
2020 __node_traits::propagate_on_container_swap::value || this->__node_alloc() == __u.__node_alloc(),
2021 "unordered container::swap: Either propagate_on_container_swap "
2022 "must be true or the allocators must compare equal");
2023 {
2024 __node_pointer_pointer __npp = __bucket_list_.release();
2025 __bucket_list_.reset(__u.__bucket_list_.release());
2026 __u.__bucket_list_.reset(__npp);
2027 }
2028 std::swap(__bucket_list_.get_deleter().size(), __u.__bucket_list_.get_deleter().size());
2029 std::__swap_allocator(__bucket_list_.get_deleter().__alloc(), __u.__bucket_list_.get_deleter().__alloc());
2030 std::__swap_allocator(__node_alloc(), __u.__node_alloc());
2031 std::swap(__first_node_.__next_, __u.__first_node_.__next_);
2032 using std::swap;
2033 swap(__size_, __u.__size_);
2034 swap(__hasher_, __u.__hasher_);
2035 swap(__max_load_factor_, __u.__max_load_factor_);
2036 swap(__key_eq_, __u.__key_eq_);
2037 if (size() > 0)
2038 __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
2039 if (__u.size() > 0)
2040 __u.__bucket_list_[std::__constrain_hash(__u.__first_node_.__next_->__hash(), __u.bucket_count())] =
2041 __u.__first_node_.__ptr();
2042 }
2043
2044 template <class _Tp, class _Hash, class _Equal, class _Alloc>
2045 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
2046 __hash_table<_Tp, _Hash, _Equal, _Alloc>::bucket_size(size_type __n) const {
2047 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
2048 __n < bucket_count(), "unordered container::bucket_size(n) called with n >= bucket_count()");
2049 __next_pointer __np = __bucket_list_[__n];
2050 size_type __bc = bucket_count();
2051 size_type __r = 0;
2052 if (__np != nullptr) {
2053 for (__np = __np->__next_; __np != nullptr && std::__constrain_hash(__np->__hash(), __bc) == __n;
2054 __np = __np->__next_, (void)++__r)
2055 ;
2056 }
2057 return __r;
2058 }
2059
2060 template <class _Tp, class _Hash, class _Equal, class _Alloc>
2061 inline _LIBCPP_HIDE_FROM_ABI void
2062 swap(__hash_table<_Tp, _Hash, _Equal, _Alloc>& __x, __hash_table<_Tp, _Hash, _Equal, _Alloc>& __y)
2063 _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) {
2064 __x.swap(__y);
2065 }
2066
2067 _LIBCPP_END_NAMESPACE_STD
2068
2069 _LIBCPP_POP_MACROS
2070
2071 #endif // _LIBCPP___HASH_TABLE