Commit f99b2be1 by Paolo Carlini Committed by Paolo Carlini

hashtable (hashtable<>::m_find, [...]): Add.

2006-05-15  Paolo Carlini  <pcarlini@suse.de>

	* include/tr1/hashtable (hashtable<>::m_find, m_insert_bucket): Add.
	(hashtable<>::find, m_insert(const value_type&, std::tr1::true_type),
	map_base<>::operator[]): Use the above.
	* testsuite/performance/23_containers/insert/unordered_map_array.cc:
	New.	

	* include/tr1/hashtable (hashtable<>::find_node,
	insert(const value_type&, ...), erase_node): Rename to m_*, adjust
	callers.
	* include/tr1/hashtable: Minor cosmetic changes.

From-SVN: r113800
parent 95dd3097
2006-05-15 Paolo Carlini <pcarlini@suse.de>
* include/tr1/hashtable (hashtable<>::m_find, m_insert_bucket): Add.
(hashtable<>::find, m_insert(const value_type&, std::tr1::true_type),
map_base<>::operator[]): Use the above.
* testsuite/performance/23_containers/insert/unordered_map_array.cc:
New.
* include/tr1/hashtable (hashtable<>::find_node,
insert(const value_type&, ...), erase_node): Rename to m_*, adjust
callers.
* include/tr1/hashtable: Minor cosmetic changes.
2006-05-13 Peter Doerfler <gcc@pdoerfler.com> 2006-05-13 Peter Doerfler <gcc@pdoerfler.com>
* include/tr1/hashtable (identity<>::operator(), * include/tr1/hashtable (identity<>::operator(),
......
...@@ -680,8 +680,11 @@ namespace Internal ...@@ -680,8 +680,11 @@ namespace Internal
operator[](const K& k) operator[](const K& k)
{ {
Hashtable* h = static_cast<Hashtable*>(this); Hashtable* h = static_cast<Hashtable*>(this);
typename Hashtable::iterator it = typename Hashtable::hash_code_t code = h->m_hash_code(k);
h->insert(std::make_pair(k, mapped_type())).first; typename Hashtable::iterator it = h->m_find(k, code);
if (!it.m_cur_node)
it = h->m_insert_bucket(std::make_pair(k, mapped_type()),
it.m_cur_bucket - h->m_buckets, code);
return it->second; return it->second;
} }
}; };
...@@ -1032,6 +1035,9 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1032,6 +1035,9 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
cache_hash_code> cache_hash_code>
const_iterator; const_iterator;
template<typename K, typename Pair, typename Hashtable>
friend struct Internal::map_base;
private: private:
typedef Internal::hash_node<Value, cache_hash_code> node; typedef Internal::hash_node<Value, cache_hash_code> node;
typedef typename Allocator::template rebind<node>::other typedef typename Allocator::template rebind<node>::other
...@@ -1188,7 +1194,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1188,7 +1194,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
public: // lookup public: // lookup
iterator iterator
find(const key_type&); find(const key_type& k);
const_iterator const_iterator
find(const key_type& k) const; find(const key_type& k) const;
...@@ -1202,7 +1208,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1202,7 +1208,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
std::pair<const_iterator, const_iterator> std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const; equal_range(const key_type& k) const;
private: // Insert and erase helper functions private: // Find, insert and erase helper functions
// ??? This dispatching is a workaround for the fact that we don't // ??? This dispatching is a workaround for the fact that we don't
// have partial specialization of member templates; it would be // have partial specialization of member templates; it would be
// better to just specialize insert on unique_keys. There may be a // better to just specialize insert on unique_keys. There may be a
...@@ -1217,31 +1223,35 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1217,31 +1223,35 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
>::type >::type
Insert_Conv_Type; Insert_Conv_Type;
iterator
m_find(const key_type&, typename hashtable::hash_code_t) const;
node* node*
find_node(node* p, const key_type& k, m_find_node(node*, const key_type&,
typename hashtable::hash_code_t c) const; typename hashtable::hash_code_t) const;
iterator
m_insert_bucket(const value_type&, size_type,
typename hashtable::hash_code_t);
std::pair<iterator, bool> std::pair<iterator, bool>
insert(const value_type&, std::tr1::true_type); m_insert(const value_type&, std::tr1::true_type);
iterator iterator
insert(const value_type&, std::tr1::false_type); m_insert(const value_type&, std::tr1::false_type);
void void
erase_node(node*, node**); m_erase_node(node*, node**);
public: // Insert and erase public: // Insert and erase
Insert_Return_Type Insert_Return_Type
insert(const value_type& v) insert(const value_type& v)
{ { return m_insert(v, std::tr1::integral_constant<bool, unique_keys>()); }
return this->insert(v, std::tr1::integral_constant<bool,
unique_keys>());
}
iterator iterator
insert(iterator, const value_type& v) insert(iterator, const value_type& v)
{ return iterator(Insert_Conv_Type()(this->insert(v))); } { return iterator(Insert_Conv_Type()(this->insert(v))); }
const_iterator const_iterator
insert(const_iterator, const value_type& v) insert(const_iterator, const value_type& v)
{ return const_iterator(Insert_Conv_Type()(this->insert(v))); } { return const_iterator(Insert_Conv_Type()(this->insert(v))); }
...@@ -1531,12 +1541,24 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1531,12 +1541,24 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
bool c, bool ci, bool u> bool c, bool ci, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::
m_find(const key_type& k, typename hashtable::hash_code_t code) const
{
std::size_t n = this->bucket_index(k, code, this->bucket_count());
node* p = m_find_node(m_buckets[n], k, code);
return iterator(p, m_buckets + n);
}
template<typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool ci, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::
find(const key_type& k) find(const key_type& k)
{ {
typename hashtable::hash_code_t code = this->m_hash_code(k); typename hashtable::hash_code_t code = this->m_hash_code(k);
std::size_t n = this->bucket_index(k, code, this->bucket_count()); iterator i = m_find(k, code);
node* p = find_node(m_buckets[n], k, code); return i.m_cur_node ? i : this->end();
return p ? iterator(p, m_buckets + n) : this->end();
} }
template<typename K, typename V, template<typename K, typename V,
...@@ -1548,11 +1570,10 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1548,11 +1570,10 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
find(const key_type& k) const find(const key_type& k) const
{ {
typename hashtable::hash_code_t code = this->m_hash_code(k); typename hashtable::hash_code_t code = this->m_hash_code(k);
std::size_t n = this->bucket_index(k, code, this->bucket_count()); const_iterator i = const_iterator(m_find(k, code));
node* p = find_node(m_buckets[n], k, code); return i.m_cur_node ? i : this->end();
return p ? const_iterator(p, m_buckets + n) : this->end();
} }
template<typename K, typename V, template<typename K, typename V,
typename A, typename Ex, typename Eq, typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP, typename H1, typename H2, typename H, typename RP,
...@@ -1584,7 +1605,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1584,7 +1605,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
typename hashtable::hash_code_t code = this->m_hash_code(k); typename hashtable::hash_code_t code = this->m_hash_code(k);
std::size_t n = this->bucket_index(k, code, this->bucket_count()); std::size_t n = this->bucket_index(k, code, this->bucket_count());
node** head = m_buckets + n; node** head = m_buckets + n;
node* p = find_node(*head, k, code); node* p = m_find_node(*head, k, code);
if (p) if (p)
{ {
...@@ -1617,7 +1638,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1617,7 +1638,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
typename hashtable::hash_code_t code = this->m_hash_code(k); typename hashtable::hash_code_t code = this->m_hash_code(k);
std::size_t n = this->bucket_index(k, code, this->bucket_count()); std::size_t n = this->bucket_index(k, code, this->bucket_count());
node** head = m_buckets + n; node** head = m_buckets + n;
node* p = find_node(*head, k, code); node* p = m_find_node(*head, k, code);
if (p) if (p)
{ {
...@@ -1644,8 +1665,8 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1644,8 +1665,8 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
bool c, bool ci, bool u> bool c, bool ci, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::node* typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::node*
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::
find_node(node* p, const key_type& k, m_find_node(node* p, const key_type& k,
typename hashtable::hash_code_t code) const typename hashtable::hash_code_t code) const
{ {
for (; p; p = p->m_next) for (; p; p = p->m_next)
if (this->compare(k, code, p)) if (this->compare(k, code, p))
...@@ -1653,34 +1674,28 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1653,34 +1674,28 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
return false; return false;
} }
// Insert v if no element with its key is already present. // Insert v in bucket n (assumes no element with its key already present).
template<typename K, typename V, template<typename K, typename V,
typename A, typename Ex, typename Eq, typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP, typename H1, typename H2, typename H, typename RP,
bool c, bool ci, bool u> bool c, bool ci, bool u>
std::pair<typename hashtable<K, V, A, Ex, Eq, H1, typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator
H2, H, RP, c, ci, u>::iterator, bool>
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::
insert(const value_type& v, std::tr1::true_type) m_insert_bucket(const value_type& v, size_type n,
typename hashtable::hash_code_t code)
{ {
const key_type& k = this->m_extract(v);
typename hashtable::hash_code_t code = this->m_hash_code(k);
std::size_t n = this->bucket_index(k, code, m_bucket_count);
if (node* p = find_node(m_buckets[n], k, code))
return std::make_pair(iterator(p, m_buckets + n), false);
std::pair<bool, std::size_t> do_rehash std::pair<bool, std::size_t> do_rehash
= m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1); = m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1);
// Allocate the new node before doing the rehash so that we don't // Allocate the new node before doing the rehash so that we don't
// do a rehash if the allocation throws. // do a rehash if the allocation throws.
node* new_node = m_allocate_node(v); node* new_node = m_allocate_node(v);
try try
{ {
if (do_rehash.first) if (do_rehash.first)
{ {
const key_type& k = this->m_extract(v);
n = this->bucket_index(k, code, do_rehash.second); n = this->bucket_index(k, code, do_rehash.second);
m_rehash(do_rehash.second); m_rehash(do_rehash.second);
} }
...@@ -1689,7 +1704,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1689,7 +1704,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
this->store_code(new_node, code); this->store_code(new_node, code);
m_buckets[n] = new_node; m_buckets[n] = new_node;
++m_element_count; ++m_element_count;
return std::make_pair(iterator(new_node, m_buckets + n), true); return iterator(new_node, m_buckets + n);
} }
catch(...) catch(...)
{ {
...@@ -1697,6 +1712,25 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1697,6 +1712,25 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
__throw_exception_again; __throw_exception_again;
} }
} }
// Insert v if no element with its key is already present.
template<typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool ci, bool u>
std::pair<typename hashtable<K, V, A, Ex, Eq, H1,
H2, H, RP, c, ci, u>::iterator, bool>
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::
m_insert(const value_type& v, std::tr1::true_type)
{
const key_type& k = this->m_extract(v);
typename hashtable::hash_code_t code = this->m_hash_code(k);
size_type n = this->bucket_index(k, code, m_bucket_count);
if (node* p = m_find_node(m_buckets[n], k, code))
return std::make_pair(iterator(p, m_buckets + n), false);
return std::make_pair(m_insert_bucket(v, n, code), true);
}
// Insert v unconditionally. // Insert v unconditionally.
template<typename K, typename V, template<typename K, typename V,
...@@ -1705,19 +1739,19 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1705,19 +1739,19 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
bool c, bool ci, bool u> bool c, bool ci, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::
insert(const value_type& v, std::tr1::false_type) m_insert(const value_type& v, std::tr1::false_type)
{ {
std::pair<bool, std::size_t> do_rehash std::pair<bool, std::size_t> do_rehash
= m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1); = m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1);
if (do_rehash.first) if (do_rehash.first)
m_rehash(do_rehash.second); m_rehash(do_rehash.second);
const key_type& k = this->m_extract(v); const key_type& k = this->m_extract(v);
typename hashtable::hash_code_t code = this->m_hash_code(k); typename hashtable::hash_code_t code = this->m_hash_code(k);
std::size_t n = this->bucket_index(k, code, m_bucket_count); size_type n = this->bucket_index(k, code, m_bucket_count);
node* new_node = m_allocate_node(v); node* new_node = m_allocate_node(v);
node* prev = find_node(m_buckets[n], k, code); node* prev = m_find_node(m_buckets[n], k, code);
if (prev) if (prev)
{ {
new_node->m_next = prev->m_next; new_node->m_next = prev->m_next;
...@@ -1741,7 +1775,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1741,7 +1775,7 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
bool c, bool ci, bool u> bool c, bool ci, bool u>
void void
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::
erase_node(node* p, node** b) m_erase_node(node* p, node** b)
{ {
node* cur = *b; node* cur = *b;
if (cur == p) if (cur == p)
...@@ -1786,25 +1820,25 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1) ...@@ -1786,25 +1820,25 @@ _GLIBCXX_BEGIN_NAMESPACE(tr1)
bool c, bool ci, bool u> bool c, bool ci, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::iterator
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::
erase(iterator i) erase(iterator it)
{ {
iterator result = i; iterator result = it;
++result; ++result;
erase_node(i.m_cur_node, i.m_cur_bucket); m_erase_node(it.m_cur_node, it.m_cur_bucket);
return result; return result;
} }
template<typename K, typename V, template<typename K, typename V,
typename A, typename Ex, typename Eq, typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP, typename H1, typename H2, typename H, typename RP,
bool c, bool ci, bool u> bool c, bool ci, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::const_iterator typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::const_iterator
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>:: hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, ci, u>::
erase(const_iterator i) erase(const_iterator it)
{ {
const_iterator result = i; const_iterator result = it;
++result; ++result;
erase_node(i.m_cur_node, i.m_cur_bucket); m_erase_node(it.m_cur_node, it.m_cur_bucket);
return result; return result;
} }
......
// Copyright (C) 2006 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 2, 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 COPYING. If not, write to the Free
// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
// USA.
// As a special exception, you may use this file as part of a free software
// library without restriction. Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License. This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
#include <tr1/unordered_map>
#include <testsuite_performance.h>
typedef std::tr1::unordered_map<int, int> map_type;
typedef std::tr1::unordered_map<int, map_type> matrix_type;
int main()
{
using namespace __gnu_test;
time_counter time;
resource_counter resource;
const int sz = 1000;
matrix_type matrix;
start_counters(time, resource);
for (int iter = 0; iter < 50; ++iter)
{
for (int i = 0; i < sz; ++i)
{
for (int j = 0; j < sz; ++j)
{
map_type& row = matrix[i / 4];
++row[j / 4];
}
}
}
stop_counters(time, resource);
report_performance(__FILE__, "", time, resource);
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