Commit 732eb076 by François Dumont

c++config (_GLIBCXX14_USE_CONSTEXPR): New.

2016-05-24  François Dumont  <fdumont@gcc.gnu.org>

	* include/bits/c++config (_GLIBCXX14_USE_CONSTEXPR): New.
	* include/bits/hashtable_policy.h
	(_Prime_rehash_policy::__has_load_factor): New. Mark rehash policy
	having load factor management.
	(_Mask_range_hashing): New.
	(__clp2): New.
	(_Power2_rehash_policy): New.
	(_Inserts<>): Remove last template parameter, _Unique_keys, so that
	partial specializations only depend on whether iterators are constant
	or not.
	* testsuite/23_containers/unordered_set/hash_policy/26132.cc: Adapt to
	test new hash policy.
	* testsuite/23_containers/unordered_set/hash_policy/load_factor.cc:
	Likewise.
	* testsuite/23_containers/unordered_set/hash_policy/rehash.cc:
	Likewise.
	* testsuite/23_containers/unordered_set/insert/hash_policy.cc:
	Likewise.
	* testsuite/23_containers/unordered_set/max_load_factor/robustness.cc:
	Likewise.
	* testsuite/23_containers/unordered_set/hash_policy/power2_rehash.cc:
	New.
	* testsuite/performance/23_containers/insert/54075.cc: Add benchmark
	using the new hash policy.
	* testsuite/performance/23_containers/insert_erase/41975.cc: Likewise.

From-SVN: r236669
parent f65e97fd
2016-05-24 François Dumont <fdumont@gcc.gnu.org>
* include/bits/c++config (_GLIBCXX14_USE_CONSTEXPR): New.
* include/bits/hashtable_policy.h
(_Prime_rehash_policy::__has_load_factor): New. Mark rehash policy
having load factor management.
(_Mask_range_hashing): New.
(__clp2): New.
(_Power2_rehash_policy): New.
(_Inserts<>): Remove last template parameter, _Unique_keys, so that
partial specializations only depend on whether iterators are constant
or not.
* testsuite/23_containers/unordered_set/hash_policy/26132.cc: Adapt to
test new hash policy.
* testsuite/23_containers/unordered_set/hash_policy/load_factor.cc:
Likewise.
* testsuite/23_containers/unordered_set/hash_policy/rehash.cc:
Likewise.
* testsuite/23_containers/unordered_set/insert/hash_policy.cc:
Likewise.
* testsuite/23_containers/unordered_set/max_load_factor/robustness.cc:
Likewise.
* testsuite/23_containers/unordered_set/hash_policy/power2_rehash.cc:
New.
* testsuite/performance/23_containers/insert/54075.cc: Add benchmark
using the new hash policy.
* testsuite/performance/23_containers/insert_erase/41975.cc: Likewise.
2016-05-24 Jonathan Wakely <jwakely@redhat.com>
* include/bits/stl_queue.h (priority_queue::value_compare): Define.
......
......@@ -106,8 +106,10 @@
#ifndef _GLIBCXX14_CONSTEXPR
# if __cplusplus >= 201402L
# define _GLIBCXX14_CONSTEXPR constexpr
# define _GLIBCXX14_USE_CONSTEXPR constexpr
# else
# define _GLIBCXX14_CONSTEXPR
# define _GLIBCXX14_USE_CONSTEXPR const
# endif
#endif
......
......@@ -23,35 +23,48 @@
#include <testsuite_hooks.h>
// libstdc++/26132
void test01()
{
bool test __attribute__((unused)) = true;
for (float lf = 1.0; lf < 101.0; lf *= 10.0)
for (int size = 1; size <= 6561; size *= 3)
{
std::unordered_set<int> us1;
typedef std::unordered_set<int>::size_type size_type;
us1.max_load_factor(10.0);
for (int i = 0; i < size; ++i)
us1.insert(i);
us1.max_load_factor(lf);
for (int i = 1; i <= 6561; i *= 81)
{
const size_type n = size * 81 / i;
us1.rehash(n);
VERIFY( us1.bucket_count() > us1.size() / us1.max_load_factor() );
VERIFY( us1.bucket_count() >= n );
}
}
}
template<typename _USet>
void test()
{
bool test __attribute__((unused)) = true;
for (float lf = 1.0; lf < 101.0; lf *= 10.0)
for (int size = 1; size <= 6561; size *= 3)
{
_USet us1;
typedef typename _USet::size_type size_type;
us1.max_load_factor(10.0);
for (int i = 0; i < size; ++i)
us1.insert(i);
us1.max_load_factor(lf);
for (int i = 1; i <= 6561; i *= 81)
{
const size_type n = size * 81 / i;
us1.rehash(n);
VERIFY( us1.bucket_count() > us1.size() / us1.max_load_factor() );
VERIFY( us1.bucket_count() >= n );
}
}
}
template<typename _Value>
using unordered_set_power2_rehash =
std::_Hashtable<_Value, _Value, std::allocator<_Value>,
std::__detail::_Identity,
std::equal_to<_Value>,
std::hash<_Value>,
std::__detail::_Mask_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Power2_rehash_policy,
std::__detail::_Hashtable_traits<false, true, true>>;
int main()
{
test01();
test<std::unordered_set<int>>();
test<unordered_set_power2_rehash<int>>();
return 0;
}
......@@ -18,41 +18,55 @@
// { dg-options "-std=gnu++11" }
#include <unordered_set>
#include <testsuite_hooks.h>
void test01()
{
bool test __attribute__((unused)) = true;
template<typename _USet>
void test()
{
std::unordered_set<int> us;
for (int i = 0; i != 100000; ++i)
bool test __attribute__((unused)) = true;
{
us.insert(i);
VERIFY( us.load_factor() <= us.max_load_factor() );
_USet us;
for (int i = 0; i != 100000; ++i)
{
us.insert(i);
VERIFY( us.load_factor() <= us.max_load_factor() );
}
}
}
{
std::unordered_set<int> us;
us.max_load_factor(3.f);
for (int i = 0; i != 100000; ++i)
{
us.insert(i);
VERIFY( us.load_factor() <= us.max_load_factor() );
_USet us;
us.max_load_factor(3.f);
for (int i = 0; i != 100000; ++i)
{
us.insert(i);
VERIFY( us.load_factor() <= us.max_load_factor() );
}
}
}
{
std::unordered_set<int> us;
us.max_load_factor(.3f);
for (int i = 0; i != 100000; ++i)
{
us.insert(i);
VERIFY( us.load_factor() <= us.max_load_factor() );
_USet us;
us.max_load_factor(.3f);
for (int i = 0; i != 100000; ++i)
{
us.insert(i);
VERIFY( us.load_factor() <= us.max_load_factor() );
}
}
}
}
template<typename _Value>
using unordered_set_power2_rehash =
std::_Hashtable<_Value, _Value, std::allocator<_Value>,
std::__detail::_Identity,
std::equal_to<_Value>,
std::hash<_Value>,
std::__detail::_Mask_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Power2_rehash_policy,
std::__detail::_Hashtable_traits<false, true, true>>;
int main()
{
test01();
test<std::unordered_set<int>>();
test<unordered_set_power2_rehash<int>>();
return 0;
}
// Copyright (C) 2016 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++11" }
#include <unordered_set>
#include <testsuite_hooks.h>
void test01()
{
bool test __attribute__((unused)) = true;
std::__detail::_Power2_rehash_policy policy;
VERIFY( policy._M_next_bkt(1) == 2 );
VERIFY( policy._M_next_bkt(2) == 4 );
VERIFY( policy._M_next_bkt(3) == 4 );
VERIFY( policy._M_next_bkt(5) == 8 );
VERIFY( policy._M_next_bkt(33) == 64 );
VERIFY( policy._M_next_bkt((std::size_t(1) << (sizeof(std::size_t) * 8 - 2)) + 1)
== (std::size_t(1) << (sizeof(std::size_t) * 8 - 1)) );
}
int main()
{
test01();
return 0;
}
......@@ -18,13 +18,15 @@
// { dg-options "-std=gnu++11" }
#include <unordered_set>
#include <testsuite_hooks.h>
void test01()
template<typename _USet>
void test()
{
bool test __attribute__((unused)) = true;
std::unordered_set<int> us;
typedef typename std::unordered_set<int>::size_type size_type;
_USet us;
typedef typename _USet::size_type size_type;
bool rehashed = false;
for (int i = 0; i != 100000; ++i)
{
......@@ -55,8 +57,20 @@ void test01()
VERIFY( rehashed );
}
template<typename _Value>
using unordered_set_power2_rehash =
std::_Hashtable<_Value, _Value, std::allocator<_Value>,
std::__detail::_Identity,
std::equal_to<_Value>,
std::hash<_Value>,
std::__detail::_Mask_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Power2_rehash_policy,
std::__detail::_Hashtable_traits<false, true, true>>;
int main()
{
test01();
test<std::unordered_set<int>>();
test<unordered_set_power2_rehash<int>>();
return 0;
}
......@@ -20,94 +20,122 @@
#include <unordered_set>
#include <vector>
#include <limits>
#include <ext/throw_allocator.h>
#include <testsuite_hooks.h>
void test01()
{
bool test __attribute__((unused)) = true;
template<template<typename _Value, typename _Hash,
typename _Pred, typename _Alloc>
typename _USet>
void test01()
{
bool test __attribute__((unused)) = true;
typedef std::numeric_limits<std::size_t> nl_size_t;
std::unordered_set<int, std::hash<int>, std::equal_to<int>,
__gnu_cxx::throw_allocator_limit<int> > us;
const int nb = 100;
int scheduled_throw_counter = 0;
std::size_t thrown_exceptions = 0;
for (int i = 0; i != nb; ++i)
{
if ((float)(us.size() + 1)
/ (float)us.bucket_count() >= us.max_load_factor())
{
// We are going to need a rehash, lets introduce allocation issues:
__gnu_cxx::limit_condition::set_limit(scheduled_throw_counter++);
}
try
{
VERIFY(us.insert(i).second);
scheduled_throw_counter = 0;
}
catch (const __gnu_cxx::forced_error&)
{
++thrown_exceptions;
--i;
}
VERIFY( us.load_factor() <= us.max_load_factor() );
__gnu_cxx::limit_condition::set_limit(nl_size_t::max());
}
// Make sure whatever happen we restore throw allocator limit at exit.
__gnu_cxx::limit_condition::adjustor_base adj;
VERIFY( thrown_exceptions != 0 );
// Check that all values have been inserted:
for (int i = 0; i != nb; ++i)
{
VERIFY( us.count(i) == 1 );
}
}
typedef std::numeric_limits<std::size_t> nl_size_t;
_USet<int, std::hash<int>, std::equal_to<int>,
__gnu_cxx::throw_allocator_limit<int> > us;
const int nb = 100;
int scheduled_throw_counter = 0;
std::size_t thrown_exceptions = 0;
for (int i = 0; i != nb; ++i)
{
if ((float)(us.size() + 1)
/ (float)us.bucket_count() >= us.max_load_factor())
{
// We are going to need a rehash, lets introduce allocation issues:
__gnu_cxx::limit_condition::set_limit(scheduled_throw_counter++);
}
try
{
VERIFY(us.insert(i).second);
scheduled_throw_counter = 0;
}
catch (const __gnu_cxx::forced_error&)
{
++thrown_exceptions;
--i;
}
VERIFY( us.load_factor() <= us.max_load_factor() );
__gnu_cxx::limit_condition::set_limit(nl_size_t::max());
}
void test02()
{
bool test __attribute__((unused)) = true;
VERIFY( thrown_exceptions != 0 );
// Check that all values have been inserted:
for (int i = 0; i != nb; ++i)
{
VERIFY( us.count(i) == 1 );
}
}
typedef std::numeric_limits<std::size_t> nl_size_t;
std::unordered_set<int, std::hash<int>, std::equal_to<int>,
__gnu_cxx::throw_allocator_limit<int> > us;
const int nb = 100;
int scheduled_throw_counter = 0;
std::size_t thrown_exceptions = 0;
for (int i = 0; i != nb; ++i)
{
if ((float)(us.size() + 2)
/ (float)us.bucket_count() >= us.max_load_factor())
{
// We are going to need a rehash, lets introduce allocation issues:
__gnu_cxx::limit_condition::set_limit(scheduled_throw_counter++);
}
try
{
std::vector<int> v = { i, i };
// Check the insert range robustness
us.insert(v.begin(), v.end());
scheduled_throw_counter = 0;
}
catch (const __gnu_cxx::forced_error&)
{
++thrown_exceptions;
--i;
}
VERIFY( us.load_factor() <= us.max_load_factor() );
__gnu_cxx::limit_condition::set_limit(nl_size_t::max());
}
template<template<typename _Value, typename _Hash,
typename _Pred, typename _Alloc>
typename _USet>
void test02()
{
bool test __attribute__((unused)) = true;
VERIFY( thrown_exceptions != 0 );
// Check that all values have been inserted:
for (int i = 0; i != nb; ++i)
{
VERIFY( us.count(i) == 1 );
}
}
// Make sure whatever happen we restore throw allocator limit at exit.
__gnu_cxx::limit_condition::adjustor_base adj;
typedef std::numeric_limits<std::size_t> nl_size_t;
_USet<int, std::hash<int>, std::equal_to<int>,
__gnu_cxx::throw_allocator_limit<int> > us;
const int nb = 100;
int scheduled_throw_counter = 0;
std::size_t thrown_exceptions = 0;
for (int i = 0; i != nb; ++i)
{
if ((float)(us.size() + 2)
/ (float)us.bucket_count() >= us.max_load_factor())
{
// We are going to need a rehash, lets introduce allocation issues:
__gnu_cxx::limit_condition::set_limit(scheduled_throw_counter++);
}
try
{
std::vector<int> v = { i, i };
// Check the insert range robustness
us.insert(v.begin(), v.end());
scheduled_throw_counter = 0;
}
catch (const __gnu_cxx::forced_error&)
{
++thrown_exceptions;
--i;
}
VERIFY( us.load_factor() <= us.max_load_factor() );
__gnu_cxx::limit_condition::set_limit(nl_size_t::max());
}
VERIFY( thrown_exceptions != 0 );
// Check that all values have been inserted:
for (int i = 0; i != nb; ++i)
{
VERIFY( us.count(i) == 1 );
}
}
template<typename _Value, typename _Hash,
typename _Pred, typename _Alloc>
using unordered_set_power2_rehash =
std::_Hashtable<_Value, _Value, _Alloc,
std::__detail::_Identity,
_Pred,
_Hash,
std::__detail::_Mask_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Power2_rehash_policy,
std::__detail::_Hashtable_traits<false, true, true>>;
int main()
{
test01();
test02();
test01<std::unordered_set>();
test01<unordered_set_power2_rehash>();
test02<std::unordered_set>();
test02<unordered_set_power2_rehash>();
return 0;
}
......@@ -22,62 +22,78 @@
#include <ext/throw_allocator.h>
#include <testsuite_hooks.h>
void test01()
{
bool test __attribute__((unused)) = true;
template<template<typename _Value, typename _Hash,
typename _Pred, typename _Alloc>
typename _USet>
void test()
{
bool test __attribute__((unused)) = true;
typedef std::numeric_limits<std::size_t> nl_size_t;
std::unordered_set<int, std::hash<int>, std::equal_to<int>,
__gnu_cxx::throw_allocator_limit<int> > us;
int val = 0;
for (; val != 100; ++val)
{
VERIFY( us.insert(val).second );
VERIFY( us.load_factor() <= us.max_load_factor() );
}
typedef std::numeric_limits<std::size_t> nl_size_t;
_USet<int, std::hash<int>, std::equal_to<int>,
__gnu_cxx::throw_allocator_limit<int> > us;
int val = 0;
for (; val != 100; ++val)
{
VERIFY( us.insert(val).second );
VERIFY( us.load_factor() <= us.max_load_factor() );
}
float cur_max_load_factor = us.max_load_factor();
int counter = 0;
std::size_t thrown_exceptions = 0;
float cur_max_load_factor = us.max_load_factor();
int counter = 0;
std::size_t thrown_exceptions = 0;
// Reduce max load factor.
us.max_load_factor(us.max_load_factor() / 2);
// Reduce max load factor.
us.max_load_factor(us.max_load_factor() / 4);
// At this point load factor is higher than max_load_factor because we can't
// rehash in max_load_factor call.
VERIFY( us.load_factor() > us.max_load_factor() );
// At this point load factor is higher than max_load_factor because we can't
// rehash in max_load_factor call.
VERIFY( us.load_factor() > us.max_load_factor() );
while (true)
{
__gnu_cxx::limit_condition::set_limit(counter++);
bool do_break = false;
try
{
size_t nbkts = us.bucket_count();
// Check that unordered_set will still be correctly resized when
// needed.
VERIFY( us.insert(val++).second );
while (true)
{
__gnu_cxx::limit_condition::limit_adjustor adjustor(counter++);
bool do_break = false;
try
{
size_t nbkts = us.bucket_count();
// Check that unordered_set will still be correctly resized when
// needed.
VERIFY( us.insert(val++).second );
VERIFY( us.bucket_count() != nbkts );
VERIFY( us.load_factor() <= us.max_load_factor() );
do_break = true;
}
catch (const __gnu_cxx::forced_error&)
{
// max load factor doesn't change.
VERIFY( us.max_load_factor() == .25f );
++thrown_exceptions;
}
VERIFY( us.bucket_count() != nbkts );
VERIFY( us.load_factor() <= us.max_load_factor() );
do_break = true;
}
catch (const __gnu_cxx::forced_error&)
{
// max load factor doesn't change.
VERIFY( us.max_load_factor() == .5f );
++thrown_exceptions;
}
if (do_break)
break;
}
if (do_break)
break;
}
VERIFY( thrown_exceptions > 0 );
}
VERIFY( thrown_exceptions > 0 );
}
template<typename _Value, typename _Hash,
typename _Pred, typename _Alloc>
using unordered_set_power2_rehash =
std::_Hashtable<_Value, _Value, _Alloc,
std::__detail::_Identity,
_Pred,
_Hash,
std::__detail::_Mask_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Power2_rehash_policy,
std::__detail::_Hashtable_traits<false, true, true>>;
int main()
{
test01();
test<std::unordered_set>();
test<unordered_set_power2_rehash>();
return 0;
}
......@@ -127,7 +127,27 @@ template<bool cache>
using __umset = std::__umset_hashtable<Foo, HashFunction,
std::equal_to<Foo>,
std::allocator<Foo>,
std::__uset_traits<cache>>;
std::__umset_traits<cache>>;
template<bool cache>
using __uset2 =
std::_Hashtable<Foo, Foo, std::allocator<Foo>,
std::__detail::_Identity,
std::equal_to<Foo>, HashFunction,
std::__detail::_Mask_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Power2_rehash_policy,
std::__uset_traits<cache>>;
template<bool cache>
using __umset2 =
std::_Hashtable<Foo, Foo, std::allocator<Foo>,
std::__detail::_Identity,
std::equal_to<Foo>, HashFunction,
std::__detail::_Mask_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Power2_rehash_policy,
std::__umset_traits<cache>>;
int main()
{
......@@ -181,6 +201,19 @@ int main()
stop_counters(time, resource);
report_performance(__FILE__, "std benches", time, resource);
start_counters(time, resource);
bench<__uset2<false>>(
"std::unordered_set2 without hash code cached ", foos);
bench<__uset2<true>>(
"std::unordered_set2 with hash code cached ", foos);
bench<__umset2<false>>(
"std::unordered_multiset2 without hash code cached ", foos);
bench<__umset2<true>>(
"std::unordered_multiset2 with hash code cached ", foos);
stop_counters(time, resource);
report_performance(__FILE__, "std2 benches", time, resource);
bench<std::unordered_set<Foo, HashFunction>>(
"std::unordered_set default cache ", foos);
bench<std::unordered_multiset<Foo, HashFunction>>(
......
......@@ -177,6 +177,16 @@ template<bool cache>
cache>;
template<bool cache>
using __uset2 =
std::_Hashtable<int, int, std::allocator<int>,
std::__detail::_Identity,
std::equal_to<int>, std::hash<int>,
std::__detail::_Mask_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Power2_rehash_policy,
std::__uset_traits<cache>>;
template<bool cache>
using __str_uset =
std::__uset_hashtable<std::string, std::hash<std::string>,
std::equal_to<std::string>,
......@@ -190,6 +200,16 @@ template<bool cache>
std::allocator<std::string>,
cache>;
template<bool cache>
using __str_uset2 =
std::_Hashtable<std::string, std::string, std::allocator<std::string>,
std::__detail::_Identity,
std::equal_to<std::string>, std::hash<std::string>,
std::__detail::_Mask_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Power2_rehash_policy,
std::__uset_traits<cache>>;
int main()
{
bench<__tr1_uset<false>>(
......@@ -202,6 +222,10 @@ int main()
"std::unordered_set<int> with hash code cached");
bench<std::unordered_set<int>>(
"std::unordered_set<int> default cache");
bench<__uset2<false>>(
"std::unordered_set2<int> without hash code cached");
bench<__uset2<true>>(
"std::unordered_set2<int> with hash code cached");
bench_str<__tr1_str_uset<false>>(
"std::tr1::unordered_set<string> without hash code cached");
bench_str<__tr1_str_uset<true>>(
......@@ -210,7 +234,11 @@ int main()
"std::unordered_set<string> without hash code cached");
bench_str<__str_uset<true>>(
"std::unordered_set<string> with hash code cached");
bench_str<std::unordered_set<std::string>>(
bench_str<std::unordered_set<std::string>>(
"std::unordered_set<string> default cache");
bench_str<__str_uset2<false>>(
"std::unordered_set2<string> without hash code cached");
bench_str<__str_uset2<true>>(
"std::unordered_set2<string> with hash code cached");
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment