This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Add std::unordered_* C++11 allocator support
- From: François Dumont <frs dot dumont at gmail dot com>
- To: "libstdc++ at gcc dot gnu dot org" <libstdc++ at gcc dot gnu dot org>
- Date: Fri, 15 Mar 2013 21:45:21 +0100
- Subject: Add std::unordered_* C++11 allocator support
Hello
I think I have completed support of C++11 allocators in unordered
containers.
I preferred to remove the const of the key part to enable copy/move
assignment in the context of std::unordered_map/multimap. This will give
more behavioral consistency accross all the std::unordered_* types.
I took the opportunity to remove include of <bits/stl_algobase.h>
from <unordered_set> and <unordered_map> Standard headers. It became
useless since _Prime_rehash_policy definition that is using
std::lower_bound moved to src/c++11/hashtable_c0x.cc. This source file
doesn't need it neither because bits/stl_algobase.h is included by the
way through an other path, should I add it explicitly ?
I also noticed that operator=(std::initializer_list<>) could reuse
existing nodes rather than reallocating everything. I kept it for a
future patch.
2013-03-31 François Dumont <fdumont@gcc.gnu.org>
* include/bits/move.h (std::__move_assign_if_noexcept): New.
* include/bits/hashtable_policy.h: Add C++11 allocator support.
* include/bits/hashtable.h: Likewise.
* include/bits/unordered_set.h: Likewise.
* include/bits/unordered_map.h: Likewise.
* include/debug/unordered_set: Likewise.
* include/debug/unordered_map: Likewise.
* include/std/unordered_set: Remove bits/algobase.h
include. Replace bits/alloc_traits.h by ext/alloc_traits.h.
* include/std/unordered_map: Likewise.
* testsuite/util/testsuite_counter_type.h: Add count of destructors.
* testsuite/23_containers/unordered_set/
not_default_constructible_hash_neg.cc: Adapt line number.
* testsuite/23_containers/unordered_set/instantiation_neg.cc: Likewise.
* testsuite/23_containers/unordered_set/allocator/copy.cc: New.
* testsuite/23_containers/unordered_set/allocator/copy_assign.cc: New.
* testsuite/23_containers/unordered_set/allocator/minimal.cc: New.
* testsuite/23_containers/unordered_set/allocator/move_assign.cc: New.
* testsuite/23_containers/unordered_set/allocator/noexcept.cc: New.
* testsuite/23_containers/unordered_set/allocator/swap.cc: New.
* testsuite/23_containers/unordered_multiset/allocator/copy.cc: New.
* testsuite/23_containers/unordered_multiset/allocator/copy_assign.cc:
New.
* testsuite/23_containers/unordered_multiset/allocator/minimal.cc: New.
* testsuite/23_containers/unordered_multiset/allocator/move_assign.cc:
New.
* testsuite/23_containers/unordered_multiset/allocator/noexcept.cc:
New.
* testsuite/23_containers/unordered_multiset/allocator/swap.cc: New.
* testsuite/23_containers/unordered_map/allocator/copy.cc: New.
* testsuite/23_containers/unordered_map/allocator/copy_assign.cc: New.
* testsuite/23_containers/unordered_map/allocator/minimal.cc: New.
* testsuite/23_containers/unordered_map/allocator/move_assign.cc: New.
* testsuite/23_containers/unordered_map/allocator/noexcept.cc:
New.
* testsuite/23_containers/unordered_map/allocator/swap.cc: New.
* testsuite/23_containers/unordered_multimap/allocator/copy.cc: New.
* testsuite/23_containers/unordered_multimap/allocator/copy_assign.cc:
New.
* testsuite/23_containers/unordered_multimap/allocator/minimal.cc: New.
* testsuite/23_containers/unordered_multimap/allocator/move_assign.cc:
New.
* testsuite/23_containers/unordered_multimap/allocator/noexcept.cc:
New.
* testsuite/23_containers/unordered_multimap/allocator/swap.cc: New.
Tested under Linux x86_64 normal and debug modes.
Ok to commit when 4.9 stage 1 open ?
François
Index: include/bits/move.h
===================================================================
--- include/bits/move.h (revision 196664)
+++ include/bits/move.h (working copy)
@@ -121,6 +121,18 @@
move_if_noexcept(_Tp& __x) noexcept
{ return std::move(__x); }
+ template<typename _Tp>
+ struct __move_assign_if_noexcept_cond
+ : public __and_<__not_<is_nothrow_move_assignable<_Tp>>,
+ is_copy_assignable<_Tp>>::type { };
+
+ template<typename _Tp>
+ inline constexpr typename
+ conditional<__move_assign_if_noexcept_cond<_Tp>::value,
+ const _Tp&, _Tp&&>::type
+ __move_assign_if_noexcept(_Tp& __x) noexcept
+ { return std::move(__x); }
+
// declval, from type_traits.
/**
Index: include/bits/hashtable_policy.h
===================================================================
--- include/bits/hashtable_policy.h (revision 196664)
+++ include/bits/hashtable_policy.h (working copy)
@@ -102,6 +102,14 @@
{ return std::get<0>(std::forward<_Tp>(__x)); }
};
+ template<typename _Value>
+ struct _Mutable_Value_Type
+ { typedef _Value type; };
+
+ template<typename _T1, typename _T2>
+ struct _Mutable_Value_Type<std::pair<_T1, _T2>>
+ { typedef std::pair<typename std::remove_const<_T1>::type, _T2> type; };
+
// Auxiliary types used for all instantiations of _Hashtable nodes
// and iterators.
@@ -156,6 +164,43 @@
};
/**
+ * struct _Hash_node_value_base
+ *
+ * Node type with the value to store.
+ */
+ template<typename _Value>
+ struct _Hash_node_value_base : _Hash_node_base
+ {
+ typename aligned_storage<sizeof(_Value), alignment_of<_Value>::value>::type
+ _M_storage;
+
+ _Value*
+ _M_valptr() noexcept
+ { return static_cast<_Value*>(static_cast<void*>(&_M_storage)); }
+
+ const _Value*
+ _M_valptr() const noexcept
+ {
+ return
+ static_cast<const _Value*>(static_cast<const void*>(&_M_storage));
+ }
+
+ _Value&
+ _M_v() noexcept
+ { return *_M_valptr(); }
+
+ const _Value&
+ _M_v() const noexcept
+ { return *_M_valptr(); }
+
+ typedef typename _Mutable_Value_Type<_Value>::type _MValue;
+
+ _MValue&
+ _M_mv() noexcept
+ { return *static_cast<_MValue*>(static_cast<void*>(&_M_storage)); }
+ };
+
+ /**
* Primary template struct _Hash_node.
*/
template<typename _Value, bool _Cache_hash_code>
@@ -164,38 +209,27 @@
/**
* Specialization for nodes with caches, struct _Hash_node.
*
- * Base class is __detail::_Hash_node_base.
+ * Base class is __detail::_Hash_node_value_base.
*/
template<typename _Value>
- struct _Hash_node<_Value, true> : _Hash_node_base
+ struct _Hash_node<_Value, true> : _Hash_node_value_base<_Value>
{
- _Value _M_v;
std::size_t _M_hash_code;
- template<typename... _Args>
- _Hash_node(_Args&&... __args)
- : _M_v(std::forward<_Args>(__args)...), _M_hash_code() { }
-
_Hash_node*
- _M_next() const { return static_cast<_Hash_node*>(_M_nxt); }
+ _M_next() const { return static_cast<_Hash_node*>(this->_M_nxt); }
};
/**
* Specialization for nodes without caches, struct _Hash_node.
*
- * Base class is __detail::_Hash_node_base.
+ * Base class is __detail::_Hash_node_value_base.
*/
template<typename _Value>
- struct _Hash_node<_Value, false> : _Hash_node_base
+ struct _Hash_node<_Value, false> : _Hash_node_value_base<_Value>
{
- _Value _M_v;
-
- template<typename... _Args>
- _Hash_node(_Args&&... __args)
- : _M_v(std::forward<_Args>(__args)...) { }
-
_Hash_node*
- _M_next() const { return static_cast<_Hash_node*>(_M_nxt); }
+ _M_next() const { return static_cast<_Hash_node*>(this->_M_nxt); }
};
/// Base class for node iterators.
@@ -255,11 +289,11 @@
reference
operator*() const
- { return this->_M_cur->_M_v; }
+ { return this->_M_cur->_M_v(); }
pointer
operator->() const
- { return std::__addressof(this->_M_cur->_M_v); }
+ { return this->_M_cur->_M_valptr(); }
_Node_iterator&
operator++()
@@ -307,11 +341,11 @@
reference
operator*() const
- { return this->_M_cur->_M_v; }
+ { return this->_M_cur->_M_v(); }
pointer
operator->() const
- { return std::__addressof(this->_M_cur->_M_v); }
+ { return this->_M_cur->_M_valptr(); }
_Node_const_iterator&
operator++()
@@ -496,7 +530,7 @@
return __h->_M_insert_unique_node(__n, __code, __p)->second;
}
- return (__p->_M_v).second;
+ return __p->_M_v().second;
}
template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
@@ -522,7 +556,7 @@
return __h->_M_insert_unique_node(__n, __code, __p)->second;
}
- return (__p->_M_v).second;
+ return __p->_M_v().second;
}
template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
@@ -542,7 +576,7 @@
if (!__p)
__throw_out_of_range(__N("_Map_base::at"));
- return (__p->_M_v).second;
+ return __p->_M_v().second;
}
template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
@@ -562,7 +596,7 @@
if (!__p)
__throw_out_of_range(__N("_Map_base::at"));
- return (__p->_M_v).second;
+ return __p->_M_v().second;
}
/**
@@ -939,7 +973,7 @@
std::size_t
_M_bucket_index(const __node_type* __p, std::size_t __n) const
- { return _M_ranged_hash()(_M_extract()(__p->_M_v), __n); }
+ { return _M_ranged_hash()(_M_extract()(__p->_M_v()), __n); }
void
_M_store_code(__node_type*, __hash_code) const
@@ -1025,7 +1059,7 @@
std::size_t
_M_bucket_index(const __node_type* __p,
std::size_t __n) const
- { return _M_h2()(_M_h1()(_M_extract()(__p->_M_v)), __n); }
+ { return _M_h2()(_M_h1()(_M_extract()(__p->_M_v())), __n); }
void
_M_store_code(__node_type*, __hash_code) const
@@ -1163,7 +1197,7 @@
static bool
_S_equals(const _Equal& __eq, const _ExtractKey& __extract,
const _Key& __k, _HashCodeType __c, _Hash_node<_Value, true>* __n)
- { return __c == __n->_M_hash_code && __eq(__k, __extract(__n->_M_v)); }
+ { return __c == __n->_M_hash_code && __eq(__k, __extract(__n->_M_v())); }
};
/// Specialization.
@@ -1174,7 +1208,7 @@
static bool
_S_equals(const _Equal& __eq, const _ExtractKey& __extract,
const _Key& __k, _HashCodeType, _Hash_node<_Value, false>* __n)
- { return __eq(__k, __extract(__n->_M_v)); }
+ { return __eq(__k, __extract(__n->_M_v())); }
};
@@ -1305,11 +1339,11 @@
reference
operator*() const
- { return this->_M_cur->_M_v; }
+ { return this->_M_cur->_M_v(); }
pointer
operator->() const
- { return std::__addressof(this->_M_cur->_M_v); }
+ { return this->_M_cur->_M_valptr(); }
_Local_iterator&
operator++()
@@ -1364,11 +1398,11 @@
reference
operator*() const
- { return this->_M_cur->_M_v; }
+ { return this->_M_cur->_M_v(); }
pointer
operator->() const
- { return std::__addressof(this->_M_cur->_M_v); }
+ { return this->_M_cur->_M_valptr(); }
_Local_const_iterator&
operator++()
@@ -1662,6 +1696,178 @@
{ }
};
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash,
+ typename _RehashPolicy, typename _Traits,
+ bool = std::is_copy_assignable<
+ typename _Mutable_Value_Type<_Value>::type>::value>
+ struct _ReuseOrAllocNode
+ {
+ private:
+ using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
+ _Equal, _H1, _H2, _Hash,
+ _RehashPolicy, _Traits>;
+ using __alloc_type = typename __hashtable::_Value_alloc_type;
+ using __alloc_traits = typename __hashtable::_Value_alloc_traits;
+ using __node_type = typename __hashtable::__node_type;
+
+ public:
+ _ReuseOrAllocNode(__node_type* __nodes, __hashtable& __h)
+ : _M_nodes(__nodes), _M_h(__h) { }
+ _ReuseOrAllocNode(const _ReuseOrAllocNode&) = delete;
+
+ ~_ReuseOrAllocNode()
+ { _M_h._M_deallocate_nodes(_M_nodes); }
+
+ __node_type*
+ operator()(const __node_type* __n) const
+ {
+ if (_M_nodes)
+ {
+ __node_type* __node = _M_nodes;
+ _M_nodes = _M_nodes->_M_next();
+ __node->_M_nxt = nullptr;
+ __alloc_type __a(_M_h._M_node_allocator());
+ __alloc_traits::destroy(__a, __node->_M_valptr());
+ __alloc_traits::construct(__a, __node->_M_valptr(), __n->_M_v());
+ return __node;
+ }
+ return _M_h._M_allocate_node(__n->_M_v());
+ }
+
+ mutable __node_type* _M_nodes;
+ __hashtable& _M_h;
+ };
+
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash,
+ typename _RehashPolicy, typename _Traits>
+ struct _ReuseOrAllocNode<_Key, _Value, _Alloc, _ExtractKey,
+ _Equal, _H1, _H2, _Hash,
+ _RehashPolicy, _Traits,
+ true>
+ {
+ private:
+ using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
+ _Equal, _H1, _H2, _Hash,
+ _RehashPolicy, _Traits>;
+ using __node_type = typename __hashtable::__node_type;
+
+ public:
+ _ReuseOrAllocNode(__node_type* __nodes, __hashtable& __h)
+ : _M_nodes(__nodes), _M_h(__h) { }
+ _ReuseOrAllocNode(const _ReuseOrAllocNode&) = delete;
+
+ ~_ReuseOrAllocNode()
+ { _M_h._M_deallocate_nodes(_M_nodes); }
+
+ __node_type*
+ operator()(const __node_type* __n) const
+ {
+ if (_M_nodes)
+ {
+ __node_type* __node = _M_nodes;
+ _M_nodes = _M_nodes->_M_next();
+ __node->_M_nxt = nullptr;
+ __node->_M_mv() = __n->_M_v();
+ return __node;
+ }
+ return _M_h._M_allocate_node(__n->_M_v());
+ }
+
+ mutable __node_type* _M_nodes;
+ __hashtable& _M_h;
+ };
+
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash,
+ typename _RehashPolicy, typename _Traits,
+ bool = std::is_move_assignable<
+ typename _Mutable_Value_Type<_Value>::type>::value>
+ struct _MoveReuseOrAllocNode
+ {
+ private:
+ using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
+ _Equal, _H1, _H2, _Hash,
+ _RehashPolicy, _Traits>;
+ using __alloc_type = typename __hashtable::_Value_alloc_type;
+ using __alloc_traits = typename __hashtable::_Value_alloc_traits;
+ using __node_type = typename __hashtable::__node_type;
+
+ public:
+ _MoveReuseOrAllocNode(__node_type* __nodes, __hashtable& __h)
+ : _M_nodes(__nodes), _M_h(__h) { }
+ _MoveReuseOrAllocNode(const _MoveReuseOrAllocNode&) = delete;
+
+ ~_MoveReuseOrAllocNode()
+ { _M_h._M_deallocate_nodes(_M_nodes); }
+
+ __node_type*
+ operator()(__node_type* __n) const
+ {
+ if (_M_nodes)
+ {
+ __node_type* __node = _M_nodes;
+ _M_nodes = _M_nodes->_M_next();
+ __node->_M_nxt = nullptr;
+ __alloc_type __a(_M_h._M_node_allocator());
+ __alloc_traits::destroy(__a, __node->_M_valptr());
+ __alloc_traits::construct(__a, __node->_M_valptr(),
+ std::move_if_noexcept(__n->_M_mv()));
+ return __node;
+ }
+ return _M_h._M_allocate_node(std::move_if_noexcept(__n->_M_mv()));
+ }
+
+ mutable __node_type* _M_nodes;
+ __hashtable& _M_h;
+ };
+
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash,
+ typename _RehashPolicy, typename _Traits>
+ struct _MoveReuseOrAllocNode<_Key, _Value, _Alloc, _ExtractKey,
+ _Equal, _H1, _H2, _Hash,
+ _RehashPolicy, _Traits,
+ true>
+ {
+ private:
+ using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
+ _Equal, _H1, _H2, _Hash,
+ _RehashPolicy, _Traits>;
+ using __node_type = typename __hashtable::__node_type;
+
+ public:
+ _MoveReuseOrAllocNode(__node_type* __nodes, __hashtable& __h)
+ : _M_nodes(__nodes), _M_h(__h) { }
+ _MoveReuseOrAllocNode(const _MoveReuseOrAllocNode&) = delete;
+
+ ~_MoveReuseOrAllocNode()
+ { _M_h._M_deallocate_nodes(_M_nodes); }
+
+ __node_type*
+ operator()(__node_type* __n) const
+ {
+ if (_M_nodes)
+ {
+ __node_type* __node = _M_nodes;
+ _M_nodes = _M_nodes->_M_next();
+ __node->_M_nxt = nullptr;
+ __node->_M_mv() = std::__move_assign_if_noexcept(__n->_M_mv());
+ return __node;
+ }
+ // else we need to allocate new nodes.
+ return _M_h._M_allocate_node(std::move_if_noexcept(__n->_M_mv()));
+ }
+
+ mutable __node_type* _M_nodes;
+ __hashtable& _M_h;
+ };
+
//@} hashtable-detail
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace __detail
Index: include/bits/hashtable.h
===================================================================
--- include/bits/hashtable.h (revision 196664)
+++ include/bits/hashtable.h (working copy)
@@ -183,18 +183,23 @@
public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, _Traits>
{
+ typedef std::allocator_traits<_Alloc> _Alloc_traits;
+ typedef typename _Alloc_traits::template rebind_alloc<_Value>
+ _Value_alloc_type;
+ typedef __gnu_cxx::__alloc_traits<_Value_alloc_type> _Value_alloc_traits;
+
public:
- typedef _Key key_type;
- typedef _Value value_type;
- typedef _Alloc allocator_type;
- typedef _Equal key_equal;
+ typedef _Key key_type;
+ typedef _Value value_type;
+ typedef _Alloc allocator_type;
+ typedef _Equal key_equal;
// mapped_type, if present, comes from _Map_base.
// hasher, if present, comes from _Hash_code_base/_Hashtable_base.
- typedef typename _Alloc::pointer pointer;
- typedef typename _Alloc::const_pointer const_pointer;
- typedef typename _Alloc::reference reference;
- typedef typename _Alloc::const_reference const_reference;
+ typedef typename _Value_alloc_traits::pointer pointer;
+ typedef typename _Value_alloc_traits::const_pointer const_pointer;
+ typedef typename _Value_alloc_traits::reference reference;
+ typedef typename _Value_alloc_traits::const_reference const_reference;
private:
using __rehash_type = _RehashPolicy;
@@ -302,6 +307,20 @@
bool _Constant_iteratorsa, bool _Unique_keysa>
friend struct __detail::_Insert;
+ template<typename _Keya, typename _Valuea, typename _Alloca,
+ typename _ExtractKeya, typename _Equala,
+ typename _H1a, typename _H2a, typename _Hasha,
+ typename _RehashPolicya, typename _Traitsa,
+ bool _IsCopyAssignable>
+ friend struct __detail::_ReuseOrAllocNode;
+
+ template<typename _Keya, typename _Valuea, typename _Alloca,
+ typename _ExtractKeya, typename _Equala,
+ typename _H1a, typename _H2a, typename _Hasha,
+ typename _RehashPolicya, typename _Traitsa,
+ bool _IsMoveAssignable>
+ friend struct __detail::_MoveReuseOrAllocNode;
+
using size_type = typename __hashtable_base::size_type;
using difference_type = typename __hashtable_base::difference_type;
@@ -313,24 +332,29 @@
const_local_iterator;
private:
- typedef typename _Alloc::template rebind<__node_type>::other
- _Node_allocator_type;
- typedef typename _Alloc::template rebind<__bucket_type>::other
- _Bucket_allocator_type;
+ typedef typename _Alloc_traits::template rebind_alloc<__node_type>
+ _Node_alloc_type;
+ // Use __gnu_cxx to benefit from _S_always_equal and al.
+ typedef __gnu_cxx::__alloc_traits<_Node_alloc_type> _Node_alloc_traits;
- using __before_begin = __detail::_Before_begin<_Node_allocator_type>;
+ typedef
+ typename _Alloc_traits::template rebind_alloc<__bucket_type>
+ _Bucket_alloc_type;
+ typedef std::allocator_traits<_Bucket_alloc_type> _Bucket_alloc_traits;
+ using __before_begin = __detail::_Before_begin<_Node_alloc_type>;
+
__bucket_type* _M_buckets;
size_type _M_bucket_count;
__before_begin _M_bbegin;
size_type _M_element_count;
_RehashPolicy _M_rehash_policy;
- _Node_allocator_type&
+ _Node_alloc_type&
_M_node_allocator()
{ return _M_bbegin; }
- const _Node_allocator_type&
+ const _Node_alloc_type&
_M_node_allocator() const
{ return _M_bbegin; }
@@ -357,7 +381,7 @@
_M_allocate_buckets(size_type __n);
void
- _M_deallocate_buckets(__bucket_type*, size_type __n);
+ _M_deallocate_buckets();
// Gets bucket begin, deals with the fact that non-empty buckets contain
// their before begin node.
@@ -368,6 +392,19 @@
_M_begin() const
{ return static_cast<__node_type*>(_M_before_begin()._M_nxt); }
+ template<typename _UnaryOp>
+ void
+ _M_assign(const _Hashtable&, const _UnaryOp&);
+
+ void
+ _M_move_assign(_Hashtable&&, std::true_type);
+
+ void
+ _M_move_assign(_Hashtable&&, std::false_type);
+
+ void
+ _M_reset();
+
public:
// Constructor, destructor, assignment, swap
_Hashtable(size_type __bucket_hint,
@@ -386,8 +423,19 @@
_Hashtable(_Hashtable&&);
+ _Hashtable(const _Hashtable&, const allocator_type&);
+
+ _Hashtable(_Hashtable&&, const allocator_type&);
+
// Use delegating constructors.
explicit
+ _Hashtable(const allocator_type& __a)
+ : _Hashtable(10, _H1(), __detail::_Mod_range_hashing(),
+ __detail::_Default_ranged_hash(), key_equal(),
+ __key_extract(), __a)
+ { }
+
+ explicit
_Hashtable(size_type __n = 10,
const _H1& __hf = _H1(),
const key_equal& __eql = key_equal(),
@@ -420,34 +468,33 @@
{ }
_Hashtable&
- operator=(const _Hashtable& __ht)
- {
- _Hashtable __tmp(__ht);
- this->swap(__tmp);
- return *this;
- }
+ operator=(const _Hashtable& __ht);
_Hashtable&
operator=(_Hashtable&& __ht)
+ noexcept(_Node_alloc_traits::_S_nothrow_move())
{
- // NB: DR 1204.
- // NB: DR 675.
- this->clear();
- this->swap(__ht);
+ constexpr bool __move_storage =
+ _Node_alloc_traits::_S_propagate_on_move_assign()
+ || _Node_alloc_traits::_S_always_equal();
+ _M_move_assign(std::move(__ht),
+ integral_constant<bool, __move_storage>());
return *this;
}
_Hashtable&
operator=(initializer_list<value_type> __l)
{
- this->clear();
+ clear();
this->insert(__l.begin(), __l.end());
return *this;
}
~_Hashtable() noexcept;
- void swap(_Hashtable&);
+ void
+ swap(_Hashtable&)
+ noexcept(_Node_alloc_traits::_S_nothrow_swap());
// Basic container operations
iterator
@@ -488,7 +535,7 @@
size_type
max_size() const noexcept
- { return _M_node_allocator().max_size(); }
+ { return _Node_alloc_traits::max_size(_M_node_allocator()); }
// Observers
key_equal
@@ -721,15 +768,18 @@
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
_M_allocate_node(_Args&&... __args)
{
- __node_type* __n = _M_node_allocator().allocate(1);
+ __node_type* __n = _Node_alloc_traits::allocate(_M_node_allocator(), 1);
__try
{
- _M_node_allocator().construct(__n, std::forward<_Args>(__args)...);
+ _Value_alloc_type __a(_M_node_allocator());
+ ::new ((void*)__n) __node_type();
+ _Value_alloc_traits::construct(__a, __n->_M_valptr(),
+ std::forward<_Args>(__args)...);
return __n;
}
__catch(...)
{
- _M_node_allocator().deallocate(__n, 1);
+ _Node_alloc_traits::deallocate(_M_node_allocator(), __n, 1);
__throw_exception_again;
}
}
@@ -743,8 +793,10 @@
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
_M_deallocate_node(__node_type* __n)
{
- _M_node_allocator().destroy(__n);
- _M_node_allocator().deallocate(__n, 1);
+ _Value_alloc_type __a(_M_node_allocator());
+ _Value_alloc_traits::destroy(__a, __n->_M_valptr());
+ __n->~__node_type();
+ _Node_alloc_traits::deallocate(_M_node_allocator(), __n, 1);
}
template<typename _Key, typename _Value,
@@ -774,9 +826,9 @@
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
_M_allocate_buckets(size_type __n)
{
- _Bucket_allocator_type __alloc(_M_node_allocator());
+ _Bucket_alloc_type __alloc(_M_node_allocator());
- __bucket_type* __p = __alloc.allocate(__n);
+ __bucket_type* __p = _Bucket_alloc_traits::allocate(__alloc, __n);
__builtin_memset(__p, 0, __n * sizeof(__bucket_type));
return __p;
}
@@ -788,10 +840,10 @@
void
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
- _M_deallocate_buckets(__bucket_type* __p, size_type __n)
+ _M_deallocate_buckets()
{
- _Bucket_allocator_type __alloc(_M_node_allocator());
- __alloc.deallocate(__p, __n);
+ _Bucket_alloc_type __alloc(_M_node_allocator());
+ _Bucket_alloc_traits::deallocate(__alloc, _M_buckets, _M_bucket_count);
}
template<typename _Key, typename _Value,
@@ -822,7 +874,6 @@
: __hashtable_base(__exk, __h1, __h2, __h, __eq),
__map_base(),
__rehash_base(),
- _M_bucket_count(0),
_M_bbegin(__a),
_M_element_count(0),
_M_rehash_policy()
@@ -846,7 +897,6 @@
: __hashtable_base(__exk, __h1, __h2, __h, __eq),
__map_base(),
__rehash_base(),
- _M_bucket_count(0),
_M_bbegin(__a),
_M_element_count(0),
_M_rehash_policy()
@@ -866,7 +916,7 @@
__catch(...)
{
clear();
- _M_deallocate_buckets(_M_buckets, _M_bucket_count);
+ _M_deallocate_buckets();
__throw_exception_again;
}
}
@@ -876,49 +926,212 @@
typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
typename _Traits>
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>&
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>::operator=(
+ const _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>& __ht)
+ {
+ if (&__ht == this)
+ return *this;
+
+ if (_Node_alloc_traits::_S_propagate_on_copy_assign())
+ {
+ auto& __this_alloc = this->_M_node_allocator();
+ auto& __that_alloc = __ht._M_node_allocator();
+ if (!_Node_alloc_traits::_S_always_equal()
+ && __this_alloc != __that_alloc)
+ {
+ // Replacement allocator cannot free existing storage.
+ _M_deallocate_nodes(_M_begin());
+ _M_before_begin()._M_nxt = nullptr;
+ _M_deallocate_buckets();
+ _M_buckets = nullptr;
+ __hashtable_base::operator=(__ht);
+ _M_bucket_count = __ht._M_bucket_count;
+ _M_element_count = __ht._M_element_count;
+ _M_rehash_policy = __ht._M_rehash_policy;
+ std::__alloc_on_copy(__this_alloc, __that_alloc);
+ _M_assign(__ht,
+ [this](const __node_type* __n)
+ { return _M_allocate_node(__n->_M_v()); });
+ return *this;
+ }
+ std::__alloc_on_copy(__this_alloc, __that_alloc);
+ }
+
+ // We can reuse allocated buckets and nodes.
+ if (_M_bucket_count != __ht._M_bucket_count)
+ {
+ auto __buckets = _M_allocate_buckets(__ht._M_bucket_count);
+ _M_deallocate_buckets();
+ _M_buckets = __buckets;
+ _M_bucket_count = __ht._M_bucket_count;
+ }
+ else
+ __builtin_memset(_M_buckets, 0,
+ _M_bucket_count * sizeof(__bucket_type));
+
+ __hashtable_base::operator=(__ht);
+ _M_element_count = __ht._M_element_count;
+ _M_rehash_policy = __ht._M_rehash_policy;
+ __detail::_ReuseOrAllocNode<_Key, _Value, _Alloc, _ExtractKey,
+ _Equal, _H1, _H2, _Hash,
+ _RehashPolicy, _Traits>
+ __roan(_M_begin(), *this);
+ _M_before_begin()._M_nxt = nullptr;
+ _M_assign(__ht, __roan);
+ return *this;
+ }
+
+ template<typename _Key, typename _Value,
+ typename _Alloc, typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+ typename _Traits>
+ template<typename _UnaryOp>
+ void
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>::
+ _M_assign(const _Hashtable& __ht, const _UnaryOp& __node_getter)
+ {
+ if (!_M_buckets)
+ _M_buckets = _M_allocate_buckets(_M_bucket_count);
+
+ __try
+ {
+ if (!__ht._M_before_begin()._M_nxt)
+ return;
+
+ // First deal with the special first node pointed to by
+ // _M_before_begin.
+ __node_type* __ht_n = __ht._M_begin();
+ __node_type* __this_n = __node_getter(__ht_n);
+ this->_M_copy_code(__this_n, __ht_n);
+ _M_before_begin()._M_nxt = __this_n;
+ _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin();
+
+ // Then deal with other nodes.
+ __node_base* __prev_n = __this_n;
+ for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next())
+ {
+ __this_n = __node_getter(__ht_n);
+ __prev_n->_M_nxt = __this_n;
+ this->_M_copy_code(__this_n, __ht_n);
+ size_type __bkt = _M_bucket_index(__this_n);
+ if (!_M_buckets[__bkt])
+ _M_buckets[__bkt] = __prev_n;
+ __prev_n = __this_n;
+ }
+ }
+ __catch(...)
+ {
+ clear();
+ _M_deallocate_buckets();
+ __throw_exception_again;
+ }
+ }
+
+ template<typename _Key, typename _Value,
+ typename _Alloc, typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+ typename _Traits>
+ void
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
+ _M_reset()
+ {
+ _M_rehash_policy = _RehashPolicy();
+ _M_bucket_count = _M_rehash_policy._M_next_bkt(0);
+ _M_buckets = _M_allocate_buckets(_M_bucket_count);
+ _M_before_begin()._M_nxt = nullptr;
+ _M_element_count = 0;
+ }
+
+ template<typename _Key, typename _Value,
+ typename _Alloc, typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+ typename _Traits>
+ void
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>::
+ _M_move_assign(_Hashtable&& __ht, std::true_type)
+ {
+ _M_deallocate_nodes(_M_begin());
+ _M_deallocate_buckets();
+
+ __hashtable_base::operator=(std::move(__ht));
+ _M_rehash_policy = __ht._M_rehash_policy;
+ _M_buckets = __ht._M_buckets;
+ _M_bucket_count = __ht._M_bucket_count;
+ _M_before_begin()._M_nxt = __ht._M_before_begin()._M_nxt;
+ _M_element_count = __ht._M_element_count;
+ std::__alloc_on_move(_M_node_allocator(), __ht._M_node_allocator());
+
+ // Fix buckets containing the _M_before_begin pointers that can't be
+ // moved.
+ if (_M_begin())
+ _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin();
+ __ht._M_reset();
+ }
+
+ template<typename _Key, typename _Value,
+ typename _Alloc, typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+ typename _Traits>
+ void
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>::
+ _M_move_assign(_Hashtable&& __ht, std::false_type)
+ {
+ if (__ht._M_node_allocator() == _M_node_allocator())
+ _M_move_assign(std::move(__ht), std::true_type());
+ else
+ {
+ // Can't move memory, move elements then.
+ if (_M_bucket_count != __ht._M_bucket_count)
+ {
+ auto __buckets = _M_allocate_buckets(__ht._M_bucket_count);
+ _M_deallocate_buckets();
+ _M_buckets = __buckets;
+ _M_bucket_count = __ht._M_bucket_count;
+ }
+ else
+ __builtin_memset(_M_buckets, 0,
+ _M_bucket_count * sizeof(__bucket_type));
+
+ __hashtable_base::operator=(std::move(__ht));
+ _M_element_count = __ht._M_element_count;
+ _M_rehash_policy = __ht._M_rehash_policy;
+ __detail::_MoveReuseOrAllocNode<_Key, _Value, _Alloc, _ExtractKey,
+ _Equal, _H1, _H2, _Hash,
+ _RehashPolicy, _Traits>
+ __mroan(_M_begin(), *this);
+ _M_before_begin()._M_nxt = nullptr;
+ _M_assign(__ht, __mroan);
+ __ht.clear();
+ }
+ }
+
+ template<typename _Key, typename _Value,
+ typename _Alloc, typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+ typename _Traits>
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>::
_Hashtable(const _Hashtable& __ht)
: __hashtable_base(__ht),
__map_base(__ht),
__rehash_base(__ht),
+ _M_buckets(),
_M_bucket_count(__ht._M_bucket_count),
- _M_bbegin(__ht._M_bbegin),
+ _M_bbegin(_Node_alloc_traits::_S_select_on_copy(
+ __ht._M_node_allocator())),
_M_element_count(__ht._M_element_count),
_M_rehash_policy(__ht._M_rehash_policy)
{
- _M_buckets = _M_allocate_buckets(_M_bucket_count);
- __try
- {
- if (!__ht._M_before_begin()._M_nxt)
- return;
-
- // First deal with the special first node pointed to by
- // _M_before_begin.
- const __node_type* __ht_n = __ht._M_begin();
- __node_type* __this_n = _M_allocate_node(__ht_n->_M_v);
- this->_M_copy_code(__this_n, __ht_n);
- _M_before_begin()._M_nxt = __this_n;
- _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin();
-
- // Then deal with other nodes.
- __node_base* __prev_n = __this_n;
- for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next())
- {
- __this_n = _M_allocate_node(__ht_n->_M_v);
- __prev_n->_M_nxt = __this_n;
- this->_M_copy_code(__this_n, __ht_n);
- size_type __bkt = _M_bucket_index(__this_n);
- if (!_M_buckets[__bkt])
- _M_buckets[__bkt] = __prev_n;
- __prev_n = __this_n;
- }
- }
- __catch(...)
- {
- clear();
- _M_deallocate_buckets(_M_buckets, _M_bucket_count);
- __throw_exception_again;
- }
+ _M_assign(__ht,
+ [this](const __node_type* __n)
+ { return _M_allocate_node(__n->_M_v()); });
}
template<typename _Key, typename _Value,
@@ -937,14 +1150,11 @@
_M_element_count(__ht._M_element_count),
_M_rehash_policy(__ht._M_rehash_policy)
{
- // Update, if necessary, bucket pointing to before begin that hasn't moved.
+ // Update, if necessary, bucket pointing to before begin that hasn't
+ // moved.
if (_M_begin())
_M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin();
- __ht._M_rehash_policy = _RehashPolicy();
- __ht._M_bucket_count = __ht._M_rehash_policy._M_next_bkt(0);
- __ht._M_buckets = __ht._M_allocate_buckets(__ht._M_bucket_count);
- __ht._M_before_begin()._M_nxt = nullptr;
- __ht._M_element_count = 0;
+ __ht._M_reset();
}
template<typename _Key, typename _Value,
@@ -953,10 +1163,69 @@
typename _Traits>
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
+ _Hashtable(const _Hashtable& __ht, const allocator_type& __a)
+ : __hashtable_base(__ht),
+ __map_base(__ht),
+ __rehash_base(__ht),
+ _M_buckets(),
+ _M_bucket_count(__ht._M_bucket_count),
+ _M_bbegin(_Node_alloc_type(__a)),
+ _M_element_count(__ht._M_element_count),
+ _M_rehash_policy(__ht._M_rehash_policy)
+ {
+ _M_assign(__ht,
+ [this](const __node_type* __n)
+ { return _M_allocate_node(__n->_M_v()); });
+ }
+
+ template<typename _Key, typename _Value,
+ typename _Alloc, typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+ typename _Traits>
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>::
+ _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
+ : __hashtable_base(__ht),
+ __map_base(__ht),
+ __rehash_base(__ht),
+ _M_buckets(),
+ _M_bucket_count(__ht._M_bucket_count),
+ _M_bbegin(_Node_alloc_type(__a)),
+ _M_element_count(__ht._M_element_count),
+ _M_rehash_policy(__ht._M_rehash_policy)
+ {
+ if (__ht._M_node_allocator() == _M_node_allocator())
+ {
+ _M_buckets = __ht._M_buckets;
+ _M_before_begin()._M_nxt = __ht._M_before_begin()._M_nxt;
+ // Update, if necessary, bucket pointing to before begin that hasn't
+ // moved.
+ if (_M_begin())
+ _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin();
+ __ht._M_reset();
+ }
+ else
+ {
+ _M_assign(__ht,
+ [this](__node_type* __n)
+ {
+ return _M_allocate_node(
+ std::move_if_noexcept(__n->_M_mv()));
+ });
+ __ht.clear();
+ }
+ }
+
+ template<typename _Key, typename _Value,
+ typename _Alloc, typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+ typename _Traits>
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>::
~_Hashtable() noexcept
{
clear();
- _M_deallocate_buckets(_M_buckets, _M_bucket_count);
+ _M_deallocate_buckets();
}
template<typename _Key, typename _Value,
@@ -967,25 +1236,22 @@
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
swap(_Hashtable& __x)
+ noexcept(_Node_alloc_traits::_S_nothrow_swap())
{
// The only base class with member variables is hash_code_base.
// We define _Hash_code_base::_M_swap because different
// specializations have different members.
this->_M_swap(__x);
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 431. Swapping containers with unequal allocators.
- std::__alloc_swap<_Node_allocator_type>::_S_do_it(_M_node_allocator(),
- __x._M_node_allocator());
-
+ std::__alloc_on_swap(_M_node_allocator(), __x._M_node_allocator());
std::swap(_M_rehash_policy, __x._M_rehash_policy);
std::swap(_M_buckets, __x._M_buckets);
std::swap(_M_bucket_count, __x._M_bucket_count);
std::swap(_M_before_begin()._M_nxt, __x._M_before_begin()._M_nxt);
std::swap(_M_element_count, __x._M_element_count);
- // Fix buckets containing the _M_before_begin pointers that
- // can't be swapped.
+ // Fix buckets containing the _M_before_begin pointers that can't be
+ // swapped.
if (_M_begin())
_M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin();
if (__x._M_begin())
@@ -1258,7 +1524,7 @@
{
// First build the node to get access to the hash code
__node_type* __node = _M_allocate_node(std::forward<_Args>(__args)...);
- const key_type& __k = this->_M_extract()(__node->_M_v);
+ const key_type& __k = this->_M_extract()(__node->_M_v());
__hash_code __code;
__try
{
@@ -1301,7 +1567,7 @@
__hash_code __code;
__try
{
- __code = this->_M_hash_code(this->_M_extract()(__node->_M_v));
+ __code = this->_M_hash_code(this->_M_extract()(__node->_M_v()));
}
__catch(...)
{
@@ -1333,7 +1599,7 @@
if (__do_rehash.first)
{
_M_rehash(__do_rehash.second, __saved_state);
- __bkt = _M_bucket_index(this->_M_extract()(__node->_M_v), __code);
+ __bkt = _M_bucket_index(this->_M_extract()(__node->_M_v()), __code);
}
this->_M_store_code(__node, __code);
@@ -1373,7 +1639,7 @@
_M_rehash(__do_rehash.second, __saved_state);
this->_M_store_code(__node, __code);
- const key_type& __k = this->_M_extract()(__node->_M_v);
+ const key_type& __k = this->_M_extract()(__node->_M_v());
size_type __bkt = _M_bucket_index(__k, __code);
// Find the node before an equivalent one.
@@ -1722,7 +1988,7 @@
}
__p = __next;
}
- _M_deallocate_buckets(_M_buckets, _M_bucket_count);
+ _M_deallocate_buckets();
_M_bucket_count = __n;
_M_buckets = __new_buckets;
}
@@ -1812,7 +2078,7 @@
__new_buckets[__next_bkt] = __prev_p;
}
- _M_deallocate_buckets(_M_buckets, _M_bucket_count);
+ _M_deallocate_buckets();
_M_bucket_count = __n;
_M_buckets = __new_buckets;
}
Index: include/bits/unordered_set.h
===================================================================
--- include/bits/unordered_set.h (revision 196664)
+++ include/bits/unordered_set.h (working copy)
@@ -108,10 +108,10 @@
//@{
/// Iterator-related typedefs.
- typedef typename allocator_type::pointer pointer;
- typedef typename allocator_type::const_pointer const_pointer;
- typedef typename allocator_type::reference reference;
- typedef typename allocator_type::const_reference const_reference;
+ typedef typename _Hashtable::pointer pointer;
+ typedef typename _Hashtable::const_pointer const_pointer;
+ typedef typename _Hashtable::reference reference;
+ typedef typename _Hashtable::const_reference const_reference;
typedef typename _Hashtable::iterator iterator;
typedef typename _Hashtable::const_iterator const_iterator;
typedef typename _Hashtable::local_iterator local_iterator;
@@ -165,6 +165,35 @@
unordered_set(unordered_set&&) = default;
/**
+ * @brief Creates an %unordered_set with no elements.
+ * @param __a An allocator object.
+ */
+ explicit
+ unordered_set(const allocator_type& __a)
+ : _M_h(__a)
+ { }
+
+ /*
+ * @brief Copy constructor with allocator argument.
+ * @param __uset Input %unordered_set to copy.
+ * @param __a An allocator object.
+ */
+ unordered_set(const unordered_set& __uset,
+ const allocator_type& __a)
+ : _M_h(__uset._M_h, __a)
+ { }
+
+ /*
+ * @brief Move constructor with allocator argument.
+ * @param __uset Input %unordered_set to move.
+ * @param __a An allocator object.
+ */
+ unordered_set(unordered_set&& __uset,
+ const allocator_type& __a)
+ : _M_h(std::move(__uset._M_h), __a)
+ { }
+
+ /**
* @brief Builds an %unordered_set from an initializer_list.
* @param __l An initializer_list.
* @param __n Minimal initial number of buckets.
@@ -482,6 +511,7 @@
*/
void
swap(unordered_set& __x)
+ noexcept( noexcept(_M_h.swap(__x._M_h)) )
{ _M_h.swap(__x._M_h); }
// observers.
@@ -713,10 +743,10 @@
//@{
/// Iterator-related typedefs.
- typedef typename allocator_type::pointer pointer;
- typedef typename allocator_type::const_pointer const_pointer;
- typedef typename allocator_type::reference reference;
- typedef typename allocator_type::const_reference const_reference;
+ typedef typename _Hashtable::pointer pointer;
+ typedef typename _Hashtable::const_pointer const_pointer;
+ typedef typename _Hashtable::reference reference;
+ typedef typename _Hashtable::const_reference const_reference;
typedef typename _Hashtable::iterator iterator;
typedef typename _Hashtable::const_iterator const_iterator;
typedef typename _Hashtable::local_iterator local_iterator;
@@ -794,9 +824,38 @@
/// Move assignment operator.
unordered_multiset&
- operator=(unordered_multiset&& __x) = default;
+ operator=(unordered_multiset&&) = default;
/**
+ * @brief Creates an %unordered_multiset with no elements.
+ * @param __a An allocator object.
+ */
+ explicit
+ unordered_multiset(const allocator_type& __a)
+ : _M_h(__a)
+ { }
+
+ /*
+ * @brief Copy constructor with allocator argument.
+ * @param __uset Input %unordered_multiset to copy.
+ * @param __a An allocator object.
+ */
+ unordered_multiset(const unordered_multiset& __umset,
+ const allocator_type& __a)
+ : _M_h(__umset._M_h, __a)
+ { }
+
+ /*
+ * @brief Move constructor with allocator argument.
+ * @param __umset Input %unordered_multiset to move.
+ * @param __a An allocator object.
+ */
+ unordered_multiset(unordered_multiset&& __umset,
+ const allocator_type& __a)
+ : _M_h(std::move(__umset._M_h), __a)
+ { }
+
+ /**
* @brief %Unordered_multiset list assignment operator.
* @param __l An initializer_list.
*
@@ -1070,6 +1129,7 @@
*/
void
swap(unordered_multiset& __x)
+ noexcept( noexcept(_M_h.swap(__x._M_h)) )
{ _M_h.swap(__x._M_h); }
// observers.
Index: include/bits/unordered_map.h
===================================================================
--- include/bits/unordered_map.h (revision 196664)
+++ include/bits/unordered_map.h (working copy)
@@ -113,10 +113,10 @@
//@{
/// Iterator-related typedefs.
- typedef typename allocator_type::pointer pointer;
- typedef typename allocator_type::const_pointer const_pointer;
- typedef typename allocator_type::reference reference;
- typedef typename allocator_type::const_reference const_reference;
+ typedef typename _Hashtable::pointer pointer;
+ typedef typename _Hashtable::const_pointer const_pointer;
+ typedef typename _Hashtable::reference reference;
+ typedef typename _Hashtable::const_reference const_reference;
typedef typename _Hashtable::iterator iterator;
typedef typename _Hashtable::const_iterator const_iterator;
typedef typename _Hashtable::local_iterator local_iterator;
@@ -171,6 +171,35 @@
unordered_map(unordered_map&&) = default;
/**
+ * @brief Creates an %unordered_map with no elements.
+ * @param __a An allocator object.
+ */
+ explicit
+ unordered_map(const allocator_type& __a)
+ : _M_h(__a)
+ { }
+
+ /*
+ * @brief Copy constructor with allocator argument.
+ * @param __uset Input %unordered_map to copy.
+ * @param __a An allocator object.
+ */
+ unordered_map(const unordered_map& __umap,
+ const allocator_type& __a)
+ : _M_h(__umap._M_h, __a)
+ { }
+
+ /*
+ * @brief Move constructor with allocator argument.
+ * @param __uset Input %unordered_map to move.
+ * @param __a An allocator object.
+ */
+ unordered_map(unordered_map&& __umap,
+ const allocator_type& __a)
+ : _M_h(std::move(__umap._M_h), __a)
+ { }
+
+ /**
* @brief Builds an %unordered_map from an initializer_list.
* @param __l An initializer_list.
* @param __n Minimal initial number of buckets.
@@ -508,6 +537,7 @@
*/
void
swap(unordered_map& __x)
+ noexcept( noexcept(_M_h.swap(__x._M_h)) )
{ _M_h.swap(__x._M_h); }
// observers.
@@ -794,10 +824,10 @@
//@{
/// Iterator-related typedefs.
- typedef typename allocator_type::pointer pointer;
- typedef typename allocator_type::const_pointer const_pointer;
- typedef typename allocator_type::reference reference;
- typedef typename allocator_type::const_reference const_reference;
+ typedef typename _Hashtable::pointer pointer;
+ typedef typename _Hashtable::const_pointer const_pointer;
+ typedef typename _Hashtable::reference reference;
+ typedef typename _Hashtable::const_reference const_reference;
typedef typename _Hashtable::iterator iterator;
typedef typename _Hashtable::const_iterator const_iterator;
typedef typename _Hashtable::local_iterator local_iterator;
@@ -852,6 +882,35 @@
unordered_multimap(unordered_multimap&&) = default;
/**
+ * @brief Creates an %unordered_multimap with no elements.
+ * @param __a An allocator object.
+ */
+ explicit
+ unordered_multimap(const allocator_type& __a)
+ : _M_h(__a)
+ { }
+
+ /*
+ * @brief Copy constructor with allocator argument.
+ * @param __uset Input %unordered_multimap to copy.
+ * @param __a An allocator object.
+ */
+ unordered_multimap(const unordered_multimap& __ummap,
+ const allocator_type& __a)
+ : _M_h(__ummap._M_h, __a)
+ { }
+
+ /*
+ * @brief Move constructor with allocator argument.
+ * @param __uset Input %unordered_multimap to move.
+ * @param __a An allocator object.
+ */
+ unordered_multimap(unordered_multimap&& __ummap,
+ const allocator_type& __a)
+ : _M_h(std::move(__ummap._M_h), __a)
+ { }
+
+ /**
* @brief Builds an %unordered_multimap from an initializer_list.
* @param __l An initializer_list.
* @param __n Minimal initial number of buckets.
@@ -1173,6 +1232,7 @@
*/
void
swap(unordered_multimap& __x)
+ noexcept( noexcept(_M_h.swap(__x._M_h)) )
{ _M_h.swap(__x._M_h); }
// observers.
Index: include/std/unordered_set
===================================================================
--- include/std/unordered_set (revision 196664)
+++ include/std/unordered_set (working copy)
@@ -39,9 +39,8 @@
#include <type_traits>
#include <initializer_list>
#include <tuple>
-#include <bits/stl_algobase.h>
#include <bits/allocator.h>
-#include <bits/alloc_traits.h>
+#include <ext/alloc_traits.h>
#include <bits/stl_function.h> // equal_to, _Identity, _Select1st
#include <bits/functional_hash.h>
#include <bits/hashtable.h>
Index: include/std/unordered_map
===================================================================
--- include/std/unordered_map (revision 196664)
+++ include/std/unordered_map (working copy)
@@ -39,9 +39,8 @@
#include <type_traits>
#include <initializer_list>
#include <tuple>
-#include <bits/stl_algobase.h>
#include <bits/allocator.h>
-#include <bits/alloc_traits.h>
+#include <ext/alloc_traits.h>
#include <bits/stl_function.h> // equal_to, _Identity, _Select1st
#include <bits/functional_hash.h>
#include <bits/hashtable.h>
Index: include/debug/unordered_map
===================================================================
--- include/debug/unordered_map (revision 196664)
+++ include/debug/unordered_map (working copy)
@@ -60,6 +60,9 @@
typedef typename _Base::const_local_iterator _Base_const_local_iterator;
typedef typename _Base::local_iterator _Base_local_iterator;
+ typedef __gnu_cxx::__alloc_traits<typename
+ _Base::allocator_type> _Alloc_traits;
+
public:
typedef typename _Base::size_type size_type;
typedef typename _Base::hasher hasher;
@@ -96,13 +99,28 @@
__gnu_debug::__base(__last), __n,
__hf, __eql, __a) { }
- unordered_map(const unordered_map& __x) = default;
+ unordered_map(const unordered_map&) = default;
unordered_map(const _Base& __x)
: _Base(__x) { }
- unordered_map(unordered_map&& __x) = default;
+ unordered_map(unordered_map&&) = default;
+ explicit
+ unordered_map(const allocator_type& __a)
+ : _Base(__a)
+ { }
+
+ unordered_map(const unordered_map& __umap,
+ const allocator_type& __a)
+ : _Base(__umap._M_base(), __a)
+ { }
+
+ unordered_map(unordered_map&& __umap,
+ const allocator_type& __a)
+ : _Base(std::move(__umap._M_base()), __a)
+ { }
+
unordered_map(initializer_list<value_type> __l,
size_type __n = 0,
const hasher& __hf = hasher(),
@@ -115,33 +133,41 @@
unordered_map&
operator=(const unordered_map& __x)
{
- *static_cast<_Base*>(this) = __x;
+ _M_base() = __x._M_base();
this->_M_invalidate_all();
return *this;
}
unordered_map&
operator=(unordered_map&& __x)
+ noexcept(_Alloc_traits::_S_nothrow_move())
{
- // NB: DR 1204.
- // NB: DR 675.
__glibcxx_check_self_move_assign(__x);
- clear();
- swap(__x);
+ bool xfer_memory = _Alloc_traits::_S_propagate_on_move_assign()
+ || __x.get_allocator() == this->get_allocator();
+ _M_base() = std::move(__x._M_base());
+ if (xfer_memory)
+ this->_M_swap(__x);
+ else
+ this->_M_invalidate_all();
+ __x._M_invalidate_all();
return *this;
}
unordered_map&
operator=(initializer_list<value_type> __l)
{
- this->clear();
- this->insert(__l);
+ _M_base() = __l;
+ this->_M_invalidate_all();
return *this;
}
void
swap(unordered_map& __x)
+ noexcept(_Alloc_traits::_S_nothrow_swap())
{
+ if (!_Alloc_traits::_S_propagate_on_swap())
+ __glibcxx_check_equal_allocs(__x);
_Base::swap(__x);
_Safe_base::_M_swap(__x);
}
@@ -490,6 +516,9 @@
typedef typename _Base::const_local_iterator _Base_const_local_iterator;
typedef typename _Base::local_iterator _Base_local_iterator;
+ typedef __gnu_cxx::__alloc_traits<typename
+ _Base::allocator_type> _Alloc_traits;
+
public:
typedef typename _Base::size_type size_type;
typedef typename _Base::hasher hasher;
@@ -526,13 +555,28 @@
__gnu_debug::__base(__last), __n,
__hf, __eql, __a) { }
- unordered_multimap(const unordered_multimap& __x) = default;
+ unordered_multimap(const unordered_multimap&) = default;
unordered_multimap(const _Base& __x)
: _Base(__x) { }
- unordered_multimap(unordered_multimap&& __x) = default;
+ unordered_multimap(unordered_multimap&&) = default;
+ explicit
+ unordered_multimap(const allocator_type& __a)
+ : _Base(__a)
+ { }
+
+ unordered_multimap(const unordered_multimap& __umap,
+ const allocator_type& __a)
+ : _Base(__umap._M_base(), __a)
+ { }
+
+ unordered_multimap(unordered_multimap&& __umap,
+ const allocator_type& __a)
+ : _Base(std::move(__umap._M_base()), __a)
+ { }
+
unordered_multimap(initializer_list<value_type> __l,
size_type __n = 0,
const hasher& __hf = hasher(),
@@ -545,33 +589,41 @@
unordered_multimap&
operator=(const unordered_multimap& __x)
{
- *static_cast<_Base*>(this) = __x;
+ _M_base() = __x._M_base();
this->_M_invalidate_all();
return *this;
}
unordered_multimap&
operator=(unordered_multimap&& __x)
+ noexcept(_Alloc_traits::_S_nothrow_move())
{
- // NB: DR 1204.
- // NB: DR 675.
__glibcxx_check_self_move_assign(__x);
- clear();
- swap(__x);
+ bool xfer_memory = _Alloc_traits::_S_propagate_on_move_assign()
+ || __x.get_allocator() == this->get_allocator();
+ _M_base() = std::move(__x._M_base());
+ if (xfer_memory)
+ this->_M_swap(__x);
+ else
+ this->_M_invalidate_all();
+ __x._M_invalidate_all();
return *this;
}
unordered_multimap&
operator=(initializer_list<value_type> __l)
{
- this->clear();
- this->insert(__l);
+ _M_base() = __l;
+ this->_M_invalidate_all();
return *this;
}
void
swap(unordered_multimap& __x)
+ noexcept(_Alloc_traits::_S_nothrow_swap())
{
+ if (!_Alloc_traits::_S_propagate_on_swap())
+ __glibcxx_check_equal_allocs(__x);
_Base::swap(__x);
_Safe_base::_M_swap(__x);
}
Index: include/debug/unordered_set
===================================================================
--- include/debug/unordered_set (revision 196664)
+++ include/debug/unordered_set (working copy)
@@ -60,6 +60,8 @@
typedef typename _Base::const_local_iterator _Base_const_local_iterator;
typedef typename _Base::local_iterator _Base_local_iterator;
+ typedef __gnu_cxx::__alloc_traits<typename
+ _Base::allocator_type> _Alloc_traits;
public:
typedef typename _Base::size_type size_type;
typedef typename _Base::hasher hasher;
@@ -96,13 +98,28 @@
__gnu_debug::__base(__last), __n,
__hf, __eql, __a) { }
- unordered_set(const unordered_set& __x) = default;
+ unordered_set(const unordered_set&) = default;
unordered_set(const _Base& __x)
: _Base(__x) { }
- unordered_set(unordered_set&& __x) = default;
+ unordered_set(unordered_set&&) = default;
+ explicit
+ unordered_set(const allocator_type& __a)
+ : _Base(__a)
+ { }
+
+ unordered_set(const unordered_set& __uset,
+ const allocator_type& __a)
+ : _Base(__uset._M_base(), __a)
+ { }
+
+ unordered_set(unordered_set&& __uset,
+ const allocator_type& __a)
+ : _Base(std::move(__uset._M_base()), __a)
+ { }
+
unordered_set(initializer_list<value_type> __l,
size_type __n = 0,
const hasher& __hf = hasher(),
@@ -115,33 +132,41 @@
unordered_set&
operator=(const unordered_set& __x)
{
- *static_cast<_Base*>(this) = __x;
+ _M_base() = __x._M_base();
this->_M_invalidate_all();
return *this;
}
unordered_set&
operator=(unordered_set&& __x)
+ noexcept(_Alloc_traits::_S_nothrow_move())
{
- // NB: DR 1204.
- // NB: DR 675.
__glibcxx_check_self_move_assign(__x);
- clear();
- swap(__x);
+ bool xfer_memory = _Alloc_traits::_S_propagate_on_move_assign()
+ || __x.get_allocator() == this->get_allocator();
+ _M_base() = std::move(__x._M_base());
+ if (xfer_memory)
+ this->_M_swap(__x);
+ else
+ this->_M_invalidate_all();
+ __x._M_invalidate_all();
return *this;
}
unordered_set&
operator=(initializer_list<value_type> __l)
{
- this->clear();
- this->insert(__l);
+ _M_base() = __l;
+ this->_M_invalidate_all();
return *this;
}
void
swap(unordered_set& __x)
+ noexcept(_Alloc_traits::_S_nothrow_swap())
{
+ if (!_Alloc_traits::_S_propagate_on_swap())
+ __glibcxx_check_equal_allocs(__x);
_Base::swap(__x);
_Safe_base::_M_swap(__x);
}
@@ -485,6 +510,9 @@
typedef typename _Base::const_local_iterator _Base_const_local_iterator;
typedef typename _Base::local_iterator _Base_local_iterator;
+ typedef __gnu_cxx::__alloc_traits<typename
+ _Base::allocator_type> _Alloc_traits;
+
public:
typedef typename _Base::size_type size_type;
typedef typename _Base::hasher hasher;
@@ -521,13 +549,28 @@
__gnu_debug::__base(__last), __n,
__hf, __eql, __a) { }
- unordered_multiset(const unordered_multiset& __x) = default;
+ unordered_multiset(const unordered_multiset&) = default;
unordered_multiset(const _Base& __x)
: _Base(__x) { }
- unordered_multiset(unordered_multiset&& __x) = default;
+ unordered_multiset(unordered_multiset&&) = default;
+ explicit
+ unordered_multiset(const allocator_type& __a)
+ : _Base(__a)
+ { }
+
+ unordered_multiset(const unordered_multiset& __uset,
+ const allocator_type& __a)
+ : _Base(__uset._M_base(), __a)
+ { }
+
+ unordered_multiset(unordered_multiset&& __uset,
+ const allocator_type& __a)
+ : _Base(std::move(__uset._M_base()), __a)
+ { }
+
unordered_multiset(initializer_list<value_type> __l,
size_type __n = 0,
const hasher& __hf = hasher(),
@@ -540,33 +583,41 @@
unordered_multiset&
operator=(const unordered_multiset& __x)
{
- *static_cast<_Base*>(this) = __x;
+ _M_base() = __x._M_base();
this->_M_invalidate_all();
return *this;
}
unordered_multiset&
operator=(unordered_multiset&& __x)
+ noexcept(_Alloc_traits::_S_nothrow_move())
{
- // NB: DR 1204.
- // NB: DR 675.
__glibcxx_check_self_move_assign(__x);
- clear();
- swap(__x);
+ bool xfer_memory = _Alloc_traits::_S_propagate_on_move_assign()
+ || __x.get_allocator() == this->get_allocator();
+ _M_base() = std::move(__x._M_base());
+ if (xfer_memory)
+ this->_M_swap(__x);
+ else
+ this->_M_invalidate_all();
+ __x._M_invalidate_all();
return *this;
}
unordered_multiset&
operator=(initializer_list<value_type> __l)
{
- this->clear();
- this->insert(__l);
+ _M_base() = __l;
+ this->_M_invalidate_all();
return *this;
}
void
swap(unordered_multiset& __x)
+ noexcept(_Alloc_traits::_S_nothrow_swap())
{
+ if (!_Alloc_traits::_S_propagate_on_swap())
+ __glibcxx_check_equal_allocs(__x);
_Base::swap(__x);
_Safe_base::_M_swap(__x);
}
Index: testsuite/util/testsuite_counter_type.h
===================================================================
--- testsuite/util/testsuite_counter_type.h (revision 196664)
+++ testsuite/util/testsuite_counter_type.h (working copy)
@@ -36,24 +36,22 @@
static int move_count;
static int move_assign_count;
#endif
+ static int destructor_count;
int val;
counter_type() : val(0)
- {
- ++default_count;
- }
+ { ++default_count; }
counter_type(int inval) : val(inval)
- {
- ++specialize_count;
- }
+ { ++specialize_count; }
counter_type(const counter_type& in) : val(in.val)
- {
- ++copy_count;
- }
+ { ++copy_count; }
+ ~counter_type()
+ { ++destructor_count; }
+
counter_type&
operator=(const counter_type& in)
{
@@ -70,7 +68,7 @@
}
counter_type&
- operator=(counter_type&& rhs)
+ operator=(counter_type&& rhs) noexcept
{
val = rhs.val;
++move_assign_count;
@@ -90,6 +88,7 @@
move_count = 0;
move_assign_count = 0;
#endif
+ destructor_count = 0;
}
bool operator==(const counter_type& rhs) const
@@ -109,6 +108,7 @@
int counter_type::move_count = 0;
int counter_type::move_assign_count = 0;
#endif
+ int counter_type::destructor_count = 0;
struct counter_type_hasher
{
Index: testsuite/23_containers/unordered_map/allocator/noexcept.cc
===================================================================
--- testsuite/23_containers/unordered_map/allocator/noexcept.cc (revision 0)
+++ testsuite/23_containers/unordered_map/allocator/noexcept.cc (revision 0)
@@ -0,0 +1,88 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+namespace __gnu_test
+{
+ inline void
+ swap(propagating_allocator<T, true>& l, propagating_allocator<T, true>& r)
+ noexcept(false)
+ {
+ typedef uneq_allocator<T> base_alloc;
+ swap(static_cast<base_alloc&>(l), static_cast<base_alloc&>(r));
+ }
+}
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ typedef std::allocator<T> alloc_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1;
+ test_type v2;
+ // this is a GNU extension for std::allocator
+ static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+ static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test02()
+{
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ test_type v2(alloc_type(2));
+ static_assert( !noexcept( v1 = std::move(v2) ), "Move assign can throw" );
+ static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test03()
+{
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ test_type v2(alloc_type(2));
+ static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+ // static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
Index: testsuite/23_containers/unordered_map/allocator/minimal.cc
===================================================================
--- testsuite/23_containers/unordered_map/allocator/minimal.cc (revision 0)
+++ testsuite/23_containers/unordered_map/allocator/minimal.cc (revision 0)
@@ -0,0 +1,63 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <memory>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+
+bool operator==(const T& l, const T& r) { return l.i == r.i; }
+bool operator<(const T& l, const T& r) { return l.i < r.i; }
+
+using __gnu_test::SimpleAllocator;
+
+template class std::unordered_map<T, T, hash, equal_to, SimpleAllocator<T>>;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef SimpleAllocator<T> alloc_type;
+ typedef std::allocator_traits<alloc_type> traits_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v(alloc_type{});
+ v.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ VERIFY( v.max_size() == traits_type::max_size(v.get_allocator()) );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: testsuite/23_containers/unordered_map/allocator/swap.cc
===================================================================
--- testsuite/23_containers/unordered_map/allocator/swap.cc (revision 0)
+++ testsuite/23_containers/unordered_map/allocator/swap.cc (revision 0)
@@ -0,0 +1,96 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+// It is undefined behaviour to swap() containers wth unequal allocators
+// if the allocator doesn't propagate, so ensure the allocators compare
+// equal, while still being able to test propagation via get_personality().
+bool
+operator==(const propagating_allocator<std::pair<const T, T>, false>&,
+ const propagating_allocator<std::pair<const T, T>, false>&)
+{
+ return true;
+}
+
+bool
+operator!=(const propagating_allocator<std::pair<const T, T>, false>&,
+ const propagating_allocator<std::pair<const T, T>, false>&)
+{
+ return false;
+}
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<std::pair<const T, T>, false> alloc_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ std::swap(v1, v2);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(2 == v2.get_allocator().get_personality());
+ // swap back so assertions in uneq_allocator::deallocate don't fail
+ std::swap(v1, v2);
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<std::pair<const T, T>, true> alloc_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ std::swap(v1, v2);
+ VERIFY(2 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_map/allocator/copy.cc
===================================================================
--- testsuite/23_containers/unordered_map/allocator/copy.cc (revision 0)
+++ testsuite/23_containers/unordered_map/allocator/copy.cc (revision 0)
@@ -0,0 +1,71 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(0 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_map/allocator/move_assign.cc
===================================================================
--- testsuite/23_containers/unordered_map/allocator/move_assign.cc (revision 0)
+++ testsuite/23_containers/unordered_map/allocator/move_assign.cc (revision 0)
@@ -0,0 +1,88 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+#include <testsuite_counter_type.h>
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::counter_type;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<counter_type, false> alloc_type;
+ typedef __gnu_test::counter_type_hasher hash;
+ typedef std::unordered_map<counter_type, counter_type, hash,
+ std::equal_to<counter_type>,
+ alloc_type> test_type;
+
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(1), std::make_tuple(1));
+
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(2), std::make_tuple(2));
+
+ counter_type::reset();
+
+ v2 = std::move(v1);
+
+ VERIFY( 1 == v1.get_allocator().get_personality() );
+ VERIFY( 2 == v2.get_allocator().get_personality() );
+
+ VERIFY( counter_type::move_assign_count == 2 );
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<counter_type, true> alloc_type;
+ typedef __gnu_test::counter_type_hasher hash;
+ typedef std::unordered_map<counter_type, counter_type, hash,
+ std::equal_to<counter_type>,
+ alloc_type> test_type;
+
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(1), std::make_tuple(1));
+
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(2), std::make_tuple(2));
+
+ counter_type::reset();
+
+ v2 = std::move(v1);
+
+ VERIFY(0 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+
+ VERIFY( counter_type::move_assign_count == 0 );
+ VERIFY( counter_type::destructor_count == 2 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_map/allocator/copy_assign.cc
===================================================================
--- testsuite/23_containers/unordered_map/allocator/copy_assign.cc (revision 0)
+++ testsuite/23_containers/unordered_map/allocator/copy_assign.cc (revision 0)
@@ -0,0 +1,77 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ v2 = v1;
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_map<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ v2 = v1;
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multimap/allocator/swap.cc
===================================================================
--- testsuite/23_containers/unordered_multimap/allocator/swap.cc (revision 0)
+++ testsuite/23_containers/unordered_multimap/allocator/swap.cc (revision 0)
@@ -0,0 +1,96 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+// It is undefined behaviour to swap() containers wth unequal allocators
+// if the allocator doesn't propagate, so ensure the allocators compare
+// equal, while still being able to test propagation via get_personality().
+bool
+operator==(const propagating_allocator<std::pair<const T, T>, false>&,
+ const propagating_allocator<std::pair<const T, T>, false>&)
+{
+ return true;
+}
+
+bool
+operator!=(const propagating_allocator<std::pair<const T, T>, false>&,
+ const propagating_allocator<std::pair<const T, T>, false>&)
+{
+ return false;
+}
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<std::pair<const T, T>, false> alloc_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ std::swap(v1, v2);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(2 == v2.get_allocator().get_personality());
+ // swap back so assertions in uneq_allocator::deallocate don't fail
+ std::swap(v1, v2);
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<std::pair<const T, T>, true> alloc_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ std::swap(v1, v2);
+ VERIFY(2 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multimap/allocator/copy.cc
===================================================================
--- testsuite/23_containers/unordered_multimap/allocator/copy.cc (revision 0)
+++ testsuite/23_containers/unordered_multimap/allocator/copy.cc (revision 0)
@@ -0,0 +1,71 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(0 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multimap/allocator/move_assign.cc
===================================================================
--- testsuite/23_containers/unordered_multimap/allocator/move_assign.cc (revision 0)
+++ testsuite/23_containers/unordered_multimap/allocator/move_assign.cc (revision 0)
@@ -0,0 +1,88 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+#include <testsuite_counter_type.h>
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::counter_type;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<counter_type, false> alloc_type;
+ typedef __gnu_test::counter_type_hasher hash;
+ typedef std::unordered_multimap<counter_type, counter_type, hash,
+ std::equal_to<counter_type>,
+ alloc_type> test_type;
+
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(1), std::make_tuple(1));
+
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(2), std::make_tuple(2));
+
+ counter_type::reset();
+
+ v2 = std::move(v1);
+
+ VERIFY( 1 == v1.get_allocator().get_personality() );
+ VERIFY( 2 == v2.get_allocator().get_personality() );
+
+ VERIFY( counter_type::move_assign_count == 2 );
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<counter_type, true> alloc_type;
+ typedef __gnu_test::counter_type_hasher hash;
+ typedef std::unordered_multimap<counter_type, counter_type, hash,
+ std::equal_to<counter_type>,
+ alloc_type> test_type;
+
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(1), std::make_tuple(1));
+
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(2), std::make_tuple(2));
+
+ counter_type::reset();
+
+ v2 = std::move(v1);
+
+ VERIFY(0 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+
+ VERIFY( counter_type::move_assign_count == 0 );
+ VERIFY( counter_type::destructor_count == 2 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multimap/allocator/copy_assign.cc
===================================================================
--- testsuite/23_containers/unordered_multimap/allocator/copy_assign.cc (revision 0)
+++ testsuite/23_containers/unordered_multimap/allocator/copy_assign.cc (revision 0)
@@ -0,0 +1,77 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ v2 = v1;
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ test_type v2(alloc_type(2));
+ v2.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ v2 = v1;
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multimap/allocator/noexcept.cc
===================================================================
--- testsuite/23_containers/unordered_multimap/allocator/noexcept.cc (revision 0)
+++ testsuite/23_containers/unordered_multimap/allocator/noexcept.cc (revision 0)
@@ -0,0 +1,88 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+namespace __gnu_test
+{
+ inline void
+ swap(propagating_allocator<T, true>& l, propagating_allocator<T, true>& r)
+ noexcept(false)
+ {
+ typedef uneq_allocator<T> base_alloc;
+ swap(static_cast<base_alloc&>(l), static_cast<base_alloc&>(r));
+ }
+}
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ typedef std::allocator<T> alloc_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1;
+ test_type v2;
+ // this is a GNU extension for std::allocator
+ static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+ static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test02()
+{
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ test_type v2(alloc_type(2));
+ static_assert( !noexcept( v1 = std::move(v2) ), "Move assign can throw" );
+ static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test03()
+{
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ test_type v2(alloc_type(2));
+ static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+ // static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multimap/allocator/minimal.cc
===================================================================
--- testsuite/23_containers/unordered_multimap/allocator/minimal.cc (revision 0)
+++ testsuite/23_containers/unordered_multimap/allocator/minimal.cc (revision 0)
@@ -0,0 +1,64 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_map>
+#include <memory>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+
+bool operator==(const T& l, const T& r) { return l.i == r.i; }
+bool operator<(const T& l, const T& r) { return l.i < r.i; }
+
+using __gnu_test::SimpleAllocator;
+
+template class std::unordered_multimap<T, T, hash, equal_to,
+ SimpleAllocator<T>>;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef SimpleAllocator<T> alloc_type;
+ typedef std::allocator_traits<alloc_type> traits_type;
+ typedef std::unordered_multimap<T, T, hash, equal_to, alloc_type> test_type;
+ test_type v(alloc_type{});
+ v.emplace(std::piecewise_construct,
+ std::make_tuple(T()), std::make_tuple(T()));
+ VERIFY( v.max_size() == traits_type::max_size(v.get_allocator()) );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multiset/allocator/copy_assign.cc
===================================================================
--- testsuite/23_containers/unordered_multiset/allocator/copy_assign.cc (revision 0)
+++ testsuite/23_containers/unordered_multiset/allocator/copy_assign.cc (revision 0)
@@ -0,0 +1,73 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(alloc_type(2));
+ v2.insert(T());
+ v2 = v1;
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(alloc_type(2));
+ v2.insert(T());
+ v2 = v1;
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multiset/allocator/noexcept.cc
===================================================================
--- testsuite/23_containers/unordered_multiset/allocator/noexcept.cc (revision 0)
+++ testsuite/23_containers/unordered_multiset/allocator/noexcept.cc (revision 0)
@@ -0,0 +1,88 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+namespace __gnu_test
+{
+ inline void
+ swap(propagating_allocator<T, true>& l, propagating_allocator<T, true>& r)
+ noexcept(false)
+ {
+ typedef uneq_allocator<T> base_alloc;
+ swap(static_cast<base_alloc&>(l), static_cast<base_alloc&>(r));
+ }
+}
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ typedef std::allocator<T> alloc_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v1;
+ test_type v2;
+ // this is a GNU extension for std::allocator
+ static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+ static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test02()
+{
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ test_type v2(alloc_type(2));
+ static_assert( !noexcept( v1 = std::move(v2) ), "Move assign can throw" );
+ static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test03()
+{
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ test_type v2(alloc_type(2));
+ static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+ // static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multiset/allocator/minimal.cc
===================================================================
--- testsuite/23_containers/unordered_multiset/allocator/minimal.cc (revision 0)
+++ testsuite/23_containers/unordered_multiset/allocator/minimal.cc (revision 0)
@@ -0,0 +1,62 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <memory>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+
+bool operator==(const T& l, const T& r) { return l.i == r.i; }
+bool operator<(const T& l, const T& r) { return l.i < r.i; }
+
+using __gnu_test::SimpleAllocator;
+
+template class std::unordered_multiset<T, hash, equal_to, SimpleAllocator<T>>;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef SimpleAllocator<T> alloc_type;
+ typedef std::allocator_traits<alloc_type> traits_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v(alloc_type{});
+ v.insert(T());
+ VERIFY( v.max_size() == traits_type::max_size(v.get_allocator()) );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multiset/allocator/swap.cc
===================================================================
--- testsuite/23_containers/unordered_multiset/allocator/swap.cc (revision 0)
+++ testsuite/23_containers/unordered_multiset/allocator/swap.cc (revision 0)
@@ -0,0 +1,92 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+// It is undefined behaviour to swap() containers wth unequal allocators
+// if the allocator doesn't propagate, so ensure the allocators compare
+// equal, while still being able to test propagation via get_personality().
+bool
+operator==(const propagating_allocator<T, false>&,
+ const propagating_allocator<T, false>&)
+{
+ return true;
+}
+
+bool
+operator!=(const propagating_allocator<T, false>&,
+ const propagating_allocator<T, false>&)
+{
+ return false;
+}
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(alloc_type(2));
+ v2.insert(T());
+ std::swap(v1, v2);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(2 == v2.get_allocator().get_personality());
+ // swap back so assertions in uneq_allocator::deallocate don't fail
+ std::swap(v1, v2);
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(alloc_type(2));
+ v2.insert(T());
+ std::swap(v1, v2);
+ VERIFY(2 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multiset/allocator/copy.cc
===================================================================
--- testsuite/23_containers/unordered_multiset/allocator/copy.cc (revision 0)
+++ testsuite/23_containers/unordered_multiset/allocator/copy.cc (revision 0)
@@ -0,0 +1,69 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(0 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_multiset<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_multiset/allocator/move_assign.cc
===================================================================
--- testsuite/23_containers/unordered_multiset/allocator/move_assign.cc (revision 0)
+++ testsuite/23_containers/unordered_multiset/allocator/move_assign.cc (revision 0)
@@ -0,0 +1,84 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+#include <testsuite_counter_type.h>
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::counter_type;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<counter_type, false> alloc_type;
+ typedef __gnu_test::counter_type_hasher hash;
+ typedef std::unordered_multiset<counter_type, hash,
+ std::equal_to<counter_type>,
+ alloc_type> test_type;
+
+ test_type v1(alloc_type(1));
+ v1.emplace(0);
+
+ test_type v2(alloc_type(2));
+ v2.emplace(1);
+
+ counter_type::reset();
+
+ v2 = std::move(v1);
+
+ VERIFY( 1 == v1.get_allocator().get_personality() );
+ VERIFY( 2 == v2.get_allocator().get_personality() );
+
+ VERIFY( counter_type::move_assign_count == 1 );
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<counter_type, true> alloc_type;
+ typedef __gnu_test::counter_type_hasher hash;
+ typedef std::unordered_multiset<counter_type, hash,
+ std::equal_to<counter_type>,
+ alloc_type> test_type;
+
+ test_type v1(alloc_type(1));
+ v1.emplace(0);
+
+ test_type v2(alloc_type(2));
+ v2.emplace(0);
+
+ counter_type::reset();
+
+ v2 = std::move(v1);
+
+ VERIFY(0 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+
+ VERIFY( counter_type::move_assign_count == 0 );
+ VERIFY( counter_type::destructor_count == 1 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_set/instantiation_neg.cc
===================================================================
--- testsuite/23_containers/unordered_set/instantiation_neg.cc (revision 196664)
+++ testsuite/23_containers/unordered_set/instantiation_neg.cc (working copy)
@@ -19,7 +19,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-error "with noexcept" "" { target *-*-* } 252 }
+// { dg-error "with noexcept" "" { target *-*-* } 257 }
#include <unordered_set>
Index: testsuite/23_containers/unordered_set/allocator/swap.cc
===================================================================
--- testsuite/23_containers/unordered_set/allocator/swap.cc (revision 0)
+++ testsuite/23_containers/unordered_set/allocator/swap.cc (revision 0)
@@ -0,0 +1,92 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+// It is undefined behaviour to swap() containers wth unequal allocators
+// if the allocator doesn't propagate, so ensure the allocators compare
+// equal, while still being able to test propagation via get_personality().
+bool
+operator==(const propagating_allocator<T, false>&,
+ const propagating_allocator<T, false>&)
+{
+ return true;
+}
+
+bool
+operator!=(const propagating_allocator<T, false>&,
+ const propagating_allocator<T, false>&)
+{
+ return false;
+}
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(alloc_type(2));
+ v2.insert(T());
+ std::swap(v1, v2);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(2 == v2.get_allocator().get_personality());
+ // swap back so assertions in uneq_allocator::deallocate don't fail
+ std::swap(v1, v2);
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(alloc_type(2));
+ v2.insert(T());
+ std::swap(v1, v2);
+ VERIFY(2 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_set/allocator/copy.cc
===================================================================
--- testsuite/23_containers/unordered_set/allocator/copy.cc (revision 0)
+++ testsuite/23_containers/unordered_set/allocator/copy.cc (revision 0)
@@ -0,0 +1,69 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(0 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_set/allocator/move_assign.cc
===================================================================
--- testsuite/23_containers/unordered_set/allocator/move_assign.cc (revision 0)
+++ testsuite/23_containers/unordered_set/allocator/move_assign.cc (revision 0)
@@ -0,0 +1,84 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+#include <testsuite_counter_type.h>
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::counter_type;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<counter_type, false> alloc_type;
+ typedef __gnu_test::counter_type_hasher hash;
+ typedef std::unordered_set<counter_type, hash,
+ std::equal_to<counter_type>,
+ alloc_type> test_type;
+
+ test_type v1(alloc_type(1));
+ v1.emplace(0);
+
+ test_type v2(alloc_type(2));
+ v2.emplace(1);
+
+ counter_type::reset();
+
+ v2 = std::move(v1);
+
+ VERIFY( 1 == v1.get_allocator().get_personality() );
+ VERIFY( 2 == v2.get_allocator().get_personality() );
+
+ VERIFY( counter_type::move_assign_count == 1 );
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<counter_type, true> alloc_type;
+ typedef __gnu_test::counter_type_hasher hash;
+ typedef std::unordered_set<counter_type, hash,
+ std::equal_to<counter_type>,
+ alloc_type> test_type;
+
+ test_type v1(alloc_type(1));
+ v1.emplace(0);
+
+ test_type v2(alloc_type(2));
+ v2.emplace(0);
+
+ counter_type::reset();
+
+ v2 = std::move(v1);
+
+ VERIFY(0 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+
+ VERIFY( counter_type::move_assign_count == 0 );
+ VERIFY( counter_type::destructor_count == 1 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_set/allocator/copy_assign.cc
===================================================================
--- testsuite/23_containers/unordered_set/allocator/copy_assign.cc (revision 0)
+++ testsuite/23_containers/unordered_set/allocator/copy_assign.cc (revision 0)
@@ -0,0 +1,73 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(alloc_type(2));
+ v2.insert(T());
+ v2 = v1;
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ v1.insert(T());
+ test_type v2(alloc_type(2));
+ v2.insert(T());
+ v2 = v1;
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
Index: testsuite/23_containers/unordered_set/allocator/noexcept.cc
===================================================================
--- testsuite/23_containers/unordered_set/allocator/noexcept.cc (revision 0)
+++ testsuite/23_containers/unordered_set/allocator/noexcept.cc (revision 0)
@@ -0,0 +1,88 @@
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+namespace __gnu_test
+{
+ inline void
+ swap(propagating_allocator<T, true>& l, propagating_allocator<T, true>& r)
+ noexcept(false)
+ {
+ typedef uneq_allocator<T> base_alloc;
+ swap(static_cast<base_alloc&>(l), static_cast<base_alloc&>(r));
+ }
+}
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ typedef std::allocator<T> alloc_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v1;
+ test_type v2;
+ // this is a GNU extension for std::allocator
+ static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+ static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test02()
+{
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ test_type v2(alloc_type(2));
+ static_assert( !noexcept( v1 = std::move(v2) ), "Move assign can throw" );
+ static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test03()
+{
+ typedef propagating_allocator<T, true> alloc_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v1(alloc_type(1));
+ test_type v2(alloc_type(2));
+ static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+ // static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
Index: testsuite/23_containers/unordered_set/allocator/minimal.cc
===================================================================
--- testsuite/23_containers/unordered_set/allocator/minimal.cc (revision 0)
+++ testsuite/23_containers/unordered_set/allocator/minimal.cc (revision 0)
@@ -0,0 +1,62 @@
+// Copyright (C) 2012-2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <unordered_set>
+#include <memory>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+struct hash
+{
+ std::size_t operator()(const T t) const noexcept
+ { return t.i; }
+};
+
+struct equal_to
+{
+ bool operator()(const T& lhs, const T& rhs) const noexcept
+ { return lhs.i == rhs.i; }
+};
+
+
+bool operator==(const T& l, const T& r) { return l.i == r.i; }
+bool operator<(const T& l, const T& r) { return l.i < r.i; }
+
+using __gnu_test::SimpleAllocator;
+
+template class std::unordered_set<T, hash, equal_to, SimpleAllocator<T>>;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef SimpleAllocator<T> alloc_type;
+ typedef std::allocator_traits<alloc_type> traits_type;
+ typedef std::unordered_set<T, hash, equal_to, alloc_type> test_type;
+ test_type v(alloc_type{});
+ v.insert(T());
+ VERIFY( v.max_size() == traits_type::max_size(v.get_allocator()) );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: testsuite/23_containers/unordered_set/not_default_constructible_hash_neg.cc
===================================================================
--- testsuite/23_containers/unordered_set/not_default_constructible_hash_neg.cc (revision 196664)
+++ testsuite/23_containers/unordered_set/not_default_constructible_hash_neg.cc (working copy)
@@ -19,7 +19,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-error "default constructible" "" { target *-*-* } 268 }
+// { dg-error "default constructible" "" { target *-*-* } 273 }
#include <unordered_set>