Skip to content

Commit f4ea232

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 5b384c3 commit f4ea232

File tree

9 files changed

+208
-145
lines changed

9 files changed

+208
-145
lines changed

libcxx/include/__cxx03/__hash_table

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

184184
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __node_value_type>::value, int> = 0>
185185
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) {
186-
return __t.__get_value();
186+
return _Up::__get_value(__t);
187187
}
188188

189189
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> > {
192192
}
193193

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

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
@@ -584,6 +584,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
584584
#include <__cxx03/__memory/allocator.h>
585585
#include <__cxx03/__tree>
586586
#include <__cxx03/__type_traits/is_allocator.h>
587+
#include <__cxx03/__type_traits/is_standard_layout.h>
587588
#include <__cxx03/__utility/forward.h>
588589
#include <__cxx03/__utility/piecewise_construct.h>
589590
#include <__cxx03/__utility/swap.h>
@@ -616,13 +617,13 @@ public:
616617
: _Compare(__c) {}
617618
_LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return *this; }
618619
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
619-
return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y.__get_value().first);
620+
return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, _CP::__get_value(__y).first);
620621
}
621622
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
622-
return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
623+
return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, __y);
623624
}
624625
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
625-
return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
626+
return static_cast<const _Compare&>(*this)(__x, _CP::__get_value(__y).first);
626627
}
627628
_LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
628629
using std::swap;
@@ -632,12 +633,12 @@ public:
632633
#if _LIBCPP_STD_VER >= 14
633634
template <typename _K2>
634635
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
635-
return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
636+
return static_cast<const _Compare&>(*this)(__x, _CP::__get_value(__y).first);
636637
}
637638

638639
template <typename _K2>
639640
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
640-
return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
641+
return static_cast<const _Compare&>(*this)(_CP::__get_value(__x).first, __y);
641642
}
642643
#endif
643644
};
@@ -654,13 +655,13 @@ public:
654655
_LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return __comp_; }
655656

656657
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
657-
return __comp_(__x.__get_value().first, __y.__get_value().first);
658+
return __comp_(_CP::__get_value(__x).first, _CP::__get_value(__y).first);
658659
}
659660
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
660-
return __comp_(__x.__get_value().first, __y);
661+
return __comp_(_CP::__get_value(__x).first, __y);
661662
}
662663
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
663-
return __comp_(__x, __y.__get_value().first);
664+
return __comp_(__x, _CP::__get_value(__y).first);
664665
}
665666
void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
666667
using std::swap;
@@ -670,12 +671,12 @@ public:
670671
#if _LIBCPP_STD_VER >= 14
671672
template <typename _K2>
672673
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
673-
return __comp_(__x, __y.__get_value().first);
674+
return __comp_(__x, _CP::__get_value(__y).first);
674675
}
675676

676677
template <typename _K2>
677678
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
678-
return __comp_(__x.__get_value().first, __y);
679+
return __comp_(_CP::__get_value(__x).first, __y);
679680
}
680681
#endif
681682
};
@@ -691,6 +692,7 @@ template <class _Allocator>
691692
class __map_node_destructor {
692693
typedef _Allocator allocator_type;
693694
typedef allocator_traits<allocator_type> __alloc_traits;
695+
typedef __alloc_traits::value_type value_type;
694696

695697
public:
696698
typedef typename __alloc_traits::pointer pointer;
@@ -720,9 +722,9 @@ public:
720722

721723
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
722724
if (__second_constructed)
723-
__alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().second));
725+
__alloc_traits::destroy(__na_, std::addressof(value_type::__get_value(__p->__value_).second));
724726
if (__first_constructed)
725-
__alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().first));
727+
__alloc_traits::destroy(__na_, std::addressof(value_type::__get_value(__p->__value_).first));
726728
if (__p)
727729
__alloc_traits::deallocate(__na_, __p, 1);
728730
}
@@ -749,34 +751,34 @@ private:
749751
value_type __cc_;
750752

751753
public:
752-
_LIBCPP_HIDE_FROM_ABI value_type& __get_value() {
754+
_LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
753755
# if _LIBCPP_STD_VER >= 17
754-
return *std::launder(std::addressof(__cc_));
756+
return *std::launder(std::addressof(reinterpret_cast<const value_type&>(__v)));
755757
# else
756-
return __cc_;
758+
return reinterpret_cast<const value_type&>(__v);
757759
# endif
758760
}
759761

760-
_LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const {
762+
_LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) {
761763
# if _LIBCPP_STD_VER >= 17
762-
return *std::launder(std::addressof(__cc_));
764+
return *std::launder(std::addressof(reinterpret_cast<value_type&>(__v)));
763765
# else
764-
return __cc_;
766+
return reinterpret_cast<value_type&>(__v);
765767
# endif
766768
}
767769

768770
_LIBCPP_HIDE_FROM_ABI __nc_ref_pair_type __ref() {
769-
value_type& __v = __get_value();
771+
value_type& __v = __get_value(*this);
770772
return __nc_ref_pair_type(const_cast<key_type&>(__v.first), __v.second);
771773
}
772774

773775
_LIBCPP_HIDE_FROM_ABI __nc_rref_pair_type __move() {
774-
value_type& __v = __get_value();
776+
value_type& __v = __get_value(*this);
775777
return __nc_rref_pair_type(std::move(const_cast<key_type&>(__v.first)), std::move(__v.second));
776778
}
777779

778780
_LIBCPP_HIDE_FROM_ABI __value_type& operator=(const __value_type& __v) {
779-
__ref() = __v.__get_value();
781+
__ref() = __get_value(__v);
780782
return *this;
781783
}
782784

@@ -808,9 +810,17 @@ struct __value_type {
808810
private:
809811
value_type __cc_;
810812

813+
private:
814+
static_assert(is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
815+
811816
public:
812-
_LIBCPP_HIDE_FROM_ABI value_type& __get_value() { return __cc_; }
813-
_LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const { return __cc_; }
817+
_LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
818+
return reinterpret_cast<value_type&>(__v);
819+
}
820+
821+
_LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) const {
822+
return reinterpret_cast<const value_type&>(__v);
823+
}
814824

815825
__value_type() = delete;
816826
__value_type(__value_type const&) = delete;
@@ -847,8 +857,10 @@ public:
847857

848858
_LIBCPP_HIDE_FROM_ABI __map_iterator(_TreeIterator __i) _NOEXCEPT : __i_(__i) {}
849859

850-
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return __i_->__get_value(); }
851-
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__i_->__get_value()); }
860+
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return value_type::__get_value(*__i_); }
861+
_LIBCPP_HIDE_FROM_ABI pointer operator->() const {
862+
return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
863+
}
852864

853865
_LIBCPP_HIDE_FROM_ABI __map_iterator& operator++() {
854866
++__i_;
@@ -905,8 +917,10 @@ public:
905917
_LIBCPP_HIDE_FROM_ABI
906918
__map_const_iterator(__map_iterator< typename _TreeIterator::__non_const_iterator> __i) _NOEXCEPT : __i_(__i.__i_) {}
907919

908-
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return __i_->__get_value(); }
909-
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__i_->__get_value()); }
920+
_LIBCPP_HIDE_FROM_ABI reference operator*() const { return value_type::__get_value(*__i_); }
921+
_LIBCPP_HIDE_FROM_ABI pointer operator->() const {
922+
return pointer_traits<pointer>::pointer_to(value_type::__get_value(*__i_));
923+
}
910924

911925
_LIBCPP_HIDE_FROM_ABI __map_const_iterator& operator++() {
912926
++__i_;
@@ -1269,7 +1283,7 @@ public:
12691283
auto [__r, __inserted] = __tree_.__emplace_hint_unique_key_args(__h.__i_, __k, __k, std::forward<_Vp>(__v));
12701284

12711285
if (!__inserted)
1272-
__r->__get_value().second = std::forward<_Vp>(__v);
1286+
__value_type::__get_value(*__r).second = std::forward<_Vp>(__v);
12731287

12741288
return __r;
12751289
}
@@ -1280,7 +1294,7 @@ public:
12801294
__tree_.__emplace_hint_unique_key_args(__h.__i_, __k, std::move(__k), std::forward<_Vp>(__v));
12811295

12821296
if (!__inserted)
1283-
__r->__get_value().second = std::forward<_Vp>(__v);
1297+
__value_type::__get_value(*__r).second = std::forward<_Vp>(__v);
12841298

12851299
return __r;
12861300
}
@@ -1492,20 +1506,22 @@ map<_Key, _Tp, _Compare, _Allocator>::map(map&& __m, const allocator_type& __a)
14921506

14931507
template <class _Key, class _Tp, class _Compare, class _Allocator>
14941508
_Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
1495-
return __tree_
1496-
.__emplace_unique_key_args(__k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
1497-
.first->__get_value()
1509+
return _Tp::__get_value(__tree_
1510+
.__emplace_unique_key_args(
1511+
__k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
1512+
.first)
14981513
.second;
14991514
}
15001515

15011516
template <class _Key, class _Tp, class _Compare, class _Allocator>
15021517
_Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k) {
15031518
// TODO investigate this clang-tidy warning.
15041519
// NOLINTBEGIN(bugprone-use-after-move)
1505-
return __tree_
1506-
.__emplace_unique_key_args(
1507-
__k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
1508-
.first->__get_value()
1520+
return _Tp::__get_value(
1521+
__tree_
1522+
.__emplace_unique_key_args(
1523+
__k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
1524+
.first)
15091525
.second;
15101526
// NOLINTEND(bugprone-use-after-move)
15111527
}
@@ -1517,9 +1533,9 @@ typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
15171533
map<_Key, _Tp, _Compare, _Allocator>::__construct_node_with_key(const key_type& __k) {
15181534
__node_allocator& __na = __tree_.__node_alloc();
15191535
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
1520-
__node_traits::construct(__na, std::addressof(__h->__value_.__get_value().first), __k);
1536+
__node_traits::construct(__na, std::addressof(_Tp::__get_value(__h->__value_).first), __k);
15211537
__h.get_deleter().__first_constructed = true;
1522-
__node_traits::construct(__na, std::addressof(__h->__value_.__get_value().second));
1538+
__node_traits::construct(__na, std::addressof(_Tp::__get_value(__h->__value_).second));
15231539
__h.get_deleter().__second_constructed = true;
15241540
return __h;
15251541
}
@@ -1534,7 +1550,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
15341550
__tree_.__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
15351551
__r = __h.release();
15361552
}
1537-
return __r->__value_.__get_value().second;
1553+
return _Tp::__get_value(__r->__value_).second;
15381554
}
15391555

15401556
#endif // _LIBCPP_CXX03_LANG
@@ -1545,7 +1561,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) {
15451561
__node_base_pointer& __child = __tree_.__find_equal(__parent, __k);
15461562
if (__child == nullptr)
15471563
__throw_out_of_range("map::at: key not found");
1548-
return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
1564+
return _Tp::__get_value(static_cast<__node_pointer>(__child)->__value_).second;
15491565
}
15501566

15511567
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 {
15541570
__node_base_pointer __child = __tree_.__find_equal(__parent, __k);
15551571
if (__child == nullptr)
15561572
__throw_out_of_range("map::at: key not found");
1557-
return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
1573+
return _Tp::__get_value(static_cast<__node_pointer>(__child)->__value_).second;
15581574
}
15591575

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

libcxx/include/__cxx03/unordered_map

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
594594
#include <__cxx03/__memory/addressof.h>
595595
#include <__cxx03/__memory/allocator.h>
596596
#include <__cxx03/__type_traits/is_allocator.h>
597+
#include <__cxx03/__type_traits/is_standard_layout.h>
597598
#include <__cxx03/__type_traits/type_identity.h>
598599
#include <__cxx03/__utility/forward.h>
599600
#include <__cxx03/stdexcept>
@@ -823,30 +824,33 @@ struct _LIBCPP_STANDALONE_DEBUG __hash_value_type {
823824
private:
824825
value_type __cc_;
825826

827+
private:
828+
static_assert(std::is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
829+
826830
public:
827-
_LIBCPP_HIDE_FROM_ABI value_type& __get_value() {
831+
_LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
828832
# if _LIBCPP_STD_VER >= 17
829-
return *std::launder(std::addressof(__cc_));
833+
return *std::launder(std::addressof(reinterpret_cast<const value_type&>(__v)));
830834
# else
831-
return __cc_;
835+
return reinterpret_cast<const value_type&>(__v);
832836
# endif
833837
}
834838

835-
_LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const {
839+
_LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) {
836840
# if _LIBCPP_STD_VER >= 17
837-
return *std::launder(std::addressof(__cc_));
841+
return *std::launder(std::addressof(reinterpret_cast<value_type&>(__v)));
838842
# else
839-
return __cc_;
843+
return reinterpret_cast<value_type&>(__v);
840844
# endif
841845
}
842846

843847
_LIBCPP_HIDE_FROM_ABI __nc_ref_pair_type __ref() {
844-
value_type& __v = __get_value();
848+
value_type& __v = __get_value(*this);
845849
return __nc_ref_pair_type(const_cast<key_type&>(__v.first), __v.second);
846850
}
847851

848852
_LIBCPP_HIDE_FROM_ABI __nc_rref_pair_type __move() {
849-
value_type& __v = __get_value();
853+
value_type& __v = __get_value(*this);
850854
return __nc_rref_pair_type(std::move(const_cast<key_type&>(__v.first)), std::move(__v.second));
851855
}
852856

@@ -885,9 +889,17 @@ struct __hash_value_type {
885889
private:
886890
value_type __cc_;
887891

892+
private:
893+
static_assert(is_standard_layout_v<__hash_value_type<_Key, _Tp>>, "");
894+
888895
public:
889-
_LIBCPP_HIDE_FROM_ABI value_type& __get_value() { return __cc_; }
890-
_LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const { return __cc_; }
896+
_LIBCPP_HIDE_FROM_ABI static value_type& __get_value(__hash_value_type& __v) {
897+
return reinterpret_cast<value_type&>(__v);
898+
}
899+
900+
_LIBCPP_HIDE_FROM_ABI static const value_type& __get_value(const __hash_value_type& __v) const {
901+
return reinterpret_cast<const value_type&>(__v);
902+
}
891903

892904
~__hash_value_type() = delete;
893905
};

0 commit comments

Comments
 (0)