[libc++] Avoid type-punning between __hash_value_type and pair (#143501)
This patch is very similar to #134819 in nature. Before this patch, we were dereferencing pointers to objects which were never constructed. Now we always assume that nodes store `pair<const KeyT, ValueT>` for unordered_maps instead, as they actually do.
This commit is contained in:
parent
7842e9eada
commit
4c8fab399b
@ -29,6 +29,7 @@
|
||||
#include <__memory/unique_ptr.h>
|
||||
#include <__new/launder.h>
|
||||
#include <__type_traits/can_extract_key.h>
|
||||
#include <__type_traits/copy_cvref.h>
|
||||
#include <__type_traits/enable_if.h>
|
||||
#include <__type_traits/invoke.h>
|
||||
#include <__type_traits/is_const.h>
|
||||
@ -108,9 +109,22 @@ struct __hash_node_base {
|
||||
_LIBCPP_HIDE_FROM_ABI explicit __hash_node_base(__next_pointer __next) _NOEXCEPT : __next_(__next) {}
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
struct __get_hash_node_value_type {
|
||||
using type _LIBCPP_NODEBUG = _Tp;
|
||||
};
|
||||
|
||||
template <class _Key, class _Tp>
|
||||
struct __get_hash_node_value_type<__hash_value_type<_Key, _Tp> > {
|
||||
using type _LIBCPP_NODEBUG = pair<const _Key, _Tp>;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
using __get_hash_node_value_type_t _LIBCPP_NODEBUG = typename __get_hash_node_value_type<_Tp>::type;
|
||||
|
||||
template <class _Tp, class _VoidPtr>
|
||||
struct __hash_node : public __hash_node_base< __rebind_pointer_t<_VoidPtr, __hash_node<_Tp, _VoidPtr> > > {
|
||||
typedef _Tp __node_value_type;
|
||||
using __node_value_type _LIBCPP_NODEBUG = __get_hash_node_value_type_t<_Tp>;
|
||||
using _Base _LIBCPP_NODEBUG = __hash_node_base<__rebind_pointer_t<_VoidPtr, __hash_node<_Tp, _VoidPtr> > >;
|
||||
using __next_pointer _LIBCPP_NODEBUG = typename _Base::__next_pointer;
|
||||
|
||||
@ -122,18 +136,20 @@ struct __hash_node : public __hash_node_base< __rebind_pointer_t<_VoidPtr, __has
|
||||
|
||||
private:
|
||||
union {
|
||||
_Tp __value_;
|
||||
__node_value_type __value_;
|
||||
};
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return __value_; }
|
||||
_LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() { return __value_; }
|
||||
#else
|
||||
|
||||
private:
|
||||
_ALIGNAS_TYPE(_Tp) char __buffer_[sizeof(_Tp)];
|
||||
_ALIGNAS_TYPE(__node_value_type) char __buffer_[sizeof(__node_value_type)];
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return *std::__launder(reinterpret_cast<_Tp*>(&__buffer_)); }
|
||||
_LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() {
|
||||
return *std::__launder(reinterpret_cast<__node_value_type*>(&__buffer_));
|
||||
}
|
||||
#endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit __hash_node(__next_pointer __next, size_t __hash) : _Base(__next), __hash_(__hash) {}
|
||||
@ -201,8 +217,8 @@ struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
|
||||
return __t;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
|
||||
return std::addressof(__n.__get_value());
|
||||
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__container_value_type& __n) {
|
||||
return std::addressof(__n);
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
|
||||
};
|
||||
@ -242,7 +258,7 @@ public:
|
||||
|
||||
typedef typename __node_base_type::__next_pointer __next_pointer;
|
||||
|
||||
typedef _Tp __node_value_type;
|
||||
using __node_value_type _LIBCPP_NODEBUG = __get_hash_node_value_type_t<_Tp>;
|
||||
typedef __rebind_pointer_t<_VoidPtr, __node_value_type> __node_value_type_pointer;
|
||||
typedef __rebind_pointer_t<_VoidPtr, const __node_value_type> __const_node_value_type_pointer;
|
||||
|
||||
@ -667,14 +683,14 @@ int __diagnose_unordered_container_requirements(void*);
|
||||
template <class _Tp, class _Hash, class _Equal, class _Alloc>
|
||||
class __hash_table {
|
||||
public:
|
||||
typedef _Tp value_type;
|
||||
using value_type = __get_hash_node_value_type_t<_Tp>;
|
||||
typedef _Hash hasher;
|
||||
typedef _Equal key_equal;
|
||||
typedef _Alloc allocator_type;
|
||||
|
||||
private:
|
||||
typedef allocator_traits<allocator_type> __alloc_traits;
|
||||
typedef typename __make_hash_node_types<value_type, typename __alloc_traits::void_pointer>::type _NodeTypes;
|
||||
typedef typename __make_hash_node_types<_Tp, typename __alloc_traits::void_pointer>::type _NodeTypes;
|
||||
|
||||
public:
|
||||
typedef typename _NodeTypes::__node_value_type __node_value_type;
|
||||
@ -845,6 +861,22 @@ public:
|
||||
return __emplace_unique(std::forward<_Pp>(__x));
|
||||
}
|
||||
|
||||
template <class _ValueT = _Tp, __enable_if_t<__is_hash_value_type<_ValueT>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node(value_type&& __value) {
|
||||
using __key_type = typename _NodeTypes::key_type;
|
||||
|
||||
__node_holder __h = __construct_node(const_cast<__key_type&&>(__value.first), std::move(__value.second));
|
||||
__node_insert_unique(__h.get());
|
||||
__h.release();
|
||||
}
|
||||
|
||||
template <class _ValueT = _Tp, __enable_if_t<!__is_hash_value_type<_ValueT>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node(value_type&& __value) {
|
||||
__node_holder __h = __construct_node(std::move(__value));
|
||||
__node_insert_unique(__h.get());
|
||||
__h.release();
|
||||
}
|
||||
|
||||
template <class _Pp>
|
||||
_LIBCPP_HIDE_FROM_ABI iterator __insert_multi(_Pp&& __x) {
|
||||
return __emplace_multi(std::forward<_Pp>(__x));
|
||||
@ -855,6 +887,22 @@ public:
|
||||
return __emplace_hint_multi(__p, std::forward<_Pp>(__x));
|
||||
}
|
||||
|
||||
template <class _ValueT = _Tp, __enable_if_t<__is_hash_value_type<_ValueT>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node(value_type&& __value) {
|
||||
using __key_type = typename _NodeTypes::key_type;
|
||||
|
||||
__node_holder __h = __construct_node(const_cast<__key_type&&>(__value.first), std::move(__value.second));
|
||||
__node_insert_multi(__h.get());
|
||||
__h.release();
|
||||
}
|
||||
|
||||
template <class _ValueT = _Tp, __enable_if_t<!__is_hash_value_type<_ValueT>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node(value_type&& __value) {
|
||||
__node_holder __h = __construct_node(std::move(__value));
|
||||
__node_insert_multi(__h.get());
|
||||
__h.release();
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __insert_unique(const __container_value_type& __x) {
|
||||
return __emplace_unique_key_args(_NodeTypes::__get_key(__x), __x);
|
||||
}
|
||||
@ -1020,6 +1068,21 @@ private:
|
||||
_LIBCPP_HIDE_FROM_ABI void __deallocate_node(__next_pointer __np) _NOEXCEPT;
|
||||
_LIBCPP_HIDE_FROM_ABI __next_pointer __detach() _NOEXCEPT;
|
||||
|
||||
template <class _From, class _ValueT = _Tp, __enable_if_t<__is_hash_value_type<_ValueT>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI void __assign_value(__get_hash_node_value_type_t<_Tp>& __lhs, _From&& __rhs) {
|
||||
using __key_type = typename _NodeTypes::key_type;
|
||||
|
||||
// This is technically UB, since the object was constructed as `const`.
|
||||
// Clang doesn't optimize on this currently though.
|
||||
const_cast<__key_type&>(__lhs.first) = const_cast<__copy_cvref_t<_From, __key_type>&&>(__rhs.first);
|
||||
__lhs.second = std::forward<_From>(__rhs).second;
|
||||
}
|
||||
|
||||
template <class _From, class _ValueT = _Tp, __enable_if_t<!__is_hash_value_type<_ValueT>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI void __assign_value(_Tp& __lhs, _From&& __rhs) {
|
||||
__lhs = std::forward<_From>(__rhs);
|
||||
}
|
||||
|
||||
template <class, class, class, class, class>
|
||||
friend class unordered_map;
|
||||
template <class, class, class, class, class>
|
||||
@ -1216,8 +1279,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
|
||||
#endif // _LIBCPP_HAS_EXCEPTIONS
|
||||
const_iterator __i = __u.begin();
|
||||
while (__cache != nullptr && __u.size() != 0) {
|
||||
__cache->__upcast()->__get_value() = std::move(__u.remove(__i++)->__get_value());
|
||||
__next_pointer __next = __cache->__next_;
|
||||
__assign_value(__cache->__upcast()->__get_value(), std::move(__u.remove(__i++)->__get_value()));
|
||||
__next_pointer __next = __cache->__next_;
|
||||
__node_insert_multi(__cache->__upcast());
|
||||
__cache = __next;
|
||||
}
|
||||
@ -1230,11 +1293,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
|
||||
__deallocate_node(__cache);
|
||||
}
|
||||
const_iterator __i = __u.begin();
|
||||
while (__u.size() != 0) {
|
||||
__node_holder __h = __construct_node(_NodeTypes::__move(__u.remove(__i++)->__get_value()));
|
||||
__node_insert_multi(__h.get());
|
||||
__h.release();
|
||||
}
|
||||
while (__u.size() != 0)
|
||||
__insert_multi_from_orphaned_node(std::move(__u.remove(__i++)->__get_value()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1262,8 +1322,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __
|
||||
try {
|
||||
#endif // _LIBCPP_HAS_EXCEPTIONS
|
||||
for (; __cache != nullptr && __first != __last; ++__first) {
|
||||
__cache->__upcast()->__get_value() = *__first;
|
||||
__next_pointer __next = __cache->__next_;
|
||||
__assign_value(__cache->__upcast()->__get_value(), *__first);
|
||||
__next_pointer __next = __cache->__next_;
|
||||
__node_insert_unique(__cache->__upcast());
|
||||
__cache = __next;
|
||||
}
|
||||
@ -1294,7 +1354,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __f
|
||||
try {
|
||||
#endif // _LIBCPP_HAS_EXCEPTIONS
|
||||
for (; __cache != nullptr && __first != __last; ++__first) {
|
||||
__cache->__upcast()->__get_value() = *__first;
|
||||
__assign_value(__cache->__upcast()->__get_value(), *__first);
|
||||
__next_pointer __next = __cache->__next_;
|
||||
__node_insert_multi(__cache->__upcast());
|
||||
__cache = __next;
|
||||
|
@ -654,9 +654,7 @@ public:
|
||||
_LIBCPP_HIDE_FROM_ABI __unordered_map_hasher(const _Hash& __h) _NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value)
|
||||
: _Hash(__h) {}
|
||||
_LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const _NOEXCEPT { return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const {
|
||||
return static_cast<const _Hash&>(*this)(__x.__get_value().first);
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const { return static_cast<const _Hash&>(*this)(__x.first); }
|
||||
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Key& __x) const { return static_cast<const _Hash&>(*this)(__x); }
|
||||
# if _LIBCPP_STD_VER >= 20
|
||||
template <typename _K2>
|
||||
@ -680,7 +678,7 @@ public:
|
||||
_LIBCPP_HIDE_FROM_ABI __unordered_map_hasher(const _Hash& __h) _NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value)
|
||||
: __hash_(__h) {}
|
||||
_LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const _NOEXCEPT { return __hash_; }
|
||||
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const { return __hash_(__x.__get_value().first); }
|
||||
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const { return __hash_(__x.first); }
|
||||
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Key& __x) const { return __hash_(__x); }
|
||||
# if _LIBCPP_STD_VER >= 20
|
||||
template <typename _K2>
|
||||
@ -713,10 +711,10 @@ public:
|
||||
: _Pred(__p) {}
|
||||
_LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const _NOEXCEPT { return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Cp& __y) const {
|
||||
return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y.__get_value().first);
|
||||
return static_cast<const _Pred&>(*this)(__x.first, __y.first);
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const {
|
||||
return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y);
|
||||
return static_cast<const _Pred&>(*this)(__x.first, __y);
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const {
|
||||
return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);
|
||||
@ -724,7 +722,7 @@ public:
|
||||
# if _LIBCPP_STD_VER >= 20
|
||||
template <typename _K2>
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _K2& __y) const {
|
||||
return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y);
|
||||
return static_cast<const _Pred&>(*this)(__x.first, __y);
|
||||
}
|
||||
template <typename _K2>
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Cp& __y) const {
|
||||
@ -755,23 +753,17 @@ public:
|
||||
_LIBCPP_HIDE_FROM_ABI __unordered_map_equal(const _Pred& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_Pred>::value)
|
||||
: __pred_(__p) {}
|
||||
_LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const _NOEXCEPT { return __pred_; }
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Cp& __y) const {
|
||||
return __pred_(__x.__get_value().first, __y.__get_value().first);
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const {
|
||||
return __pred_(__x.__get_value().first, __y);
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const {
|
||||
return __pred_(__x, __y.__get_value().first);
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Cp& __y) const { return __pred_(__x.first, __y.first); }
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const { return __pred_(__x.first, __y); }
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const { return __pred_(__x, __y.first); }
|
||||
# if _LIBCPP_STD_VER >= 20
|
||||
template <typename _K2>
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _K2& __y) const {
|
||||
return __pred_(__x.__get_value().first, __y);
|
||||
return __pred_(__x.first, __y);
|
||||
}
|
||||
template <typename _K2>
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Cp& __y) const {
|
||||
return __pred_(__x, __y.__get_value().first);
|
||||
return __pred_(__x, __y.first);
|
||||
}
|
||||
template <typename _K2>
|
||||
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _K2& __y) const {
|
||||
@ -833,96 +825,16 @@ public:
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
|
||||
if (__second_constructed)
|
||||
__alloc_traits::destroy(__na_, std::addressof(__p->__get_value().__get_value().second));
|
||||
__alloc_traits::destroy(__na_, std::addressof(__p->__get_value().second));
|
||||
if (__first_constructed)
|
||||
__alloc_traits::destroy(__na_, std::addressof(__p->__get_value().__get_value().first));
|
||||
__alloc_traits::destroy(__na_, std::addressof(__p->__get_value().first));
|
||||
if (__p)
|
||||
__alloc_traits::deallocate(__na_, __p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
template <class _Key, class _Tp>
|
||||
struct _LIBCPP_STANDALONE_DEBUG __hash_value_type {
|
||||
typedef _Key key_type;
|
||||
typedef _Tp mapped_type;
|
||||
typedef pair<const key_type, mapped_type> value_type;
|
||||
typedef pair<key_type&, mapped_type&> __nc_ref_pair_type;
|
||||
typedef pair<key_type&&, mapped_type&&> __nc_rref_pair_type;
|
||||
|
||||
private:
|
||||
value_type __cc_;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI value_type& __get_value() {
|
||||
# if _LIBCPP_STD_VER >= 17
|
||||
return *std::launder(std::addressof(__cc_));
|
||||
# else
|
||||
return __cc_;
|
||||
# endif
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const {
|
||||
# if _LIBCPP_STD_VER >= 17
|
||||
return *std::launder(std::addressof(__cc_));
|
||||
# else
|
||||
return __cc_;
|
||||
# endif
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __nc_ref_pair_type __ref() {
|
||||
value_type& __v = __get_value();
|
||||
return __nc_ref_pair_type(const_cast<key_type&>(__v.first), __v.second);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __nc_rref_pair_type __move() {
|
||||
value_type& __v = __get_value();
|
||||
return __nc_rref_pair_type(std::move(const_cast<key_type&>(__v.first)), std::move(__v.second));
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __hash_value_type& operator=(const __hash_value_type& __v) {
|
||||
__ref() = __v.__get_value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __hash_value_type& operator=(__hash_value_type&& __v) {
|
||||
__ref() = __v.__move();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _ValueTp, __enable_if_t<__is_same_uncvref<_ValueTp, value_type>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI __hash_value_type& operator=(_ValueTp&& __v) {
|
||||
__ref() = std::forward<_ValueTp>(__v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
__hash_value_type(const __hash_value_type& __v) = delete;
|
||||
__hash_value_type(__hash_value_type&& __v) = delete;
|
||||
template <class... _Args>
|
||||
explicit __hash_value_type(_Args&&... __args) = delete;
|
||||
|
||||
~__hash_value_type() = delete;
|
||||
};
|
||||
|
||||
# else
|
||||
|
||||
template <class _Key, class _Tp>
|
||||
struct __hash_value_type {
|
||||
typedef _Key key_type;
|
||||
typedef _Tp mapped_type;
|
||||
typedef pair<const key_type, mapped_type> value_type;
|
||||
|
||||
private:
|
||||
value_type __cc_;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI value_type& __get_value() { return __cc_; }
|
||||
_LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const { return __cc_; }
|
||||
|
||||
~__hash_value_type() = delete;
|
||||
};
|
||||
|
||||
# endif
|
||||
struct __hash_value_type;
|
||||
|
||||
template <class _HashIterator>
|
||||
class __hash_map_iterator {
|
||||
@ -941,8 +853,8 @@ public:
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __hash_map_iterator(_HashIterator __i) _NOEXCEPT : __i_(__i) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return __i_->__get_value(); }
|
||||
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__i_->__get_value()); }
|
||||
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return *__i_; }
|
||||
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(*__i_); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __hash_map_iterator& operator++() {
|
||||
++__i_;
|
||||
@ -995,8 +907,8 @@ public:
|
||||
__hash_map_const_iterator(__hash_map_iterator<typename _HashIterator::__non_const_iterator> __i) _NOEXCEPT
|
||||
: __i_(__i.__i_) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return __i_->__get_value(); }
|
||||
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__i_->__get_value()); }
|
||||
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return *__i_; }
|
||||
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(*__i_); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __hash_map_const_iterator& operator++() {
|
||||
++__i_;
|
||||
@ -1053,8 +965,8 @@ public:
|
||||
|
||||
private:
|
||||
typedef __hash_value_type<key_type, mapped_type> __value_type;
|
||||
typedef __unordered_map_hasher<key_type, __value_type, hasher, key_equal> __hasher;
|
||||
typedef __unordered_map_equal<key_type, __value_type, key_equal, hasher> __key_equal;
|
||||
typedef __unordered_map_hasher<key_type, value_type, hasher, key_equal> __hasher;
|
||||
typedef __unordered_map_equal<key_type, value_type, key_equal, hasher> __key_equal;
|
||||
typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
|
||||
|
||||
typedef __hash_table<__value_type, __hasher, __key_equal, __allocator_type> __table;
|
||||
@ -1073,9 +985,6 @@ private:
|
||||
|
||||
static_assert(__check_valid_allocator<allocator_type>::value, "");
|
||||
|
||||
static_assert(is_same<typename __table::__container_value_type, value_type>::value, "");
|
||||
static_assert(is_same<typename __table::__node_value_type, __value_type>::value, "");
|
||||
|
||||
public:
|
||||
typedef typename __alloc_traits::pointer pointer;
|
||||
typedef typename __alloc_traits::const_pointer const_pointer;
|
||||
@ -1680,9 +1589,8 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(unordered_map&& __
|
||||
: __table_(std::move(__u.__table_), typename __table::allocator_type(__a)) {
|
||||
if (__a != __u.get_allocator()) {
|
||||
iterator __i = __u.begin();
|
||||
while (__u.size() != 0) {
|
||||
__table_.__emplace_unique(__u.__table_.remove((__i++).__i_)->__get_value().__move());
|
||||
}
|
||||
while (__u.size() != 0)
|
||||
__table_.__insert_unique_from_orphaned_node(std::move(__u.__table_.remove((__i++).__i_)->__get_value()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1741,8 +1649,7 @@ template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
_Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k) {
|
||||
return __table_
|
||||
.__emplace_unique_key_args(__k, piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
|
||||
.first->__get_value()
|
||||
.second;
|
||||
.first->second;
|
||||
}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
@ -1750,8 +1657,7 @@ _Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](key_type&& __k)
|
||||
return __table_
|
||||
.__emplace_unique_key_args(
|
||||
__k, piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
|
||||
.first->__get_value()
|
||||
.second;
|
||||
.first->second;
|
||||
}
|
||||
# else // _LIBCPP_CXX03_LANG
|
||||
|
||||
@ -1760,9 +1666,9 @@ typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
|
||||
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node_with_key(const key_type& __k) {
|
||||
__node_allocator& __na = __table_.__node_alloc();
|
||||
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
|
||||
__node_traits::construct(__na, std::addressof(__h->__get_value().__get_value().first), __k);
|
||||
__node_traits::construct(__na, std::addressof(__h->__get_value().first), __k);
|
||||
__h.get_deleter().__first_constructed = true;
|
||||
__node_traits::construct(__na, std::addressof(__h->__get_value().__get_value().second));
|
||||
__node_traits::construct(__na, std::addressof(__h->__get_value().second));
|
||||
__h.get_deleter().__second_constructed = true;
|
||||
return __h;
|
||||
}
|
||||
@ -1869,8 +1775,8 @@ public:
|
||||
|
||||
private:
|
||||
typedef __hash_value_type<key_type, mapped_type> __value_type;
|
||||
typedef __unordered_map_hasher<key_type, __value_type, hasher, key_equal> __hasher;
|
||||
typedef __unordered_map_equal<key_type, __value_type, key_equal, hasher> __key_equal;
|
||||
typedef __unordered_map_hasher<key_type, value_type, hasher, key_equal> __hasher;
|
||||
typedef __unordered_map_equal<key_type, value_type, key_equal, hasher> __key_equal;
|
||||
typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
|
||||
|
||||
typedef __hash_table<__value_type, __hasher, __key_equal, __allocator_type> __table;
|
||||
@ -2439,9 +2345,8 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
|
||||
: __table_(std::move(__u.__table_), typename __table::allocator_type(__a)) {
|
||||
if (__a != __u.get_allocator()) {
|
||||
iterator __i = __u.begin();
|
||||
while (__u.size() != 0) {
|
||||
__table_.__insert_multi(__u.__table_.remove((__i++).__i_)->__get_value().__move());
|
||||
}
|
||||
while (__u.size() != 0)
|
||||
__table_.__insert_multi_from_orphaned_node(std::move(__u.__table_.remove((__i++).__i_)->__get_value()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
@ -109,6 +110,19 @@ int main(int, char**) {
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
{ // Test with std::pair, since we have some special handling for pairs inside __hash_table
|
||||
struct pair_hash {
|
||||
size_t operator()(std::pair<int, int> val) const TEST_NOEXCEPT { return val.first | val.second; }
|
||||
};
|
||||
|
||||
std::pair<int, int> arr[] = {
|
||||
std::make_pair(1, 2), std::make_pair(2, 3), std::make_pair(3, 4), std::make_pair(4, 5)};
|
||||
std::unordered_set<std::pair<int, int>, pair_hash> a(arr, arr + 4);
|
||||
std::unordered_set<std::pair<int, int>, pair_hash> b;
|
||||
|
||||
b = a;
|
||||
assert(a == b);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -65,16 +65,6 @@ def _remove_generics(typename):
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def _cc_field(node):
|
||||
"""Previous versions of libcxx had inconsistent field naming naming. Handle
|
||||
both types.
|
||||
"""
|
||||
try:
|
||||
return node["__value_"]["__cc_"]
|
||||
except:
|
||||
return node["__value_"]["__cc"]
|
||||
|
||||
|
||||
def _data_field(node):
|
||||
"""Previous versions of libcxx had inconsistent field naming naming. Handle
|
||||
both types.
|
||||
@ -829,7 +819,7 @@ class StdUnorderedMapPrinter(AbstractUnorderedCollectionPrinter):
|
||||
"""Print a std::unordered_(multi)map."""
|
||||
|
||||
def _get_key_value(self, node):
|
||||
key_value = _cc_field(node)
|
||||
key_value = node["__value_"]
|
||||
return [key_value["first"], key_value["second"]]
|
||||
|
||||
def display_hint(self):
|
||||
@ -885,7 +875,7 @@ class StdUnorderedMapIteratorPrinter(AbstractHashMapIteratorPrinter):
|
||||
self._initialize(val, val["__i_"]["__node_"])
|
||||
|
||||
def _get_key_value(self):
|
||||
key_value = _cc_field(self.node)
|
||||
key_value = self.node["__value_"]
|
||||
return [key_value["first"], key_value["second"]]
|
||||
|
||||
def display_hint(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user