re PR libstdc++/41975 ([C++0x] [DR579] unordered_set::erase performs worse when nearly empty)
2011-11-23 François Dumont <fdumont@gcc.gnu.org> PR libstdc++/41975 * include/bits/hashtable.h (_Hashtable<>): Major data model modification to limit performance impact of empty buckets in erase(iterator) implementation. * include/bits/hashtable_policy.h (_Hashtable_iterator, _Hashtable_const_iterator): Remove not used anymore. * include/bits/hashtable_policy.h (_Prime_rehash_policy): Remove _M_grow_factor, just use natural evolution of prime numbers. Add _M_prev_size to know when the number of buckets can be reduced. * include/bits/unordered_set.h (__unordered_set<>, __unordered_multiset<>), unordered_map.h (__unordered_map<>, __unordered_multimap<>): Change default value of cache hash code template parameter, false for integral types with noexcept hash functor, true otherwise. * include/debug/unordered_map, unordered_set: Adapt transformation from iterator/const_iterator to respectively local_iterator/const_local_iterator. * testsuite/performance/23_containers/copy_construct/unordered_set.cc: New. * testsuite/23_containers/unordered_set/instantiation_neg.cc: New. * testsuite/23_containers/unordered_set/hash_policy/rehash.cc: New. * testsuite/23_containers/unordered_multiset/cons/copy.cc: New. * testsuite/23_containers/unordered_multiset/erase/1.cc, 24061-multiset.cc: Add checks on the number of bucket elements. * testsuite/23_containers/unordered_multiset/insert/multiset_range.cc, multiset_single.cc, multiset_single_move.cc: Likewise. From-SVN: r181677
This commit is contained in:
parent
2ff12653cd
commit
da29608a7a
16 changed files with 976 additions and 411 deletions
|
@ -1,3 +1,32 @@
|
|||
2011-11-23 François Dumont <fdumont@gcc.gnu.org>
|
||||
|
||||
PR libstdc++/41975
|
||||
* include/bits/hashtable.h (_Hashtable<>): Major data model
|
||||
modification to limit performance impact of empty buckets in
|
||||
erase(iterator) implementation.
|
||||
* include/bits/hashtable_policy.h (_Hashtable_iterator,
|
||||
_Hashtable_const_iterator): Remove not used anymore.
|
||||
* include/bits/hashtable_policy.h (_Prime_rehash_policy): Remove
|
||||
_M_grow_factor, just use natural evolution of prime numbers. Add
|
||||
_M_prev_size to know when the number of buckets can be reduced.
|
||||
* include/bits/unordered_set.h (__unordered_set<>,
|
||||
__unordered_multiset<>), unordered_map.h (__unordered_map<>,
|
||||
__unordered_multimap<>): Change default value of cache hash code
|
||||
template parameter, false for integral types with noexcept hash
|
||||
functor, true otherwise.
|
||||
* include/debug/unordered_map, unordered_set: Adapt transformation
|
||||
from iterator/const_iterator to respectively
|
||||
local_iterator/const_local_iterator.
|
||||
* testsuite/performance/23_containers/copy_construct/unordered_set.cc:
|
||||
New.
|
||||
* testsuite/23_containers/unordered_set/instantiation_neg.cc: New.
|
||||
* testsuite/23_containers/unordered_set/hash_policy/rehash.cc: New.
|
||||
* testsuite/23_containers/unordered_multiset/cons/copy.cc: New.
|
||||
* testsuite/23_containers/unordered_multiset/erase/1.cc,
|
||||
24061-multiset.cc: Add checks on the number of bucket elements.
|
||||
* testsuite/23_containers/unordered_multiset/insert/multiset_range.cc,
|
||||
multiset_single.cc, multiset_single_move.cc: Likewise.
|
||||
|
||||
2011-11-21 Jonathan Wakely <jwakely.gcc@gmail.com>
|
||||
|
||||
* include/std/functional (is_placeholder, is_bind_expression): Add
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -59,6 +59,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return __distance_fw(__first, __last, _Tag());
|
||||
}
|
||||
|
||||
// Helper type used to detect when the hash functor is noexcept qualified or
|
||||
// not
|
||||
template <typename _Key, typename _Hash>
|
||||
struct __is_noexcept_hash : std::integral_constant<bool,
|
||||
noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
|
||||
{};
|
||||
|
||||
// Auxiliary types used for all instantiations of _Hashtable: nodes
|
||||
// and iterators.
|
||||
|
||||
|
@ -211,155 +218,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
};
|
||||
|
||||
template<typename _Value, bool __cache>
|
||||
struct _Hashtable_iterator_base
|
||||
{
|
||||
_Hashtable_iterator_base(_Hash_node<_Value, __cache>* __node,
|
||||
_Hash_node<_Value, __cache>** __bucket)
|
||||
: _M_cur_node(__node), _M_cur_bucket(__bucket) { }
|
||||
|
||||
void
|
||||
_M_incr()
|
||||
{
|
||||
_M_cur_node = _M_cur_node->_M_next;
|
||||
if (!_M_cur_node)
|
||||
_M_incr_bucket();
|
||||
}
|
||||
|
||||
void
|
||||
_M_incr_bucket();
|
||||
|
||||
_Hash_node<_Value, __cache>* _M_cur_node;
|
||||
_Hash_node<_Value, __cache>** _M_cur_bucket;
|
||||
};
|
||||
|
||||
// Global iterators, used for arbitrary iteration within a hash
|
||||
// table. Larger and more expensive than local iterators.
|
||||
template<typename _Value, bool __cache>
|
||||
void
|
||||
_Hashtable_iterator_base<_Value, __cache>::
|
||||
_M_incr_bucket()
|
||||
{
|
||||
++_M_cur_bucket;
|
||||
|
||||
// This loop requires the bucket array to have a non-null sentinel.
|
||||
while (!*_M_cur_bucket)
|
||||
++_M_cur_bucket;
|
||||
_M_cur_node = *_M_cur_bucket;
|
||||
}
|
||||
|
||||
template<typename _Value, bool __cache>
|
||||
inline bool
|
||||
operator==(const _Hashtable_iterator_base<_Value, __cache>& __x,
|
||||
const _Hashtable_iterator_base<_Value, __cache>& __y)
|
||||
{ return __x._M_cur_node == __y._M_cur_node; }
|
||||
|
||||
template<typename _Value, bool __cache>
|
||||
inline bool
|
||||
operator!=(const _Hashtable_iterator_base<_Value, __cache>& __x,
|
||||
const _Hashtable_iterator_base<_Value, __cache>& __y)
|
||||
{ return __x._M_cur_node != __y._M_cur_node; }
|
||||
|
||||
template<typename _Value, bool __constant_iterators, bool __cache>
|
||||
struct _Hashtable_iterator
|
||||
: public _Hashtable_iterator_base<_Value, __cache>
|
||||
{
|
||||
typedef _Value value_type;
|
||||
typedef typename std::conditional<__constant_iterators,
|
||||
const _Value*, _Value*>::type
|
||||
pointer;
|
||||
typedef typename std::conditional<__constant_iterators,
|
||||
const _Value&, _Value&>::type
|
||||
reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
_Hashtable_iterator()
|
||||
: _Hashtable_iterator_base<_Value, __cache>(0, 0) { }
|
||||
|
||||
_Hashtable_iterator(_Hash_node<_Value, __cache>* __p,
|
||||
_Hash_node<_Value, __cache>** __b)
|
||||
: _Hashtable_iterator_base<_Value, __cache>(__p, __b) { }
|
||||
|
||||
explicit
|
||||
_Hashtable_iterator(_Hash_node<_Value, __cache>** __b)
|
||||
: _Hashtable_iterator_base<_Value, __cache>(*__b, __b) { }
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{ return this->_M_cur_node->_M_v; }
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{ return std::__addressof(this->_M_cur_node->_M_v); }
|
||||
|
||||
_Hashtable_iterator&
|
||||
operator++()
|
||||
{
|
||||
this->_M_incr();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Hashtable_iterator
|
||||
operator++(int)
|
||||
{
|
||||
_Hashtable_iterator __tmp(*this);
|
||||
this->_M_incr();
|
||||
return __tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Value, bool __constant_iterators, bool __cache>
|
||||
struct _Hashtable_const_iterator
|
||||
: public _Hashtable_iterator_base<_Value, __cache>
|
||||
{
|
||||
typedef _Value value_type;
|
||||
typedef const _Value* pointer;
|
||||
typedef const _Value& reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
_Hashtable_const_iterator()
|
||||
: _Hashtable_iterator_base<_Value, __cache>(0, 0) { }
|
||||
|
||||
_Hashtable_const_iterator(_Hash_node<_Value, __cache>* __p,
|
||||
_Hash_node<_Value, __cache>** __b)
|
||||
: _Hashtable_iterator_base<_Value, __cache>(__p, __b) { }
|
||||
|
||||
explicit
|
||||
_Hashtable_const_iterator(_Hash_node<_Value, __cache>** __b)
|
||||
: _Hashtable_iterator_base<_Value, __cache>(*__b, __b) { }
|
||||
|
||||
_Hashtable_const_iterator(const _Hashtable_iterator<_Value,
|
||||
__constant_iterators, __cache>& __x)
|
||||
: _Hashtable_iterator_base<_Value, __cache>(__x._M_cur_node,
|
||||
__x._M_cur_bucket) { }
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{ return this->_M_cur_node->_M_v; }
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{ return std::__addressof(this->_M_cur_node->_M_v); }
|
||||
|
||||
_Hashtable_const_iterator&
|
||||
operator++()
|
||||
{
|
||||
this->_M_incr();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Hashtable_const_iterator
|
||||
operator++(int)
|
||||
{
|
||||
_Hashtable_const_iterator __tmp(*this);
|
||||
this->_M_incr();
|
||||
return __tmp;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Many of class template _Hashtable's template parameters are policy
|
||||
// classes. These are defaults for the policies.
|
||||
|
||||
|
@ -388,7 +246,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct _Prime_rehash_policy
|
||||
{
|
||||
_Prime_rehash_policy(float __z = 1.0)
|
||||
: _M_max_load_factor(__z), _M_growth_factor(2.f), _M_next_resize(0) { }
|
||||
: _M_max_load_factor(__z), _M_prev_resize(0), _M_next_resize(0) { }
|
||||
|
||||
float
|
||||
max_load_factor() const noexcept
|
||||
|
@ -410,10 +268,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_M_need_rehash(std::size_t __n_bkt, std::size_t __n_elt,
|
||||
std::size_t __n_ins) const;
|
||||
|
||||
typedef std::pair<std::size_t, std::size_t> _State;
|
||||
|
||||
_State
|
||||
_M_state() const
|
||||
{ return std::make_pair(_M_prev_resize, _M_next_resize); }
|
||||
|
||||
void
|
||||
_M_reset(const _State& __state)
|
||||
{
|
||||
_M_prev_resize = __state.first;
|
||||
_M_next_resize = __state.second;
|
||||
}
|
||||
|
||||
enum { _S_n_primes = sizeof(unsigned long) != 8 ? 256 : 256 + 48 };
|
||||
|
||||
float _M_max_load_factor;
|
||||
float _M_growth_factor;
|
||||
mutable std::size_t _M_prev_resize;
|
||||
mutable std::size_t _M_next_resize;
|
||||
};
|
||||
|
||||
|
@ -429,15 +300,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{
|
||||
// Optimize lookups involving the first elements of __prime_list.
|
||||
// (useful to speed-up, eg, constructors)
|
||||
static const unsigned char __fast_bkt[12]
|
||||
static const unsigned long __fast_bkt[12]
|
||||
= { 2, 2, 2, 3, 5, 5, 7, 7, 11, 11, 11, 11 };
|
||||
|
||||
const unsigned long __p
|
||||
= __n <= 11 ? __fast_bkt[__n]
|
||||
: *std::lower_bound(__prime_list + 5,
|
||||
__prime_list + _S_n_primes, __n);
|
||||
_M_next_resize = __builtin_floor(__p * (long double)_M_max_load_factor);
|
||||
return __p;
|
||||
const unsigned long* __p
|
||||
= __n <= 11 ? __fast_bkt + __n
|
||||
: std::lower_bound(__prime_list + 5,
|
||||
__prime_list + _S_n_primes, __n);
|
||||
|
||||
_M_prev_resize = __builtin_floor(*__p * (long double)_M_max_load_factor);
|
||||
if (__p != __fast_bkt)
|
||||
_M_prev_resize = std::min(_M_prev_resize,
|
||||
static_cast<std::size_t>(*(__p - 1)));
|
||||
// Lets guaranty a minimal grow step of 11:
|
||||
if (*__p - __n < 11)
|
||||
__p = std::lower_bound(__prime_list + 5,
|
||||
__prime_list + _S_n_primes, __n + 11);
|
||||
_M_next_resize = __builtin_floor(*__p * (long double)_M_max_load_factor);
|
||||
return *__p;
|
||||
}
|
||||
|
||||
// Return the smallest prime p such that alpha p >= n, where alpha
|
||||
|
@ -461,17 +341,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_M_need_rehash(std::size_t __n_bkt, std::size_t __n_elt,
|
||||
std::size_t __n_ins) const
|
||||
{
|
||||
if (__n_elt + __n_ins > _M_next_resize)
|
||||
if (__n_elt + __n_ins >= _M_next_resize)
|
||||
{
|
||||
long double __min_bkts = ((__n_elt + __n_ins)
|
||||
/ (long double)_M_max_load_factor);
|
||||
if (__min_bkts > __n_bkt)
|
||||
{
|
||||
__min_bkts = std::max(__min_bkts, (long double)_M_growth_factor
|
||||
* __n_bkt);
|
||||
return std::make_pair(true,
|
||||
_M_next_bkt(__builtin_ceil(__min_bkts)));
|
||||
}
|
||||
long double __min_bkts = (__n_elt + __n_ins)
|
||||
/ (long double)_M_max_load_factor;
|
||||
if (__min_bkts >= __n_bkt)
|
||||
return std::make_pair(true,
|
||||
_M_next_bkt(__builtin_floor(__min_bkts) + 1));
|
||||
else
|
||||
{
|
||||
_M_next_resize
|
||||
|
@ -479,6 +355,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return std::make_pair(false, 0);
|
||||
}
|
||||
}
|
||||
else if (__n_elt + __n_ins < _M_prev_resize)
|
||||
{
|
||||
long double __min_bkts = (__n_elt + __n_ins)
|
||||
/ (long double)_M_max_load_factor;
|
||||
return std::make_pair(true,
|
||||
_M_next_bkt(__builtin_floor(__min_bkts) + 1));
|
||||
}
|
||||
else
|
||||
return std::make_pair(false, 0);
|
||||
}
|
||||
|
@ -538,8 +421,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
std::size_t __n = __h->_M_bucket_index(__k, __code,
|
||||
__h->_M_bucket_count);
|
||||
|
||||
typename _Hashtable::_Node* __p =
|
||||
__h->_M_find_node(__h->_M_buckets[__n], __k, __code);
|
||||
typename _Hashtable::_Node* __p = __h->_M_find_node(__n, __k, __code);
|
||||
if (!__p)
|
||||
return __h->_M_insert_bucket(std::make_pair(__k, mapped_type()),
|
||||
__n, __code)->second;
|
||||
|
@ -557,8 +439,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
std::size_t __n = __h->_M_bucket_index(__k, __code,
|
||||
__h->_M_bucket_count);
|
||||
|
||||
typename _Hashtable::_Node* __p =
|
||||
__h->_M_find_node(__h->_M_buckets[__n], __k, __code);
|
||||
typename _Hashtable::_Node* __p = __h->_M_find_node(__n, __k, __code);
|
||||
if (!__p)
|
||||
return __h->_M_insert_bucket(std::make_pair(std::move(__k),
|
||||
mapped_type()),
|
||||
|
@ -577,8 +458,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
std::size_t __n = __h->_M_bucket_index(__k, __code,
|
||||
__h->_M_bucket_count);
|
||||
|
||||
typename _Hashtable::_Node* __p =
|
||||
__h->_M_find_node(__h->_M_buckets[__n], __k, __code);
|
||||
typename _Hashtable::_Node* __p = __h->_M_find_node(__n, __k, __code);
|
||||
if (!__p)
|
||||
__throw_out_of_range(__N("_Map_base::at"));
|
||||
return (__p->_M_v).second;
|
||||
|
@ -595,8 +475,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
std::size_t __n = __h->_M_bucket_index(__k, __code,
|
||||
__h->_M_bucket_count);
|
||||
|
||||
typename _Hashtable::_Node* __p =
|
||||
__h->_M_find_node(__h->_M_buckets[__n], __k, __code);
|
||||
typename _Hashtable::_Node* __p = __h->_M_find_node(__n, __k, __code);
|
||||
if (!__p)
|
||||
__throw_out_of_range(__N("_Map_base::at"));
|
||||
return (__p->_M_v).second;
|
||||
|
|
|
@ -40,7 +40,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
|
|||
class _Hash = hash<_Key>,
|
||||
class _Pred = std::equal_to<_Key>,
|
||||
class _Alloc = std::allocator<std::pair<const _Key, _Tp> >,
|
||||
bool __cache_hash_code = false>
|
||||
bool __cache_hash_code =
|
||||
__not_<__and_<is_integral<_Key>,
|
||||
__detail::__is_noexcept_hash<_Key, _Hash>>>::value>
|
||||
class __unordered_map
|
||||
: public _Hashtable<_Key, std::pair<const _Key, _Tp>, _Alloc,
|
||||
std::_Select1st<std::pair<const _Key, _Tp> >, _Pred,
|
||||
|
@ -109,7 +111,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
|
|||
class _Hash = hash<_Key>,
|
||||
class _Pred = std::equal_to<_Key>,
|
||||
class _Alloc = std::allocator<std::pair<const _Key, _Tp> >,
|
||||
bool __cache_hash_code = false>
|
||||
bool __cache_hash_code =
|
||||
__not_<__and_<is_integral<_Key>,
|
||||
__detail::__is_noexcept_hash<_Key, _Hash>>>::value>
|
||||
class __unordered_multimap
|
||||
: public _Hashtable<_Key, std::pair<const _Key, _Tp>,
|
||||
_Alloc,
|
||||
|
|
|
@ -40,7 +40,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
|
|||
class _Hash = hash<_Value>,
|
||||
class _Pred = std::equal_to<_Value>,
|
||||
class _Alloc = std::allocator<_Value>,
|
||||
bool __cache_hash_code = false>
|
||||
bool __cache_hash_code =
|
||||
__not_<__and_<is_integral<_Value>,
|
||||
__detail::__is_noexcept_hash<_Value, _Hash>>>::value>
|
||||
class __unordered_set
|
||||
: public _Hashtable<_Value, _Value, _Alloc,
|
||||
std::_Identity<_Value>, _Pred,
|
||||
|
@ -121,7 +123,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
|
|||
class _Hash = hash<_Value>,
|
||||
class _Pred = std::equal_to<_Value>,
|
||||
class _Alloc = std::allocator<_Value>,
|
||||
bool __cache_hash_code = false>
|
||||
bool __cache_hash_code =
|
||||
__not_<__and_<is_integral<_Value>,
|
||||
__detail::__is_noexcept_hash<_Value, _Hash>>>::value>
|
||||
class __unordered_multiset
|
||||
: public _Hashtable<_Value, _Value, _Alloc,
|
||||
std::_Identity<_Value>, _Pred,
|
||||
|
|
|
@ -395,11 +395,11 @@ namespace __debug
|
|||
|
||||
static _Base_local_iterator
|
||||
_S_to_local(_Base_iterator __it)
|
||||
{ return _Base_local_iterator(__it._M_cur_node); }
|
||||
{ return _Base_local_iterator(__it._M_cur); }
|
||||
|
||||
static _Base_const_local_iterator
|
||||
_S_to_local(_Base_const_iterator __it)
|
||||
{ return _Base_const_local_iterator(__it._M_cur_node); }
|
||||
{ return _Base_const_local_iterator(__it._M_cur); }
|
||||
};
|
||||
|
||||
template<typename _Key, typename _Tp, typename _Hash,
|
||||
|
@ -774,11 +774,11 @@ namespace __debug
|
|||
|
||||
static _Base_local_iterator
|
||||
_S_to_local(_Base_iterator __it)
|
||||
{ return _Base_local_iterator(__it._M_cur_node); }
|
||||
{ return _Base_local_iterator(__it._M_cur); }
|
||||
|
||||
static _Base_const_local_iterator
|
||||
_S_to_local(_Base_const_iterator __it)
|
||||
{ return _Base_const_local_iterator(__it._M_cur_node); }
|
||||
{ return _Base_const_local_iterator(__it._M_cur); }
|
||||
};
|
||||
|
||||
template<typename _Key, typename _Tp, typename _Hash,
|
||||
|
|
|
@ -394,11 +394,11 @@ namespace __debug
|
|||
|
||||
static _Base_local_iterator
|
||||
_S_to_local(_Base_iterator __it)
|
||||
{ return _Base_local_iterator(__it._M_cur_node); }
|
||||
{ return _Base_local_iterator(__it._M_cur); }
|
||||
|
||||
static _Base_const_local_iterator
|
||||
_S_to_local(_Base_const_iterator __it)
|
||||
{ return _Base_const_local_iterator(__it._M_cur_node); }
|
||||
{ return _Base_const_local_iterator(__it._M_cur); }
|
||||
};
|
||||
|
||||
template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
|
||||
|
@ -759,11 +759,11 @@ namespace __debug
|
|||
|
||||
static _Base_local_iterator
|
||||
_S_to_local(_Base_iterator __it)
|
||||
{ return _Base_local_iterator(__it._M_cur_node); }
|
||||
{ return _Base_local_iterator(__it._M_cur); }
|
||||
|
||||
static _Base_const_local_iterator
|
||||
_S_to_local(_Base_const_iterator __it)
|
||||
{ return _Base_const_local_iterator(__it._M_cur_node); }
|
||||
{ return _Base_const_local_iterator(__it._M_cur); }
|
||||
};
|
||||
|
||||
template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
// Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
// NOTE: This makes use of the fact that we know how moveable
|
||||
// is implemented on set (via swap). If the implementation changed
|
||||
// this test may begin to fail.
|
||||
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
const int nb = 10000;
|
||||
std::unordered_multiset<int> ref;
|
||||
for (int i = 0; i != nb; ++i)
|
||||
{
|
||||
ref.insert(i);
|
||||
ref.insert(i);
|
||||
}
|
||||
|
||||
std::unordered_multiset<int> copy(ref);
|
||||
VERIFY( copy.size() == ref.size() );
|
||||
VERIFY( std::equal(ref.begin(), ref.end(), copy.begin()) );
|
||||
return 0;
|
||||
}
|
|
@ -23,6 +23,18 @@
|
|||
#include <string>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::size_t
|
||||
get_nb_bucket_elems(const std::unordered_multiset<std::string>& us)
|
||||
{
|
||||
std::size_t nb = 0;
|
||||
for (std::size_t b = 0; b != us.bucket_count(); ++b)
|
||||
nb += us.bucket_size(b);
|
||||
return nb;
|
||||
}
|
||||
}
|
||||
|
||||
void test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
@ -45,14 +57,17 @@ void test01()
|
|||
ms1.insert("one line behind");
|
||||
ms1.insert("because to why");
|
||||
VERIFY( ms1.size() == 11 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
|
||||
VERIFY( ms1.erase("eeilo") == 1 );
|
||||
VERIFY( ms1.size() == 10 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
iterator it1 = ms1.find("eeilo");
|
||||
VERIFY( it1 == ms1.end() );
|
||||
|
||||
VERIFY( ms1.erase("tillsammans") == 1 );
|
||||
VERIFY( ms1.size() == 9 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
iterator it2 = ms1.find("tillsammans");
|
||||
VERIFY( it2 == ms1.end() );
|
||||
|
||||
|
@ -61,17 +76,20 @@ void test01()
|
|||
VERIFY( it3 != ms1.end() );
|
||||
VERIFY( ms1.erase(*it3) == 1 );
|
||||
VERIFY( ms1.size() == 8 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
it3 = ms1.find("belonging (no longer mix)");
|
||||
VERIFY( it3 == ms1.end() );
|
||||
|
||||
VERIFY( !ms1.erase("abra") );
|
||||
VERIFY( ms1.size() == 8 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
|
||||
VERIFY( !ms1.erase("eeilo") );
|
||||
VERIFY( ms1.size() == 8 );
|
||||
|
||||
VERIFY( ms1.erase("because to why") == 2 );
|
||||
VERIFY( ms1.size() == 6 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
iterator it4 = ms1.find("because to why");
|
||||
VERIFY( it4 == ms1.end() );
|
||||
|
||||
|
@ -87,11 +105,13 @@ void test01()
|
|||
|
||||
VERIFY( ms1.erase(*it5) == 1 );
|
||||
VERIFY( ms1.size() == 5 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
it5 = ms1.find("umbra/penumbra");
|
||||
VERIFY( it5 == ms1.end() );
|
||||
|
||||
VERIFY( ms1.erase(*it6) == 1 );
|
||||
VERIFY( ms1.size() == 4 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
it6 = ms1.find("one line behind");
|
||||
VERIFY( it6 == ms1.end() );
|
||||
|
||||
|
@ -103,6 +123,7 @@ void test01()
|
|||
|
||||
VERIFY( ms1.erase(*it8) == 1 );
|
||||
VERIFY( ms1.size() == 3 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
VERIFY( ++it7 == it9 );
|
||||
|
||||
iterator it10 = it9;
|
||||
|
@ -110,15 +131,18 @@ void test01()
|
|||
iterator it11 = it10;
|
||||
|
||||
VERIFY( ms1.erase(*it9) == 1 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
VERIFY( ms1.size() == 2 );
|
||||
VERIFY( ++it10 == ms1.end() );
|
||||
|
||||
VERIFY( ms1.erase(ms1.begin()) != ms1.end() );
|
||||
VERIFY( ms1.size() == 1 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
VERIFY( ms1.begin() == it11 );
|
||||
|
||||
VERIFY( ms1.erase(*ms1.begin()) == 1 );
|
||||
VERIFY( ms1.size() == 0 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
VERIFY( ms1.begin() == ms1.end() );
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,20 @@
|
|||
#include <string>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::size_t
|
||||
get_nb_bucket_elems(const std::unordered_multiset<std::string>& us)
|
||||
{
|
||||
std::size_t nb = 0;
|
||||
for (std::size_t b = 0; b != us.bucket_count(); ++b)
|
||||
{
|
||||
nb += us.bucket_size(b);
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
}
|
||||
|
||||
// libstdc++/24061
|
||||
void test01()
|
||||
{
|
||||
|
@ -49,6 +63,7 @@ void test01()
|
|||
ms1.insert("love is not enough");
|
||||
ms1.insert("every day is exactly the same");
|
||||
VERIFY( ms1.size() == 13 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
|
||||
iterator it1 = ms1.begin();
|
||||
++it1;
|
||||
|
@ -56,6 +71,7 @@ void test01()
|
|||
++it2;
|
||||
iterator it3 = ms1.erase(it1);
|
||||
VERIFY( ms1.size() == 12 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
VERIFY( it3 == it2 );
|
||||
VERIFY( *it3 == *it2 );
|
||||
|
||||
|
@ -68,6 +84,7 @@ void test01()
|
|||
++it5;
|
||||
iterator it6 = ms1.erase(it4, it5);
|
||||
VERIFY( ms1.size() == 10 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
VERIFY( it6 == it5 );
|
||||
VERIFY( *it6 == *it5 );
|
||||
|
||||
|
@ -79,6 +96,7 @@ void test01()
|
|||
++it8;
|
||||
const_iterator it9 = ms1.erase(it7);
|
||||
VERIFY( ms1.size() == 9 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
VERIFY( it9 == it8 );
|
||||
VERIFY( *it9 == *it8 );
|
||||
|
||||
|
@ -91,11 +109,13 @@ void test01()
|
|||
++it11;
|
||||
const_iterator it12 = ms1.erase(it10, it11);
|
||||
VERIFY( ms1.size() == 5 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
VERIFY( it12 == it11 );
|
||||
VERIFY( *it12 == *it11 );
|
||||
|
||||
iterator it13 = ms1.erase(ms1.begin(), ms1.end());
|
||||
VERIFY( ms1.size() == 0 );
|
||||
VERIFY( get_nb_bucket_elems(ms1) == ms1.size() );
|
||||
VERIFY( it13 == ms1.end() );
|
||||
VERIFY( it13 == ms1.begin() );
|
||||
}
|
||||
|
|
|
@ -25,6 +25,19 @@
|
|||
#include <unordered_set>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename _Tp>
|
||||
std::size_t
|
||||
get_nb_bucket_elems(const std::unordered_multiset<_Tp>& us)
|
||||
{
|
||||
std::size_t nb = 0;
|
||||
for (std::size_t b = 0; b != us.bucket_count(); ++b)
|
||||
nb += us.bucket_size(b);
|
||||
return nb;
|
||||
}
|
||||
}
|
||||
|
||||
void test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
@ -38,8 +51,9 @@ void test01()
|
|||
"magenta", "yellow", "orange", "pink", "gray" };
|
||||
|
||||
s.insert(A+0, A+N);
|
||||
VERIFY(s.size() == static_cast<unsigned int>(N));
|
||||
VERIFY(std::distance(s.begin(), s.end()) == N);
|
||||
VERIFY( s.size() == static_cast<unsigned int>(N) );
|
||||
VERIFY( std::distance(s.begin(), s.end()) == N );
|
||||
VERIFY( get_nb_bucket_elems(s) == N );
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
std::string str = A[i];
|
||||
|
@ -62,6 +76,7 @@ void test02()
|
|||
s.insert(A+0, A+N);
|
||||
VERIFY(s.size() == static_cast<unsigned int>(N));
|
||||
VERIFY(std::distance(s.begin(), s.end()) == N);
|
||||
VERIFY( get_nb_bucket_elems(s) == N );
|
||||
|
||||
VERIFY(std::count(s.begin(), s.end(), 2) == 1);
|
||||
VERIFY(std::count(s.begin(), s.end(), 3) == 1);
|
||||
|
|
|
@ -24,6 +24,19 @@
|
|||
#include <unordered_set>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::size_t
|
||||
get_nb_bucket_elems(const std::unordered_multiset<std::string>& us)
|
||||
{
|
||||
std::size_t nb = 0;
|
||||
for (std::size_t b = 0; b != us.bucket_count(); ++b)
|
||||
nb += us.bucket_size(b);
|
||||
return nb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
@ -33,7 +46,8 @@ void test01()
|
|||
VERIFY(s.empty());
|
||||
|
||||
Set::iterator i = s.insert("abcde");
|
||||
VERIFY(s.size() == 1);
|
||||
VERIFY( s.size() == 1 );
|
||||
VERIFY( get_nb_bucket_elems(s) == 1 );
|
||||
VERIFY(std::distance(s.begin(), s.end()) == 1);
|
||||
VERIFY(i == s.begin());
|
||||
VERIFY(*i == "abcde");
|
||||
|
@ -50,6 +64,7 @@ void test02()
|
|||
s.insert("abcde");
|
||||
Set::iterator i = s.insert("abcde");
|
||||
VERIFY(s.size() == 2);
|
||||
VERIFY( get_nb_bucket_elems(s) == 2 );
|
||||
VERIFY(std::distance(s.begin(), s.end()) == 2);
|
||||
VERIFY(*i == "abcde");
|
||||
|
||||
|
|
|
@ -26,6 +26,19 @@
|
|||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_rvalref.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename _Tp>
|
||||
std::size_t
|
||||
get_nb_bucket_elems(const std::unordered_multiset<_Tp>& us)
|
||||
{
|
||||
std::size_t nb = 0;
|
||||
for (std::size_t b = 0; b != us.bucket_count(); ++b)
|
||||
nb += us.bucket_size(b);
|
||||
return nb;
|
||||
}
|
||||
}
|
||||
|
||||
void test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
@ -37,6 +50,7 @@ void test01()
|
|||
|
||||
Set::iterator i = s.insert(rvalstruct(1));
|
||||
VERIFY( s.size() == 1 );
|
||||
VERIFY( get_nb_bucket_elems(s) == 1 );
|
||||
VERIFY( std::distance(s.begin(), s.end()) == 1 );
|
||||
VERIFY( i == s.begin() );
|
||||
VERIFY( (*i).val == 1 );
|
||||
|
@ -54,6 +68,7 @@ void test02()
|
|||
s.insert(rvalstruct(2));
|
||||
Set::iterator i = s.insert(rvalstruct(2));
|
||||
VERIFY( s.size() == 2 );
|
||||
VERIFY( get_nb_bucket_elems(s) == 2 );
|
||||
VERIFY( std::distance(s.begin(), s.end()) == 2 );
|
||||
VERIFY( (*i).val == 2 );
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
#include <unordered_set>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
std::unordered_set<int> us;
|
||||
typedef typename std::unordered_set<int>::size_type size_type;
|
||||
bool rehashed = false;
|
||||
for (int i = 0; i != 100000; ++i)
|
||||
{
|
||||
size_type bkt_count = us.bucket_count();
|
||||
us.insert(i);
|
||||
if (bkt_count != us.bucket_count())
|
||||
{
|
||||
// Container has been rehashed, lets check that it won't be rehash again
|
||||
// if we remove and restore the last 2 inserted elements:
|
||||
rehashed = true;
|
||||
bkt_count = us.bucket_count();
|
||||
VERIFY( us.erase(i) == 1 );
|
||||
VERIFY( bkt_count == us.bucket_count() );
|
||||
if (i > 0)
|
||||
{
|
||||
VERIFY( us.erase(i - 1) == 1 );
|
||||
VERIFY( bkt_count == us.bucket_count() );
|
||||
|
||||
VERIFY( us.insert(i - 1).second );
|
||||
VERIFY( bkt_count == us.bucket_count() );
|
||||
}
|
||||
VERIFY( us.insert(i).second );
|
||||
VERIFY( bkt_count == us.bucket_count() );
|
||||
}
|
||||
}
|
||||
|
||||
// At lest we check a rehash once:
|
||||
VERIFY( rehashed );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
// { dg-require-normal-mode "" }
|
||||
|
||||
// Copyright (C) 2011 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 Pred the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-error "static assertion failed" "" { target *-*-* } 177 }
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct hash_without_noexcept
|
||||
{
|
||||
std::size_t operator() (int) const
|
||||
{ return 0; }
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
std::__unordered_set<int, hash_without_noexcept,
|
||||
std::equal_to<int>, std::allocator<int>,
|
||||
false> us;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// { dg-options "-std=gnu++0x" }
|
||||
// Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include <unordered_set>
|
||||
#include <testsuite_performance.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace __gnu_test;
|
||||
|
||||
time_counter time;
|
||||
resource_counter resource;
|
||||
|
||||
std::unordered_set<int> ref;
|
||||
for (int i = 0; i != 500000; ++i)
|
||||
ref.insert(i);
|
||||
|
||||
start_counters(time, resource);
|
||||
|
||||
for (unsigned i = 0; i < 500; ++i)
|
||||
std::unordered_set<int> v(ref);
|
||||
|
||||
stop_counters(time, resource);
|
||||
report_performance(__FILE__, "unordered_set<int> copy", time, resource);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue