Commit a188284c by François Dumont

re PR libstdc++/51608 ([C++11] Unordered containers end(size_type) isn't constant time)

2011-12-29  François Dumont <fdumont@gcc.gnu.org>

	PR libstdc++/51608
	* include/bits/hashtable_policy.h (_Equal_helper<>): New, change the
	way the _Equal functor is used depending on whether hash code is
	cached or not.
	(_Ebo_helper<>): New helper type to introduce EBO when possible.
	(_Hash_code_base): Use _Ebo_helper to limit memory footprint. Move
	_Equal functor management...
	(_Hashtable_base): ...here, new, use _Equal_helper.
	(_Local_iterator_base<>, _Locale_iterator<>, _Locale_const_iterator<>):
	New, use _Hash_code_base, implementation of...
	* include/bits/hashtable.h (_Hashtable<>::local_iterator,
	_Hashtable<>::const_local_iterator): ...those. Add static assertions
	checking that some functors are empty depending on whether hash code
	is cache or not.
	(_Hashtable<>::_M_bucket_index): New overloads using current bucket
	count, use through out the _Hastable<> implementation.
	* include/bits/unordered_set.h (__unordered_set<>,
	__unordered_multiset<>): Cache hash code iff hash functor is not
	empty and not final.
	* include/bits/unordered_map.h (__unordered_map<>,
	__unordered_multimap<>): Likewise.
	* include/debug/unordered_map
	(unordered_map<>::_S_to_local, unordered_multimap<>::_S_to_local):
	Adapt to match new local iterator implementation.
	* include/debug/unordered_set (unordered_set<>::_S_to_local,
	unordered_multiset<>::_S_to_local): Likewise.
	* include/profile/unordered_map (unordered_map<>::_M_profile_destruct,
	unordered_multimap<>::_M_profile_destruct): Enhance thanks to usage of
	local iterators.
	* include/profile/unordered_set (unordered_set<>::_M_profile_destruct,
	unordered_multiset<>::_M_profile_destruct): Likewise.
	* testsuite_files/23_containers/unordered_set/instantiation_neg.cc:
	Fix error line.
	* testsuite_files/23_containers/unordered_set/final_hash.cc: New.
	* testsuite_files/23_containers/unordered_multiset/final_hash.cc: New.
	* testsuite_files/23_containers/unordered_map/final_hash.cc: New.
	* testsuite_files/23_containers/unordered_multimap/final_hash.cc: New.

From-SVN: r182727
parent 497081e8
2011-12-29 François Dumont <fdumont@gcc.gnu.org>
PR libstdc++/51608
* include/bits/hashtable_policy.h (_Equal_helper<>): New, change the
way the _Equal functor is used depending on whether hash code is
cached or not.
(_Ebo_helper<>): New helper type to introduce EBO when possible.
(_Hash_code_base): Use _Ebo_helper to limit memory footprint. Move
_Equal functor management...
(_Hashtable_base): ...here, new, use _Equal_helper.
(_Local_iterator_base<>, _Locale_iterator<>, _Locale_const_iterator<>):
New, use _Hash_code_base, implementation of...
* include/bits/hashtable.h (_Hashtable<>::local_iterator,
_Hashtable<>::const_local_iterator): ...those. Add static assertions
checking that some functors are empty depending on whether hash code
is cache or not.
(_Hashtable<>::_M_bucket_index): New overloads using current bucket
count, use through out the _Hastable<> implementation.
* include/bits/unordered_set.h (__unordered_set<>,
__unordered_multiset<>): Cache hash code iff hash functor is not
empty and not final.
* include/bits/unordered_map.h (__unordered_map<>,
__unordered_multimap<>): Likewise.
* include/debug/unordered_map
(unordered_map<>::_S_to_local, unordered_multimap<>::_S_to_local):
Adapt to match new local iterator implementation.
* include/debug/unordered_set (unordered_set<>::_S_to_local,
unordered_multiset<>::_S_to_local): Likewise.
* include/profile/unordered_map (unordered_map<>::_M_profile_destruct,
unordered_multimap<>::_M_profile_destruct): Enhance thanks to usage of
local iterators.
* include/profile/unordered_set (unordered_set<>::_M_profile_destruct,
unordered_multiset<>::_M_profile_destruct): Likewise.
* testsuite_files/23_containers/unordered_set/instantiation_neg.cc:
Fix error line.
* testsuite_files/23_containers/unordered_set/final_hash.cc: New.
* testsuite_files/23_containers/unordered_multiset/final_hash.cc: New.
* testsuite_files/23_containers/unordered_map/final_hash.cc: New.
* testsuite_files/23_containers/unordered_multimap/final_hash.cc: New.
2011-12-29 Jonathan Wakely <jwakely.gcc@gmail.com> 2011-12-29 Jonathan Wakely <jwakely.gcc@gmail.com>
PR libstdc++/51701 PR libstdc++/51701
......
...@@ -41,7 +41,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER ...@@ -41,7 +41,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
class _Pred = std::equal_to<_Key>, class _Pred = std::equal_to<_Key>,
class _Alloc = std::allocator<std::pair<const _Key, _Tp> >, class _Alloc = std::allocator<std::pair<const _Key, _Tp> >,
bool __cache_hash_code = bool __cache_hash_code =
__not_<__and_<is_integral<_Key>, __not_<__and_<is_integral<_Key>, is_empty<_Hash>,
integral_constant<bool, !__is_final(_Hash)>,
__detail::__is_noexcept_hash<_Key, _Hash>>>::value> __detail::__is_noexcept_hash<_Key, _Hash>>>::value>
class __unordered_map class __unordered_map
: public _Hashtable<_Key, std::pair<const _Key, _Tp>, _Alloc, : public _Hashtable<_Key, std::pair<const _Key, _Tp>, _Alloc,
...@@ -112,7 +113,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER ...@@ -112,7 +113,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
class _Pred = std::equal_to<_Key>, class _Pred = std::equal_to<_Key>,
class _Alloc = std::allocator<std::pair<const _Key, _Tp> >, class _Alloc = std::allocator<std::pair<const _Key, _Tp> >,
bool __cache_hash_code = bool __cache_hash_code =
__not_<__and_<is_integral<_Key>, __not_<__and_<is_integral<_Key>, is_empty<_Hash>,
integral_constant<bool, !__is_final(_Hash)>,
__detail::__is_noexcept_hash<_Key, _Hash>>>::value> __detail::__is_noexcept_hash<_Key, _Hash>>>::value>
class __unordered_multimap class __unordered_multimap
: public _Hashtable<_Key, std::pair<const _Key, _Tp>, : public _Hashtable<_Key, std::pair<const _Key, _Tp>,
......
...@@ -41,7 +41,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER ...@@ -41,7 +41,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
class _Pred = std::equal_to<_Value>, class _Pred = std::equal_to<_Value>,
class _Alloc = std::allocator<_Value>, class _Alloc = std::allocator<_Value>,
bool __cache_hash_code = bool __cache_hash_code =
__not_<__and_<is_integral<_Value>, __not_<__and_<is_integral<_Value>, is_empty<_Hash>,
integral_constant<bool, !__is_final(_Hash)>,
__detail::__is_noexcept_hash<_Value, _Hash>>>::value> __detail::__is_noexcept_hash<_Value, _Hash>>>::value>
class __unordered_set class __unordered_set
: public _Hashtable<_Value, _Value, _Alloc, : public _Hashtable<_Value, _Value, _Alloc,
...@@ -124,7 +125,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER ...@@ -124,7 +125,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
class _Pred = std::equal_to<_Value>, class _Pred = std::equal_to<_Value>,
class _Alloc = std::allocator<_Value>, class _Alloc = std::allocator<_Value>,
bool __cache_hash_code = bool __cache_hash_code =
__not_<__and_<is_integral<_Value>, __not_<__and_<is_integral<_Value>, is_empty<_Hash>,
integral_constant<bool, !__is_final(_Hash)>,
__detail::__is_noexcept_hash<_Value, _Hash>>>::value> __detail::__is_noexcept_hash<_Value, _Hash>>>::value>
class __unordered_multiset class __unordered_multiset
: public _Hashtable<_Value, _Value, _Alloc, : public _Hashtable<_Value, _Value, _Alloc,
......
...@@ -418,11 +418,19 @@ namespace __debug ...@@ -418,11 +418,19 @@ namespace __debug
static _Base_local_iterator static _Base_local_iterator
_S_to_local(_Base_iterator __it) _S_to_local(_Base_iterator __it)
{ return _Base_local_iterator(__it._M_cur); } {
// The returned local iterator will not be incremented so we don't
// need to compute __it's node bucket
return _Base_local_iterator(__it._M_cur, 0, 0);
}
static _Base_const_local_iterator static _Base_const_local_iterator
_S_to_local(_Base_const_iterator __it) _S_to_local(_Base_const_iterator __it)
{ return _Base_const_local_iterator(__it._M_cur); } {
// The returned local iterator will not be incremented so we don't
// need to compute __it's node bucket
return _Base_const_local_iterator(__it._M_cur, 0, 0);
}
}; };
template<typename _Key, typename _Tp, typename _Hash, template<typename _Key, typename _Tp, typename _Hash,
...@@ -820,11 +828,19 @@ namespace __debug ...@@ -820,11 +828,19 @@ namespace __debug
static _Base_local_iterator static _Base_local_iterator
_S_to_local(_Base_iterator __it) _S_to_local(_Base_iterator __it)
{ return _Base_local_iterator(__it._M_cur); } {
// The returned local iterator will not be incremented so we don't
// need to compute __it's node bucket
return _Base_local_iterator(__it._M_cur, 0, 0);
}
static _Base_const_local_iterator static _Base_const_local_iterator
_S_to_local(_Base_const_iterator __it) _S_to_local(_Base_const_iterator __it)
{ return _Base_const_local_iterator(__it._M_cur); } {
// The returned local iterator will not be incremented so we don't
// need to compute __it's node bucket
return _Base_const_local_iterator(__it._M_cur, 0, 0);
}
}; };
template<typename _Key, typename _Tp, typename _Hash, template<typename _Key, typename _Tp, typename _Hash,
......
...@@ -417,11 +417,19 @@ namespace __debug ...@@ -417,11 +417,19 @@ namespace __debug
static _Base_local_iterator static _Base_local_iterator
_S_to_local(_Base_iterator __it) _S_to_local(_Base_iterator __it)
{ return _Base_local_iterator(__it._M_cur); } {
// The returned local iterator will not be incremented so we don't
// need to compute __it's node bucket
return _Base_local_iterator(__it._M_cur, 0, 0);
}
static _Base_const_local_iterator static _Base_const_local_iterator
_S_to_local(_Base_const_iterator __it) _S_to_local(_Base_const_iterator __it)
{ return _Base_const_local_iterator(__it._M_cur); } {
// The returned local iterator will not be incremented so we don't
// need to compute __it's node bucket
return _Base_const_local_iterator(__it._M_cur, 0, 0);
}
}; };
template<typename _Value, typename _Hash, typename _Pred, typename _Alloc> template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
...@@ -805,11 +813,19 @@ namespace __debug ...@@ -805,11 +813,19 @@ namespace __debug
static _Base_local_iterator static _Base_local_iterator
_S_to_local(_Base_iterator __it) _S_to_local(_Base_iterator __it)
{ return _Base_local_iterator(__it._M_cur); } {
// The returned local iterator will not be incremented so we don't
// need to compute __it's node bucket
return _Base_local_iterator(__it._M_cur, 0, 0);
}
static _Base_const_local_iterator static _Base_const_local_iterator
_S_to_local(_Base_const_iterator __it) _S_to_local(_Base_const_iterator __it)
{ return _Base_const_local_iterator(__it._M_cur); } {
// The returned local iterator will not be incremented so we don't
// need to compute __it's node bucket
return _Base_const_local_iterator(__it._M_cur, 0, 0);
}
}; };
template<typename _Value, typename _Hash, typename _Pred, typename _Alloc> template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
......
...@@ -308,9 +308,9 @@ namespace __profile ...@@ -308,9 +308,9 @@ namespace __profile
while (__it != this->end()) while (__it != this->end())
{ {
size_type __bkt = this->bucket(__it->first); size_type __bkt = this->bucket(__it->first);
for (++__it; __it != this->end() auto __lit = this->begin(__bkt);
&& this->bucket(__it->first) == __bkt; auto __lend = this->end(__bkt);
++__it) for (++__it, ++__lit; __lit != __lend; ++__it, ++__lit)
++__chain; ++__chain;
if (__chain) if (__chain)
{ {
...@@ -577,9 +577,9 @@ namespace __profile ...@@ -577,9 +577,9 @@ namespace __profile
while (__it != this->end()) while (__it != this->end())
{ {
size_type __bkt = this->bucket(__it->first); size_type __bkt = this->bucket(__it->first);
for (++__it; __it != this->end() auto __lit = this->begin(__bkt);
&& this->bucket(__it->first) == __bkt; auto __lend = this->end(__bkt);
++__it) for (++__it, ++__lit; __lit != __lend; ++__it, ++__lit)
++__chain; ++__chain;
if (__chain) if (__chain)
{ {
......
...@@ -277,10 +277,10 @@ namespace __profile ...@@ -277,10 +277,10 @@ namespace __profile
while (__it != this->end()) while (__it != this->end())
{ {
size_type __bkt = this->bucket(*__it); size_type __bkt = this->bucket(*__it);
for (++__it; __it != this->end() && this->bucket(*__it) == __bkt; auto __lit = this->begin(__bkt);
++__it) auto __lend = this->end(__bkt);
for (++__it, ++__lit; __lit != __lend; ++__it, ++__lit)
++__chain; ++__chain;
if (__chain) if (__chain)
{ {
++__chain; ++__chain;
...@@ -539,10 +539,10 @@ namespace __profile ...@@ -539,10 +539,10 @@ namespace __profile
while (__it != this->end()) while (__it != this->end())
{ {
size_type __bkt = this->bucket(*__it); size_type __bkt = this->bucket(*__it);
for (++__it; __it != this->end() && this->bucket(*__it) == __bkt; auto __lit = this->begin(__bkt);
++__it) auto __lend = this->end(__bkt);
for (++__it, ++__lit; __lit != __lend; ++__it, ++__lit)
++__chain; ++__chain;
if (__chain) if (__chain)
{ {
++__chain; ++__chain;
......
// { dg-do compile }
// { 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 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/>.
#include <string>
#include <unordered_map>
namespace
{
template<typename _Tp>
struct final_hash final
{
std::size_t operator() (const _Tp&) const noexcept
{ return 0; }
};
}
// A non-integral type:
template class std::unordered_map<std::string, int, final_hash<std::string>>;
// An integral type;
template class std::unordered_map<int, int, final_hash<int>>;
// { dg-do compile }
// { 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 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/>.
#include <string>
#include <unordered_map>
namespace
{
template<typename _Tp>
struct final_hash final
{
std::size_t operator() (const _Tp&) const noexcept
{ return 0; }
};
}
// A non-integral type:
template class std::unordered_multimap<std::string, int,
final_hash<std::string>>;
// An integral type;
template class std::unordered_multimap<int, int, final_hash<int>>;
// { dg-do compile }
// { 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 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/>.
#include <string>
#include <unordered_set>
namespace
{
template<typename _Tp>
struct final_hash final
{
std::size_t operator() (const _Tp&) const noexcept
{ return 0; }
};
}
// A non-integral type:
template class std::unordered_multiset<std::string, final_hash<std::string>>;
// An integral type;
template class std::unordered_multiset<int, final_hash<int>>;
// { dg-do compile }
// { 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 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/>.
#include <string>
#include <unordered_set>
namespace
{
template<typename _Tp>
struct final_hash final
{
std::size_t operator() (const _Tp&) const noexcept
{ return 0; }
};
}
// A non-integral type:
template class std::unordered_set<std::string, final_hash<std::string>>;
// An integral type;
template class std::unordered_set<int, final_hash<int>>;
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
// with this library; see the file COPYING3. If not see // with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>. // <http://www.gnu.org/licenses/>.
// { dg-error "static assertion failed" "" { target *-*-* } 177 } // { dg-error "static assertion failed" "" { target *-*-* } 185 }
#include <unordered_set> #include <unordered_set>
......
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