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 + struct __move_assign_if_noexcept_cond + : public __and_<__not_>, + is_copy_assignable<_Tp>>::type { }; + + template + 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 + struct _Mutable_Value_Type + { typedef _Value type; }; + + template + struct _Mutable_Value_Type> + { typedef std::pair::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 + struct _Hash_node_value_base : _Hash_node_base + { + typename aligned_storage::value>::type + _M_storage; + + _Value* + _M_valptr() noexcept + { return static_cast<_Value*>(static_cast(&_M_storage)); } + + const _Value* + _M_valptr() const noexcept + { + return + static_cast(static_cast(&_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(&_M_storage)); } + }; + + /** * Primary template struct _Hash_node. */ template @@ -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 - 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 - _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 - struct _Hash_node<_Value, false> : _Hash_node_base + struct _Hash_node<_Value, false> : _Hash_node_value_base<_Value> { - _Value _M_v; - - template - _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_M_insert_unique_node(__n, __code, __p)->second; } - return (__p->_M_v).second; + return __p->_M_v().second; } template_M_v).second; + return __p->_M_v().second; } template_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::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 + 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::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 + 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 + friend struct __detail::_ReuseOrAllocNode; + + template + 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 + 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()); return *this; } _Hashtable& operator=(initializer_list __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:: _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 _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 + template + 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 + 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 + 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 + 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 + _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 _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 + _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 + _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:: 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 #include #include -#include #include -#include +#include #include // equal_to, _Identity, _Select1st #include #include Index: include/std/unordered_map =================================================================== --- include/std/unordered_map (revision 196664) +++ include/std/unordered_map (working copy) @@ -39,9 +39,8 @@ #include #include #include -#include #include -#include +#include #include // equal_to, _Identity, _Select1st #include #include 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 _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 __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 __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 _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 __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 __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 _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 __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 __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 _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 __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 __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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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& l, propagating_allocator& r) + noexcept(false) + { + typedef uneq_allocator base_alloc; + swap(static_cast(l), static_cast(r)); + } +} + +using __gnu_test::propagating_allocator; + +void test01() +{ + typedef std::allocator alloc_type; + typedef std::unordered_map 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 alloc_type; + typedef std::unordered_map 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 alloc_type; + typedef std::unordered_map 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include +#include + +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>; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef SimpleAllocator alloc_type; + typedef std::allocator_traits traits_type; + typedef std::unordered_map 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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, false>&, + const propagating_allocator, false>&) +{ + return true; +} + +bool +operator!=(const propagating_allocator, false>&, + const propagating_allocator, false>&) +{ + return false; +} + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator, false> alloc_type; + typedef std::unordered_map 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, true> alloc_type; + typedef std::unordered_map 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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 alloc_type; + typedef std::unordered_map 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 alloc_type; + typedef std::unordered_map 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include +#include + +using __gnu_test::propagating_allocator; +using __gnu_test::counter_type; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef __gnu_test::counter_type_hasher hash; + typedef std::unordered_map, + 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 alloc_type; + typedef __gnu_test::counter_type_hasher hash; + typedef std::unordered_map, + 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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 alloc_type; + typedef std::unordered_map 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 alloc_type; + typedef std::unordered_map 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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, false>&, + const propagating_allocator, false>&) +{ + return true; +} + +bool +operator!=(const propagating_allocator, false>&, + const propagating_allocator, false>&) +{ + return false; +} + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator, false> alloc_type; + typedef std::unordered_multimap 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, true> alloc_type; + typedef std::unordered_multimap 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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 alloc_type; + typedef std::unordered_multimap 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 alloc_type; + typedef std::unordered_multimap 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include +#include + +using __gnu_test::propagating_allocator; +using __gnu_test::counter_type; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef __gnu_test::counter_type_hasher hash; + typedef std::unordered_multimap, + 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 alloc_type; + typedef __gnu_test::counter_type_hasher hash; + typedef std::unordered_multimap, + 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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 alloc_type; + typedef std::unordered_multimap 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 alloc_type; + typedef std::unordered_multimap 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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& l, propagating_allocator& r) + noexcept(false) + { + typedef uneq_allocator base_alloc; + swap(static_cast(l), static_cast(r)); + } +} + +using __gnu_test::propagating_allocator; + +void test01() +{ + typedef std::allocator alloc_type; + typedef std::unordered_multimap 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 alloc_type; + typedef std::unordered_multimap 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 alloc_type; + typedef std::unordered_multimap 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include +#include + +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>; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef SimpleAllocator alloc_type; + typedef std::allocator_traits traits_type; + typedef std::unordered_multimap 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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 alloc_type; + typedef std::unordered_multiset 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 alloc_type; + typedef std::unordered_multiset 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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& l, propagating_allocator& r) + noexcept(false) + { + typedef uneq_allocator base_alloc; + swap(static_cast(l), static_cast(r)); + } +} + +using __gnu_test::propagating_allocator; + +void test01() +{ + typedef std::allocator alloc_type; + typedef std::unordered_multiset 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 alloc_type; + typedef std::unordered_multiset 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 alloc_type; + typedef std::unordered_multiset 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include +#include + +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>; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef SimpleAllocator alloc_type; + typedef std::allocator_traits traits_type; + typedef std::unordered_multiset 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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&, + const propagating_allocator&) +{ + return true; +} + +bool +operator!=(const propagating_allocator&, + const propagating_allocator&) +{ + return false; +} + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::unordered_multiset 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 alloc_type; + typedef std::unordered_multiset 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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 alloc_type; + typedef std::unordered_multiset 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 alloc_type; + typedef std::unordered_multiset 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include +#include + +using __gnu_test::propagating_allocator; +using __gnu_test::counter_type; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef __gnu_test::counter_type_hasher hash; + typedef std::unordered_multiset, + 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 alloc_type; + typedef __gnu_test::counter_type_hasher hash; + typedef std::unordered_multiset, + 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 // . -// { dg-error "with noexcept" "" { target *-*-* } 252 } +// { dg-error "with noexcept" "" { target *-*-* } 257 } #include 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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&, + const propagating_allocator&) +{ + return true; +} + +bool +operator!=(const propagating_allocator&, + const propagating_allocator&) +{ + return false; +} + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::unordered_set 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 alloc_type; + typedef std::unordered_set 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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 alloc_type; + typedef std::unordered_set 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 alloc_type; + typedef std::unordered_set 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include +#include + +using __gnu_test::propagating_allocator; +using __gnu_test::counter_type; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef __gnu_test::counter_type_hasher hash; + typedef std::unordered_set, + 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 alloc_type; + typedef __gnu_test::counter_type_hasher hash; + typedef std::unordered_set, + 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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 alloc_type; + typedef std::unordered_set 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 alloc_type; + typedef std::unordered_set 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include + +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& l, propagating_allocator& r) + noexcept(false) + { + typedef uneq_allocator base_alloc; + swap(static_cast(l), static_cast(r)); + } +} + +using __gnu_test::propagating_allocator; + +void test01() +{ + typedef std::allocator alloc_type; + typedef std::unordered_set 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 alloc_type; + typedef std::unordered_set 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 alloc_type; + typedef std::unordered_set 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 +// . + +// { dg-options "-std=c++11" } + +#include +#include +#include +#include + +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>; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef SimpleAllocator alloc_type; + typedef std::allocator_traits traits_type; + typedef std::unordered_set 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 // . -// { dg-error "default constructible" "" { target *-*-* } 268 } +// { dg-error "default constructible" "" { target *-*-* } 273 } #include