763 using PolicyTraits = hash_policy_traits<Policy>;
765 KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
768 using init_type =
typename PolicyTraits::init_type;
769 using key_type =
typename PolicyTraits::key_type;
772 using slot_type =
typename PolicyTraits::slot_type;
773 using allocator_type = Alloc;
774 using size_type = size_t;
775 using difference_type = ptrdiff_t;
777 using key_equal = Eq;
778 using policy_type = Policy;
779 using value_type =
typename PolicyTraits::value_type;
780 using reference = value_type&;
781 using const_reference =
const value_type&;
783 allocator_type>::template rebind_traits<value_type>::pointer;
785 allocator_type>::template rebind_traits<value_type>::const_pointer;
792 using key_arg =
typename KeyArgImpl::template type<K, key_type>;
796 auto KeyTypeCanBeHashed(
const Hash& h,
const key_type& k) ->
decltype(h(k));
797 auto KeyTypeCanBeEq(
const Eq& eq,
const key_type& k) ->
decltype(eq(k, k));
799 using Layout = phmap::priv::Layout<ctrl_t, slot_type>;
801 static Layout MakeLayout(
size_t capacity) {
802 assert(IsValidCapacity(capacity));
803 return Layout(capacity + Group::kWidth + 1, capacity);
808 allocator_type>::template rebind_alloc<slot_type>;
810 allocator_type>::template rebind_traits<slot_type>;
812 static_assert(std::is_lvalue_reference<reference>::value,
813 "Policy::element() must return a reference");
815 template <
typename T>
816 struct SameAsElementReference
817 : std::is_same<typename std::remove_cv<
818 typename std::remove_reference<reference>::type>::type,
819 typename std::remove_cv<
820 typename std::remove_reference<T>::type>::type> {};
828 using RequiresInsertable =
typename std::enable_if<
830 SameAsElementReference<T>>::value,
836 using RequiresNotInit =
837 typename std::enable_if<!std::is_same<T, init_type>::value,
int>::type;
839 template <
class... Ts>
840 using IsDecomposable = IsDecomposable<void, PolicyTraits,
Hash, Eq, Ts...>;
843 static_assert(std::is_same<pointer, value_type*>::value,
844 "Allocators with custom pointer types are not supported");
845 static_assert(std::is_same<const_pointer, const value_type*>::value,
846 "Allocators with custom pointer types are not supported");
853 using iterator_category = std::forward_iterator_tag;
854 using value_type =
typename raw_hash_set::value_type;
856 phmap::conditional_t<PolicyTraits::constant_iterators::value,
857 const value_type&, value_type&>;
858 using pointer = phmap::remove_reference_t<reference>*;
859 using difference_type =
typename raw_hash_set::difference_type;
864 reference operator*()
const {
return PolicyTraits::element(slot_); }
867 pointer operator->()
const {
return &operator*(); }
873 skip_empty_or_deleted();
883#if PHMAP_BIDIRECTIONAL
890 }
while (IsEmptyOrDeleted(*ctrl_));
903 return a.ctrl_ == b.ctrl_;
910 iterator(ctrl_t* ctrl) : ctrl_(ctrl) {}
911 iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {}
913 void skip_empty_or_deleted() {
914 while (IsEmptyOrDeleted(*ctrl_)) {
919 uint32_t shift =
Group{ctrl_}.CountLeadingEmptyOrDeleted();
925 ctrl_t* ctrl_ =
nullptr;
938 using iterator_category =
typename iterator::iterator_category;
939 using value_type =
typename raw_hash_set::value_type;
940 using reference =
typename raw_hash_set::const_reference;
941 using pointer =
typename raw_hash_set::const_pointer;
942 using difference_type =
typename raw_hash_set::difference_type;
948 reference operator*()
const {
return *inner_; }
949 pointer operator->()
const {
return inner_.operator->(); }
958 return a.inner_ == b.inner_;
966 : inner_(
const_cast<ctrl_t*
>(ctrl),
const_cast<slot_type*
>(slot)) {}
971 using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>;
972 using insert_return_type = InsertReturnType<iterator, node_type>;
975 std::is_nothrow_default_constructible<
hasher>::value&&
976 std::is_nothrow_default_constructible<key_equal>::value&&
977 std::is_nothrow_default_constructible<allocator_type>::value) {}
979 explicit raw_hash_set(
size_t bucket_cnt,
const hasher& hashfn = hasher(),
980 const key_equal& eq = key_equal(),
981 const allocator_type& alloc = allocator_type())
982 : ctrl_(EmptyGroup()), settings_(0, hashfn, eq, alloc) {
984 capacity_ = NormalizeCapacity(bucket_cnt);
990 raw_hash_set(
size_t bucket_cnt,
const hasher& hashfn,
991 const allocator_type& alloc)
992 : raw_hash_set(bucket_cnt, hashfn, key_equal(), alloc) {}
994 raw_hash_set(
size_t bucket_cnt,
const allocator_type& alloc)
995 : raw_hash_set(bucket_cnt, hasher(), key_equal(), alloc) {}
997 explicit raw_hash_set(
const allocator_type& alloc)
998 : raw_hash_set(0, hasher(), key_equal(), alloc) {}
1000 template <
class InputIter>
1001 raw_hash_set(InputIter first, InputIter last,
size_t bucket_cnt = 0,
1002 const hasher& hashfn = hasher(),
const key_equal& eq = key_equal(),
1003 const allocator_type& alloc = allocator_type())
1004 : raw_hash_set(bucket_cnt, hashfn, eq, alloc) {
1005 insert(first, last);
1008 template <
class InputIter>
1009 raw_hash_set(InputIter first, InputIter last,
size_t bucket_cnt,
1010 const hasher& hashfn,
const allocator_type& alloc)
1011 : raw_hash_set(first, last, bucket_cnt, hashfn, key_equal(), alloc) {}
1013 template <
class InputIter>
1014 raw_hash_set(InputIter first, InputIter last,
size_t bucket_cnt,
1015 const allocator_type& alloc)
1016 : raw_hash_set(first, last, bucket_cnt, hasher(), key_equal(), alloc) {}
1018 template <
class InputIter>
1019 raw_hash_set(InputIter first, InputIter last,
const allocator_type& alloc)
1020 : raw_hash_set(first, last, 0, hasher(), key_equal(), alloc) {}
1043 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
1044 raw_hash_set(std::initializer_list<T> init,
size_t bucket_cnt = 0,
1045 const hasher& hashfn = hasher(),
const key_equal& eq = key_equal(),
1046 const allocator_type& alloc = allocator_type())
1047 : raw_hash_set(init.begin(), init.end(), bucket_cnt, hashfn, eq, alloc) {}
1049 raw_hash_set(std::initializer_list<init_type> init,
size_t bucket_cnt = 0,
1050 const hasher& hashfn = hasher(),
const key_equal& eq = key_equal(),
1051 const allocator_type& alloc = allocator_type())
1052 : raw_hash_set(init.begin(), init.end(), bucket_cnt, hashfn, eq, alloc) {}
1054 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
1055 raw_hash_set(std::initializer_list<T> init,
size_t bucket_cnt,
1056 const hasher& hashfn,
const allocator_type& alloc)
1057 : raw_hash_set(init, bucket_cnt, hashfn, key_equal(), alloc) {}
1059 raw_hash_set(std::initializer_list<init_type> init,
size_t bucket_cnt,
1060 const hasher& hashfn,
const allocator_type& alloc)
1061 : raw_hash_set(init, bucket_cnt, hashfn, key_equal(), alloc) {}
1063 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
1064 raw_hash_set(std::initializer_list<T> init,
size_t bucket_cnt,
1065 const allocator_type& alloc)
1066 : raw_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {}
1068 raw_hash_set(std::initializer_list<init_type> init,
size_t bucket_cnt,
1069 const allocator_type& alloc)
1070 : raw_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {}
1072 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
1073 raw_hash_set(std::initializer_list<T> init,
const allocator_type& alloc)
1074 : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {}
1076 raw_hash_set(std::initializer_list<init_type> init,
1077 const allocator_type& alloc)
1078 : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {}
1080 raw_hash_set(
const raw_hash_set& that)
1081 : raw_hash_set(that, AllocTraits::select_on_container_copy_construction(
1082 that.alloc_ref())) {}
1084 raw_hash_set(
const raw_hash_set& that,
const allocator_type& a)
1085 : raw_hash_set(0, that.hash_ref(), that.eq_ref(), a) {
1086 reserve(that.size());
1089 for (
const auto& v : that) {
1090 const size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, v);
1091 auto target = find_first_non_full(hashval);
1092 set_ctrl(target.offset, H2(hashval));
1093 emplace_at(target.offset, v);
1094 infoz_.RecordInsert(hashval, target.probe_length);
1096 size_ = that.size();
1097 growth_left() -= that.size();
1100 raw_hash_set(raw_hash_set&& that)
noexcept(
1101 std::is_nothrow_copy_constructible<hasher>::value&&
1102 std::is_nothrow_copy_constructible<key_equal>::value&&
1103 std::is_nothrow_copy_constructible<allocator_type>::value)
1104 : ctrl_(phmap::exchange(that.ctrl_, EmptyGroup())),
1105 slots_(phmap::exchange(that.slots_, nullptr)),
1106 size_(phmap::exchange(that.size_, 0)),
1107 capacity_(phmap::exchange(that.capacity_, 0)),
1108 infoz_(phmap::exchange(that.infoz_, HashtablezInfoHandle())),
1112 settings_(that.settings_) {
1114 that.growth_left() = 0;
1117 raw_hash_set(raw_hash_set&& that,
const allocator_type& a)
1118 : ctrl_(EmptyGroup()),
1122 settings_(0, that.hash_ref(), that.eq_ref(), a) {
1123 if (a == that.alloc_ref()) {
1124 std::swap(ctrl_, that.ctrl_);
1125 std::swap(slots_, that.slots_);
1126 std::swap(size_, that.size_);
1127 std::swap(capacity_, that.capacity_);
1128 std::swap(growth_left(), that.growth_left());
1129 std::swap(infoz_, that.infoz_);
1131 reserve(that.size());
1134 for (
auto& elem : that) insert(std::move(elem));
1138 raw_hash_set& operator=(
const raw_hash_set& that) {
1139 raw_hash_set tmp(that,
1140 AllocTraits::propagate_on_container_copy_assignment::value
1147 raw_hash_set& operator=(raw_hash_set&& that)
noexcept(
1149 std::is_nothrow_move_assignable<hasher>::value&&
1150 std::is_nothrow_move_assignable<key_equal>::value) {
1155 typename AllocTraits::propagate_on_container_move_assignment());
1158 ~raw_hash_set() { destroy_slots(); }
1161 auto it = iterator_at(0);
1162 it.skip_empty_or_deleted();
1167#if PHMAP_BIDIRECTIONAL
1168 return iterator_at(capacity_);
1170 return {ctrl_ + capacity_};
1174 const_iterator begin()
const {
1175 return const_cast<raw_hash_set*
>(
this)->begin();
1177 const_iterator end()
const {
return const_cast<raw_hash_set*
>(
this)->end(); }
1178 const_iterator cbegin()
const {
return begin(); }
1179 const_iterator cend()
const {
return end(); }
1181 bool empty()
const {
return !size(); }
1182 size_t size()
const {
return size_; }
1183 size_t capacity()
const {
return capacity_; }
1184 size_t max_size()
const {
return (std::numeric_limits<size_t>::max)(); }
1186 PHMAP_ATTRIBUTE_REINITIALIZES
void clear() {
1196 if (capacity_ > 127) {
1198 }
else if (capacity_) {
1199 for (
size_t i = 0; i != capacity_; ++i) {
1200 if (IsFull(ctrl_[i])) {
1201 PolicyTraits::destroy(&alloc_ref(), slots_ + i);
1206 reset_growth_left();
1209 infoz_.RecordStorageChanged(0, capacity_);
1217 template <
class T, RequiresInsertable<T> = 0,
1218 typename std::enable_if<IsDecomposable<T>::value,
int>::type = 0,
1220 std::pair<iterator, bool> insert(T&& value) {
1221 return emplace(std::forward<T>(value));
1238 template <
class T, RequiresInsertable<T> = 0,
1239 typename std::enable_if<IsDecomposable<const T&>::value,
int>::type = 0>
1240 std::pair<iterator, bool> insert(
const T& value) {
1241 return emplace(value);
1249 std::pair<iterator, bool> insert(init_type&& value) {
1250 return emplace(std::move(value));
1253 template <
class T, RequiresInsertable<T> = 0,
1254 typename std::enable_if<IsDecomposable<T>::value,
int>::type = 0,
1256 iterator insert(const_iterator, T&& value) {
1257 return insert(std::forward<T>(value)).first;
1263 template <
class T, RequiresInsertable<T> = 0,
1264 typename std::enable_if<IsDecomposable<const T&>::value,
int>::type = 0>
1265 iterator insert(const_iterator,
const T& value) {
1266 return insert(value).first;
1269 iterator insert(const_iterator, init_type&& value) {
1270 return insert(std::move(value)).first;
1273 template <
typename It>
1274 using IsRandomAccess = std::is_same<typename std::iterator_traits<It>::iterator_category,
1275 std::random_access_iterator_tag>;
1278 template<
typename T>
1282 using yes = std::true_type;
1283 using no = std::false_type;
1285 template<
typename U>
static auto test(
int) ->
decltype(std::declval<U>() - std::declval<U>() == 1, yes());
1286 template<
typename>
static no test(...);
1289 static constexpr bool value = std::is_same<decltype(test<T>(0)), yes>::value;
1292 template <class InputIt, typename phmap::enable_if_t<has_difference_operator<InputIt>::value,
int> = 0>
1293 void insert(InputIt first, InputIt last) {
1294 this->reserve(this->size() + (last - first));
1295 for (; first != last; ++first)
1299 template <class InputIt, typename phmap::enable_if_t<!has_difference_operator<InputIt>::value,
int> = 0>
1300 void insert(InputIt first, InputIt last) {
1301 for (; first != last; ++first)
1305 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<const T&> = 0>
1306 void insert(std::initializer_list<T> ilist) {
1307 insert(ilist.begin(), ilist.end());
1310 void insert(std::initializer_list<init_type> ilist) {
1311 insert(ilist.begin(), ilist.end());
1314 insert_return_type insert(node_type&& node) {
1315 if (!node)
return {end(),
false, node_type()};
1316 const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
1317 auto res = PolicyTraits::apply(
1318 InsertSlot<false>{*
this, std::move(*CommonAccess::GetSlot(node))},
1321 CommonAccess::Reset(&node);
1322 return {res.first,
true, node_type()};
1324 return {res.first,
false, std::move(node)};
1328 insert_return_type insert(node_type&& node,
size_t hashval) {
1329 if (!node)
return {end(),
false, node_type()};
1330 const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
1331 auto res = PolicyTraits::apply(
1332 InsertSlotWithHash<false>{*
this, std::move(*CommonAccess::GetSlot(node)), hashval},
1335 CommonAccess::Reset(&node);
1336 return {res.first,
true, node_type()};
1338 return {res.first,
false, std::move(node)};
1342 iterator insert(const_iterator, node_type&& node) {
1343 return insert(std::move(node)).first;
1355 template <
class... Args,
typename std::enable_if<
1356 IsDecomposable<Args...>::value,
int>::type = 0>
1357 std::pair<iterator, bool> emplace(Args&&... args) {
1358 return PolicyTraits::apply(EmplaceDecomposable{*
this},
1359 std::forward<Args>(args)...);
1365 template <
class... Args,
typename std::enable_if<
1366 !IsDecomposable<Args...>::value,
int>::type = 0>
1367 std::pair<iterator, bool> emplace(Args&&... args) {
1368 typename std::aligned_storage<
sizeof(slot_type),
alignof(slot_type)>::type
1370 slot_type* slot =
reinterpret_cast<slot_type*
>(&raw);
1372 PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
1373 const auto& elem = PolicyTraits::element(slot);
1374 return PolicyTraits::apply(InsertSlot<true>{*
this, std::move(*slot)}, elem);
1377 template <
class... Args>
1378 iterator emplace_hint(const_iterator, Args&&... args) {
1379 return emplace(std::forward<Args>(args)...).first;
1409 template <
class... Args>
1410 void operator()(Args&&... args)
const {
1412 PolicyTraits::construct(alloc_, *slot_, std::forward<Args>(args)...);
1417 constructor(allocator_type* a, slot_type** slot) : alloc_(a), slot_(slot) {}
1419 allocator_type* alloc_;
1423 template <
class K = key_type,
class F>
1424 iterator lazy_emplace(
const key_arg<K>& key, F&& f) {
1425 auto res = find_or_prepare_insert(key);
1427 lazy_emplace_at(res.first, std::forward<F>(f));
1429 return iterator_at(res.first);
1432 template <
class K = key_type,
class F>
1433 iterator lazy_emplace_with_hash(
const key_arg<K>& key,
size_t &hashval, F&& f) {
1434 auto res = find_or_prepare_insert(key, hashval);
1436 lazy_emplace_at(res.first, std::forward<F>(f));
1438 return iterator_at(res.first);
1441 template <
class K = key_type,
class F>
1442 void lazy_emplace_at(
size_t& idx, F&& f) {
1443 slot_type* slot = slots_ + idx;
1444 std::forward<F>(f)(constructor(&alloc_ref(), &slot));
1458 template <
class K = key_type>
1459 size_type erase(
const key_arg<K>& key) {
1460 auto it = find(key);
1461 if (it == end())
return 0;
1467 iterator erase(const_iterator cit) {
return erase(cit.inner_); }
1481 void _erase(iterator it) {
1482 assert(it != end());
1483 PolicyTraits::destroy(&alloc_ref(), it.slot_);
1484 erase_meta_only(it);
1486 void _erase(const_iterator cit) { _erase(cit.inner_); }
1490 iterator erase(iterator it) {
1497 iterator erase(const_iterator first, const_iterator last) {
1498 while (first != last) {
1506 template <
typename H,
typename E>
1507 void merge(raw_hash_set<Policy, H, E, Alloc>& src) {
1508 assert(
this != &src);
1509 for (
auto it = src.begin(), e = src.end(); it != e; ++it) {
1510 if (PolicyTraits::apply(InsertSlot<false>{*
this, std::move(*it.slot_)},
1511 PolicyTraits::element(it.slot_))
1513 src.erase_meta_only(it);
1518 template <
typename H,
typename E>
1519 void merge(raw_hash_set<Policy, H, E, Alloc>&& src) {
1523 node_type extract(const_iterator position) {
1525 CommonAccess::Make<node_type>(alloc_ref(), position.inner_.slot_);
1526 erase_meta_only(position);
1532 typename std::enable_if<!std::is_same<K, iterator>::value,
int>::type = 0>
1533 node_type extract(
const key_arg<K>& key) {
1534 auto it = find(key);
1535 return it == end() ? node_type() : extract(const_iterator{it});
1538 void swap(raw_hash_set& that)
noexcept(
1539 IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
1540 (!AllocTraits::propagate_on_container_swap::value ||
1541 IsNoThrowSwappable<allocator_type>())) {
1543 swap(ctrl_, that.ctrl_);
1544 swap(slots_, that.slots_);
1545 swap(size_, that.size_);
1546 swap(capacity_, that.capacity_);
1547 swap(growth_left(), that.growth_left());
1548 swap(hash_ref(), that.hash_ref());
1549 swap(eq_ref(), that.eq_ref());
1550 swap(infoz_, that.infoz_);
1551 if (AllocTraits::propagate_on_container_swap::value) {
1552 swap(alloc_ref(), that.alloc_ref());
1559#ifndef PHMAP_NON_DETERMINISTIC
1560 template<
typename OutputArchive>
1561 bool dump(OutputArchive&)
const;
1563 template<
typename InputArchive>
1564 bool load(InputArchive&);
1567 void rehash(
size_t n) {
1568 if (n == 0 && capacity_ == 0)
return;
1569 if (n == 0 && size_ == 0) {
1571 infoz_.RecordStorageChanged(0, 0);
1576 auto m = NormalizeCapacity((std::max)(n, size()));
1578 if (n == 0 || m > capacity_) {
1583 void reserve(
size_t n) { rehash(GrowthToLowerboundCapacity(n)); }
1594 template <
class K = key_type>
1595 size_t count(
const key_arg<K>& key)
const {
1596 return find(key) == end() ? size_t(0) : size_t(1);
1604 void prefetch_hash(
size_t hashval)
const {
1606#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
1607 auto seq = probe(hashval);
1608 _mm_prefetch((
const char *)(ctrl_ + seq.offset()), _MM_HINT_NTA);
1609 _mm_prefetch((
const char *)(slots_ + seq.offset()), _MM_HINT_NTA);
1610#elif defined(__GNUC__)
1611 auto seq = probe(hashval);
1612 __builtin_prefetch(
static_cast<const void*
>(ctrl_ + seq.offset()));
1613 __builtin_prefetch(
static_cast<const void*
>(slots_ + seq.offset()));
1617 template <
class K = key_type>
1618 void prefetch(
const key_arg<K>& key)
const {
1619 prefetch_hash(this->hash(key));
1629 template <
class K = key_type>
1630 iterator find(
const key_arg<K>& key,
size_t hashval) {
1631 auto seq = probe(hashval);
1633 Group g{ctrl_ + seq.offset()};
1634 for (
int i : g.Match((h2_t)H2(hashval))) {
1635 if (PHMAP_PREDICT_TRUE(PolicyTraits::apply(
1636 EqualElement<K>{key, eq_ref()},
1637 PolicyTraits::element(slots_ + seq.offset((
size_t)i)))))
1638 return iterator_at(seq.offset((
size_t)i));
1640 if (PHMAP_PREDICT_TRUE(g.MatchEmpty()))
1645 template <
class K = key_type>
1646 iterator find(
const key_arg<K>& key) {
1647 return find(key, this->hash(key));
1650 template <
class K = key_type>
1651 const_iterator find(
const key_arg<K>& key,
size_t hashval)
const {
1652 return const_cast<raw_hash_set*
>(
this)->find(key, hashval);
1654 template <
class K = key_type>
1655 const_iterator find(
const key_arg<K>& key)
const {
1656 return find(key, this->hash(key));
1659 template <
class K = key_type>
1660 bool contains(
const key_arg<K>& key)
const {
1661 return find(key) != end();
1664 template <
class K = key_type>
1665 bool contains(
const key_arg<K>& key,
size_t hashval)
const {
1666 return find(key, hashval) != end();
1669 template <
class K = key_type>
1670 std::pair<iterator, iterator> equal_range(
const key_arg<K>& key) {
1671 auto it = find(key);
1672 if (it != end())
return {it, std::next(it)};
1675 template <
class K = key_type>
1676 std::pair<const_iterator, const_iterator> equal_range(
1677 const key_arg<K>& key)
const {
1678 auto it = find(key);
1679 if (it != end())
return {it, std::next(it)};
1683 size_t bucket_count()
const {
return capacity_; }
1684 float load_factor()
const {
1685 return capacity_ ?
static_cast<double>(size()) / capacity_ : 0.0;
1687 float max_load_factor()
const {
return 1.0f; }
1688 void max_load_factor(
float) {
1692 hasher hash_function()
const {
return hash_ref(); }
1693 key_equal key_eq()
const {
return eq_ref(); }
1694 allocator_type get_allocator()
const {
return alloc_ref(); }
1696 friend bool operator==(
const raw_hash_set& a,
const raw_hash_set& b) {
1697 if (a.size() != b.size())
return false;
1698 const raw_hash_set* outer = &a;
1699 const raw_hash_set* inner = &b;
1700 if (outer->capacity() > inner->capacity())
1701 std::swap(outer, inner);
1702 for (
const value_type& elem : *outer)
1703 if (!inner->has_element(elem)) return false;
1707 friend bool operator!=(
const raw_hash_set& a,
const raw_hash_set& b) {
1711 friend void swap(raw_hash_set& a,
1712 raw_hash_set& b)
noexcept(
noexcept(a.swap(b))) {
1717 size_t hash(
const K& key)
const {
1718 return HashElement{hash_ref()}(key);
1722 template <
class Container,
typename Enabler>
1727 template <
class K,
class... Args>
1728 const_iterator operator()(
const K& key, Args&&...)
const {
1731 const raw_hash_set& s;
1736 template <
class K,
class... Args>
1737 size_t operator()(
const K& key, Args&&...)
const {
1738 return phmap_mix<sizeof(size_t)>()(h(key));
1746 template <
class K2,
class... Args>
1747 bool operator()(
const K2& lhs, Args&&...)
const {
1748 return eq(lhs, rhs);
1751 const key_equal& eq;
1754 template <
class K,
class... Args>
1755 std::pair<iterator, bool> emplace_decomposable(
const K& key,
size_t hashval,
1758 auto res = find_or_prepare_insert(key, hashval);
1760 emplace_at(res.first, std::forward<Args>(args)...);
1762 return {iterator_at(res.first), res.second};
1765 struct EmplaceDecomposable
1767 template <
class K,
class... Args>
1768 std::pair<iterator, bool> operator()(
const K& key, Args&&... args)
const {
1769 return s.emplace_decomposable(key, s.hash(key), std::forward<Args>(args)...);
1774 template <
bool do_destroy>
1777 template <
class K,
class... Args>
1778 std::pair<iterator, bool> operator()(
const K& key, Args&&...) && {
1779 auto res = s.find_or_prepare_insert(key);
1781 PolicyTraits::transfer(&s.alloc_ref(), s.slots_ + res.first, &slot);
1782 }
else if (do_destroy) {
1783 PolicyTraits::destroy(&s.alloc_ref(), &slot);
1785 return {s.iterator_at(res.first), res.second};
1792 template <
bool do_destroy>
1793 struct InsertSlotWithHash
1795 template <
class K,
class... Args>
1796 std::pair<iterator, bool> operator()(
const K& key, Args&&...) && {
1797 auto res = s.find_or_prepare_insert(key, hashval);
1799 PolicyTraits::transfer(&s.alloc_ref(), s.slots_ + res.first, &slot);
1800 }
else if (do_destroy) {
1801 PolicyTraits::destroy(&s.alloc_ref(), &slot);
1803 return {s.iterator_at(res.first), res.second};
1815 void erase_meta_only(const_iterator it) {
1816 assert(IsFull(*it.inner_.ctrl_) &&
"erasing a dangling iterator");
1818 const size_t index = (size_t)(it.inner_.ctrl_ - ctrl_);
1819 const size_t index_before = (index - Group::kWidth) & capacity_;
1820 const auto empty_after = Group(it.inner_.ctrl_).MatchEmpty();
1821 const auto empty_before = Group(ctrl_ + index_before).MatchEmpty();
1826 bool was_never_full =
1827 empty_before && empty_after &&
1828 static_cast<size_t>(empty_after.TrailingZeros() +
1829 empty_before.LeadingZeros()) < Group::kWidth;
1831 set_ctrl(index, was_never_full ? kEmpty : kDeleted);
1832 growth_left() += was_never_full;
1833 infoz_.RecordErase();
1836 void initialize_slots() {
1838 if (std::is_same<SlotAlloc, std::allocator<slot_type>>::value &&
1839 slots_ ==
nullptr) {
1843 auto layout = MakeLayout(capacity_);
1844 char* mem =
static_cast<char*
>(
1845 Allocate<Layout::Alignment()>(&alloc_ref(), layout.AllocSize()));
1846 ctrl_ =
reinterpret_cast<ctrl_t*
>(layout.template Pointer<0>(mem));
1847 slots_ = layout.template Pointer<1>(mem);
1849 reset_growth_left();
1850 infoz_.RecordStorageChanged(size_, capacity_);
1853 void destroy_slots() {
1854 if (!capacity_)
return;
1855 for (
size_t i = 0; i != capacity_; ++i) {
1856 if (IsFull(ctrl_[i])) {
1857 PolicyTraits::destroy(&alloc_ref(), slots_ + i);
1860 auto layout = MakeLayout(capacity_);
1862 SanitizerUnpoisonMemoryRegion(slots_,
sizeof(slot_type) * capacity_);
1863 Deallocate<Layout::Alignment()>(&alloc_ref(), ctrl_, layout.AllocSize());
1864 ctrl_ = EmptyGroup();
1871 void resize(
size_t new_capacity) {
1872 assert(IsValidCapacity(new_capacity));
1873 auto* old_ctrl = ctrl_;
1874 auto* old_slots = slots_;
1875 const size_t old_capacity = capacity_;
1876 capacity_ = new_capacity;
1879 for (
size_t i = 0; i != old_capacity; ++i) {
1880 if (IsFull(old_ctrl[i])) {
1881 size_t hashval = PolicyTraits::apply(HashElement{hash_ref()},
1882 PolicyTraits::element(old_slots + i));
1883 auto target = find_first_non_full(hashval);
1884 size_t new_i = target.offset;
1885 set_ctrl(new_i, H2(hashval));
1886 PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, old_slots + i);
1890 SanitizerUnpoisonMemoryRegion(old_slots,
1891 sizeof(slot_type) * old_capacity);
1892 auto layout = MakeLayout(old_capacity);
1893 Deallocate<Layout::Alignment()>(&alloc_ref(), old_ctrl,
1894 layout.AllocSize());
1898 void drop_deletes_without_resize() PHMAP_ATTRIBUTE_NOINLINE {
1899 assert(IsValidCapacity(capacity_));
1900 assert(!is_small());
1917 ConvertDeletedToEmptyAndFullToDeleted(ctrl_, capacity_);
1918 typename std::aligned_storage<
sizeof(slot_type),
alignof(slot_type)>::type
1920 slot_type* slot =
reinterpret_cast<slot_type*
>(&raw);
1921 for (
size_t i = 0; i != capacity_; ++i) {
1922 if (!IsDeleted(ctrl_[i]))
continue;
1923 size_t hashval = PolicyTraits::apply(HashElement{hash_ref()},
1924 PolicyTraits::element(slots_ + i));
1925 auto target = find_first_non_full(hashval);
1926 size_t new_i = target.offset;
1931 const auto probe_index = [&](
size_t pos) {
1932 return ((pos - probe(hashval).offset()) & capacity_) / Group::kWidth;
1936 if (PHMAP_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) {
1937 set_ctrl(i, H2(hashval));
1940 if (IsEmpty(ctrl_[new_i])) {
1944 set_ctrl(new_i, H2(hashval));
1945 PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slots_ + i);
1946 set_ctrl(i, kEmpty);
1948 assert(IsDeleted(ctrl_[new_i]));
1949 set_ctrl(new_i, H2(hashval));
1952 PolicyTraits::transfer(&alloc_ref(), slot, slots_ + i);
1953 PolicyTraits::transfer(&alloc_ref(), slots_ + i, slots_ + new_i);
1954 PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slot);
1958 reset_growth_left();
1961 void rehash_and_grow_if_necessary() {
1962 if (capacity_ == 0) {
1964 }
else if (size() <= CapacityToGrowth(capacity()) / 2) {
1966 drop_deletes_without_resize();
1969 resize(capacity_ * 2 + 1);
1973 bool has_element(
const value_type& elem,
size_t hashval)
const {
1974 auto seq = probe(hashval);
1976 Group g{ctrl_ + seq.offset()};
1977 for (
int i : g.Match((h2_t)H2(hashval))) {
1978 if (PHMAP_PREDICT_TRUE(PolicyTraits::element(slots_ + seq.offset((
size_t)i)) ==
1982 if (PHMAP_PREDICT_TRUE(g.MatchEmpty()))
return false;
1984 assert(seq.getindex() < capacity_ &&
"full table!");
1989 bool has_element(
const value_type& elem)
const {
1990 size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, elem);
1991 return has_element(elem, hashval);
2006 size_t probe_length;
2008 FindInfo find_first_non_full(
size_t hashval) {
2009 auto seq = probe(hashval);
2011 Group g{ctrl_ + seq.offset()};
2012 auto mask = g.MatchEmptyOrDeleted();
2014 return {seq.offset((
size_t)mask.LowestBitSet()), seq.getindex()};
2016 assert(seq.getindex() < capacity_ &&
"full table!");
2022 raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) {
2023 raw_hash_set tmp(std::move(that));
2027 raw_hash_set& move_assign(raw_hash_set&& that, std::false_type) {
2028 raw_hash_set tmp(std::move(that), alloc_ref());
2035 std::pair<size_t, bool> find_or_prepare_insert(
const K& key,
size_t hashval) {
2036 auto seq = probe(hashval);
2038 Group g{ctrl_ + seq.offset()};
2039 for (
int i : g.Match((h2_t)H2(hashval))) {
2040 if (PHMAP_PREDICT_TRUE(PolicyTraits::apply(
2041 EqualElement<K>{key, eq_ref()},
2042 PolicyTraits::element(slots_ + seq.offset((
size_t)i)))))
2043 return {seq.offset((
size_t)i),
false};
2045 if (PHMAP_PREDICT_TRUE(g.MatchEmpty()))
break;
2048 return {prepare_insert(hashval),
true};
2052 std::pair<size_t, bool> find_or_prepare_insert(
const K& key) {
2053 return find_or_prepare_insert(key, this->hash(key));
2056 size_t prepare_insert(
size_t hashval) PHMAP_ATTRIBUTE_NOINLINE {
2057 auto target = find_first_non_full(hashval);
2058 if (PHMAP_PREDICT_FALSE(growth_left() == 0 &&
2059 !IsDeleted(ctrl_[target.offset]))) {
2060 rehash_and_grow_if_necessary();
2061 target = find_first_non_full(hashval);
2064 growth_left() -= IsEmpty(ctrl_[target.offset]);
2065 set_ctrl(target.offset, H2(hashval));
2066 infoz_.RecordInsert(hashval, target.probe_length);
2067 return target.offset;
2078 template <
class... Args>
2079 void emplace_at(
size_t i, Args&&... args) {
2080 PolicyTraits::construct(&alloc_ref(), slots_ + i,
2081 std::forward<Args>(args)...);
2083 assert(PolicyTraits::apply(FindElement{*
this}, *iterator_at(i)) ==
2085 "constructed value does not match the lookup key");
2088 iterator iterator_at(
size_t i) {
return {ctrl_ + i, slots_ + i}; }
2089 const_iterator iterator_at(
size_t i)
const {
return {ctrl_ + i, slots_ + i}; }
2092 friend struct RawHashSetTestOnlyAccess;
2094 probe_seq<Group::kWidth> probe(
size_t hashval)
const {
2095 return probe_seq<Group::kWidth>(H1(hashval, ctrl_), capacity_);
2100 std::memset(ctrl_, kEmpty, capacity_ + Group::kWidth);
2101 ctrl_[capacity_] = kSentinel;
2102 SanitizerPoisonMemoryRegion(slots_,
sizeof(slot_type) * capacity_);
2105 void reset_growth_left() {
2106 growth_left() = CapacityToGrowth(capacity()) - size_;
2111 void set_ctrl(
size_t i, ctrl_t h) {
2112 assert(i < capacity_);
2115 SanitizerUnpoisonObject(slots_ + i);
2117 SanitizerPoisonObject(slots_ + i);
2121 ctrl_[((i - Group::kWidth) & capacity_) + 1 +
2122 ((Group::kWidth - 1) & capacity_)] = h;
2125 size_t& growth_left() {
return settings_.template get<0>(); }
2128 template <
class,
class,
class,
class>
class RefSet,
2129 class M,
class P,
class H,
class E,
class A>
2130 friend class parallel_hash_set;
2133 template <
class,
class,
class,
class>
class RefSet,
2134 class M,
class P,
class H,
class E,
class A>
2135 friend class parallel_hash_map;
2151 bool is_small()
const {
return capacity_ < Group::kWidth - 1; }
2153 hasher& hash_ref() {
return settings_.template get<1>(); }
2154 const hasher& hash_ref()
const {
return settings_.template get<1>(); }
2155 key_equal& eq_ref() {
return settings_.template get<2>(); }
2156 const key_equal& eq_ref()
const {
return settings_.template get<2>(); }
2157 allocator_type& alloc_ref() {
return settings_.template get<3>(); }
2158 const allocator_type& alloc_ref()
const {
2159 return settings_.template get<3>();
2165 ctrl_t* ctrl_ = EmptyGroup();
2166 slot_type* slots_ =
nullptr;
2168 size_t capacity_ = 0;
2169 HashtablezInfoHandle infoz_;
2171 key_equal, allocator_type>
2172 settings_{0, hasher{}, key_equal{}, allocator_type{}};
2360 using PolicyTraits = hash_policy_traits<Policy>;
2362 KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
2364 static_assert(N <= 12,
"N = 12 means 4096 hash tables!");
2365 constexpr static size_t num_tables = 1 << N;
2366 constexpr static size_t mask = num_tables - 1;
2369 using EmbeddedSet = RefSet<Policy, Hash, Eq, Alloc>;
2370 using EmbeddedIterator=
typename EmbeddedSet::iterator;
2371 using EmbeddedConstIterator=
typename EmbeddedSet::const_iterator;
2372 using constructor =
typename EmbeddedSet::constructor;
2373 using init_type =
typename PolicyTraits::init_type;
2374 using key_type =
typename PolicyTraits::key_type;
2375 using slot_type =
typename PolicyTraits::slot_type;
2376 using allocator_type = Alloc;
2377 using size_type = size_t;
2378 using difference_type = ptrdiff_t;
2380 using key_equal = Eq;
2381 using policy_type = Policy;
2382 using value_type =
typename PolicyTraits::value_type;
2383 using reference = value_type&;
2384 using const_reference =
const value_type&;
2386 allocator_type>::template rebind_traits<value_type>::pointer;
2388 allocator_type>::template rebind_traits<value_type>::const_pointer;
2396 using key_arg =
typename KeyArgImpl::template type<K, key_type>;
2404 bool operator==(
const Inner& o)
const
2406 typename Lockable::SharedLocks l(
const_cast<Inner &
>(*
this),
const_cast<Inner &
>(o));
2407 return set_ == o.set_;
2416 auto KeyTypeCanBeHashed(
const Hash& h,
const key_type& k) ->
decltype(h(k));
2417 auto KeyTypeCanBeEq(
const Eq& eq,
const key_type& k) ->
decltype(eq(k, k));
2421 static_assert(std::is_lvalue_reference<reference>::value,
2422 "Policy::element() must return a reference");
2424 template <
typename T>
2425 struct SameAsElementReference : std::is_same<
2426 typename std::remove_cv<typename std::remove_reference<reference>::type>::type,
2427 typename std::remove_cv<typename std::remove_reference<T>::type>::type> {};
2436 using RequiresInsertable =
typename std::enable_if<
2438 SameAsElementReference<T>>::value,
2444 using RequiresNotInit =
2445 typename std::enable_if<!std::is_same<T, init_type>::value,
int>::type;
2447 template <
class... Ts>
2451 static_assert(std::is_same<pointer, value_type*>::value,
2452 "Allocators with custom pointer types are not supported");
2453 static_assert(std::is_same<const_pointer, const value_type*>::value,
2454 "Allocators with custom pointer types are not supported");
2462 using iterator_category = std::forward_iterator_tag;
2463 using value_type =
typename parallel_hash_set::value_type;
2465 phmap::conditional_t<PolicyTraits::constant_iterators::value,
2466 const value_type&, value_type&>;
2467 using pointer = phmap::remove_reference_t<reference>*;
2468 using difference_type =
typename parallel_hash_set::difference_type;
2470 using EmbeddedSet =
typename parallel_hash_set::EmbeddedSet;
2471 using EmbeddedIterator =
typename EmbeddedSet::iterator;
2475 reference operator*()
const {
return *it_; }
2476 pointer operator->()
const {
return &operator*(); }
2493 return a.inner_ == b.inner_ && (!a.inner_ || a.it_ == b.it_);
2501 iterator(Inner *inner, Inner *inner_end,
const EmbeddedIterator& it) :
2502 inner_(inner), inner_end_(inner_end), it_(it) {
2504 it_end_ = inner->set_.end();
2508 while (it_ == it_end_) {
2510 if (inner_ == inner_end_) {
2515 it_ = inner_->set_.begin();
2516 it_end_ = inner_->set_.end();
2521 Inner *inner_ =
nullptr;
2522 Inner *inner_end_ =
nullptr;
2523 EmbeddedIterator it_, it_end_;
2532 using iterator_category =
typename iterator::iterator_category;
2533 using value_type =
typename parallel_hash_set::value_type;
2534 using reference =
typename parallel_hash_set::const_reference;
2535 using pointer =
typename parallel_hash_set::const_pointer;
2536 using difference_type =
typename parallel_hash_set::difference_type;
2543 reference operator*()
const {
return *(iter_); }
2544 pointer operator->()
const {
return iter_.operator->(); }
2553 return a.iter_ == b.iter_;
2560 const_iterator(
const Inner *inner,
const Inner *inner_end,
const EmbeddedIterator& it)
2561 : iter_(
const_cast<Inner**
>(inner),
2562 const_cast<Inner**
>(inner_end),
2563 const_cast<EmbeddedIterator*
>(it)) {}
2568 using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>;
2569 using insert_return_type = InsertReturnType<iterator, node_type>;
2574 std::is_nothrow_default_constructible<
hasher>::value&&
2575 std::is_nothrow_default_constructible<key_equal>::value&&
2576 std::is_nothrow_default_constructible<allocator_type>::value) {}
2579 const hasher& hash_param = hasher(),
2580 const key_equal& eq = key_equal(),
2581 const allocator_type& alloc = allocator_type()) {
2582 for (
auto& inner : sets_)
2583 inner.set_ = EmbeddedSet(bucket_cnt / N, hash_param, eq, alloc);
2586 parallel_hash_set(
size_t bucket_cnt,
2587 const hasher& hash_param,
2588 const allocator_type& alloc)
2589 : parallel_hash_set(bucket_cnt, hash_param, key_equal(), alloc) {}
2591 parallel_hash_set(
size_t bucket_cnt,
const allocator_type& alloc)
2592 : parallel_hash_set(bucket_cnt, hasher(), key_equal(), alloc) {}
2594 explicit parallel_hash_set(
const allocator_type& alloc)
2595 : parallel_hash_set(0, hasher(), key_equal(), alloc) {}
2597 template <
class InputIter>
2598 parallel_hash_set(InputIter first, InputIter last,
size_t bucket_cnt = 0,
2599 const hasher& hash_param = hasher(),
const key_equal& eq = key_equal(),
2600 const allocator_type& alloc = allocator_type())
2601 : parallel_hash_set(bucket_cnt, hash_param, eq, alloc) {
2602 insert(first, last);
2605 template <
class InputIter>
2606 parallel_hash_set(InputIter first, InputIter last,
size_t bucket_cnt,
2607 const hasher& hash_param,
const allocator_type& alloc)
2608 : parallel_hash_set(first, last, bucket_cnt, hash_param, key_equal(), alloc) {}
2610 template <
class InputIter>
2611 parallel_hash_set(InputIter first, InputIter last,
size_t bucket_cnt,
2612 const allocator_type& alloc)
2613 : parallel_hash_set(first, last, bucket_cnt, hasher(), key_equal(), alloc) {}
2615 template <
class InputIter>
2616 parallel_hash_set(InputIter first, InputIter last,
const allocator_type& alloc)
2617 : parallel_hash_set(first, last, 0, hasher(), key_equal(), alloc) {}
2641 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
2642 parallel_hash_set(std::initializer_list<T> init,
size_t bucket_cnt = 0,
2643 const hasher& hash_param = hasher(),
const key_equal& eq = key_equal(),
2644 const allocator_type& alloc = allocator_type())
2645 : parallel_hash_set(init.begin(), init.end(), bucket_cnt, hash_param, eq, alloc) {}
2647 parallel_hash_set(std::initializer_list<init_type> init,
size_t bucket_cnt = 0,
2648 const hasher& hash_param = hasher(),
const key_equal& eq = key_equal(),
2649 const allocator_type& alloc = allocator_type())
2650 : parallel_hash_set(init.begin(), init.end(), bucket_cnt, hash_param, eq, alloc) {}
2652 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
2653 parallel_hash_set(std::initializer_list<T> init,
size_t bucket_cnt,
2654 const hasher& hash_param,
const allocator_type& alloc)
2655 : parallel_hash_set(init, bucket_cnt, hash_param, key_equal(), alloc) {}
2657 parallel_hash_set(std::initializer_list<init_type> init,
size_t bucket_cnt,
2658 const hasher& hash_param,
const allocator_type& alloc)
2659 : parallel_hash_set(init, bucket_cnt, hash_param, key_equal(), alloc) {}
2661 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
2662 parallel_hash_set(std::initializer_list<T> init,
size_t bucket_cnt,
2663 const allocator_type& alloc)
2664 : parallel_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {}
2666 parallel_hash_set(std::initializer_list<init_type> init,
size_t bucket_cnt,
2667 const allocator_type& alloc)
2668 : parallel_hash_set(init, bucket_cnt, hasher(), key_equal(), alloc) {}
2670 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
2671 parallel_hash_set(std::initializer_list<T> init,
const allocator_type& alloc)
2672 : parallel_hash_set(init, 0, hasher(), key_equal(), alloc) {}
2674 parallel_hash_set(std::initializer_list<init_type> init,
2675 const allocator_type& alloc)
2676 : parallel_hash_set(init, 0, hasher(), key_equal(), alloc) {}
2678 parallel_hash_set(
const parallel_hash_set& that)
2679 : parallel_hash_set(that, AllocTraits::select_on_container_copy_construction(
2680 that.alloc_ref())) {}
2682 parallel_hash_set(
const parallel_hash_set& that,
const allocator_type& a)
2683 : parallel_hash_set(0, that.hash_ref(), that.eq_ref(), a) {
2684 for (
size_t i=0; i<num_tables; ++i)
2685 sets_[i].set_ = { that.sets_[i].set_, a };
2688 parallel_hash_set(parallel_hash_set&& that)
noexcept(
2689 std::is_nothrow_copy_constructible<hasher>::value&&
2690 std::is_nothrow_copy_constructible<key_equal>::value&&
2691 std::is_nothrow_copy_constructible<allocator_type>::value)
2692 : parallel_hash_set(std::move(that), that.alloc_ref()) {
2695 parallel_hash_set(parallel_hash_set&& that,
const allocator_type& a)
2697 for (
size_t i=0; i<num_tables; ++i)
2698 sets_[i].set_ = { std::move(that.sets_[i]).set_, a };
2701 parallel_hash_set& operator=(
const parallel_hash_set& that) {
2702 for (
size_t i=0; i<num_tables; ++i)
2703 sets_[i].set_ = that.sets_[i].set_;
2707 parallel_hash_set& operator=(parallel_hash_set&& that)
noexcept(
2709 std::is_nothrow_move_assignable<hasher>::value &&
2710 std::is_nothrow_move_assignable<key_equal>::value) {
2711 for (
size_t i=0; i<num_tables; ++i)
2712 sets_[i].set_ = std::move(that.sets_[i].set_);
2716 ~parallel_hash_set() {}
2719 auto it = iterator(&sets_[0], &sets_[0] + num_tables, sets_[0].set_.begin());
2724 iterator end() {
return iterator(); }
2725 const_iterator begin()
const {
return const_cast<parallel_hash_set *
>(
this)->begin(); }
2726 const_iterator end()
const {
return const_cast<parallel_hash_set *
>(
this)->end(); }
2727 const_iterator cbegin()
const {
return begin(); }
2728 const_iterator cend()
const {
return end(); }
2730 bool empty()
const {
return !size(); }
2732 size_t size()
const {
2734 for (
const auto& inner : sets_)
2735 sz += inner.set_.size();
2739 size_t capacity()
const {
2741 for (
const auto& inner : sets_)
2742 c += inner.set_.capacity();
2746 size_t max_size()
const {
return (std::numeric_limits<size_t>::max)(); }
2748 PHMAP_ATTRIBUTE_REINITIALIZES
void clear() {
2749 for (
auto& inner : sets_)
2751 typename Lockable::UniqueLock m(inner);
2758 void clear(std::size_t submap_index) {
2759 Inner& inner = sets_[submap_index];
2760 typename Lockable::UniqueLock m(inner);
2770 template <
class T, RequiresInsertable<T> = 0,
2771 typename std::enable_if<IsDecomposable<T>::value,
int>::type = 0,
2773 std::pair<iterator, bool> insert(T&& value) {
2774 return emplace(std::forward<T>(value));
2793 class T, RequiresInsertable<T> = 0,
2794 typename std::enable_if<IsDecomposable<const T&>::value,
int>::type = 0>
2795 std::pair<iterator, bool> insert(
const T& value) {
2796 return emplace(value);
2805 std::pair<iterator, bool> insert(init_type&& value) {
2806 return emplace(std::move(value));
2809 template <
class T, RequiresInsertable<T> = 0,
2810 typename std::enable_if<IsDecomposable<T>::value,
int>::type = 0,
2812 iterator insert(const_iterator, T&& value) {
2813 return insert(std::forward<T>(value)).first;
2821 class T, RequiresInsertable<T> = 0,
2822 typename std::enable_if<IsDecomposable<const T&>::value,
int>::type = 0>
2823 iterator insert(const_iterator,
const T& value) {
2824 return insert(value).first;
2827 iterator insert(const_iterator, init_type&& value) {
2828 return insert(std::move(value)).first;
2831 template <
class InputIt>
2832 void insert(InputIt first, InputIt last) {
2833 for (; first != last; ++first) insert(*first);
2836 template <
class T, RequiresNotInit<T> = 0, RequiresInsertable<const T&> = 0>
2837 void insert(std::initializer_list<T> ilist) {
2838 insert(ilist.begin(), ilist.end());
2841 void insert(std::initializer_list<init_type> ilist) {
2842 insert(ilist.begin(), ilist.end());
2845 insert_return_type insert(node_type&& node) {
2847 return {end(),
false, node_type()};
2848 auto& key = node.key();
2849 size_t hashval = this->hash(key);
2850 Inner& inner = sets_[subidx(hashval)];
2851 auto& set = inner.set_;
2853 typename Lockable::UniqueLock m(inner);
2854 auto res = set.insert(std::move(node), hashval);
2855 return { make_iterator(&inner, res.position),
2857 res.inserted ? node_type() : std::move(res.node) };
2860 iterator insert(const_iterator, node_type&& node) {
2861 return insert(std::move(node)).first;
2866 template <
class Key,
class... Args>
2867 Key operator()(Key&& k,
const Args&...)
const {
2868 return std::forward<Key>(k);
2877 template <
class K,
class... Args>
2878 std::pair<iterator, bool> emplace_decomposable_with_hash(
const K& key,
size_t hashval, Args&&... args)
2880 Inner& inner = sets_[subidx(hashval)];
2881 auto& set = inner.set_;
2882 typename Lockable::UniqueLock m(inner);
2883 return make_rv(&inner, set.emplace_decomposable(key, hashval, std::forward<Args>(args)...));
2888 template <
class K,
class... Args>
2889 std::pair<iterator, bool> operator()(
const K& key, Args&&... args)
const {
2890 return s.emplace_decomposable_with_hash(key, hashval, std::forward<Args>(args)...);
2906 template <
class... Args,
typename std::enable_if<
2907 IsDecomposable<Args...>::value,
int>::type = 0>
2908 std::pair<iterator, bool> emplace_with_hash(
size_t hashval, Args&&... args) {
2910 std::forward<Args>(args)...);
2917 template <
class... Args,
typename std::enable_if<
2918 !IsDecomposable<Args...>::value,
int>::type = 0>
2919 std::pair<iterator, bool> emplace_with_hash(
size_t hashval, Args&&... args) {
2920 typename std::aligned_storage<
sizeof(slot_type),
alignof(slot_type)>::type raw;
2921 slot_type* slot =
reinterpret_cast<slot_type*
>(&raw);
2923 PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
2924 const auto& elem = PolicyTraits::element(slot);
2925 Inner& inner = sets_[subidx(hashval)];
2926 auto& set = inner.set_;
2927 typename Lockable::UniqueLock m(inner);
2928 typename EmbeddedSet::template InsertSlotWithHash<true> f {
2929 inner, std::move(*slot), hashval};
2930 return make_rv(PolicyTraits::apply(f, elem));
2933 template <
class... Args>
2934 iterator emplace_hint_with_hash(
size_t hashval, const_iterator, Args&&... args) {
2935 return emplace_with_hash(hashval, std::forward<Args>(args)...).first;
2938 template <
class K = key_type,
class F>
2939 iterator lazy_emplace_with_hash(
size_t hashval,
const key_arg<K>& key, F&& f) {
2940 Inner& inner = sets_[subidx(hashval)];
2941 auto& set = inner.set_;
2942 typename Lockable::UniqueLock m(inner);
2943 return make_iterator(&inner, set.lazy_emplace_with_hash(key, hashval, std::forward<F>(f)));
2950 template <
class K,
class... Args>
2951 std::pair<iterator, bool> emplace_decomposable(
const K& key, Args&&... args)
2953 size_t hashval = this->hash(key);
2954 Inner& inner = sets_[subidx(hashval)];
2955 auto& set = inner.set_;
2956 typename Lockable::UniqueLock m(inner);
2957 return make_rv(&inner, set.emplace_decomposable(key, hashval, std::forward<Args>(args)...));
2962 template <
class K,
class... Args>
2963 std::pair<iterator, bool> operator()(
const K& key, Args&&... args)
const {
2964 return s.emplace_decomposable(key, std::forward<Args>(args)...);
2979 template <
class... Args,
typename std::enable_if<
2980 IsDecomposable<Args...>::value,
int>::type = 0>
2981 std::pair<iterator, bool> emplace(Args&&... args) {
2983 std::forward<Args>(args)...);
2990 template <
class... Args,
typename std::enable_if<
2991 !IsDecomposable<Args...>::value,
int>::type = 0>
2992 std::pair<iterator, bool> emplace(Args&&... args) {
2993 typename std::aligned_storage<
sizeof(slot_type),
alignof(slot_type)>::type raw;
2994 slot_type* slot =
reinterpret_cast<slot_type*
>(&raw);
2995 size_t hashval = this->hash(PolicyTraits::key(slot));
2997 PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
2998 const auto& elem = PolicyTraits::element(slot);
2999 Inner& inner = sets_[subidx(hashval)];
3000 auto& set = inner.set_;
3001 typename Lockable::UniqueLock m(inner);
3002 typename EmbeddedSet::template InsertSlotWithHash<true> f {
3003 inner, std::move(*slot), hashval};
3004 return make_rv(PolicyTraits::apply(f, elem));
3007 template <
class... Args>
3008 iterator emplace_hint(const_iterator, Args&&... args) {
3009 return emplace(std::forward<Args>(args)...).first;
3012 iterator make_iterator(Inner* inner,
const EmbeddedIterator it)
3014 if (it == inner->set_.end())
3016 return iterator(inner, &sets_[0] + num_tables, it);
3019 std::pair<iterator, bool> make_rv(Inner* inner,
3020 const std::pair<EmbeddedIterator, bool>& res)
3022 return {iterator(inner, &sets_[0] + num_tables, res.first), res.second};
3025 template <
class K = key_type,
class F>
3026 iterator lazy_emplace(
const key_arg<K>& key, F&& f) {
3027 auto hashval = this->hash(key);
3028 Inner& inner = sets_[subidx(hashval)];
3029 auto& set = inner.set_;
3030 typename Lockable::UniqueLock m(inner);
3031 return make_iterator(&inner, set.lazy_emplace_with_hash(key, hashval, std::forward<F>(f)));
3034 template <
class K = key_type,
class FExists,
class FEmplace>
3035 bool lazy_emplace_l(
const key_arg<K>& key, FExists&& fExists, FEmplace&& fEmplace) {
3036 typename Lockable::UniqueLock m;
3037 auto res = this->find_or_prepare_insert(key, m);
3038 Inner* inner = std::get<0>(res);
3039 if (std::get<2>(res))
3040 inner->set_.lazy_emplace_at(std::get<1>(res), std::forward<FEmplace>(fEmplace));
3042 auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res)));
3043 std::forward<FExists>(fExists)(Policy::value(&*it));
3045 return std::get<2>(res);
3058 template <
class K = key_type>
3059 size_type erase(
const key_arg<K>& key) {
3060 auto hashval = this->hash(key);
3061 Inner& inner = sets_[subidx(hashval)];
3062 auto& set = inner.set_;
3063 typename Lockable::UpgradeLock m(inner);
3064 auto it = set.find(key, hashval);
3065 if (it == set.end())
3068 typename Lockable::UpgradeToUnique unique(m);
3074 iterator erase(const_iterator cit) {
return erase(cit.iter_); }
3089 void _erase(iterator it) {
3090 assert(it.inner_ !=
nullptr);
3091 it.inner_->set_._erase(it.it_);
3093 void _erase(const_iterator cit) { _erase(cit.iter_); }
3098 iterator erase(iterator it) { _erase(it++);
return it; }
3100 iterator erase(const_iterator first, const_iterator last) {
3101 while (first != last) {
3110 template <
typename E = Eq>
3111 void merge(parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, E, Alloc>& src) {
3112 assert(
this != &src);
3115 for (
size_t i=0; i<num_tables; ++i)
3117 typename Lockable::UniqueLocks l(sets_[i], src.sets_[i]);
3118 sets_[i].set_.merge(src.sets_[i].set_);
3123 template <
typename E = Eq>
3124 void merge(parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, E, Alloc>&& src) {
3128 node_type extract(const_iterator position) {
3129 return position.iter_.inner_->set_.extract(EmbeddedConstIterator(position.iter_.it_));
3134 typename std::enable_if<!std::is_same<K, iterator>::value,
int>::type = 0>
3135 node_type extract(
const key_arg<K>& key) {
3136 auto it = find(key);
3137 return it == end() ? node_type() : extract(const_iterator{it});
3140 void swap(parallel_hash_set& that)
noexcept(
3141 IsNoThrowSwappable<EmbeddedSet>() &&
3142 (!AllocTraits::propagate_on_container_swap::value ||
3143 IsNoThrowSwappable<allocator_type>())) {
3145 for (
size_t i=0; i<num_tables; ++i)
3147 typename Lockable::UniqueLocks l(sets_[i], that.sets_[i]);
3148 swap(sets_[i].set_, that.sets_[i].set_);
3152 void rehash(
size_t n) {
3153 size_t nn = n / num_tables;
3154 for (
auto& inner : sets_)
3156 typename Lockable::UniqueLock m(inner);
3157 inner.set_.rehash(nn);
3161 void reserve(
size_t n)
3163 size_t target = GrowthToLowerboundCapacity(n);
3164 size_t normalized = 16 * NormalizeCapacity(n / num_tables);
3165 rehash(normalized > target ? normalized : target);
3178 template <
class K = key_type>
3179 size_t count(
const key_arg<K>& key)
const {
3180 return find(key) == end() ? 0 : 1;
3189 template <
class K = key_type>
3190 void prefetch(
const key_arg<K>& key)
const {
3192 size_t hashval = this->hash(key);
3193 const Inner& inner = sets_[subidx(hashval)];
3194 const auto& set = inner.set_;
3195 typename Lockable::SharedLock m(
const_cast<Inner&
>(inner));
3196 set.prefetch_hash(hashval);
3207 template <
class K = key_type>
3208 iterator find(
const key_arg<K>& key,
size_t hashval) {
3209 typename Lockable::SharedLock m;
3210 return find(key, hashval, m);
3213 template <
class K = key_type>
3214 iterator find(
const key_arg<K>& key) {
3215 return find(key, this->hash(key));
3218 template <
class K = key_type>
3219 const_iterator find(
const key_arg<K>& key,
size_t hashval)
const {
3220 return const_cast<parallel_hash_set*
>(
this)->find(key, hashval);
3223 template <
class K = key_type>
3224 const_iterator find(
const key_arg<K>& key)
const {
3225 return find(key, this->hash(key));
3228 template <
class K = key_type>
3229 bool contains(
const key_arg<K>& key)
const {
3230 return find(key) != end();
3233 template <
class K = key_type>
3234 bool contains(
const key_arg<K>& key,
size_t hashval)
const {
3235 return find(key, hashval) != end();
3238 template <
class K = key_type>
3239 std::pair<iterator, iterator> equal_range(
const key_arg<K>& key) {
3240 auto it = find(key);
3241 if (it != end())
return {it, std::next(it)};
3245 template <
class K = key_type>
3246 std::pair<const_iterator, const_iterator> equal_range(
3247 const key_arg<K>& key)
const {
3248 auto it = find(key);
3249 if (it != end())
return {it, std::next(it)};
3253 size_t bucket_count()
const {
3255 for (
const auto& inner : sets_)
3257 typename Lockable::SharedLock m(
const_cast<Inner&
>(inner));
3258 sz += inner.set_.bucket_count();
3263 float load_factor()
const {
3264 size_t _capacity = bucket_count();
3265 return _capacity ?
static_cast<float>(
static_cast<double>(size()) / _capacity) : 0;
3268 float max_load_factor()
const {
return 1.0f; }
3269 void max_load_factor(
float) {
3273 hasher hash_function()
const {
return hash_ref(); }
3274 key_equal key_eq()
const {
return eq_ref(); }
3275 allocator_type get_allocator()
const {
return alloc_ref(); }
3277 friend bool operator==(
const parallel_hash_set& a,
const parallel_hash_set& b) {
3278 return std::equal(a.sets_.begin(), a.sets_.end(), b.sets_.begin());
3281 friend bool operator!=(
const parallel_hash_set& a,
const parallel_hash_set& b) {
3285 friend void swap(parallel_hash_set& a,
3286 parallel_hash_set& b)
noexcept(
noexcept(a.swap(b))) {
3291 size_t hash(
const K& key)
const {
3292 return HashElement{hash_ref()}(key);
3295#ifndef PHMAP_NON_DETERMINISTIC
3296 template<
typename OutputArchive>
3297 bool dump(OutputArchive& ar)
const;
3299 template<
typename InputArchive>
3300 bool load(InputArchive& ar);
3304 template <
class Container,
typename Enabler>
3309 template <
class K,
class... Args>
3310 const_iterator operator()(
const K& key, Args&&...)
const {
3313 const parallel_hash_set& s;
3318 template <
class K,
class... Args>
3319 size_t operator()(
const K& key, Args&&...)
const {
3320 return phmap_mix<sizeof(size_t)>()(h(key));
3328 template <
class K2,
class... Args>
3329 bool operator()(
const K2& lhs, Args&&...)
const {
3330 return eq(lhs, rhs);
3333 const key_equal& eq;
3341 void erase_meta_only(const_iterator cit) {
3342 auto &it = cit.iter_;
3343 assert(it.set_ !=
nullptr);
3344 it.set_.erase_meta_only(const_iterator(it.it_));
3347 void drop_deletes_without_resize() PHMAP_ATTRIBUTE_NOINLINE {
3348 for (
auto& inner : sets_)
3350 typename Lockable::UniqueLock m(inner);
3351 inner.set_.drop_deletes_without_resize();
3355 bool has_element(
const value_type& elem)
const {
3356 size_t hashval = PolicyTraits::apply(HashElement{hash_ref()}, elem);
3357 Inner& inner = sets_[subidx(hashval)];
3358 auto& set = inner.set_;
3359 typename Lockable::SharedLock m(
const_cast<Inner&
>(inner));
3360 return set.has_element(elem, hashval);
3365 parallel_hash_set& move_assign(parallel_hash_set&& that, std::true_type) {
3366 parallel_hash_set tmp(std::move(that));
3371 parallel_hash_set& move_assign(parallel_hash_set&& that, std::false_type) {
3372 parallel_hash_set tmp(std::move(that), alloc_ref());
3378 template <
class K = key_type,
class L =
typename Lockable::SharedLock>
3379 iterator find(
const key_arg<K>& key,
size_t hashval, L &mutexlock) {
3380 Inner& inner = sets_[subidx(hashval)];
3381 auto& set = inner.set_;
3382 mutexlock = std::move(L(inner));
3383 auto it = set.find(key, hashval);
3384 return make_iterator(&inner, it);
3388 std::tuple<Inner*, size_t, bool>
3389 find_or_prepare_insert_with_hash(
size_t hashval,
const K& key,
typename Lockable::UniqueLock &mutexlock) {
3390 Inner& inner = sets_[subidx(hashval)];
3391 auto& set = inner.set_;
3392 mutexlock = std::move(
typename Lockable::UniqueLock(inner));
3393 auto p = set.find_or_prepare_insert(key, hashval);
3394 return std::make_tuple(&inner, p.first, p.second);
3398 std::tuple<Inner*, size_t, bool>
3399 find_or_prepare_insert(
const K& key,
typename Lockable::UniqueLock &mutexlock) {
3400 return find_or_prepare_insert_with_hash<K>(this->hash(key), key, mutexlock);
3403 iterator iterator_at(Inner *inner,
3404 const EmbeddedIterator& it) {
3405 return {inner, &sets_[0] + num_tables, it};
3407 const_iterator iterator_at(Inner *inner,
3408 const EmbeddedIterator& it)
const {
3409 return {inner, &sets_[0] + num_tables, it};
3412 static size_t subidx(
size_t hashval) {
3413 return ((hashval >> 8) ^ (hashval >> 16) ^ (hashval >> 24)) & mask;
3416 static size_t subcnt() {
3421 friend struct RawHashSetTestOnlyAccess;
3423 size_t growth_left() {
3425 for (
const auto& set : sets_)
3426 sz += set.growth_left();
3430 hasher& hash_ref() {
return sets_[0].set_.hash_ref(); }
3431 const hasher& hash_ref()
const {
return sets_[0].set_.hash_ref(); }
3432 key_equal& eq_ref() {
return sets_[0].set_.eq_ref(); }
3433 const key_equal& eq_ref()
const {
return sets_[0].set_.eq_ref(); }
3434 allocator_type& alloc_ref() {
return sets_[0].set_.alloc_ref(); }
3435 const allocator_type& alloc_ref()
const {
3436 return sets_[0].set_.alloc_ref();
3440 std::array<Inner, num_tables> sets_;
3455 using MappedReference =
decltype(P::value(
3456 std::addressof(std::declval<typename parallel_hash_map::reference>())));
3460 using MappedConstReference =
decltype(P::value(
3461 std::addressof(std::declval<typename parallel_hash_map::const_reference>())));
3464 KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
3466 using Base =
typename parallel_hash_map::parallel_hash_set;
3470 using key_type =
typename Policy::key_type;
3471 using mapped_type =
typename Policy::mapped_type;
3473 using key_arg =
typename KeyArgImpl::template type<K, key_type>;
3475 static_assert(!std::is_reference<key_type>::value,
"");
3478 static_assert(!std::is_reference<mapped_type>::value,
"");
3480 using iterator =
typename parallel_hash_map::parallel_hash_set::iterator;
3481 using const_iterator =
typename parallel_hash_map::parallel_hash_set::const_iterator;
3485#ifdef __INTEL_COMPILER
3486 using Base::parallel_hash_set;
3488 using parallel_hash_map::parallel_hash_set::parallel_hash_set;
3498 template <
class K = key_type,
class V = mapped_type, K* =
nullptr,
3500 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v) {
3501 return insert_or_assign_impl(std::forward<K>(k), std::forward<V>(v));
3504 template <
class K = key_type,
class V = mapped_type, K* =
nullptr>
3505 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k,
const V& v) {
3506 return insert_or_assign_impl(std::forward<K>(k), v);
3509 template <
class K = key_type,
class V = mapped_type, V* =
nullptr>
3510 std::pair<iterator, bool> insert_or_assign(
const key_arg<K>& k, V&& v) {
3511 return insert_or_assign_impl(k, std::forward<V>(v));
3514 template <
class K = key_type,
class V = mapped_type>
3515 std::pair<iterator, bool> insert_or_assign(
const key_arg<K>& k,
const V& v) {
3516 return insert_or_assign_impl(k, v);
3519 template <
class K = key_type,
class V = mapped_type, K* =
nullptr,
3521 iterator insert_or_assign(const_iterator, key_arg<K>&& k, V&& v) {
3522 return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
3525 template <
class K = key_type,
class V = mapped_type, K* =
nullptr>
3526 iterator insert_or_assign(const_iterator, key_arg<K>&& k,
const V& v) {
3527 return insert_or_assign(std::forward<K>(k), v).first;
3530 template <
class K = key_type,
class V = mapped_type, V* =
nullptr>
3531 iterator insert_or_assign(const_iterator,
const key_arg<K>& k, V&& v) {
3532 return insert_or_assign(k, std::forward<V>(v)).first;
3535 template <
class K = key_type,
class V = mapped_type>
3536 iterator insert_or_assign(const_iterator,
const key_arg<K>& k,
const V& v) {
3537 return insert_or_assign(k, v).first;
3540 template <
class K = key_type,
class... Args,
3541 typename std::enable_if<
3542 !std::is_convertible<K, const_iterator>::value,
int>::type = 0,
3544 std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args) {
3545 return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
3548 template <
class K = key_type,
class... Args,
3549 typename std::enable_if<
3550 !std::is_convertible<K, const_iterator>::value,
int>::type = 0>
3551 std::pair<iterator, bool> try_emplace(
const key_arg<K>& k, Args&&... args) {
3552 return try_emplace_impl(k, std::forward<Args>(args)...);
3555 template <
class K = key_type,
class... Args, K* =
nullptr>
3556 iterator try_emplace(const_iterator, key_arg<K>&& k, Args&&... args) {
3557 return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
3560 template <
class K = key_type,
class... Args>
3561 iterator try_emplace(const_iterator,
const key_arg<K>& k, Args&&... args) {
3562 return try_emplace(k, std::forward<Args>(args)...).first;
3565 template <
class K = key_type,
class P = Policy>
3566 MappedReference<P> at(
const key_arg<K>& key) {
3567 auto it = this->find(key);
3568 if (it == this->end())
3569 phmap::base_internal::ThrowStdOutOfRange(
"phmap at(): lookup non-existent key");
3570 return Policy::value(&*it);
3573 template <
class K = key_type,
class P = Policy>
3574 MappedConstReference<P> at(
const key_arg<K>& key)
const {
3575 auto it = this->find(key);
3576 if (it == this->end())
3577 phmap::base_internal::ThrowStdOutOfRange(
"phmap at(): lookup non-existent key");
3578 return Policy::value(&*it);
3583 template <
class K = key_type,
class... Args,
3584 typename std::enable_if<
3585 !std::is_convertible<K, const_iterator>::value,
int>::type = 0,
3587 std::pair<iterator, bool> try_emplace_with_hash(
size_t hashval, key_arg<K>&& k, Args&&... args) {
3588 return try_emplace_impl_with_hash(hashval, std::forward<K>(k), std::forward<Args>(args)...);
3591 template <
class K = key_type,
class... Args,
3592 typename std::enable_if<
3593 !std::is_convertible<K, const_iterator>::value,
int>::type = 0>
3594 std::pair<iterator, bool> try_emplace_with_hash(
size_t hashval,
const key_arg<K>& k, Args&&... args) {
3595 return try_emplace_impl_with_hash(hashval, k, std::forward<Args>(args)...);
3598 template <
class K = key_type,
class... Args, K* =
nullptr>
3599 iterator try_emplace_with_hash(
size_t hashval, const_iterator, key_arg<K>&& k, Args&&... args) {
3600 return try_emplace_with_hash(hashval, std::forward<K>(k), std::forward<Args>(args)...).first;
3603 template <
class K = key_type,
class... Args>
3604 iterator try_emplace_with_hash(
size_t hashval, const_iterator,
const key_arg<K>& k, Args&&... args) {
3605 return try_emplace_with_hash(hashval, k, std::forward<Args>(args)...).first;
3611 template <
class K = key_type,
class F>
3612 bool if_contains(
const key_arg<K>& key, F&& f)
const {
3614 modify_if_impl<K, F, typename Lockable::SharedLock>(key, std::forward<F>(f));
3620 template <
class K = key_type,
class F>
3621 bool modify_if(
const key_arg<K>& key, F&& f) {
3622 return modify_if_impl<K, F, typename Lockable::UniqueLock>(key, std::forward<F>(f));
3631 template <
class K = key_type,
class F>
3632 bool erase_if(
const key_arg<K>& key, F&& f) {
3633 return erase_if_impl<K, F, typename Lockable::UniqueLock>(key, std::forward<F>(f));
3642 template <
class K = key_type,
class F,
class... Args>
3643 bool try_emplace_l(K&& k, F&& f, Args&&... args) {
3644 typename Lockable::UniqueLock m;
3645 auto res = this->find_or_prepare_insert(k, m);
3646 typename Base::Inner *inner = std::get<0>(res);
3647 if (std::get<2>(res))
3648 inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct,
3649 std::forward_as_tuple(std::forward<K>(k)),
3650 std::forward_as_tuple(std::forward<Args>(args)...));
3652 auto it = this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res)));
3653 std::forward<F>(f)(Policy::value(&*it));
3655 return std::get<2>(res);
3660 template <
class K = key_type,
class P = Policy, K* =
nullptr>
3661 MappedReference<P> operator[](key_arg<K>&& key) {
3662 return Policy::value(&*try_emplace(std::forward<K>(key)).first);
3665 template <
class K = key_type,
class P = Policy>
3666 MappedReference<P> operator[](
const key_arg<K>& key) {
3667 return Policy::value(&*try_emplace(key).first);
3671 template <
class K = key_type,
class F,
class L>
3672 bool modify_if_impl(
const key_arg<K>& key, F&& f) {
3673#if __cplusplus >= 201703L
3674 static_assert(std::is_invocable<F, mapped_type&>::value);
3677 auto it = this->
template find<K, L>(key, this->hash(key), m);
3678 if (it == this->end())
3680 std::forward<F>(f)(Policy::value(&*it));
3684 template <
class K = key_type,
class F,
class L>
3685 bool erase_if_impl(
const key_arg<K>& key, F&& f) {
3686#if __cplusplus >= 201703L
3687 static_assert(std::is_invocable<F, mapped_type&>::value);
3690 auto it = this->
template find<K, L>(key, this->hash(key), m);
3691 if (it == this->end())
3693 if (std::forward<F>(f)(Policy::value(&*it)))
3702 template <
class K,
class V>
3703 std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v) {
3704 typename Lockable::UniqueLock m;
3705 auto res = this->find_or_prepare_insert(k, m);
3706 typename Base::Inner *inner = std::get<0>(res);
3707 if (std::get<2>(res))
3708 inner->set_.emplace_at(std::get<1>(res), std::forward<K>(k), std::forward<V>(v));
3710 Policy::value(&*inner->set_.iterator_at(std::get<1>(res))) = std::forward<V>(v);
3711 return {this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))),
3715 template <
class K = key_type,
class... Args>
3716 std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args) {
3717 typename Lockable::UniqueLock m;
3718 auto res = this->find_or_prepare_insert(k, m);
3719 typename Base::Inner *inner = std::get<0>(res);
3720 if (std::get<2>(res))
3721 inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct,
3722 std::forward_as_tuple(std::forward<K>(k)),
3723 std::forward_as_tuple(std::forward<Args>(args)...));
3724 return {this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))),
3728 template <
class K = key_type,
class... Args>
3729 std::pair<iterator, bool> try_emplace_impl_with_hash(
size_t hashval, K&& k, Args&&... args) {
3730 typename Lockable::UniqueLock m;
3731 auto res = this->find_or_prepare_insert_with_hash(hashval, k, m);
3732 typename Base::Inner *inner = std::get<0>(res);
3733 if (std::get<2>(res))
3734 inner->set_.emplace_at(std::get<1>(res), std::piecewise_construct,
3735 std::forward_as_tuple(std::forward<K>(k)),
3736 std::forward_as_tuple(std::forward<Args>(args)...));
3737 return {this->iterator_at(inner, inner->set_.iterator_at(std::get<1>(res))),