Skip to content

Commit af1f06e

Browse files
authored
[libc++] Refactor key extraction for __hash_table and __tree (llvm#154512)
This patch replaces `__can_extract_key` with an overload set to try to extract the key. This simplifies the code, since we don't need to have separate overload sets for the unordered and associative containers. It also allows extending the set of extraction cases more easily, since we have a single place to define how the key is extracted.
1 parent 4b30563 commit af1f06e

File tree

15 files changed

+308
-352
lines changed

15 files changed

+308
-352
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,6 @@ set(files
792792
__type_traits/aligned_storage.h
793793
__type_traits/aligned_union.h
794794
__type_traits/alignment_of.h
795-
__type_traits/can_extract_key.h
796795
__type_traits/common_reference.h
797796
__type_traits/common_type.h
798797
__type_traits/conditional.h
@@ -933,6 +932,7 @@ set(files
933932
__utility/small_buffer.h
934933
__utility/swap.h
935934
__utility/to_underlying.h
935+
__utility/try_key_extraction.h
936936
__utility/unreachable.h
937937
__variant/monostate.h
938938
__vector/comparison.h

libcxx/include/__fwd/tuple.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ struct tuple_element;
2626
template <class...>
2727
class tuple;
2828

29+
template <class>
30+
inline const bool __is_tuple_v = false;
31+
32+
template <class... _Tp>
33+
inline const bool __is_tuple_v<tuple<_Tp...>> = true;
34+
2935
template <size_t _Ip, class... _Tp>
3036
struct tuple_element<_Ip, tuple<_Tp...> > {
3137
using type _LIBCPP_NODEBUG = __type_pack_element<_Ip, _Tp...>;

libcxx/include/__hash_table

Lines changed: 65 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
#include <__memory/swap_allocator.h>
3030
#include <__memory/unique_ptr.h>
3131
#include <__new/launder.h>
32-
#include <__type_traits/can_extract_key.h>
3332
#include <__type_traits/copy_cvref.h>
3433
#include <__type_traits/enable_if.h>
3534
#include <__type_traits/invoke.h>
@@ -46,6 +45,7 @@
4645
#include <__utility/move.h>
4746
#include <__utility/pair.h>
4847
#include <__utility/swap.h>
48+
#include <__utility/try_key_extraction.h>
4949
#include <limits>
5050

5151
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -797,40 +797,66 @@ public:
797797
_LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd);
798798
_LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(const_iterator __p, __node_pointer __nd);
799799

800-
template <class _Key, class... _Args>
801-
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_key_args(_Key const& __k, _Args&&... __args);
802-
803-
template <class... _Args>
804-
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_impl(_Args&&... __args);
805-
806-
template <class _Pp>
807-
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_Pp&& __x) {
808-
return __emplace_unique_extract_key(std::forward<_Pp>(__x), __can_extract_key<_Pp, key_type>());
809-
}
810-
811-
template <class _First,
812-
class _Second,
813-
__enable_if_t<__can_extract_map_key<_First, key_type, value_type>::value, int> = 0>
814-
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_First&& __f, _Second&& __s) {
815-
return __emplace_unique_key_args(__f, std::forward<_First>(__f), std::forward<_Second>(__s));
816-
}
817-
818800
template <class... _Args>
819801
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_Args&&... __args) {
820-
return __emplace_unique_impl(std::forward<_Args>(__args)...);
821-
}
822-
823-
template <class _Pp>
824-
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_fail_tag) {
825-
return __emplace_unique_impl(std::forward<_Pp>(__x));
826-
}
827-
template <class _Pp>
828-
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_self_tag) {
829-
return __emplace_unique_key_args(__x, std::forward<_Pp>(__x));
830-
}
831-
template <class _Pp>
832-
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_first_tag) {
833-
return __emplace_unique_key_args(__x.first, std::forward<_Pp>(__x));
802+
return std::__try_key_extraction<key_type>(
803+
[this](const key_type& __key, _Args&&... __args2) {
804+
size_t __hash = hash_function()(__key);
805+
size_type __bc = bucket_count();
806+
bool __inserted = false;
807+
__next_pointer __nd;
808+
size_t __chash;
809+
if (__bc != 0) {
810+
__chash = std::__constrain_hash(__hash, __bc);
811+
__nd = __bucket_list_[__chash];
812+
if (__nd != nullptr) {
813+
for (__nd = __nd->__next_;
814+
__nd != nullptr &&
815+
(__nd->__hash() == __hash || std::__constrain_hash(__nd->__hash(), __bc) == __chash);
816+
__nd = __nd->__next_) {
817+
if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __key))
818+
goto __done;
819+
}
820+
}
821+
}
822+
{
823+
__node_holder __h = __construct_node_hash(__hash, std::forward<_Args>(__args2)...);
824+
if (size() + 1 > __bc * max_load_factor() || __bc == 0) {
825+
__rehash_unique(std::max<size_type>(2 * __bc + !std::__is_hash_power2(__bc),
826+
size_type(__math::ceil(float(size() + 1) / max_load_factor()))));
827+
__bc = bucket_count();
828+
__chash = std::__constrain_hash(__hash, __bc);
829+
}
830+
// insert_after __bucket_list_[__chash], or __first_node if bucket is null
831+
__next_pointer __pn = __bucket_list_[__chash];
832+
if (__pn == nullptr) {
833+
__pn = __first_node_.__ptr();
834+
__h->__next_ = __pn->__next_;
835+
__pn->__next_ = __h.get()->__ptr();
836+
// fix up __bucket_list_
837+
__bucket_list_[__chash] = __pn;
838+
if (__h->__next_ != nullptr)
839+
__bucket_list_[std::__constrain_hash(__h->__next_->__hash(), __bc)] = __h.get()->__ptr();
840+
} else {
841+
__h->__next_ = __pn->__next_;
842+
__pn->__next_ = static_cast<__next_pointer>(__h.get());
843+
}
844+
__nd = static_cast<__next_pointer>(__h.release());
845+
// increment size
846+
++size();
847+
__inserted = true;
848+
}
849+
__done:
850+
return pair<iterator, bool>(iterator(__nd), __inserted);
851+
},
852+
[this](_Args&&... __args2) {
853+
__node_holder __h = __construct_node(std::forward<_Args>(__args2)...);
854+
pair<iterator, bool> __r = __node_insert_unique(__h.get());
855+
if (__r.second)
856+
__h.release();
857+
return __r;
858+
},
859+
std::forward<_Args>(__args)...);
834860
}
835861

836862
template <class... _Args>
@@ -999,8 +1025,8 @@ private:
9991025
template <class... _Args>
10001026
_LIBCPP_HIDE_FROM_ABI __node_holder __construct_node(_Args&&... __args);
10011027

1002-
template <class _First, class... _Rest>
1003-
_LIBCPP_HIDE_FROM_ABI __node_holder __construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest);
1028+
template <class... _Args>
1029+
_LIBCPP_HIDE_FROM_ABI __node_holder __construct_node_hash(size_t __hash, _Args&&... __args);
10041030

10051031
_LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __hash_table& __u) {
10061032
__copy_assign_alloc(__u, integral_constant<bool, __node_traits::propagate_on_container_copy_assignment::value>());
@@ -1614,69 +1640,6 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(const_iterator __p
16141640
return __node_insert_multi(__cp);
16151641
}
16161642

1617-
template <class _Tp, class _Hash, class _Equal, class _Alloc>
1618-
template <class _Key, class... _Args>
1619-
pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1620-
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const& __k, _Args&&... __args) {
1621-
size_t __hash = hash_function()(__k);
1622-
size_type __bc = bucket_count();
1623-
bool __inserted = false;
1624-
__next_pointer __nd;
1625-
size_t __chash;
1626-
if (__bc != 0) {
1627-
__chash = std::__constrain_hash(__hash, __bc);
1628-
__nd = __bucket_list_[__chash];
1629-
if (__nd != nullptr) {
1630-
for (__nd = __nd->__next_;
1631-
__nd != nullptr && (__nd->__hash() == __hash || std::__constrain_hash(__nd->__hash(), __bc) == __chash);
1632-
__nd = __nd->__next_) {
1633-
if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __k))
1634-
goto __done;
1635-
}
1636-
}
1637-
}
1638-
{
1639-
__node_holder __h = __construct_node_hash(__hash, std::forward<_Args>(__args)...);
1640-
if (size() + 1 > __bc * max_load_factor() || __bc == 0) {
1641-
__rehash_unique(std::max<size_type>(
1642-
2 * __bc + !std::__is_hash_power2(__bc), size_type(__math::ceil(float(size() + 1) / max_load_factor()))));
1643-
__bc = bucket_count();
1644-
__chash = std::__constrain_hash(__hash, __bc);
1645-
}
1646-
// insert_after __bucket_list_[__chash], or __first_node if bucket is null
1647-
__next_pointer __pn = __bucket_list_[__chash];
1648-
if (__pn == nullptr) {
1649-
__pn = __first_node_.__ptr();
1650-
__h->__next_ = __pn->__next_;
1651-
__pn->__next_ = __h.get()->__ptr();
1652-
// fix up __bucket_list_
1653-
__bucket_list_[__chash] = __pn;
1654-
if (__h->__next_ != nullptr)
1655-
__bucket_list_[std::__constrain_hash(__h->__next_->__hash(), __bc)] = __h.get()->__ptr();
1656-
} else {
1657-
__h->__next_ = __pn->__next_;
1658-
__pn->__next_ = static_cast<__next_pointer>(__h.get());
1659-
}
1660-
__nd = static_cast<__next_pointer>(__h.release());
1661-
// increment size
1662-
++size();
1663-
__inserted = true;
1664-
}
1665-
__done:
1666-
return pair<iterator, bool>(iterator(__nd), __inserted);
1667-
}
1668-
1669-
template <class _Tp, class _Hash, class _Equal, class _Alloc>
1670-
template <class... _Args>
1671-
pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1672-
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_impl(_Args&&... __args) {
1673-
__node_holder __h = __construct_node(std::forward<_Args>(__args)...);
1674-
pair<iterator, bool> __r = __node_insert_unique(__h.get());
1675-
if (__r.second)
1676-
__h.release();
1677-
return __r;
1678-
}
1679-
16801643
template <class _Tp, class _Hash, class _Equal, class _Alloc>
16811644
template <class... _Args>
16821645
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
@@ -1928,15 +1891,14 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&&... __args) {
19281891
}
19291892

19301893
template <class _Tp, class _Hash, class _Equal, class _Alloc>
1931-
template <class _First, class... _Rest>
1894+
template <class... _Args>
19321895
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1933-
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest) {
1934-
static_assert(!__is_hash_value_type<_First, _Rest...>::value, "Construct cannot be called with a hash value type");
1896+
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(size_t __hash, _Args&&... __args) {
1897+
static_assert(!__is_hash_value_type<_Args...>::value, "Construct cannot be called with a hash value type");
19351898
__node_allocator& __na = __node_alloc();
19361899
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
19371900
std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ __hash);
1938-
__node_traits::construct(
1939-
__na, std::addressof(__h->__get_value()), std::forward<_First>(__f), std::forward<_Rest>(__rest)...);
1901+
__node_traits::construct(__na, std::addressof(__h->__get_value()), std::forward<_Args>(__args)...);
19401902
__h.get_deleter().__value_constructed = true;
19411903
return __h;
19421904
}

0 commit comments

Comments
 (0)