| 
29 | 29 | #include <__memory/swap_allocator.h>  | 
30 | 30 | #include <__memory/unique_ptr.h>  | 
31 | 31 | #include <__new/launder.h>  | 
 | 32 | +#include <__type_traits/can_extract_key.h>  | 
32 | 33 | #include <__type_traits/copy_cvref.h>  | 
33 | 34 | #include <__type_traits/enable_if.h>  | 
34 | 35 | #include <__type_traits/invoke.h>  | 
 | 
45 | 46 | #include <__utility/move.h>  | 
46 | 47 | #include <__utility/pair.h>  | 
47 | 48 | #include <__utility/swap.h>  | 
48 |  | -#include <__utility/try_key_extraction.h>  | 
49 | 49 | #include <limits>  | 
50 | 50 | 
 
  | 
51 | 51 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)  | 
@@ -797,66 +797,40 @@ public:  | 
797 | 797 |   _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd);  | 
798 | 798 |   _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(const_iterator __p, __node_pointer __nd);  | 
799 | 799 | 
 
  | 
 | 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 | + | 
800 | 818 |   template <class... _Args>  | 
801 | 819 |   _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_Args&&... __args) {  | 
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)...);  | 
 | 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));  | 
860 | 834 |   }  | 
861 | 835 | 
 
  | 
862 | 836 |   template <class... _Args>  | 
@@ -1025,8 +999,8 @@ private:  | 
1025 | 999 |   template <class... _Args>  | 
1026 | 1000 |   _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node(_Args&&... __args);  | 
1027 | 1001 | 
 
  | 
1028 |  | -  template <class... _Args>  | 
1029 |  | -  _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node_hash(size_t __hash, _Args&&... __args);  | 
 | 1002 | +  template <class _First, class... _Rest>  | 
 | 1003 | +  _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest);  | 
1030 | 1004 | 
 
  | 
1031 | 1005 |   _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __hash_table& __u) {  | 
1032 | 1006 |     __copy_assign_alloc(__u, integral_constant<bool, __node_traits::propagate_on_container_copy_assignment::value>());  | 
@@ -1640,6 +1614,69 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(const_iterator __p  | 
1640 | 1614 |   return __node_insert_multi(__cp);  | 
1641 | 1615 | }  | 
1642 | 1616 | 
 
  | 
 | 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 | + | 
1643 | 1680 | template <class _Tp, class _Hash, class _Equal, class _Alloc>  | 
1644 | 1681 | template <class... _Args>  | 
1645 | 1682 | typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator  | 
@@ -1891,14 +1928,15 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&&... __args) {  | 
1891 | 1928 | }  | 
1892 | 1929 | 
 
  | 
1893 | 1930 | template <class _Tp, class _Hash, class _Equal, class _Alloc>  | 
1894 |  | -template <class... _Args>  | 
 | 1931 | +template <class _First, class... _Rest>  | 
1895 | 1932 | typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder  | 
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");  | 
 | 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");  | 
1898 | 1935 |   __node_allocator& __na = __node_alloc();  | 
1899 | 1936 |   __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));  | 
1900 | 1937 |   std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ __hash);  | 
1901 |  | -  __node_traits::construct(__na, std::addressof(__h->__get_value()), std::forward<_Args>(__args)...);  | 
 | 1938 | +  __node_traits::construct(  | 
 | 1939 | +      __na, std::addressof(__h->__get_value()), std::forward<_First>(__f), std::forward<_Rest>(__rest)...);  | 
1902 | 1940 |   __h.get_deleter().__value_constructed = true;  | 
1903 | 1941 |   return __h;  | 
1904 | 1942 | }  | 
 | 
0 commit comments