Author: ericwf Date: Thu Feb 11 15:45:53 2016 New Revision: 260601 URL: http://llvm.org/viewvc/llvm-project?rev=260601&view=rev Log: Fix LWG issue 2469 - Use piecewise construction in unordered_map::operator[].
unordered_map's allocator may only be used to construct objects of 'value_type', or in this case 'pair<const Key, Value>'. In order to respect this requirement in operator[], which requires default constructing the 'mapped_type', we have to use pair's piecewise constructor with '(tuple<Kep>, tuple<>)'. Unfortunately we still need to provide a fallback implementation for C++03 since we don't have <tuple>. Even worse this fallback is the last remaining user of '__hash_map_node_destructor' and '__construct_node_with_key'. Modified: libcxx/trunk/include/unordered_map libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index.pass.cpp libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index_tuple.pass.cpp libcxx/trunk/test/support/container_test_types.h Modified: libcxx/trunk/include/unordered_map URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/unordered_map?rev=260601&r1=260600&r2=260601&view=diff ============================================================================== --- libcxx/trunk/include/unordered_map (original) +++ libcxx/trunk/include/unordered_map Thu Feb 11 15:45:53 2016 @@ -369,6 +369,7 @@ template <class Key, class T, class Hash #include <__hash_table> #include <functional> #include <stdexcept> +#include <tuple> #include <__debug> @@ -1128,7 +1129,7 @@ public: {return __table_.__equal_range_unique(__k);} mapped_type& operator[](const key_type& __k); -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +#ifndef _LIBCPP_CXX03_LANG mapped_type& operator[](key_type&& __k); #endif @@ -1184,10 +1185,10 @@ public: #endif // _LIBCPP_DEBUG_LEVEL >= 2 private: -#ifndef _LIBCPP_CXX03_LANG - __node_holder __construct_node_with_key(key_type&& __k); -#endif // _LIBCPP_CXX03_LANG + +#ifdef _LIBCPP_CXX03_LANG __node_holder __construct_node_with_key(const key_type& __k); +#endif }; template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> @@ -1394,23 +1395,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _ #endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS -#ifndef _LIBCPP_CXX03_LANG - -template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> -typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node_with_key(key_type&& __k) -{ - __node_allocator& __na = __table_.__node_alloc(); - __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); - __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.first), _VSTD::move(__k)); - __h.get_deleter().__first_constructed = true; - __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.second)); - __h.get_deleter().__second_constructed = true; - return __h; -} - -#endif - +#ifdef _LIBCPP_CXX03_LANG template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> 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) @@ -1423,6 +1408,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _ __h.get_deleter().__second_constructed = true; return _LIBCPP_EXPLICIT_MOVE(__h); // explicitly moved for C++03 } +#endif template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> template <class _InputIterator> @@ -1435,6 +1421,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _ __table_.__insert_unique(*__first); } +#ifdef _LIBCPP_CXX03_LANG template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> _Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k) @@ -1447,23 +1434,27 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _ __h.release(); return __r.first->second; } +#else -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +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, + std::piecewise_construct, std::forward_as_tuple(__k), + std::forward_as_tuple()).first->__cc.second; +} template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> _Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](key_type&& __k) { - iterator __i = find(__k); - if (__i != end()) - return __i->second; - __node_holder __h = __construct_node_with_key(_VSTD::move(__k)); - pair<iterator, bool> __r = __table_.__node_insert_unique(__h.get()); - __h.release(); - return __r.first->second; + return __table_.__emplace_unique_key_args(__k, + std::piecewise_construct, std::forward_as_tuple(std::move(__k)), + std::forward_as_tuple()).first->__cc.second; } -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES +#endif // !_LIBCPP_CXX03_MODE template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> _Tp& Modified: libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index.pass.cpp?rev=260601&r1=260600&r2=260601&view=diff ============================================================================== --- libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index.pass.cpp (original) +++ libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index.pass.cpp Thu Feb 11 15:45:53 2016 @@ -19,8 +19,11 @@ #include <string> #include <cassert> +#include "test_macros.h" #include "MoveOnly.h" #include "min_allocator.h" +#include "count_new.hpp" +#include "container_test_types.h" int main() { @@ -44,7 +47,7 @@ int main() assert(c.size() == 5); assert(c.at(11) == "eleven"); } -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +#if TEST_STD_VER >= 11 { typedef std::unordered_map<MoveOnly, std::string> C; typedef std::pair<int, std::string> P; @@ -65,8 +68,6 @@ int main() assert(c.size() == 5); assert(c.at(11) == "eleven"); } -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES -#if __cplusplus >= 201103L { typedef std::unordered_map<int, std::string, std::hash<int>, std::equal_to<int>, min_allocator<std::pair<const int, std::string>>> C; @@ -88,7 +89,7 @@ int main() assert(c.size() == 5); assert(c.at(11) == "eleven"); } -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + { typedef std::unordered_map<MoveOnly, std::string, std::hash<MoveOnly>, std::equal_to<MoveOnly>, min_allocator<std::pair<const MoveOnly, std::string>>> C; @@ -110,6 +111,50 @@ int main() assert(c.size() == 5); assert(c.at(11) == "eleven"); } -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES + { + using Container = TCT::unordered_map<>; + using Key = Container::key_type; + using MappedType = Container::mapped_type; + using ValueTp = Container::value_type; + ConstructController* cc = getConstructController(); + cc->reset(); + { + Container c; + const Key k(1); + cc->expect<std::piecewise_construct_t const&, std::tuple<Key const&>&&, std::tuple<>&&>(); + MappedType& mref = c[k]; + assert(!cc->unchecked()); + { + DisableAllocationGuard g; + MappedType& mref2 = c[k]; + assert(&mref == &mref2); + } + } + { + Container c; + Key k(1); + cc->expect<std::piecewise_construct_t const&, std::tuple<Key const&>&&, std::tuple<>&&>(); + MappedType& mref = c[k]; + assert(!cc->unchecked()); + { + DisableAllocationGuard g; + MappedType& mref2 = c[k]; + assert(&mref == &mref2); + } + } + { + Container c; + Key k(1); + cc->expect<std::piecewise_construct_t const&, std::tuple<Key &&>&&, std::tuple<>&&>(); + MappedType& mref = c[std::move(k)]; + assert(!cc->unchecked()); + { + Key k2(1); + DisableAllocationGuard g; + MappedType& mref2 = c[std::move(k2)]; + assert(&mref == &mref2); + } + } + } #endif } Modified: libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index_tuple.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index_tuple.pass.cpp?rev=260601&r1=260600&r2=260601&view=diff ============================================================================== --- libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index_tuple.pass.cpp (original) +++ libcxx/trunk/test/std/containers/unord/unord.map/unord.map.elem/index_tuple.pass.cpp Thu Feb 11 15:45:53 2016 @@ -7,6 +7,8 @@ // //===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03 + // <unordered_map> // template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>, @@ -18,9 +20,6 @@ // http://llvm.org/bugs/show_bug.cgi?id=16542 #include <unordered_map> - -#ifndef _LIBCPP_HAS_NO_VARIADICS - #include <tuple> using namespace std; @@ -30,12 +29,8 @@ struct my_hash size_t operator()(const tuple<int,int>&) const {return 0;} }; -#endif - int main() { -#ifndef _LIBCPP_HAS_NO_VARIADICS unordered_map<tuple<int,int>, size_t, my_hash> m; m[make_tuple(2,3)]=7; -#endif } Modified: libcxx/trunk/test/support/container_test_types.h URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/container_test_types.h?rev=260601&r1=260600&r2=260601&view=diff ============================================================================== --- libcxx/trunk/test/support/container_test_types.h (original) +++ libcxx/trunk/test/support/container_test_types.h Thu Feb 11 15:45:53 2016 @@ -393,6 +393,11 @@ struct CopyInsertable { } } + CopyInsertable() : data(0), copied_once(false), constructed_under_allocator(true) + { + assert(getConstructController()->isInAllocatorConstruct()); + } + CopyInsertable(CopyInsertable const& other) : data(other.data), copied_once(true), constructed_under_allocator(true) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits