[libcxx-commits] [libcxx] map, unordered_map: use static method for getting value of __hash_value_type (PR #135365)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Apr 11 06:22:58 PDT 2025
https://github.com/sssersh created https://github.com/llvm/llvm-project/pull/135365
Method __get_value() in __hash_value_type is used to access to address of stored in __hash_value_type value.
This method called in __hash_table::__construct_node via _NodeTypes::__get_ptr() **before** creation of object __hash_value_type.
But according to [basic.life]: "The program has undefined behavior if [...] the pointer is used to access a non-static data member or call a non-static member function of the object [...]".
But it's possible to access to member in __hash_value_type using pointer interconvertibility according to [basic.compound]: "Two objects `a` and `b` are pointer-interconvertible if [...] - one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object, or [...]. If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a `reinterpret_cast`."
>From f4ea232a5bff2ebf3ca61929d378a21a4ef972d6 Mon Sep 17 00:00:00 2001
From: "s.dobychin" <s.dobychin at vk.team>
Date: Fri, 11 Apr 2025 16:21:51 +0300
Subject: [PATCH] map, unordered_map: use static method for getting value of
__hash_value_type
Method __get_value() in __hash_value_type is used to access to address of stored in __hash_value_type value.
This method called in __hash_table::__construct_node via _NodeTypes::__get_ptr() **before** creation of object __hash_value_type.
But according to [basic.life]: "The program has undefined behavior if [...] the pointer is used to access a non-static data member or call a non-static member function of the object [...]".
But it's possible to access to member in __hash_value_type using pointer interconvertibility according to [basic.compound]:
"Two objects `a` and `b` are pointer-interconvertible if [...] - one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object, or [...]. If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a `reinterpret_cast`."
---
libcxx/include/__cxx03/__hash_table | 4 +-
libcxx/include/__cxx03/__tree | 6 +-
libcxx/include/__cxx03/map | 98 +++++++++++++++-----------
libcxx/include/__cxx03/unordered_map | 32 ++++++---
libcxx/include/__hash_table | 4 +-
libcxx/include/__tree | 4 +-
libcxx/include/ext/hash_map | 8 +--
libcxx/include/map | 97 +++++++++++++++-----------
libcxx/include/unordered_map | 100 ++++++++++++++++-----------
9 files changed, 208 insertions(+), 145 deletions(-)
diff --git a/libcxx/include/__cxx03/__hash_table b/libcxx/include/__cxx03/__hash_table
index a4eff8c654f11..4ffe633b14501 100644
--- a/libcxx/include/__cxx03/__hash_table
+++ b/libcxx/include/__cxx03/__hash_table
@@ -183,7 +183,7 @@ struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __node_value_type>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) {
- return __t.__get_value();
+ return _Up::__get_value(__t);
}
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
@@ -192,7 +192,7 @@ struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
}
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
- return std::addressof(__n.__get_value());
+ return std::addressof(__node_value_type::__get_value(__n));
}
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
};
diff --git a/libcxx/include/__cxx03/__tree b/libcxx/include/__cxx03/__tree
index aec20a7541b26..1c4cd18804817 100644
--- a/libcxx/include/__cxx03/__tree
+++ b/libcxx/include/__cxx03/__tree
@@ -533,7 +533,7 @@ struct __tree_key_value_types<__value_type<_Key, _Tp> > {
static const bool __is_map = true;
_LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(__node_value_type const& __t) {
- return __t.__get_value().first;
+ return __node_value_type::__get_value(__t).first;
}
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
@@ -542,7 +542,7 @@ struct __tree_key_value_types<__value_type<_Key, _Tp> > {
}
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __t) {
- return __t.__get_value();
+ return __node_value_type::__get_value(__t);
}
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
@@ -551,7 +551,7 @@ struct __tree_key_value_types<__value_type<_Key, _Tp> > {
}
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
- return std::addressof(__n.__get_value());
+ return std::addressof(__node_value_type::__get_value(__n));
}
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
diff --git a/libcxx/include/__cxx03/map b/libcxx/include/__cxx03/map
index ca097f583acc0..3371f3d7dcd3f 100644
--- a/libcxx/include/__cxx03/map
+++ b/libcxx/include/__cxx03/map
@@ -584,6 +584,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
#include <__cxx03/__memory/allocator.h>
#include <__cxx03/__tree>
#include <__cxx03/__type_traits/is_allocator.h>
+#include <__cxx03/__type_traits/is_standard_layout.h>
#include <__cxx03/__utility/forward.h>
#include <__cxx03/__utility/piecewise_construct.h>
#include <__cxx03/__utility/swap.h>
@@ -616,13 +617,13 @@ public:
: _Compare(__c) {}
_LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return *this; }
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
- return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y.__get_value().first);
+ return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, _CP::__get_value(__y).first);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
- return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
+ return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, __y);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
- return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
+ return static_cast<const _Compare&>(*this)(__x, _CP::__get_value(__y).first);
}
_LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
using std::swap;
@@ -632,12 +633,12 @@ public:
#if _LIBCPP_STD_VER >= 14
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
- return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
+ return static_cast<const _Compare&>(*this)(__x, _CP::__get_value(__y).first);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
- return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
+ return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, __y);
}
#endif
};
@@ -654,13 +655,13 @@ public:
_LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return __comp_; }
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
- return __comp_(__x.__get_value().first, __y.__get_value().first);
+ return __comp_(_CP::__get_value(__x).first, _CP::__get_value(__y).first);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
- return __comp_(__x.__get_value().first, __y);
+ return __comp_(_CP::__get_value(__x).first, __y);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
- return __comp_(__x, __y.__get_value().first);
+ return __comp_(__x, _CP::__get_value(__y).first);
}
void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
using std::swap;
@@ -670,12 +671,12 @@ public:
#if _LIBCPP_STD_VER >= 14
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
- return __comp_(__x, __y.__get_value().first);
+ return __comp_(__x, _CP::__get_value(__y).first);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
- return __comp_(__x.__get_value().first, __y);
+ return __comp_(_CP::__get_value(__x).first, __y);
}
#endif
};
@@ -691,6 +692,7 @@ template <class _Allocator>
class __map_node_destructor {
typedef _Allocator allocator_type;
typedef allocator_traits<allocator_type> __alloc_traits;
+ typedef __alloc_traits::value_type value_type;
public:
typedef typename __alloc_traits::pointer pointer;
@@ -720,9 +722,9 @@ public:
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
if (__second_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().second));
+ __alloc_traits::destroy(__na_, std::addressof(value_type::__get_value(__p->__value_).second));
if (__first_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().first));
+ __alloc_traits::destroy(__na_, std::addressof(value_type::__get_value(__p->__value_).first));
if (__p)
__alloc_traits::deallocate(__na_, __p, 1);
}
@@ -749,34 +751,34 @@ private:
value_type __cc_;
public:
- _LIBCPP_HIDE_FROM_ABI value_type& __get_value() {
+ _LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
+ return *std::launder(std::addressof(reinterpret_cast<const value_type&>(__v)));
# else
- return __cc_;
+ return reinterpret_cast<const value_type&>(__v);
# endif
}
- _LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const {
+ _LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) {
# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
+ return *std::launder(std::addressof(reinterpret_cast<value_type&>(__v)));
# else
- return __cc_;
+ return reinterpret_cast<value_type&>(__v);
# endif
}
_LIBCPP_HIDE_FROM_ABI __nc_ref_pair_type __ref() {
- value_type& __v = __get_value();
+ value_type& __v = __get_value(*this);
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();
+ value_type& __v = __get_value(*this);
return __nc_rref_pair_type(std::move(const_cast<key_type&>(__v.first)), std::move(__v.second));
}
_LIBCPP_HIDE_FROM_ABI __value_type& operator=(const __value_type& __v) {
- __ref() = __v.__get_value();
+ __ref() = __get_value(__v);
return *this;
}
@@ -808,9 +810,17 @@ struct __value_type {
private:
value_type __cc_;
+private:
+ static_assert(is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
+
public:
- _LIBCPP_HIDE_FROM_ABI value_type& __get_value() { return __cc_; }
- _LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const { return __cc_; }
+ _LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
+ return reinterpret_cast<value_type&>(__v);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) const {
+ return reinterpret_cast<const value_type&>(__v);
+ }
__value_type() = delete;
__value_type(__value_type const&) = delete;
@@ -847,8 +857,10 @@ public:
_LIBCPP_HIDE_FROM_ABI __map_iterator(_TreeIterator __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 value_type::__get_value(*__i_); }
+ _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
+ return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
+ }
_LIBCPP_HIDE_FROM_ABI __map_iterator& operator++() {
++__i_;
@@ -905,8 +917,10 @@ public:
_LIBCPP_HIDE_FROM_ABI
__map_const_iterator(__map_iterator< typename _TreeIterator::__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 value_type::__get_value(*__i_); }
+ _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
+ return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
+ }
_LIBCPP_HIDE_FROM_ABI __map_const_iterator& operator++() {
++__i_;
@@ -1269,7 +1283,7 @@ public:
auto [__r, __inserted] = __tree_.__emplace_hint_unique_key_args(__h.__i_, __k, __k, std::forward<_Vp>(__v));
if (!__inserted)
- __r->__get_value().second = std::forward<_Vp>(__v);
+ __value_type::__get_value(*__r).second = std::forward<_Vp>(__v);
return __r;
}
@@ -1280,7 +1294,7 @@ public:
__tree_.__emplace_hint_unique_key_args(__h.__i_, __k, std::move(__k), std::forward<_Vp>(__v));
if (!__inserted)
- __r->__get_value().second = std::forward<_Vp>(__v);
+ __value_type::__get_value(*__r).second = std::forward<_Vp>(__v);
return __r;
}
@@ -1492,9 +1506,10 @@ map<_Key, _Tp, _Compare, _Allocator>::map(map&& __m, const allocator_type& __a)
template <class _Key, class _Tp, class _Compare, class _Allocator>
_Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
- return __tree_
- .__emplace_unique_key_args(__k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
- .first->__get_value()
+ return _Tp::__get_value(__tree_
+ .__emplace_unique_key_args(
+ __k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
+ .first)
.second;
}
@@ -1502,10 +1517,11 @@ template <class _Key, class _Tp, class _Compare, class _Allocator>
_Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k) {
// TODO investigate this clang-tidy warning.
// NOLINTBEGIN(bugprone-use-after-move)
- return __tree_
- .__emplace_unique_key_args(
- __k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
- .first->__get_value()
+ return _Tp::__get_value(
+ __tree_
+ .__emplace_unique_key_args(
+ __k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
+ .first)
.second;
// NOLINTEND(bugprone-use-after-move)
}
@@ -1517,9 +1533,9 @@ typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
map<_Key, _Tp, _Compare, _Allocator>::__construct_node_with_key(const key_type& __k) {
__node_allocator& __na = __tree_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, std::addressof(__h->__value_.__get_value().first), __k);
+ __node_traits::construct(__na, std::addressof(_Tp::__get_value(__h->__value_).first), __k);
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, std::addressof(__h->__value_.__get_value().second));
+ __node_traits::construct(__na, std::addressof(_Tp::__get_value(__h->__value_).second));
__h.get_deleter().__second_constructed = true;
return __h;
}
@@ -1534,7 +1550,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
__tree_.__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
}
- return __r->__value_.__get_value().second;
+ return _Tp::__get_value(__r->__value_).second;
}
#endif // _LIBCPP_CXX03_LANG
@@ -1545,7 +1561,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) {
__node_base_pointer& __child = __tree_.__find_equal(__parent, __k);
if (__child == nullptr)
__throw_out_of_range("map::at: key not found");
- return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
+ return _Tp::__get_value(static_cast<__node_pointer>(__child)->__value_).second;
}
template <class _Key, class _Tp, class _Compare, class _Allocator>
@@ -1554,7 +1570,7 @@ const _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const {
__node_base_pointer __child = __tree_.__find_equal(__parent, __k);
if (__child == nullptr)
__throw_out_of_range("map::at: key not found");
- return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
+ return _Tp::__get_value(static_cast<__node_pointer>(__child)->__value_).second;
}
template <class _Key, class _Tp, class _Compare, class _Allocator>
diff --git a/libcxx/include/__cxx03/unordered_map b/libcxx/include/__cxx03/unordered_map
index 10e84f35a3578..647c00a5a0594 100644
--- a/libcxx/include/__cxx03/unordered_map
+++ b/libcxx/include/__cxx03/unordered_map
@@ -594,6 +594,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
#include <__cxx03/__memory/addressof.h>
#include <__cxx03/__memory/allocator.h>
#include <__cxx03/__type_traits/is_allocator.h>
+#include <__cxx03/__type_traits/is_standard_layout.h>
#include <__cxx03/__type_traits/type_identity.h>
#include <__cxx03/__utility/forward.h>
#include <__cxx03/stdexcept>
@@ -823,30 +824,33 @@ struct _LIBCPP_STANDALONE_DEBUG __hash_value_type {
private:
value_type __cc_;
+private:
+ static_assert(std::is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
+
public:
- _LIBCPP_HIDE_FROM_ABI value_type& __get_value() {
+ _LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
+ return *std::launder(std::addressof(reinterpret_cast<const value_type&>(__v)));
# else
- return __cc_;
+ return reinterpret_cast<const value_type&>(__v);
# endif
}
- _LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const {
+ _LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) {
# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
+ return *std::launder(std::addressof(reinterpret_cast<value_type&>(__v)));
# else
- return __cc_;
+ return reinterpret_cast<value_type&>(__v);
# endif
}
_LIBCPP_HIDE_FROM_ABI __nc_ref_pair_type __ref() {
- value_type& __v = __get_value();
+ value_type& __v = __get_value(*this);
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();
+ value_type& __v = __get_value(*this);
return __nc_rref_pair_type(std::move(const_cast<key_type&>(__v.first)), std::move(__v.second));
}
@@ -885,9 +889,17 @@ struct __hash_value_type {
private:
value_type __cc_;
+private:
+ static_assert(is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
+
public:
- _LIBCPP_HIDE_FROM_ABI value_type& __get_value() { return __cc_; }
- _LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const { return __cc_; }
+ _LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
+ return reinterpret_cast<value_type&>(__v);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) const {
+ return reinterpret_cast<const value_type&>(__v);
+ }
~__hash_value_type() = delete;
};
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index fca58ca296067..9bcf042a9306e 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -193,7 +193,7 @@ struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __node_value_type>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) {
- return __t.__get_value();
+ return __node_value_type::__get_value(__t);
}
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
@@ -202,7 +202,7 @@ struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
}
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
- return std::addressof(__n.__get_value());
+ return std::addressof(__node_value_type::__get_value(__n));
}
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
};
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index e84bc4ffda0bd..bcb25924b0bed 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -534,7 +534,7 @@ struct __tree_key_value_types<__value_type<_Key, _Tp> > {
}
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __t) {
- return __t.__get_value();
+ return __node_value_type::__get_value(__t);
}
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
@@ -543,7 +543,7 @@ struct __tree_key_value_types<__value_type<_Key, _Tp> > {
}
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
- return std::addressof(__n.__get_value());
+ return std::addressof(__node_value_type::__get_value(__n));
}
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
diff --git a/libcxx/include/ext/hash_map b/libcxx/include/ext/hash_map
index da2a34aa56dfb..d5f7f7e02d128 100644
--- a/libcxx/include/ext/hash_map
+++ b/libcxx/include/ext/hash_map
@@ -329,9 +329,9 @@ public:
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) {
if (__second_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().second));
+ __alloc_traits::destroy(__na_, std::addressof(value_type::__get_value(*__p).second));
if (__first_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().first));
+ __alloc_traits::destroy(__na_, std::addressof(value_type::__get_value(*__p).first));
if (__p)
__alloc_traits::deallocate(__na_, __p, 1);
}
@@ -614,9 +614,9 @@ typename hash_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
hash_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(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().first), __k);
+ __node_traits::construct(__na, std::addressof(_Tp::__get_value(*__h).first, __k);
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, std::addressof(__h->__get_value().second));
+ __node_traits::construct(__na, std::addressof(_Tp::__get_value(*__h).second));
__h.get_deleter().__second_constructed = true;
return __h;
}
diff --git a/libcxx/include/map b/libcxx/include/map
index a244696295fb8..cb1ded3b7af0b 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -601,6 +601,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
# include <__tree>
# include <__type_traits/container_traits.h>
# include <__type_traits/is_allocator.h>
+# include <__type_traits/is_standard_layout.h>
# include <__type_traits/remove_const.h>
# include <__type_traits/type_identity.h>
# include <__utility/forward.h>
@@ -645,13 +646,13 @@ public:
: _Compare(__c) {}
_LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return *this; }
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
- return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y.__get_value().first);
+ return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, _CP::__get_value(__y).first);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
- return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
+ return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, __y);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
- return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
+ return static_cast<const _Compare&>(*this)(__x, _CP::__get_value(__y).first);
}
_LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
using std::swap;
@@ -661,12 +662,12 @@ public:
# if _LIBCPP_STD_VER >= 14
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
- return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
+ return static_cast<const _Compare&>(*this)(__x, _CP::__get_value(__y).first);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
- return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
+ return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, __y);
}
# endif
};
@@ -683,13 +684,13 @@ public:
_LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return __comp_; }
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
- return __comp_(__x.__get_value().first, __y.__get_value().first);
+ return __comp_(_CP::__get_value(__x).first, _CP::__get_value(__y).first);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
- return __comp_(__x.__get_value().first, __y);
+ return __comp_(_CP::__get_value(__x).first, __y);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
- return __comp_(__x, __y.__get_value().first);
+ return __comp_(__x, _CP::__get_value(__y).first);
}
void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
using std::swap;
@@ -699,12 +700,12 @@ public:
# if _LIBCPP_STD_VER >= 14
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
- return __comp_(__x, __y.__get_value().first);
+ return __comp_(__x, _CP::__get_value(__y).first);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
- return __comp_(__x.__get_value().first, __y);
+ return __comp_(_CP::__get_value(__x).first, __y);
}
# endif
};
@@ -749,9 +750,9 @@ public:
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
if (__second_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().second));
+ __alloc_traits::destroy(__na_, std::addressof(_CP::__get_value(__p->__value_).second));
if (__first_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().first));
+ __alloc_traits::destroy(__na_, std::addressof(_CP::__get_value(__p->__value_).first));
if (__p)
__alloc_traits::deallocate(__na_, __p, 1);
}
@@ -773,35 +774,38 @@ struct _LIBCPP_STANDALONE_DEBUG __value_type {
private:
value_type __cc_;
+private:
+ static_assert(is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
+
public:
- _LIBCPP_HIDE_FROM_ABI value_type& __get_value() {
+ _LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
+ return *std::launder(std::addressof(reinterpret_cast<value_type&>(__v)));
# else
- return __cc_;
+ return reinterpret_cast<value_type&>(__v);
# endif
}
- _LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const {
+ _LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) {
# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
+ return *std::launder(std::addressof(reinterpret_cast<value_type&>(__v)));
# else
- return __cc_;
+ return reinterpret_cast<const value_type&>(__v);
# endif
}
_LIBCPP_HIDE_FROM_ABI __nc_ref_pair_type __ref() {
- value_type& __v = __get_value();
+ value_type& __v = __get_value(*this);
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();
+ value_type& __v = __get_value(*this);
return __nc_rref_pair_type(std::move(const_cast<key_type&>(__v.first)), std::move(__v.second));
}
_LIBCPP_HIDE_FROM_ABI __value_type& operator=(const __value_type& __v) {
- __ref() = __v.__get_value();
+ __ref() = __get_value(__v);
return *this;
}
@@ -834,8 +838,13 @@ 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_; }
+ _LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
+ return reinterpret_cast<value_type&>(__v);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) const {
+ return reinterpret_cast<const value_type&>(__v);
+ }
__value_type() = delete;
__value_type(__value_type const&) = delete;
@@ -872,8 +881,10 @@ public:
_LIBCPP_HIDE_FROM_ABI __map_iterator(_TreeIterator __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 value_type::__get_value(*__i_); }
+ _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
+ return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
+ }
_LIBCPP_HIDE_FROM_ABI __map_iterator& operator++() {
++__i_;
@@ -930,8 +941,10 @@ public:
_LIBCPP_HIDE_FROM_ABI
__map_const_iterator(__map_iterator< typename _TreeIterator::__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 value_type::__get_value(*__i_); }
+ _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
+ return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
+ }
_LIBCPP_HIDE_FROM_ABI __map_const_iterator& operator++() {
++__i_;
@@ -1294,7 +1307,7 @@ public:
auto [__r, __inserted] = __tree_.__emplace_hint_unique_key_args(__h.__i_, __k, __k, std::forward<_Vp>(__v));
if (!__inserted)
- __r->__get_value().second = std::forward<_Vp>(__v);
+ __value_type::__get_value(*__r).second = std::forward<_Vp>(__v);
return __r;
}
@@ -1305,7 +1318,7 @@ public:
__tree_.__emplace_hint_unique_key_args(__h.__i_, __k, std::move(__k), std::forward<_Vp>(__v));
if (!__inserted)
- __r->__get_value().second = std::forward<_Vp>(__v);
+ __value_type::__get_value(__r).second = std::forward<_Vp>(__v);
return __r;
}
@@ -1517,9 +1530,10 @@ map<_Key, _Tp, _Compare, _Allocator>::map(map&& __m, const allocator_type& __a)
template <class _Key, class _Tp, class _Compare, class _Allocator>
_Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
- return __tree_
- .__emplace_unique_key_args(__k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
- .first->__get_value()
+ return _Tp::__get_value(*__tree_
+ .__emplace_unique_key_args(
+ __k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
+ .first)
.second;
}
@@ -1527,10 +1541,11 @@ template <class _Key, class _Tp, class _Compare, class _Allocator>
_Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k) {
// TODO investigate this clang-tidy warning.
// NOLINTBEGIN(bugprone-use-after-move)
- return __tree_
- .__emplace_unique_key_args(
- __k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
- .first->__get_value()
+ return _Tp::__get_value(
+ *__tree_
+ .__emplace_unique_key_args(
+ __k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
+ .first)
.second;
// NOLINTEND(bugprone-use-after-move)
}
@@ -1542,9 +1557,9 @@ typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
map<_Key, _Tp, _Compare, _Allocator>::__construct_node_with_key(const key_type& __k) {
__node_allocator& __na = __tree_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, std::addressof(__h->__value_.__get_value().first), __k);
+ __node_traits::construct(__na, std::addressof(_Tp::__get_value(__h->__value_).first), __k);
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, std::addressof(__h->__value_.__get_value().second));
+ __node_traits::construct(__na, std::addressof(_Tp::__get_value(__h->__value_).second));
__h.get_deleter().__second_constructed = true;
return __h;
}
@@ -1559,7 +1574,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
__tree_.__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
}
- return __r->__value_.__get_value().second;
+ return _Tp::__get_value(__r->__value_).second;
}
# endif // _LIBCPP_CXX03_LANG
@@ -1570,7 +1585,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) {
__node_base_pointer& __child = __tree_.__find_equal(__parent, __k);
if (__child == nullptr)
std::__throw_out_of_range("map::at: key not found");
- return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
+ return _Tp::__get_value(static_cast<__node_pointer>(__child)->__value_).second;
}
template <class _Key, class _Tp, class _Compare, class _Allocator>
@@ -1579,7 +1594,7 @@ const _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const {
__node_base_pointer __child = __tree_.__find_equal(__parent, __k);
if (__child == nullptr)
std::__throw_out_of_range("map::at: key not found");
- return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
+ return _Tp::__get_value(static_cast<__node_pointer>(__child)->__value_).second;
}
template <class _Key, class _Tp, class _Compare, class _Allocator>
diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index 61c89a0ca73bb..a9c118fe7adf6 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -613,6 +613,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
# include <__type_traits/invoke.h>
# include <__type_traits/is_allocator.h>
# include <__type_traits/is_integral.h>
+# include <__type_traits/is_standard_layout.h>
# include <__type_traits/remove_const.h>
# include <__type_traits/type_identity.h>
# include <__utility/forward.h>
@@ -655,7 +656,7 @@ public:
: _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);
+ return static_cast<const _Hash&>(*this)(_Cp::get_value(__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
@@ -680,7 +681,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_(_Cp::__get_value(__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,22 +714,22 @@ 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)(_Cp::__get_value(__x).first, _Cp::__get_value(__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)(_Cp::__get_value(__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);
+ return static_cast<const _Pred&>(*this)(__x, _Cp::__get_value(__y).first);
}
# 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)(_Cp::__get_value(__x).first, __y);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Cp& __y) const {
- return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);
+ return static_cast<const _Pred&>(*this)(__x, _Cp::__get_value(__y).first);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _K2& __y) const {
@@ -756,22 +757,22 @@ public:
: __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);
+ return __pred_(_Cp::__get_value(__x).first, _Cp::__get_value(__y).first);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const {
- return __pred_(__x.__get_value().first, __y);
+ return __pred_(_Cp::__get_value(__x).first, __y);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const {
- return __pred_(__x, __y.__get_value().first);
+ return __pred_(__x, _Cp::__get_value(__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_(_Cp::__get_value(__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, _Cp::__get_value(__y).first);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _K2& __y) const {
@@ -832,10 +833,12 @@ public:
# endif // _LIBCPP_CXX03_LANG
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
+ using __alloc_traits::value_type::__get_value;
+
if (__second_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().__get_value().second));
+ __alloc_traits::destroy(__na_, std::addressof(__get_value(__get_value(*__p)).second));
if (__first_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().__get_value().first));
+ __alloc_traits::destroy(__na_, std::addressof(__get_value(__get_value(*__p)).first));
if (__p)
__alloc_traits::deallocate(__na_, __p, 1);
}
@@ -853,35 +856,38 @@ struct _LIBCPP_STANDALONE_DEBUG __hash_value_type {
private:
value_type __cc_;
+private:
+ static_assert(is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
+
public:
- _LIBCPP_HIDE_FROM_ABI value_type& __get_value() {
+ _LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
+ return *std::launder(std::addressof(reinterpret_cast<value_type&>(__v)));
# else
- return __cc_;
+ return reinterpret_cast<value_type&>(__v);
# endif
}
- _LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const {
+ _LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) {
# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
+ return *std::launder(std::addressof(reinterpret_cast<const value_type&>(__v)));
# else
- return __cc_;
+ return reinterpret_cast<const value_type&>(__v);
# endif
}
_LIBCPP_HIDE_FROM_ABI __nc_ref_pair_type __ref() {
- value_type& __v = __get_value();
+ value_type& __v = __get_value(*this);
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();
+ value_type& __v = __get_value(*this);
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();
+ __ref() = __get_value(__v);
return *this;
}
@@ -915,9 +921,17 @@ struct __hash_value_type {
private:
value_type __cc_;
+private:
+ static_assert(std::is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
+
public:
- _LIBCPP_HIDE_FROM_ABI value_type& __get_value() { return __cc_; }
- _LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const { return __cc_; }
+ _LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
+ return reinterpret_cast<value_type&>(__v);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) const {
+ return reinterpret_cast<const value_type&>(__v);
+ }
~__hash_value_type() = delete;
};
@@ -941,8 +955,10 @@ 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 value_type::__get_value(*__i_); }
+ _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
+ return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
+ }
_LIBCPP_HIDE_FROM_ABI __hash_map_iterator& operator++() {
++__i_;
@@ -995,8 +1011,10 @@ 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 value_type::__get_value(*__i_); }
+ _LIBCPP_HIDE_FROM_ABI pointer operator->() const {
+ return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
+ }
_LIBCPP_HIDE_FROM_ABI __hash_map_const_iterator& operator++() {
++__i_;
@@ -1681,7 +1699,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(unordered_map&& __
if (__a != __u.get_allocator()) {
iterator __i = __u.begin();
while (__u.size() != 0) {
- __table_.__emplace_unique(__u.__table_.remove((__i++).__i_)->__get_value().__move());
+ __table_.__emplace_unique(_Tp::__get_value(*__u.__table_.remove((__i++).__i_)).__move());
}
}
}
@@ -1739,18 +1757,20 @@ inline void unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(_InputIterato
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()
+ return _Tp::__get_value(*__table_
+ .__emplace_unique_key_args(
+ __k, piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
+ .first)
.second;
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
_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()
+ return _Tp::__get_value(
+ *__table_
+ .__emplace_unique_key_args(
+ __k, piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
+ .first)
.second;
}
# else // _LIBCPP_CXX03_LANG
@@ -1760,9 +1780,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(_Tp::__get_value(_Tp::__get_value(*__h).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(_Tp::__get_value(_Tp::__get_value(*__h).second));
__h.get_deleter().__second_constructed = true;
return __h;
}
@@ -2438,7 +2458,7 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
if (__a != __u.get_allocator()) {
iterator __i = __u.begin();
while (__u.size() != 0) {
- __table_.__insert_multi(__u.__table_.remove((__i++).__i_)->__get_value().__move());
+ __table_.__insert_multi(_Tp::__get_value(*__u.__table_.remove((__i++).__i_)).__move());
}
}
}
More information about the libcxx-commits
mailing list