[libcxx] r260601 - Fix LWG issue 2469 - Use piecewise construction in unordered_map::operator[].
Eric Fiselier via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 11 13:45:54 PST 2016
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) {
More information about the cfe-commits
mailing list