Skip to content

Commit 8edb37a

Browse files
author
s.dobychin
committed
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`."
1 parent fb96d51 commit 8edb37a

File tree

10 files changed

+211
-148
lines changed

10 files changed

+211
-148
lines changed

libcxx/include/__cxx03/__hash_table

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
185185

186186
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __node_value_type>::value, int> = 0>
187187
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) {
188-
return __t.__get_value();
188+
return _Up::__get_value(__t);
189189
}
190190

191191
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
@@ -194,7 +194,7 @@ struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
194194
}
195195

196196
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
197-
return std::addressof(__n.__get_value());
197+
return std::addressof(__node_value_type::__get_value(__n));
198198
}
199199
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
200200
};

libcxx/include/__cxx03/__node_handle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ template <class _NodeType, class _Derived>
170170
struct __set_node_handle_specifics {
171171
typedef typename _NodeType::__node_value_type value_type;
172172

173-
_LIBCPP_HIDE_FROM_ABI value_type& value() const { return static_cast<_Derived const*>(this)->__ptr_->__get_value(); }
173+
_LIBCPP_HIDE_FROM_ABI value_type& value() const { return value_type::__get_value(*static_cast<_Derived const*>(this)->__ptr_); }
174174
};
175175

176176
template <class _NodeType, class _Derived>
@@ -179,11 +179,11 @@ struct __map_node_handle_specifics {
179179
typedef typename _NodeType::__node_value_type::mapped_type mapped_type;
180180

181181
_LIBCPP_HIDE_FROM_ABI key_type& key() const {
182-
return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().first;
182+
return value_type::__get_value(*static_cast<_Derived const*>(this)->__ptr_).__ref().first;
183183
}
184184

185185
_LIBCPP_HIDE_FROM_ABI mapped_type& mapped() const {
186-
return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().second;
186+
return value_type::__get_value(*static_cast<_Derived const*>(this)->__ptr_).__ref().second;
187187
}
188188
};
189189

libcxx/include/__cxx03/__tree

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ struct __tree_key_value_types<__value_type<_Key, _Tp> > {
533533
static const bool __is_map = true;
534534

535535
_LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(__node_value_type const& __t) {
536-
return __t.__get_value().first;
536+
return __node_value_type::__get_value(__t).first;
537537
}
538538

539539
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> > {
542542
}
543543

544544
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __t) {
545-
return __t.__get_value();
545+
return __node_value_type::__get_value(__t);
546546
}
547547

548548
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> > {
551551
}
552552

553553
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
554-
return std::addressof(__n.__get_value());
554+
return std::addressof(__node_value_type::__get_value(__n));
555555
}
556556

557557
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }

libcxx/include/__cxx03/map

Lines changed: 57 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
592592
#include <__cxx03/__ranges/from_range.h>
593593
#include <__cxx03/__tree>
594594
#include <__cxx03/__type_traits/is_allocator.h>
595+
#include <__cxx03/__type_traits/is_standard_layout.h>
595596
#include <__cxx03/__utility/forward.h>
596597
#include <__cxx03/__utility/piecewise_construct.h>
597598
#include <__cxx03/__utility/swap.h>
@@ -633,13 +634,13 @@ public:
633634
: _Compare(__c) {}
634635
_LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return *this; }
635636
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
636-
return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y.__get_value().first);
637+
return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, _CP::__get_value(__y).first);
637638
}
638639
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
639-
return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
640+
return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, __y);
640641
}
641642
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
642-
return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
643+
return static_cast<const _Compare&>(*this)(__x, _CP::__get_value(__y).first);
643644
}
644645
_LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
645646
using std::swap;
@@ -649,12 +650,12 @@ public:
649650
#if _LIBCPP_STD_VER >= 14
650651
template <typename _K2>
651652
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
652-
return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
653+
return static_cast<const _Compare&>(*this)(__x, _CP::__get_value(__y).first);
653654
}
654655

655656
template <typename _K2>
656657
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
657-
return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
658+
return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, __y);
658659
}
659660
#endif
660661
};
@@ -671,13 +672,13 @@ public:
671672
_LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return __comp_; }
672673

673674
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
674-
return __comp_(__x.__get_value().first, __y.__get_value().first);
675+
return __comp_(_CP::__get_value(__x).first, _CP::__get_value(__y).first);
675676
}
676677
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
677-
return __comp_(__x.__get_value().first, __y);
678+
return __comp_(_CP::__get_value(__x).first, __y);
678679
}
679680
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
680-
return __comp_(__x, __y.__get_value().first);
681+
return __comp_(__x, _CP::__get_value(__y).first);
681682
}
682683
void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
683684
using std::swap;
@@ -687,12 +688,12 @@ public:
687688
#if _LIBCPP_STD_VER >= 14
688689
template <typename _K2>
689690
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
690-
return __comp_(__x, __y.__get_value().first);
691+
return __comp_(__x, _CP::__get_value(__y).first);
691692
}
692693

693694
template <typename _K2>
694695
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
695-
return __comp_(__x.__get_value().first, __y);
696+
return __comp_(_CP::__get_value(__x).first, __y);
696697
}
697698
#endif
698699
};
@@ -708,6 +709,7 @@ template <class _Allocator>
708709
class __map_node_destructor {
709710
typedef _Allocator allocator_type;
710711
typedef allocator_traits<allocator_type> __alloc_traits;
712+
typedef __alloc_traits::value_type value_type;
711713

712714
public:
713715
typedef typename __alloc_traits::pointer pointer;
@@ -737,9 +739,9 @@ public:
737739

738740
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
739741
if (__second_constructed)
740-
__alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().second));
742+
__alloc_traits::destroy(__na_, std::addressof(value_type::__get_value(__p->__value_).second));
741743
if (__first_constructed)
742-
__alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().first));
744+
__alloc_traits::destroy(__na_, std::addressof(value_type::__get_value(__p->__value_).first));
743745
if (__p)
744746
__alloc_traits::deallocate(__na_, __p, 1);
745747
}
@@ -765,35 +767,38 @@ struct _LIBCPP_STANDALONE_DEBUG __value_type {
765767
private:
766768
value_type __cc_;
767769

770+
private:
771+
static_assert(is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
772+
768773
public:
769-
_LIBCPP_HIDE_FROM_ABI value_type& __get_value() {
774+
_LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
770775
# if _LIBCPP_STD_VER >= 17
771-
return *std::launder(std::addressof(__cc_));
776+
return *std::launder(std::addressof(reinterpret_cast<value_type&>(__v)));
772777
# else
773-
return __cc_;
778+
return reinterpret_cast<value_type&>(__v);
774779
# endif
775780
}
776781

777-
_LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const {
782+
_LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) {
778783
# if _LIBCPP_STD_VER >= 17
779-
return *std::launder(std::addressof(__cc_));
784+
return *std::launder(std::addressof(reinterpret_cast<const value_type&>(__v)));
780785
# else
781-
return __cc_;
786+
return reinterpret_cast<const value_type&>(__v);
782787
# endif
783788
}
784789

785790
_LIBCPP_HIDE_FROM_ABI __nc_ref_pair_type __ref() {
786-
value_type& __v = __get_value();
791+
value_type& __v = __get_value(*this);
787792
return __nc_ref_pair_type(const_cast<key_type&>(__v.first), __v.second);
788793
}
789794

790795
_LIBCPP_HIDE_FROM_ABI __nc_rref_pair_type __move() {
791-
value_type& __v = __get_value();
796+
value_type& __v = __get_value(*this);
792797
return __nc_rref_pair_type(std::move(const_cast<key_type&>(__v.first)), std::move(__v.second));
793798
}
794799

795800
_LIBCPP_HIDE_FROM_ABI __value_type& operator=(const __value_type& __v) {
796-
__ref() = __v.__get_value();
801+
__ref() = __get_value(__v);
797802
return *this;
798803
}
799804

@@ -826,8 +831,13 @@ private:
826831
value_type __cc_;
827832

828833
public:
829-
_LIBCPP_HIDE_FROM_ABI value_type& __get_value() { return __cc_; }
830-
_LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const { return __cc_; }
834+
_LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
835+
return reinterpret_cast<value_type&>(__v);
836+
}
837+
838+
_LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) const {
839+
return reinterpret_cast<const value_type&>(__v);
840+
}
831841

832842
__value_type() = delete;
833843
__value_type(__value_type const&) = delete;
@@ -864,8 +874,10 @@ public:
864874

865875
_LIBCPP_HIDE_FROM_ABI __map_iterator(_TreeIterator __i) _NOEXCEPT : __i_(__i) {}
866876

867-
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return __i_->__get_value(); }
868-
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__i_->__get_value()); }
877+
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return value_type::__get_value(*__i_); }
878+
_LIBCPP_HIDE_FROM_ABI pointer operator->() const {
879+
return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
880+
}
869881

870882
_LIBCPP_HIDE_FROM_ABI __map_iterator& operator++() {
871883
++__i_;
@@ -922,8 +934,10 @@ public:
922934
_LIBCPP_HIDE_FROM_ABI
923935
__map_const_iterator(__map_iterator< typename _TreeIterator::__non_const_iterator> __i) _NOEXCEPT : __i_(__i.__i_) {}
924936

925-
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return __i_->__get_value(); }
926-
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__i_->__get_value()); }
937+
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return value_type::__get_value(*__i_); }
938+
_LIBCPP_HIDE_FROM_ABI pointer operator->() const {
939+
return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
940+
}
927941

928942
_LIBCPP_HIDE_FROM_ABI __map_const_iterator& operator++() {
929943
++__i_;
@@ -1286,7 +1300,7 @@ public:
12861300
auto [__r, __inserted] = __tree_.__emplace_hint_unique_key_args(__h.__i_, __k, __k, std::forward<_Vp>(__v));
12871301

12881302
if (!__inserted)
1289-
__r->__get_value().second = std::forward<_Vp>(__v);
1303+
__value_type::__get_value(*__r).second = std::forward<_Vp>(__v);
12901304

12911305
return __r;
12921306
}
@@ -1297,7 +1311,7 @@ public:
12971311
__tree_.__emplace_hint_unique_key_args(__h.__i_, __k, std::move(__k), std::forward<_Vp>(__v));
12981312

12991313
if (!__inserted)
1300-
__r->__get_value().second = std::forward<_Vp>(__v);
1314+
__value_type::__get_value(*__r).second = std::forward<_Vp>(__v);
13011315

13021316
return __r;
13031317
}
@@ -1509,20 +1523,22 @@ map<_Key, _Tp, _Compare, _Allocator>::map(map&& __m, const allocator_type& __a)
15091523

15101524
template <class _Key, class _Tp, class _Compare, class _Allocator>
15111525
_Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
1512-
return __tree_
1513-
.__emplace_unique_key_args(__k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
1514-
.first->__get_value()
1526+
return _Tp::__get_value(__tree_
1527+
.__emplace_unique_key_args(
1528+
__k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
1529+
.first)
15151530
.second;
15161531
}
15171532

15181533
template <class _Key, class _Tp, class _Compare, class _Allocator>
15191534
_Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k) {
15201535
// TODO investigate this clang-tidy warning.
15211536
// NOLINTBEGIN(bugprone-use-after-move)
1522-
return __tree_
1523-
.__emplace_unique_key_args(
1524-
__k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
1525-
.first->__get_value()
1537+
return _Tp::__get_value(
1538+
__tree_
1539+
.__emplace_unique_key_args(
1540+
__k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
1541+
.first)
15261542
.second;
15271543
// NOLINTEND(bugprone-use-after-move)
15281544
}
@@ -1534,9 +1550,9 @@ typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
15341550
map<_Key, _Tp, _Compare, _Allocator>::__construct_node_with_key(const key_type& __k) {
15351551
__node_allocator& __na = __tree_.__node_alloc();
15361552
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
1537-
__node_traits::construct(__na, std::addressof(__h->__value_.__get_value().first), __k);
1553+
__node_traits::construct(__na, std::addressof(_Tp::__get_value(__h->__value_).first), __k);
15381554
__h.get_deleter().__first_constructed = true;
1539-
__node_traits::construct(__na, std::addressof(__h->__value_.__get_value().second));
1555+
__node_traits::construct(__na, std::addressof(_Tp::__get_value(__h->__value_).second));
15401556
__h.get_deleter().__second_constructed = true;
15411557
return __h;
15421558
}
@@ -1551,7 +1567,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
15511567
__tree_.__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
15521568
__r = __h.release();
15531569
}
1554-
return __r->__value_.__get_value().second;
1570+
return _Tp::__get_value(__r->__value_).second;
15551571
}
15561572

15571573
#endif // _LIBCPP_CXX03_LANG
@@ -1562,7 +1578,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) {
15621578
__node_base_pointer& __child = __tree_.__find_equal(__parent, __k);
15631579
if (__child == nullptr)
15641580
__throw_out_of_range("map::at: key not found");
1565-
return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
1581+
return _Tp::__get_value(static_cast<__node_pointer>(__child)->__value_).second;
15661582
}
15671583

15681584
template <class _Key, class _Tp, class _Compare, class _Allocator>
@@ -1571,7 +1587,7 @@ const _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const {
15711587
__node_base_pointer __child = __tree_.__find_equal(__parent, __k);
15721588
if (__child == nullptr)
15731589
__throw_out_of_range("map::at: key not found");
1574-
return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
1590+
return _Tp::__get_value(static_cast<__node_pointer>(__child)->__value_).second;
15751591
}
15761592

15771593
template <class _Key, class _Tp, class _Compare, class _Allocator>

0 commit comments

Comments
 (0)