mirror of
https://github.com/llvm-mirror/libcxx.git
synced 2025-10-25 04:56:13 +08:00
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'. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@260601 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -369,6 +369,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
|
|||||||
#include <__hash_table>
|
#include <__hash_table>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include <__debug>
|
#include <__debug>
|
||||||
|
|
||||||
@@ -1128,7 +1129,7 @@ public:
|
|||||||
{return __table_.__equal_range_unique(__k);}
|
{return __table_.__equal_range_unique(__k);}
|
||||||
|
|
||||||
mapped_type& operator[](const key_type& __k);
|
mapped_type& operator[](const key_type& __k);
|
||||||
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
#ifndef _LIBCPP_CXX03_LANG
|
||||||
mapped_type& operator[](key_type&& __k);
|
mapped_type& operator[](key_type&& __k);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1184,10 +1185,10 @@ public:
|
|||||||
#endif // _LIBCPP_DEBUG_LEVEL >= 2
|
#endif // _LIBCPP_DEBUG_LEVEL >= 2
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef _LIBCPP_CXX03_LANG
|
|
||||||
__node_holder __construct_node_with_key(key_type&& __k);
|
#ifdef _LIBCPP_CXX03_LANG
|
||||||
#endif // _LIBCPP_CXX03_LANG
|
|
||||||
__node_holder __construct_node_with_key(const key_type& __k);
|
__node_holder __construct_node_with_key(const key_type& __k);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||||
@@ -1394,23 +1395,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(
|
|||||||
|
|
||||||
#endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
|
#endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
|
||||||
|
|
||||||
#ifndef _LIBCPP_CXX03_LANG
|
#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(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
|
|
||||||
|
|
||||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||||
typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
|
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)
|
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, _Alloc>::__construct_node_with_key(const
|
|||||||
__h.get_deleter().__second_constructed = true;
|
__h.get_deleter().__second_constructed = true;
|
||||||
return _LIBCPP_EXPLICIT_MOVE(__h); // explicitly moved for C++03
|
return _LIBCPP_EXPLICIT_MOVE(__h); // explicitly moved for C++03
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||||
template <class _InputIterator>
|
template <class _InputIterator>
|
||||||
@@ -1435,6 +1421,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(_InputIterator __first,
|
|||||||
__table_.__insert_unique(*__first);
|
__table_.__insert_unique(*__first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _LIBCPP_CXX03_LANG
|
||||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||||
_Tp&
|
_Tp&
|
||||||
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k)
|
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k)
|
||||||
@@ -1447,23 +1434,27 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k)
|
|||||||
__h.release();
|
__h.release();
|
||||||
return __r.first->second;
|
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>
|
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||||
_Tp&
|
_Tp&
|
||||||
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](key_type&& __k)
|
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](key_type&& __k)
|
||||||
{
|
{
|
||||||
iterator __i = find(__k);
|
return __table_.__emplace_unique_key_args(__k,
|
||||||
if (__i != end())
|
std::piecewise_construct, std::forward_as_tuple(std::move(__k)),
|
||||||
return __i->second;
|
std::forward_as_tuple()).first->__cc.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
#endif // !_LIBCPP_CXX03_MODE
|
||||||
|
|
||||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||||
_Tp&
|
_Tp&
|
||||||
|
|||||||
@@ -19,8 +19,11 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
#include "MoveOnly.h"
|
#include "MoveOnly.h"
|
||||||
#include "min_allocator.h"
|
#include "min_allocator.h"
|
||||||
|
#include "count_new.hpp"
|
||||||
|
#include "container_test_types.h"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
@@ -44,7 +47,7 @@ int main()
|
|||||||
assert(c.size() == 5);
|
assert(c.size() == 5);
|
||||||
assert(c.at(11) == "eleven");
|
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::unordered_map<MoveOnly, std::string> C;
|
||||||
typedef std::pair<int, std::string> P;
|
typedef std::pair<int, std::string> P;
|
||||||
@@ -65,8 +68,6 @@ int main()
|
|||||||
assert(c.size() == 5);
|
assert(c.size() == 5);
|
||||||
assert(c.at(11) == "eleven");
|
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>,
|
typedef std::unordered_map<int, std::string, std::hash<int>, std::equal_to<int>,
|
||||||
min_allocator<std::pair<const int, std::string>>> C;
|
min_allocator<std::pair<const int, std::string>>> C;
|
||||||
@@ -88,7 +89,7 @@ int main()
|
|||||||
assert(c.size() == 5);
|
assert(c.size() == 5);
|
||||||
assert(c.at(11) == "eleven");
|
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>,
|
typedef std::unordered_map<MoveOnly, std::string, std::hash<MoveOnly>, std::equal_to<MoveOnly>,
|
||||||
min_allocator<std::pair<const MoveOnly, std::string>>> C;
|
min_allocator<std::pair<const MoveOnly, std::string>>> C;
|
||||||
@@ -110,6 +111,50 @@ int main()
|
|||||||
assert(c.size() == 5);
|
assert(c.size() == 5);
|
||||||
assert(c.at(11) == "eleven");
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++98, c++03
|
||||||
|
|
||||||
// <unordered_map>
|
// <unordered_map>
|
||||||
|
|
||||||
// template <class Key, class T, class Hash = hash<Key>, class Pred = equal_to<Key>,
|
// 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
|
// http://llvm.org/bugs/show_bug.cgi?id=16542
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#ifndef _LIBCPP_HAS_NO_VARIADICS
|
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@@ -30,12 +29,8 @@ struct my_hash
|
|||||||
size_t operator()(const tuple<int,int>&) const {return 0;}
|
size_t operator()(const tuple<int,int>&) const {return 0;}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
#ifndef _LIBCPP_HAS_NO_VARIADICS
|
|
||||||
unordered_map<tuple<int,int>, size_t, my_hash> m;
|
unordered_map<tuple<int,int>, size_t, my_hash> m;
|
||||||
m[make_tuple(2,3)]=7;
|
m[make_tuple(2,3)]=7;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
CopyInsertable(CopyInsertable const& other) : data(other.data),
|
||||||
copied_once(true),
|
copied_once(true),
|
||||||
constructed_under_allocator(true) {
|
constructed_under_allocator(true) {
|
||||||
|
|||||||
Reference in New Issue
Block a user