Commit 18dbb859 by Paolo Carlini Committed by Paolo Carlini

re PR libstdc++/44480 ([C++0x] Linear performance of begin() in unordered associative containers)

2010-08-31  Paolo Carlini  <paolo.carlini@oracle.com>

	PR libstdc++/44480
	* include/bits/hashtable.h (_Hashtable<>::_M_begin_bucket_index):
	Add, caching the index of the first non-empty bucket.
	(begin, cbegin): Use it.
	(_Hashtable<>::_Hashtable(_InputIterator, _InputIterator, ...),
	_Hashtable(const _Hashtable&), _Hashtable(_Hashtable&&),
	swap(_Hashtable&), clear): Adjust.
	(_M_insert_bucket, _M_insert, erase(const_iterator),
	erase(const key_type&), _M_rehash): Update it.

	* include/bits/hashtable.h (_Hashtable<>::_M_erase): Remove.
	(erase(const_iterator)): Inline the latter.

From-SVN: r163686
parent 6208468d
2010-08-31 Paolo Carlini <paolo.carlini@oracle.com> 2010-08-31 Paolo Carlini <paolo.carlini@oracle.com>
PR libstdc++/44480
* include/bits/hashtable.h (_Hashtable<>::_M_begin_bucket_index):
Add, caching the index of the first non-empty bucket.
(begin, cbegin): Use it.
(_Hashtable<>::_Hashtable(_InputIterator, _InputIterator, ...),
_Hashtable(const _Hashtable&), _Hashtable(_Hashtable&&),
swap(_Hashtable&), clear): Adjust.
(_M_insert_bucket, _M_insert, erase(const_iterator),
erase(const key_type&), _M_rehash): Update it.
* include/bits/hashtable.h (_Hashtable<>::_M_erase): Remove.
(erase(const_iterator)): Inline the latter.
2010-08-31 Paolo Carlini <paolo.carlini@oracle.com>
* testsuite/23_containers/forward_list/operations/remove_freed.cc: * testsuite/23_containers/forward_list/operations/remove_freed.cc:
Fix test01 return type to void. Fix test01 return type to void.
* testsuite/util/exception/safety.h: Avoid -Wall -m32 warnings. * testsuite/util/exception/safety.h: Avoid -Wall -m32 warnings.
......
...@@ -175,6 +175,7 @@ namespace std ...@@ -175,6 +175,7 @@ namespace std
_Node_allocator_type _M_node_allocator; _Node_allocator_type _M_node_allocator;
_Node** _M_buckets; _Node** _M_buckets;
size_type _M_bucket_count; size_type _M_bucket_count;
size_type _M_begin_bucket_index; // First non-empty bucket.
size_type _M_element_count; size_type _M_element_count;
_RehashPolicy _M_rehash_policy; _RehashPolicy _M_rehash_policy;
...@@ -236,21 +237,11 @@ namespace std ...@@ -236,21 +237,11 @@ namespace std
// Basic container operations // Basic container operations
iterator iterator
begin() begin()
{ { return iterator(_M_buckets + _M_begin_bucket_index); }
iterator __i(_M_buckets);
if (!__i._M_cur_node)
__i._M_incr_bucket();
return __i;
}
const_iterator const_iterator
begin() const begin() const
{ { return const_iterator(_M_buckets + _M_begin_bucket_index); }
const_iterator __i(_M_buckets);
if (!__i._M_cur_node)
__i._M_incr_bucket();
return __i;
}
iterator iterator
end() end()
...@@ -262,12 +253,7 @@ namespace std ...@@ -262,12 +253,7 @@ namespace std
const_iterator const_iterator
cbegin() const cbegin() const
{ { return const_iterator(_M_buckets + _M_begin_bucket_index); }
const_iterator __i(_M_buckets);
if (!__i._M_cur_node)
__i._M_incr_bucket();
return __i;
}
const_iterator const_iterator
cend() const cend() const
...@@ -408,9 +394,6 @@ namespace std ...@@ -408,9 +394,6 @@ namespace std
iterator iterator
_M_insert(const value_type&, std::false_type); _M_insert(const value_type&, std::false_type);
void
_M_erase_node(_Node*, _Node**);
public: public:
// Insert and erase // Insert and erase
_Insert_Return_Type _Insert_Return_Type
...@@ -571,6 +554,7 @@ namespace std ...@@ -571,6 +554,7 @@ namespace std
{ {
_M_bucket_count = _M_rehash_policy._M_next_bkt(__bucket_hint); _M_bucket_count = _M_rehash_policy._M_next_bkt(__bucket_hint);
_M_buckets = _M_allocate_buckets(_M_bucket_count); _M_buckets = _M_allocate_buckets(_M_bucket_count);
_M_begin_bucket_index = _M_bucket_count;
} }
template<typename _Key, typename _Value, template<typename _Key, typename _Value,
...@@ -601,6 +585,7 @@ namespace std ...@@ -601,6 +585,7 @@ namespace std
__distance_fw(__f, __distance_fw(__f,
__l))); __l)));
_M_buckets = _M_allocate_buckets(_M_bucket_count); _M_buckets = _M_allocate_buckets(_M_bucket_count);
_M_begin_bucket_index = _M_bucket_count;
__try __try
{ {
for (; __f != __l; ++__f) for (; __f != __l; ++__f)
...@@ -627,6 +612,7 @@ namespace std ...@@ -627,6 +612,7 @@ namespace std
__detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(__ht), __detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(__ht),
_M_node_allocator(__ht._M_node_allocator), _M_node_allocator(__ht._M_node_allocator),
_M_bucket_count(__ht._M_bucket_count), _M_bucket_count(__ht._M_bucket_count),
_M_begin_bucket_index(__ht._M_begin_bucket_index),
_M_element_count(__ht._M_element_count), _M_element_count(__ht._M_element_count),
_M_rehash_policy(__ht._M_rehash_policy) _M_rehash_policy(__ht._M_rehash_policy)
{ {
...@@ -668,12 +654,14 @@ namespace std ...@@ -668,12 +654,14 @@ namespace std
_M_node_allocator(__ht._M_node_allocator), _M_node_allocator(__ht._M_node_allocator),
_M_buckets(__ht._M_buckets), _M_buckets(__ht._M_buckets),
_M_bucket_count(__ht._M_bucket_count), _M_bucket_count(__ht._M_bucket_count),
_M_begin_bucket_index(__ht._M_begin_bucket_index),
_M_element_count(__ht._M_element_count), _M_element_count(__ht._M_element_count),
_M_rehash_policy(__ht._M_rehash_policy) _M_rehash_policy(__ht._M_rehash_policy)
{ {
size_type __n_bkt = __ht._M_rehash_policy._M_next_bkt(0); size_type __n_bkt = __ht._M_rehash_policy._M_next_bkt(0);
__ht._M_buckets = __ht._M_allocate_buckets(__n_bkt); __ht._M_buckets = __ht._M_allocate_buckets(__n_bkt);
__ht._M_bucket_count = __n_bkt; __ht._M_bucket_count = __n_bkt;
__ht._M_begin_bucket_index = __ht._M_bucket_count;
__ht._M_element_count = 0; __ht._M_element_count = 0;
__ht._M_rehash_policy = _RehashPolicy(); __ht._M_rehash_policy = _RehashPolicy();
} }
...@@ -713,6 +701,7 @@ namespace std ...@@ -713,6 +701,7 @@ namespace std
std::swap(_M_rehash_policy, __x._M_rehash_policy); std::swap(_M_rehash_policy, __x._M_rehash_policy);
std::swap(_M_buckets, __x._M_buckets); std::swap(_M_buckets, __x._M_buckets);
std::swap(_M_bucket_count, __x._M_bucket_count); std::swap(_M_bucket_count, __x._M_bucket_count);
std::swap(_M_begin_bucket_index, __x._M_begin_bucket_index);
std::swap(_M_element_count, __x._M_element_count); std::swap(_M_element_count, __x._M_element_count);
} }
...@@ -915,6 +904,8 @@ namespace std ...@@ -915,6 +904,8 @@ namespace std
this->_M_store_code(__new_node, __code); this->_M_store_code(__new_node, __code);
_M_buckets[__n] = __new_node; _M_buckets[__n] = __new_node;
++_M_element_count; ++_M_element_count;
if (__n < _M_begin_bucket_index)
_M_begin_bucket_index = __n;
return iterator(__new_node, _M_buckets + __n); return iterator(__new_node, _M_buckets + __n);
} }
__catch(...) __catch(...)
...@@ -981,6 +972,8 @@ namespace std ...@@ -981,6 +972,8 @@ namespace std
{ {
__new_node->_M_next = _M_buckets[__n]; __new_node->_M_next = _M_buckets[__n];
_M_buckets[__n] = __new_node; _M_buckets[__n] = __new_node;
if (__n < _M_begin_bucket_index)
_M_begin_bucket_index = __n;
} }
this->_M_store_code(__new_node, __code); this->_M_store_code(__new_node, __code);
...@@ -988,34 +981,6 @@ namespace std ...@@ -988,34 +981,6 @@ namespace std
return iterator(__new_node, _M_buckets + __n); return iterator(__new_node, _M_buckets + __n);
} }
// For erase(iterator) and erase(const_iterator).
template<typename _Key, typename _Value,
typename _Allocator, typename _ExtractKey, typename _Equal,
typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
bool __chc, bool __cit, bool __uk>
void
_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
_M_erase_node(_Node* __p, _Node** __b)
{
_Node* __cur = *__b;
if (__cur == __p)
*__b = __cur->_M_next;
else
{
_Node* __next = __cur->_M_next;
while (__next != __p)
{
__cur = __next;
__next = __cur->_M_next;
}
__cur->_M_next = __next->_M_next;
}
_M_deallocate_node(__p);
--_M_element_count;
}
template<typename _Key, typename _Value, template<typename _Key, typename _Value,
typename _Allocator, typename _ExtractKey, typename _Equal, typename _Allocator, typename _ExtractKey, typename _Equal,
typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
...@@ -1050,7 +1015,31 @@ namespace std ...@@ -1050,7 +1015,31 @@ namespace std
{ {
iterator __result(__it._M_cur_node, __it._M_cur_bucket); iterator __result(__it._M_cur_node, __it._M_cur_bucket);
++__result; ++__result;
_M_erase_node(__it._M_cur_node, __it._M_cur_bucket);
_Node* __cur = *__it._M_cur_bucket;
if (__cur == __it._M_cur_node)
{
*__it._M_cur_bucket = __cur->_M_next;
// If _M_begin_bucket_index no longer indexes the first non-empty
// bucket - its single node is being erased - update it.
if (!_M_buckets[_M_begin_bucket_index])
_M_begin_bucket_index = __result._M_cur_bucket - _M_buckets;
}
else
{
_Node* __next = __cur->_M_next;
while (__next != __it._M_cur_node)
{
__cur = __next;
__next = __cur->_M_next;
}
__cur->_M_next = __next->_M_next;
}
_M_deallocate_node(__it._M_cur_node);
--_M_element_count;
return __result; return __result;
} }
...@@ -1104,6 +1093,20 @@ namespace std ...@@ -1104,6 +1093,20 @@ namespace std
++__result; ++__result;
} }
// If the entire bucket indexed by _M_begin_bucket_index has been
// erased look forward for the first non-empty bucket.
if (!_M_buckets[_M_begin_bucket_index])
{
if (!_M_element_count)
_M_begin_bucket_index = _M_bucket_count;
else
{
++_M_begin_bucket_index;
while (!_M_buckets[_M_begin_bucket_index])
++_M_begin_bucket_index;
}
}
return __result; return __result;
} }
...@@ -1137,6 +1140,7 @@ namespace std ...@@ -1137,6 +1140,7 @@ namespace std
{ {
_M_deallocate_nodes(_M_buckets, _M_bucket_count); _M_deallocate_nodes(_M_buckets, _M_bucket_count);
_M_element_count = 0; _M_element_count = 0;
_M_begin_bucket_index = _M_bucket_count;
} }
template<typename _Key, typename _Value, template<typename _Key, typename _Value,
...@@ -1165,6 +1169,7 @@ namespace std ...@@ -1165,6 +1169,7 @@ namespace std
_Node** __new_array = _M_allocate_buckets(__n); _Node** __new_array = _M_allocate_buckets(__n);
__try __try
{ {
_M_begin_bucket_index = __n;
for (size_type __i = 0; __i < _M_bucket_count; ++__i) for (size_type __i = 0; __i < _M_bucket_count; ++__i)
while (_Node* __p = _M_buckets[__i]) while (_Node* __p = _M_buckets[__i])
{ {
...@@ -1172,6 +1177,8 @@ namespace std ...@@ -1172,6 +1177,8 @@ namespace std
_M_buckets[__i] = __p->_M_next; _M_buckets[__i] = __p->_M_next;
__p->_M_next = __new_array[__new_index]; __p->_M_next = __new_array[__new_index];
__new_array[__new_index] = __p; __new_array[__new_index] = __p;
if (__new_index < _M_begin_bucket_index)
_M_begin_bucket_index = __new_index;
} }
_M_deallocate_buckets(_M_buckets, _M_bucket_count); _M_deallocate_buckets(_M_buckets, _M_bucket_count);
_M_bucket_count = __n; _M_bucket_count = __n;
...@@ -1187,6 +1194,7 @@ namespace std ...@@ -1187,6 +1194,7 @@ namespace std
_M_deallocate_buckets(__new_array, __n); _M_deallocate_buckets(__new_array, __n);
_M_deallocate_nodes(_M_buckets, _M_bucket_count); _M_deallocate_nodes(_M_buckets, _M_bucket_count);
_M_element_count = 0; _M_element_count = 0;
_M_begin_bucket_index = _M_bucket_count;
__throw_exception_again; __throw_exception_again;
} }
} }
......
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