Commit 7ffd2d94 by Paolo Carlini Committed by Paolo Carlini

hashtable: Trivial formatting fixes.

2005-06-15  Paolo Carlini  <pcarlini@suse.de>

	* include/tr1/hashtable: Trivial formatting fixes.
	* include/tr1/unordered_map: Likewise.
	* include/tr1/unordered_set: Likewise.

From-SVN: r100988
parent 63a4ef6f
2005-06-15 Paolo Carlini <pcarlini@suse.de>
* include/tr1/hashtable: Trivial formatting fixes.
* include/tr1/unordered_map: Likewise.
* include/tr1/unordered_set: Likewise.
2005-06-14 Tom Tromey <tromey@redhat.com> 2005-06-14 Tom Tromey <tromey@redhat.com>
PR libgcj/19877: PR libgcj/19877:
......
...@@ -64,40 +64,39 @@ ...@@ -64,40 +64,39 @@
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// General utilities // General utilities
namespace Internal { namespace Internal
template <bool Flag, typename IfTrue, typename IfFalse> struct IF;
template <typename IfTrue, typename IfFalse>
struct IF <true, IfTrue, IfFalse> { typedef IfTrue type; };
template <typename IfTrue, typename IfFalse>
struct IF <false, IfTrue, IfFalse> { typedef IfFalse type; };
// Helper function: return distance(first, last) for forward
// iterators, or 0 for input iterators.
template <class Iterator>
inline typename std::iterator_traits<Iterator>::difference_type
distance_fw (Iterator first, Iterator last, std::input_iterator_tag)
{
return 0;
}
template <class Iterator>
inline typename std::iterator_traits<Iterator>::difference_type
distance_fw (Iterator first, Iterator last, std::forward_iterator_tag)
{
return std::distance(first, last);
}
template <class Iterator>
inline typename std::iterator_traits<Iterator>::difference_type
distance_fw (Iterator first, Iterator last)
{ {
typedef typename std::iterator_traits<Iterator>::iterator_category tag; template<bool Flag, typename IfTrue, typename IfFalse>
return distance_fw(first, last, tag()); struct IF;
}
template<typename IfTrue, typename IfFalse>
struct IF<true, IfTrue, IfFalse>
{ typedef IfTrue type; };
template <typename IfTrue, typename IfFalse>
struct IF<false, IfTrue, IfFalse>
{ typedef IfFalse type; };
// Helper function: return distance(first, last) for forward
// iterators, or 0 for input iterators.
template<class Iterator>
inline typename std::iterator_traits<Iterator>::difference_type
distance_fw(Iterator first, Iterator last, std::input_iterator_tag)
{ return 0; }
template<class Iterator>
inline typename std::iterator_traits<Iterator>::difference_type
distance_fw(Iterator first, Iterator last, std::forward_iterator_tag)
{ return std::distance(first, last); }
template<class Iterator>
inline typename std::iterator_traits<Iterator>::difference_type
distance_fw(Iterator first, Iterator last)
{
typedef typename std::iterator_traits<Iterator>::iterator_category tag;
return distance_fw(first, last, tag());
}
} // namespace Internal } // namespace Internal
//---------------------------------------------------------------------- //----------------------------------------------------------------------
...@@ -109,140 +108,187 @@ distance_fw (Iterator first, Iterator last) ...@@ -109,140 +108,187 @@ distance_fw (Iterator first, Iterator last)
// nodes also store a hash code. In some cases (e.g. strings) this may // nodes also store a hash code. In some cases (e.g. strings) this may
// be a performance win. // be a performance win.
namespace Internal { namespace Internal
template <typename Value, bool cache_hash_code> struct hash_node;
template <typename Value>
struct hash_node<Value, true> {
Value m_v;
std::size_t hash_code;
hash_node* m_next;
};
template <typename Value>
struct hash_node<Value, false> {
Value m_v;
hash_node* m_next;
};
// Local iterators, used to iterate within a bucket but not between
// buckets.
template <typename Value, bool cache>
struct node_iterator_base {
node_iterator_base(hash_node<Value, cache>* p) : m_cur(p) { }
void incr() { m_cur = m_cur->m_next; }
hash_node<Value, cache>* m_cur;
};
template <typename Value, bool cache>
inline bool operator== (const node_iterator_base<Value, cache>& x,
const node_iterator_base<Value, cache>& y)
{ {
return x.m_cur == y.m_cur; template<typename Value, bool cache_hash_code>
} struct hash_node;
template <typename Value, bool cache> template<typename Value>
inline bool operator!= (const node_iterator_base<Value, cache>& x, struct hash_node<Value, true>
const node_iterator_base<Value, cache>& y) {
{ Value m_v;
return x.m_cur != y.m_cur; std::size_t hash_code;
} hash_node* m_next;
};
template <typename Value, bool is_const, bool cache>
struct node_iterator : public node_iterator_base<Value, cache> { template<typename Value>
typedef Value value_type; struct hash_node<Value, false>
typedef typename IF<is_const, const Value*, Value*>::type pointer; {
typedef typename IF<is_const, const Value&, Value&>::type reference; Value m_v;
typedef std::ptrdiff_t difference_type; hash_node* m_next;
typedef std::forward_iterator_tag iterator_category; };
explicit node_iterator (hash_node<Value, cache>* p = 0) // Local iterators, used to iterate within a bucket but not between
: node_iterator_base<Value, cache>(p) { } // buckets.
node_iterator (const node_iterator<Value, true, cache>& x)
: node_iterator_base<Value, cache>(x.m_cur) { } template<typename Value, bool cache>
struct node_iterator_base
reference operator*() const { return this->m_cur->m_v; } {
pointer operator->() const { return &this->m_cur->m_v; } node_iterator_base(hash_node<Value, cache>* p)
: m_cur(p) { }
node_iterator& operator++() { this->incr(); return *this; }
node_iterator operator++(int) void
{ node_iterator tmp(*this); this->incr(); return tmp; } incr()
}; { m_cur = m_cur->m_next; }
template <typename Value, bool cache> hash_node<Value, cache>* m_cur;
struct hashtable_iterator_base { };
hashtable_iterator_base(hash_node<Value, cache>* node,
hash_node<Value, cache>** bucket) template<typename Value, bool cache>
: m_cur_node (node), m_cur_bucket (bucket) inline bool
{ } operator==(const node_iterator_base<Value, cache>& x,
const node_iterator_base<Value, cache>& y)
{ return x.m_cur == y.m_cur; }
template<typename Value, bool cache>
inline bool
operator!=(const node_iterator_base<Value, cache>& x,
const node_iterator_base<Value, cache>& y)
{ return x.m_cur != y.m_cur; }
template<typename Value, bool is_const, bool cache>
struct node_iterator
: public node_iterator_base<Value, cache>
{
typedef Value value_type;
typedef typename IF<is_const, const Value*, Value*>::type pointer;
typedef typename IF<is_const, const Value&, Value&>::type reference;
typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
explicit
node_iterator(hash_node<Value, cache>* p = 0)
: node_iterator_base<Value, cache>(p) { }
node_iterator(const node_iterator<Value, true, cache>& x)
: node_iterator_base<Value, cache>(x.m_cur) { }
reference
operator*() const
{ return this->m_cur->m_v; }
pointer
operator->() const
{ return &this->m_cur->m_v; }
node_iterator&
operator++()
{
this->incr();
return *this;
}
node_iterator
operator++(int)
{
node_iterator tmp(*this);
this->incr();
return tmp;
}
};
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
incr()
{
m_cur_node = m_cur_node->m_next;
if (!m_cur_node)
m_incr_bucket();
}
void incr() { void
m_cur_node = m_cur_node->m_next;
if (!m_cur_node)
m_incr_bucket(); 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 hash_node<Value, cache>* m_cur_node;
// table. Larger and more expensive than local iterators. hash_node<Value, cache>** m_cur_bucket;
};
template <typename Value, bool cache>
void hashtable_iterator_base<Value, cache>::m_incr_bucket() // Global iterators, used for arbitrary iteration within a hash
{ // table. Larger and more expensive than local iterators.
++m_cur_bucket; template<typename Value, bool cache>
void
// This loop requires the bucket array to have a non-null sentinel hashtable_iterator_base<Value, cache>::
while (!*m_cur_bucket) m_incr_bucket()
++m_cur_bucket; {
m_cur_node = *m_cur_bucket; ++m_cur_bucket;
}
// This loop requires the bucket array to have a non-null sentinel.
template <typename Value, bool cache> while (!*m_cur_bucket)
inline bool operator== (const hashtable_iterator_base<Value, cache>& x, ++m_cur_bucket;
const hashtable_iterator_base<Value, cache>& y) m_cur_node = *m_cur_bucket;
{ }
return x.m_cur_node == y.m_cur_node;
}
template <typename Value, bool cache> template<typename Value, bool cache>
inline bool operator!= (const hashtable_iterator_base<Value, cache>& x, inline bool
const hashtable_iterator_base<Value, cache>& y) operator==(const hashtable_iterator_base<Value, cache>& x,
{ const hashtable_iterator_base<Value, cache>& y)
return x.m_cur_node != y.m_cur_node; { 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 is_const, bool cache>
struct hashtable_iterator
: public hashtable_iterator_base<Value, cache>
{
typedef Value value_type;
typedef typename IF<is_const, const Value*, Value*>::type pointer;
typedef typename IF<is_const, const Value&, Value&>::type reference;
typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
hashtable_iterator(hash_node<Value, cache>* p,
hash_node<Value, cache>** b)
: hashtable_iterator_base<Value, cache>(p, b) { }
hashtable_iterator(hash_node<Value, cache>** b)
: hashtable_iterator_base<Value, cache>(*b, b) { }
hashtable_iterator(const hashtable_iterator<Value, true, cache>& x)
: hashtable_iterator_base<Value, cache>(x.m_cur_node, x.m_cur_bucket) { }
template <typename Value, bool is_const, bool cache> reference
struct hashtable_iterator : public hashtable_iterator_base<Value, cache> operator*() const
{ { return this->m_cur_node->m_v; }
typedef Value value_type;
typedef typename IF<is_const, const Value*, Value*>::type pointer; pointer
typedef typename IF<is_const, const Value&, Value&>::type reference; operator->() const
typedef std::ptrdiff_t difference_type; { return &this->m_cur_node->m_v; }
typedef std::forward_iterator_tag iterator_category;
hashtable_iterator&
hashtable_iterator (hash_node<Value, cache>* p, hash_node<Value, cache>** b) operator++()
: hashtable_iterator_base<Value, cache>(p, b) { } {
hashtable_iterator (hash_node<Value, cache>** b) this->incr();
: hashtable_iterator_base<Value, cache>(*b, b) { } return *this;
hashtable_iterator (const hashtable_iterator<Value, true, cache>& x) }
: hashtable_iterator_base<Value, cache>(x.m_cur_node, x.m_cur_bucket) { }
hashtable_iterator
reference operator*() const { return this->m_cur_node->m_v; } operator++(int)
pointer operator->() const { return &this->m_cur_node->m_v; } {
hashtable_iterator tmp(*this);
hashtable_iterator& operator++() { this->incr(); return *this; } this->incr();
hashtable_iterator operator++(int) return tmp; }
{ hashtable_iterator tmp(*this); this->incr(); return tmp; } };
};
} // namespace Internal } // namespace Internal
...@@ -250,193 +296,218 @@ struct hashtable_iterator : public hashtable_iterator_base<Value, cache> ...@@ -250,193 +296,218 @@ struct hashtable_iterator : public hashtable_iterator_base<Value, cache>
// Many of class template hashtable's template parameters are policy // Many of class template hashtable's template parameters are policy
// classes. These are defaults for the policies. // classes. These are defaults for the policies.
namespace Internal { namespace Internal
// The two key extraction policies used by the *set and *map variants.
template <typename T>
struct identity {
T operator()(const T& t) const { return t; }
};
template <typename Pair>
struct extract1st {
typename Pair::first_type operator()(const Pair& p) const { return p.first; }
};
// Default range hashing function: use division to fold a large number
// into the range [0, N).
struct mod_range_hashing
{ {
typedef std::size_t first_argument_type; // The two key extraction policies used by the *set and *map variants.
typedef std::size_t second_argument_type; template<typename T>
typedef std::size_t result_type; struct identity
{
T
operator()(const T& t) const
{ return t; }
};
template<typename Pair>
struct extract1st
{
typename Pair::first_type
operator()(const Pair& p) const
{ return p.first; }
};
// Default range hashing function: use division to fold a large number
// into the range [0, N).
struct mod_range_hashing
{
typedef std::size_t first_argument_type;
typedef std::size_t second_argument_type;
typedef std::size_t result_type;
result_type operator() (first_argument_type r, second_argument_type N) const result_type
operator() (first_argument_type r, second_argument_type N) const
{ return r % N; } { return r % N; }
}; };
// Default ranged hash function H. In principle it should be a
// function object composed from objects of type H1 and H2 such that
// h(k, N) = h2(h1(k), N), but that would mean making extra copies of
// h1 and h2. So instead we'll just use a tag to tell class template
// hashtable to do that composition.
struct default_ranged_hash { };
// Default value for rehash policy. Bucket size is (usually) the // Default ranged hash function H. In principle it should be a
// smallest prime that keeps the load factor small enough. // function object composed from objects of type H1 and H2 such that
// h(k, N) = h2(h1(k), N), but that would mean making extra copies of
// h1 and h2. So instead we'll just use a tag to tell class template
// hashtable to do that composition.
struct default_ranged_hash { };
struct prime_rehash_policy // Default value for rehash policy. Bucket size is (usually) the
{ // smallest prime that keeps the load factor small enough.
prime_rehash_policy (float z = 1.0); struct prime_rehash_policy
float max_load_factor() const;
// Return a bucket size no smaller than n.
std::size_t next_bkt (std::size_t n) const;
// Return a bucket count appropriate for n elements
std::size_t bkt_for_elements (std::size_t n) const;
// n_bkt is current bucket count, n_elt is current element count,
// and n_ins is number of elements to be inserted. Do we need to
// increase bucket count? If so, return make_pair(true, n), where n
// is the new bucket count. If not, return make_pair(false, 0).
std::pair<bool, std::size_t>
need_rehash (std::size_t n_bkt, std::size_t n_elt, std::size_t n_ins) const;
float m_max_load_factor;
float m_growth_factor;
mutable std::size_t m_next_resize;
};
// XXX This is a hack. prime_rehash_policy's member functions, and
// certainly the list of primes, should be defined in a .cc file.
// We're temporarily putting them in a header because we don't have a
// place to put TR1 .cc files yet. There's no good reason for any of
// prime_rehash_policy's member functions to be inline, and there's
// certainly no good reason for X<> to exist at all.
struct lt {
template <typename X, typename Y> bool operator()(X x, Y y) { return x < y; }
};
template <int dummy>
struct X {
static const int n_primes = 256;
static const unsigned long primes[n_primes + 1];
};
template <int dummy>
const int X<dummy>::n_primes;
template <int dummy>
const unsigned long X<dummy>::primes[n_primes + 1] =
{ {
2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul, prime_rehash_policy(float z = 1.0);
37ul, 41ul, 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul,
83ul, 89ul, 97ul, 103ul, 109ul, 113ul, 127ul, 137ul, 139ul, 149ul, float
157ul, 167ul, 179ul, 193ul, 199ul, 211ul, 227ul, 241ul, 257ul, max_load_factor() const;
277ul, 293ul, 313ul, 337ul, 359ul, 383ul, 409ul, 439ul, 467ul,
503ul, 541ul, 577ul, 619ul, 661ul, 709ul, 761ul, 823ul, 887ul, // Return a bucket size no smaller than n.
953ul, 1031ul, 1109ul, 1193ul, 1289ul, 1381ul, 1493ul, 1613ul, std::size_t
1741ul, 1879ul, 2029ul, 2179ul, 2357ul, 2549ul, 2753ul, 2971ul, next_bkt(std::size_t n) const;
3209ul, 3469ul, 3739ul, 4027ul, 4349ul, 4703ul, 5087ul, 5503ul,
5953ul, 6427ul, 6949ul, 7517ul, 8123ul, 8783ul, 9497ul, 10273ul, // Return a bucket count appropriate for n elements
11113ul, 12011ul, 12983ul, 14033ul, 15173ul, 16411ul, 17749ul, std::size_t
19183ul, 20753ul, 22447ul, 24281ul, 26267ul, 28411ul, 30727ul, bkt_for_elements(std::size_t n) const;
33223ul, 35933ul, 38873ul, 42043ul, 45481ul, 49201ul, 53201ul,
57557ul, 62233ul, 67307ul, 72817ul, 78779ul, 85229ul, 92203ul, // n_bkt is current bucket count, n_elt is current element count,
99733ul, 107897ul, 116731ul, 126271ul, 136607ul, 147793ul, // and n_ins is number of elements to be inserted. Do we need to
159871ul, 172933ul, 187091ul, 202409ul, 218971ul, 236897ul, // increase bucket count? If so, return make_pair(true, n), where n
256279ul, 277261ul, 299951ul, 324503ul, 351061ul, 379787ul, // is the new bucket count. If not, return make_pair(false, 0).
410857ul, 444487ul, 480881ul, 520241ul, 562841ul, 608903ul, std::pair<bool, std::size_t>
658753ul, 712697ul, 771049ul, 834181ul, 902483ul, 976369ul, need_rehash(std::size_t n_bkt, std::size_t n_elt, std::size_t n_ins) const;
1056323ul, 1142821ul, 1236397ul, 1337629ul, 1447153ul, 1565659ul,
1693859ul, 1832561ul, 1982627ul, 2144977ul, 2320627ul, 2510653ul, float m_max_load_factor;
2716249ul, 2938679ul, 3179303ul, 3439651ul, 3721303ul, 4026031ul, float m_growth_factor;
4355707ul, 4712381ul, 5098259ul, 5515729ul, 5967347ul, 6456007ul, mutable std::size_t m_next_resize;
6984629ul, 7556579ul, 8175383ul, 8844859ul, 9569143ul, 10352717ul,
11200489ul, 12117689ul, 13109983ul, 14183539ul, 15345007ul,
16601593ul, 17961079ul, 19431899ul, 21023161ul, 22744717ul,
24607243ul, 26622317ul, 28802401ul, 31160981ul, 33712729ul,
36473443ul, 39460231ul, 42691603ul, 46187573ul, 49969847ul,
54061849ul, 58488943ul, 63278561ul, 68460391ul, 74066549ul,
80131819ul, 86693767ul, 93793069ul, 101473717ul, 109783337ul,
118773397ul, 128499677ul, 139022417ul, 150406843ul, 162723577ul,
176048909ul, 190465427ul, 206062531ul, 222936881ul, 241193053ul,
260944219ul, 282312799ul, 305431229ul, 330442829ul, 357502601ul,
386778277ul, 418451333ul, 452718089ul, 489790921ul, 529899637ul,
573292817ul, 620239453ul, 671030513ul, 725980837ul, 785430967ul,
849749479ul, 919334987ul, 994618837ul, 1076067617ul, 1164186217ul,
1259520799ul, 1362662261ul, 1474249943ul, 1594975441ul,
1725587117ul, 1866894511ul, 2019773507ul, 2185171673ul,
2364114217ul, 2557710269ul, 2767159799ul, 2993761039ul,
3238918481ul, 3504151727ul, 3791104843ul, 4101556399ul,
4294967291ul,
4294967291ul // sentinel so we don't have to test result of lower_bound
}; };
inline prime_rehash_policy::prime_rehash_policy (float z) // XXX This is a hack. prime_rehash_policy's member functions, and
: m_max_load_factor(z), // certainly the list of primes, should be defined in a .cc file.
m_growth_factor (2.f), // We're temporarily putting them in a header because we don't have a
m_next_resize (0) // place to put TR1 .cc files yet. There's no good reason for any of
{ } // prime_rehash_policy's member functions to be inline, and there's
// certainly no good reason for X<> to exist at all.
inline float prime_rehash_policy::max_load_factor() const
{ struct lt
return m_max_load_factor; {
} template<typename X, typename Y>
bool
operator()(X x, Y y)
{ return x < y; }
};
// Return a prime no smaller than n. template<int dummy>
inline std::size_t prime_rehash_policy::next_bkt (std::size_t n) const struct X
{ {
const unsigned long* const last = X<0>::primes + X<0>::n_primes; static const int n_primes = 256;
const unsigned long* p = std::lower_bound (X<0>::primes, last, n); static const unsigned long primes[n_primes + 1];
m_next_resize = static_cast<std::size_t>(std::ceil(*p * m_max_load_factor)); };
return *p;
} template<int dummy>
const int X<dummy>::n_primes;
template<int dummy>
const unsigned long X<dummy>::primes[n_primes + 1] =
{
2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul,
37ul, 41ul, 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul,
83ul, 89ul, 97ul, 103ul, 109ul, 113ul, 127ul, 137ul, 139ul, 149ul,
157ul, 167ul, 179ul, 193ul, 199ul, 211ul, 227ul, 241ul, 257ul,
277ul, 293ul, 313ul, 337ul, 359ul, 383ul, 409ul, 439ul, 467ul,
503ul, 541ul, 577ul, 619ul, 661ul, 709ul, 761ul, 823ul, 887ul,
953ul, 1031ul, 1109ul, 1193ul, 1289ul, 1381ul, 1493ul, 1613ul,
1741ul, 1879ul, 2029ul, 2179ul, 2357ul, 2549ul, 2753ul, 2971ul,
3209ul, 3469ul, 3739ul, 4027ul, 4349ul, 4703ul, 5087ul, 5503ul,
5953ul, 6427ul, 6949ul, 7517ul, 8123ul, 8783ul, 9497ul, 10273ul,
11113ul, 12011ul, 12983ul, 14033ul, 15173ul, 16411ul, 17749ul,
19183ul, 20753ul, 22447ul, 24281ul, 26267ul, 28411ul, 30727ul,
33223ul, 35933ul, 38873ul, 42043ul, 45481ul, 49201ul, 53201ul,
57557ul, 62233ul, 67307ul, 72817ul, 78779ul, 85229ul, 92203ul,
99733ul, 107897ul, 116731ul, 126271ul, 136607ul, 147793ul,
159871ul, 172933ul, 187091ul, 202409ul, 218971ul, 236897ul,
256279ul, 277261ul, 299951ul, 324503ul, 351061ul, 379787ul,
410857ul, 444487ul, 480881ul, 520241ul, 562841ul, 608903ul,
658753ul, 712697ul, 771049ul, 834181ul, 902483ul, 976369ul,
1056323ul, 1142821ul, 1236397ul, 1337629ul, 1447153ul, 1565659ul,
1693859ul, 1832561ul, 1982627ul, 2144977ul, 2320627ul, 2510653ul,
2716249ul, 2938679ul, 3179303ul, 3439651ul, 3721303ul, 4026031ul,
4355707ul, 4712381ul, 5098259ul, 5515729ul, 5967347ul, 6456007ul,
6984629ul, 7556579ul, 8175383ul, 8844859ul, 9569143ul, 10352717ul,
11200489ul, 12117689ul, 13109983ul, 14183539ul, 15345007ul,
16601593ul, 17961079ul, 19431899ul, 21023161ul, 22744717ul,
24607243ul, 26622317ul, 28802401ul, 31160981ul, 33712729ul,
36473443ul, 39460231ul, 42691603ul, 46187573ul, 49969847ul,
54061849ul, 58488943ul, 63278561ul, 68460391ul, 74066549ul,
80131819ul, 86693767ul, 93793069ul, 101473717ul, 109783337ul,
118773397ul, 128499677ul, 139022417ul, 150406843ul, 162723577ul,
176048909ul, 190465427ul, 206062531ul, 222936881ul, 241193053ul,
260944219ul, 282312799ul, 305431229ul, 330442829ul, 357502601ul,
386778277ul, 418451333ul, 452718089ul, 489790921ul, 529899637ul,
573292817ul, 620239453ul, 671030513ul, 725980837ul, 785430967ul,
849749479ul, 919334987ul, 994618837ul, 1076067617ul, 1164186217ul,
1259520799ul, 1362662261ul, 1474249943ul, 1594975441ul,
1725587117ul, 1866894511ul, 2019773507ul, 2185171673ul,
2364114217ul, 2557710269ul, 2767159799ul, 2993761039ul,
3238918481ul, 3504151727ul, 3791104843ul, 4101556399ul,
4294967291ul,
4294967291ul // sentinel so we don't have to test result of lower_bound
};
inline
prime_rehash_policy::
prime_rehash_policy(float z)
: m_max_load_factor(z), m_growth_factor(2.f), m_next_resize(0)
{ }
// Return the smallest prime p such that alpha p >= n, where alpha inline float
// is the load factor. prime_rehash_policy::
inline std::size_t prime_rehash_policy::bkt_for_elements (std::size_t n) const max_load_factor() const
{ { return m_max_load_factor; }
const unsigned long* const last = X<0>::primes + X<0>::n_primes;
const float min_bkts = n / m_max_load_factor;
const unsigned long* p = std::lower_bound (X<0>::primes, last, min_bkts, lt());
m_next_resize = static_cast<std::size_t>(std::ceil(*p * m_max_load_factor));
return *p;
}
// Finds the smallest prime p such that alpha p > n_elt + n_ins. // Return a prime no smaller than n.
// If p > n_bkt, return make_pair(true, p); otherwise return inline std::size_t
// make_pair(false, 0). In principle this isn't very different from prime_rehash_policy::
// bkt_for_elements. next_bkt(std::size_t n) const
{
const unsigned long* const last = X<0>::primes + X<0>::n_primes;
const unsigned long* p = std::lower_bound (X<0>::primes, last, n);
m_next_resize = static_cast<std::size_t>(std::ceil(*p * m_max_load_factor));
return *p;
}
// The only tricky part is that we're caching the element count at // Return the smallest prime p such that alpha p >= n, where alpha
// which we need to rehash, so we don't have to do a floating-point // is the load factor.
// multiply for every insertion. inline std::size_t
prime_rehash_policy::
bkt_for_elements(std::size_t n) const
{
const unsigned long* const last = X<0>::primes + X<0>::n_primes;
const float min_bkts = n / m_max_load_factor;
const unsigned long* p = std::lower_bound (X<0>::primes, last,
min_bkts, lt());
m_next_resize = static_cast<std::size_t>(std::ceil(*p * m_max_load_factor));
return *p;
}
inline std::pair<bool, std::size_t> // Finds the smallest prime p such that alpha p > n_elt + n_ins.
prime_rehash_policy // If p > n_bkt, return make_pair(true, p); otherwise return
::need_rehash (std::size_t n_bkt, std::size_t n_elt, std::size_t n_ins) const // make_pair(false, 0). In principle this isn't very different from
{ // bkt_for_elements.
if (n_elt + n_ins > m_next_resize) {
float min_bkts = (float(n_ins) + float(n_elt)) / m_max_load_factor; // The only tricky part is that we're caching the element count at
if (min_bkts > n_bkt) { // which we need to rehash, so we don't have to do a floating-point
min_bkts = std::max (min_bkts, m_growth_factor * n_bkt); // multiply for every insertion.
const unsigned long* const last = X<0>::primes + X<0>::n_primes;
const unsigned long* p = std::lower_bound (X<0>::primes, last, min_bkts, lt()); inline std::pair<bool, std::size_t>
m_next_resize = static_cast<std::size_t>(std::ceil(*p * m_max_load_factor)); prime_rehash_policy::
return std::make_pair(true, *p); need_rehash(std::size_t n_bkt, std::size_t n_elt, std::size_t n_ins) const
} {
else { if (n_elt + n_ins > m_next_resize)
m_next_resize = static_cast<std::size_t>(std::ceil(n_bkt * m_max_load_factor)); {
float min_bkts = (float(n_ins) + float(n_elt)) / m_max_load_factor;
if (min_bkts > n_bkt)
{
min_bkts = std::max (min_bkts, m_growth_factor * n_bkt);
const unsigned long* const last = X<0>::primes + X<0>::n_primes;
const unsigned long* p = std::lower_bound (X<0>::primes, last,
min_bkts, lt());
m_next_resize =
static_cast<std::size_t>(std::ceil(*p * m_max_load_factor));
return std::make_pair(true, *p);
}
else
{
m_next_resize =
static_cast<std::size_t>(std::ceil(n_bkt * m_max_load_factor));
return std::make_pair(false, 0);
}
}
else
return std::make_pair(false, 0); return std::make_pair(false, 0);
}
} }
else
return std::make_pair(false, 0);
}
} // namespace Internal } // namespace Internal
...@@ -449,983 +520,1182 @@ prime_rehash_policy ...@@ -449,983 +520,1182 @@ prime_rehash_policy
// need to access other members of class template hashtable, so we use // need to access other members of class template hashtable, so we use
// the "curiously recurring template pattern" for them. // the "curiously recurring template pattern" for them.
namespace Internal { namespace Internal
// class template map_base. If the hashtable has a value type of the
// form pair<T1, T2> and a key extraction policy that returns the
// first part of the pair, the hashtable gets a mapped_type typedef.
// If it satisfies those criteria and also has unique keys, then it
// also gets an operator[].
template <typename K, typename V, typename Ex, bool unique, typename Hashtable>
struct map_base { };
template <typename K, typename Pair, typename Hashtable>
struct map_base<K, Pair, extract1st<Pair>, false, Hashtable>
{
typedef typename Pair::second_type mapped_type;
};
template <typename K, typename Pair, typename Hashtable>
struct map_base<K, Pair, extract1st<Pair>, true, Hashtable>
{
typedef typename Pair::second_type mapped_type;
mapped_type& operator[](const K& k) {
Hashtable* h = static_cast<Hashtable*>(this);
typename Hashtable::iterator it = h->insert(std::make_pair(k, mapped_type())).first;
return it->second;
}
};
// class template rehash_base. Give hashtable the max_load_factor
// functions iff the rehash policy is prime_rehash_policy.
template <typename RehashPolicy, typename Hashtable>
struct rehash_base { };
template <typename Hashtable>
struct rehash_base<prime_rehash_policy, Hashtable>
{ {
float max_load_factor() const { // class template map_base. If the hashtable has a value type of the
const Hashtable* This = static_cast<const Hashtable*>(this); // form pair<T1, T2> and a key extraction policy that returns the
return This->rehash_policy()->max_load_factor(); // first part of the pair, the hashtable gets a mapped_type typedef.
} // If it satisfies those criteria and also has unique keys, then it
// also gets an operator[].
void max_load_factor(float z) {
Hashtable* This = static_cast<Hashtable*>(this);
This->rehash_policy(prime_rehash_policy(z));
}
};
// Class template hash_code_base. Encapsulates two policy issues that
// aren't quite orthogonal.
// (1) the difference between using a ranged hash function and using
// the combination of a hash function and a range-hashing function.
// In the former case we don't have such things as hash codes, so
// we have a dummy type as placeholder.
// (2) Whether or not we cache hash codes. Caching hash codes is
// meaningless if we have a ranged hash function.
// We also put the key extraction and equality comparison function
// objects here, for convenience.
// Primary template: unused except as a hook for specializations.
template <typename Key, typename Value,
typename ExtractKey, typename Equal,
typename H1, typename H2, typename H,
bool cache_hash_code>
struct hash_code_base;
// Specialization: ranged hash function, no caching hash codes. H1
// and H2 are provided but ignored. We define a dummy hash code type.
template <typename Key, typename Value,
typename ExtractKey, typename Equal,
typename H1, typename H2, typename H>
struct hash_code_base <Key, Value, ExtractKey, Equal, H1, H2, H, false>
{
protected:
hash_code_base (const ExtractKey& ex, const Equal& eq,
const H1&, const H2&, const H& h)
: m_extract(ex), m_eq(eq), m_ranged_hash(h) { }
typedef void* hash_code_t;
hash_code_t m_hash_code (const Key& k) const { return 0; }
std::size_t bucket_index (const Key& k, hash_code_t, std::size_t N) const
{ return m_ranged_hash (k, N); }
std::size_t bucket_index (const hash_node<Value, false>* p, std::size_t N) const {
return m_ranged_hash (m_extract (p->m_v), N);
}
bool compare (const Key& k, hash_code_t, hash_node<Value, false>* n) const template<typename K, typename V, typename Ex, bool unique, typename Hashtable>
{ return m_eq (k, m_extract(n->m_v)); } struct map_base { };
void copy_code (hash_node<Value, false>*, const hash_node<Value, false>*) const { } template<typename K, typename Pair, typename Hashtable>
struct map_base<K, Pair, extract1st<Pair>, false, Hashtable>
void m_swap(hash_code_base& x) { {
m_extract.m_swap(x); typedef typename Pair::second_type mapped_type;
m_eq.m_swap(x); };
m_ranged_hash.m_swap(x);
} template<typename K, typename Pair, typename Hashtable>
struct map_base<K, Pair, extract1st<Pair>, true, Hashtable>
protected: {
ExtractKey m_extract; typedef typename Pair::second_type mapped_type;
Equal m_eq;
H m_ranged_hash; mapped_type&
}; operator[](const K& k)
{
Hashtable* h = static_cast<Hashtable*>(this);
// No specialization for ranged hash function while caching hash codes. typename Hashtable::iterator it =
// That combination is meaningless, and trying to do it is an error. h->insert(std::make_pair(k, mapped_type())).first;
return it->second;
}
};
// class template rehash_base. Give hashtable the max_load_factor
// functions iff the rehash policy is prime_rehash_policy.
template<typename RehashPolicy, typename Hashtable>
struct rehash_base { };
template<typename Hashtable>
struct rehash_base<prime_rehash_policy, Hashtable>
{
float
max_load_factor() const
{
const Hashtable* This = static_cast<const Hashtable*>(this);
return This->rehash_policy()->max_load_factor();
}
void
max_load_factor(float z)
{
Hashtable* This = static_cast<Hashtable*>(this);
This->rehash_policy(prime_rehash_policy(z));
}
};
// Class template hash_code_base. Encapsulates two policy issues that
// aren't quite orthogonal.
// (1) the difference between using a ranged hash function and using
// the combination of a hash function and a range-hashing function.
// In the former case we don't have such things as hash codes, so
// we have a dummy type as placeholder.
// (2) Whether or not we cache hash codes. Caching hash codes is
// meaningless if we have a ranged hash function.
// We also put the key extraction and equality comparison function
// objects here, for convenience.
// Primary template: unused except as a hook for specializations.
template<typename Key, typename Value,
typename ExtractKey, typename Equal,
typename H1, typename H2, typename H,
bool cache_hash_code>
struct hash_code_base;
// Specialization: ranged hash function, no caching hash codes. H1
// and H2 are provided but ignored. We define a dummy hash code type.
template<typename Key, typename Value,
typename ExtractKey, typename Equal,
typename H1, typename H2, typename H>
struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H, false>
{
protected:
hash_code_base(const ExtractKey& ex, const Equal& eq,
const H1&, const H2&, const H& h)
: m_extract(ex), m_eq(eq), m_ranged_hash(h) { }
typedef void* hash_code_t;
hash_code_t
m_hash_code(const Key& k) const
{ return 0; }
std::size_t
bucket_index(const Key& k, hash_code_t, std::size_t N) const
{ return m_ranged_hash (k, N); }
// Specialization: ranged hash function, cache hash codes. This std::size_t
// combination is meaningless, so we provide only a declaration bucket_index(const hash_node<Value, false>* p, std::size_t N) const
// and no definition. { return m_ranged_hash (m_extract (p->m_v), N); }
bool
compare(const Key& k, hash_code_t, hash_node<Value, false>* n) const
{ return m_eq (k, m_extract(n->m_v)); }
void
copy_code(hash_node<Value, false>*, const hash_node<Value, false>*) const
{ }
void
m_swap(hash_code_base& x)
{
m_extract.m_swap(x);
m_eq.m_swap(x);
m_ranged_hash.m_swap(x);
}
template <typename Key, typename Value, protected:
typename ExtractKey, typename Equal, ExtractKey m_extract;
typename H1, typename H2, typename H> Equal m_eq;
struct hash_code_base <Key, Value, ExtractKey, Equal, H1, H2, H, true>; H m_ranged_hash;
};
// Specialization: hash function and range-hashing function, no // No specialization for ranged hash function while caching hash codes.
// caching of hash codes. H is provided but ignored. Provides // That combination is meaningless, and trying to do it is an error.
// typedef and accessor required by TR1.
// Specialization: ranged hash function, cache hash codes. This
// combination is meaningless, so we provide only a declaration
// and no definition.
template<typename Key, typename Value,
typename ExtractKey, typename Equal,
typename H1, typename H2, typename H>
struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H, true>;
template <typename Key, typename Value,
typename ExtractKey, typename Equal,
typename H1, typename H2>
struct hash_code_base <Key, Value, ExtractKey, Equal, H1, H2, default_ranged_hash, false>
{
typedef H1 hasher;
hasher hash_function() const { return m_h1; }
protected:
hash_code_base (const ExtractKey& ex, const Equal& eq,
const H1& h1, const H2& h2, const default_ranged_hash&)
: m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { }
typedef std::size_t hash_code_t;
hash_code_t m_hash_code (const Key& k) const { return m_h1(k); }
std::size_t bucket_index (const Key&, hash_code_t c, std::size_t N) const
{ return m_h2 (c, N); }
std::size_t bucket_index (const hash_node<Value, false>* p, std::size_t N) const {
return m_h2 (m_h1 (m_extract (p->m_v)), N);
}
bool compare (const Key& k, hash_code_t, hash_node<Value, false>* n) const // Specialization: hash function and range-hashing function, no
{ return m_eq (k, m_extract(n->m_v)); } // caching of hash codes. H is provided but ignored. Provides
// typedef and accessor required by TR1.
template<typename Key, typename Value,
typename ExtractKey, typename Equal,
typename H1, typename H2>
struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2,
default_ranged_hash, false>
{
typedef H1 hasher;
hasher
hash_function() const
{ return m_h1; }
protected:
hash_code_base(const ExtractKey& ex, const Equal& eq,
const H1& h1, const H2& h2, const default_ranged_hash&)
: m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { }
typedef std::size_t hash_code_t;
hash_code_t
m_hash_code(const Key& k) const
{ return m_h1(k); }
std::size_t
bucket_index(const Key&, hash_code_t c, std::size_t N) const
{ return m_h2 (c, N); }
std::size_t
bucket_index(const hash_node<Value, false>* p, std::size_t N) const
{ return m_h2 (m_h1 (m_extract (p->m_v)), N); }
bool
compare(const Key& k, hash_code_t, hash_node<Value, false>* n) const
{ return m_eq (k, m_extract(n->m_v)); }
void
copy_code(hash_node<Value, false>*, const hash_node<Value, false>*) const
{ }
void
m_swap(hash_code_base& x)
{
m_extract.m_swap(x);
m_eq.m_swap(x);
m_h1.m_swap(x);
m_h2.m_swap(x);
}
void copy_code (hash_node<Value, false>*, const hash_node<Value, false>*) const { } protected:
ExtractKey m_extract;
Equal m_eq;
H1 m_h1;
H2 m_h2;
};
// Specialization: hash function and range-hashing function,
// caching hash codes. H is provided but ignored. Provides
// typedef and accessor required by TR1.
template<typename Key, typename Value,
typename ExtractKey, typename Equal,
typename H1, typename H2>
struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2,
default_ranged_hash, true>
{
typedef H1 hasher;
hasher
hash_function() const
{ return m_h1; }
protected:
hash_code_base(const ExtractKey& ex, const Equal& eq,
const H1& h1, const H2& h2, const default_ranged_hash&)
: m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { }
typedef std::size_t hash_code_t;
hash_code_t
m_hash_code (const Key& k) const
{ return m_h1(k); }
std::size_t
bucket_index(const Key&, hash_code_t c, std::size_t N) const
{ return m_h2 (c, N); }
std::size_t
bucket_index(const hash_node<Value, true>* p, std::size_t N) const
{ return m_h2 (p->hash_code, N); }
bool
compare(const Key& k, hash_code_t c, hash_node<Value, true>* n) const
{ return c == n->hash_code && m_eq(k, m_extract(n->m_v)); }
void
copy_code(hash_node<Value, true>* to,
const hash_node<Value, true>* from) const
{ to->hash_code = from->hash_code; }
void
m_swap(hash_code_base& x)
{
m_extract.m_swap(x);
m_eq.m_swap(x);
m_h1.m_swap(x);
m_h2.m_swap(x);
}
protected:
ExtractKey m_extract;
Equal m_eq;
H1 m_h1;
H2 m_h2;
};
void m_swap(hash_code_base& x) { } // namespace internal
m_extract.m_swap(x);
m_eq.m_swap(x);
m_h1.m_swap(x);
m_h2.m_swap(x);
}
protected: namespace std
ExtractKey m_extract; {
Equal m_eq; namespace tr1
H1 m_h1;
H2 m_h2;
};
// Specialization: hash function and range-hashing function,
// caching hash codes. H is provided but ignored. Provides
// typedef and accessor required by TR1.
template <typename Key, typename Value,
typename ExtractKey, typename Equal,
typename H1, typename H2>
struct hash_code_base <Key, Value, ExtractKey, Equal, H1, H2, default_ranged_hash, true>
{ {
typedef H1 hasher; //----------------------------------------------------------------------
hasher hash_function() const { return m_h1; } // Class template hashtable, class definition.
protected: // Meaning of class template hashtable's template parameters
hash_code_base (const ExtractKey& ex, const Equal& eq,
const H1& h1, const H2& h2, const default_ranged_hash&) // Key and Value: arbitrary CopyConstructible types.
: m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { }
// Allocator: an allocator type ([lib.allocator.requirements]) whose
typedef std::size_t hash_code_t; // value type is Value.
hash_code_t m_hash_code (const Key& k) const { return m_h1(k); }
std::size_t bucket_index (const Key&, hash_code_t c, std::size_t N) const // ExtractKey: function object that takes a object of type Value
{ return m_h2 (c, N); } // and returns a value of type Key.
std::size_t bucket_index (const hash_node<Value, true>* p, std::size_t N) const { // Equal: function object that takes two objects of type k and returns
return m_h2 (p->hash_code, N); // a bool-like value that is true if the two objects are considered equal.
}
// H1: the hash function. A unary function object with argument type
bool compare (const Key& k, hash_code_t c, hash_node<Value, true>* n) const // Key and result type size_t. Return values should be distributed
{ return c == n->hash_code && m_eq (k, m_extract(n->m_v)); } // over the entire range [0, numeric_limits<size_t>:::max()].
// H2: the range-hashing function (in the terminology of Tavori and
// Dreizin). A binary function object whose argument types and result
// type are all size_t. Given arguments r and N, the return value is
// in the range [0, N).
// H: the ranged hash function (Tavori and Dreizin). A binary function
// whose argument types are Key and size_t and whose result type is
// size_t. Given arguments k and N, the return value is in the range
// [0, N). Default: h(k, N) = h2(h1(k), N). If H is anything other
// than the default, H1 and H2 are ignored.
// RehashPolicy: Policy class with three members, all of which govern
// the bucket count. n_bkt(n) returns a bucket count no smaller
// than n. bkt_for_elements(n) returns a bucket count appropriate
// for an element count of n. need_rehash(n_bkt, n_elt, n_ins)
// determines whether, if the current bucket count is n_bkt and the
// current element count is n_elt, we need to increase the bucket
// count. If so, returns make_pair(true, n), where n is the new
// bucket count. If not, returns make_pair(false, <anything>).
// ??? Right now it is hard-wired that the number of buckets never
// shrinks. Should we allow RehashPolicy to change that?
// cache_hash_code: bool. true if we store the value of the hash
// function along with the value. This is a time-space tradeoff.
// Storing it may improve lookup speed by reducing the number of times
// we need to call the Equal function.
// mutable_iterators: bool. true if hashtable::iterator is a mutable
// iterator, false if iterator and const_iterator are both const
// iterators. This is true for unordered_map and unordered_multimap,
// false for unordered_set and unordered_multiset.
// unique_keys: bool. true if the return value of hashtable::count(k)
// is always at most one, false if it may be an arbitrary number. This
// true for unordered_set and unordered_map, false for unordered_multiset
// and unordered_multimap.
template<typename Key, typename Value,
typename Allocator,
typename ExtractKey, typename Equal,
typename H1, typename H2,
typename H, typename RehashPolicy,
bool cache_hash_code,
bool mutable_iterators,
bool unique_keys>
class hashtable
: public Internal::rehash_base<RehashPolicy,
hashtable<Key, Value, Allocator, ExtractKey,
Equal, H1, H2, H, RehashPolicy,
cache_hash_code, mutable_iterators,
unique_keys> >,
public Internal::hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H,
cache_hash_code>,
public Internal::map_base<Key, Value, ExtractKey, unique_keys,
hashtable<Key, Value, Allocator, ExtractKey,
Equal, H1, H2, H, RehashPolicy,
cache_hash_code, mutable_iterators,
unique_keys> >
{
public:
typedef Allocator allocator_type;
typedef Value value_type;
typedef Key key_type;
typedef Equal key_equal;
// mapped_type, if present, comes from map_base.
// hasher, if present, comes from hash_code_base.
typedef typename Allocator::difference_type difference_type;
typedef typename Allocator::size_type size_type;
typedef typename Allocator::reference reference;
typedef typename Allocator::const_reference const_reference;
typedef Internal::node_iterator<value_type, !mutable_iterators,
cache_hash_code>
local_iterator;
typedef Internal::node_iterator<value_type, false, cache_hash_code>
const_local_iterator;
typedef Internal::hashtable_iterator<value_type, !mutable_iterators,
cache_hash_code>
iterator;
typedef Internal::hashtable_iterator<value_type, false, cache_hash_code>
const_iterator;
private:
typedef Internal::hash_node<Value, cache_hash_code> node;
typedef typename Allocator::template rebind<node>::other
node_allocator_t;
typedef typename Allocator::template rebind<node*>::other
bucket_allocator_t;
private:
node_allocator_t m_node_allocator;
node** m_buckets;
size_type m_bucket_count;
size_type m_element_count;
RehashPolicy m_rehash_policy;
node*
m_allocate_node(const value_type& v);
void
m_deallocate_node(node* n);
void
m_deallocate_nodes(node**, size_type);
void copy_code (hash_node<Value, true>* to, const hash_node<Value, true>* from) const node**
{ to->hash_code = from->hash_code; } m_allocate_buckets(size_type n);
void
m_deallocate_buckets(node**, size_type n);
public: // Constructor, destructor, assignment, swap
hashtable(size_type bucket_hint,
const H1&, const H2&, const H&,
const Equal&, const ExtractKey&,
const allocator_type&);
template<typename InIter>
hashtable(InIter first, InIter last,
size_type bucket_hint,
const H1&, const H2&, const H&,
const Equal&, const ExtractKey&,
const allocator_type&);
hashtable(const hashtable&);
hashtable&
operator=(const hashtable&);
~hashtable();
void swap(hashtable&);
public: // Basic container operations
iterator
begin()
{
iterator i(m_buckets);
if (!i.m_cur_node)
i.m_incr_bucket();
return i;
}
void m_swap(hash_code_base& x) { const_iterator
m_extract.m_swap(x); begin() const
m_eq.m_swap(x); {
m_h1.m_swap(x); const_iterator i(m_buckets);
m_h2.m_swap(x); if (!i.m_cur_node)
} i.m_incr_bucket();
return i;
}
protected: iterator
ExtractKey m_extract; end()
Equal m_eq; { return iterator(m_buckets + m_bucket_count); }
H1 m_h1;
H2 m_h2;
};
} // namespace internal const_iterator
end() const
{ return const_iterator(m_buckets + m_bucket_count); }
namespace std { namespace tr1 { size_type
size() const
{ return m_element_count; }
bool
empty() const
{ return size() == 0; }
//---------------------------------------------------------------------- allocator_type
// Class template hashtable, class definition. get_allocator() const
{ return m_node_allocator; }
// Meaning of class template hashtable's template parameters
// Key and Value: arbitrary CopyConstructible types.
// Allocator: an allocator type ([lib.allocator.requirements]) whose
// value type is Value.
// ExtractKey: function object that takes a object of type Value
// and returns a value of type Key.
// Equal: function object that takes two objects of type k and returns
// a bool-like value that is true if the two objects are considered equal.
// H1: the hash function. A unary function object with argument type
// Key and result type size_t. Return values should be distributed
// over the entire range [0, numeric_limits<size_t>:::max()].
// H2: the range-hashing function (in the terminology of Tavori and
// Dreizin). A binary function object whose argument types and result
// type are all size_t. Given arguments r and N, the return value is
// in the range [0, N).
// H: the ranged hash function (Tavori and Dreizin). A binary function
// whose argument types are Key and size_t and whose result type is
// size_t. Given arguments k and N, the return value is in the range
// [0, N). Default: h(k, N) = h2(h1(k), N). If H is anything other
// than the default, H1 and H2 are ignored.
// RehashPolicy: Policy class with three members, all of which govern
// the bucket count. n_bkt(n) returns a bucket count no smaller
// than n. bkt_for_elements(n) returns a bucket count appropriate
// for an element count of n. need_rehash(n_bkt, n_elt, n_ins)
// determines whether, if the current bucket count is n_bkt and the
// current element count is n_elt, we need to increase the bucket
// count. If so, returns make_pair(true, n), where n is the new
// bucket count. If not, returns make_pair(false, <anything>).
// ??? Right now it is hard-wired that the number of buckets never
// shrinks. Should we allow RehashPolicy to change that?
// cache_hash_code: bool. true if we store the value of the hash
// function along with the value. This is a time-space tradeoff.
// Storing it may improve lookup speed by reducing the number of times
// we need to call the Equal function.
// mutable_iterators: bool. true if hashtable::iterator is a mutable
// iterator, false if iterator and const_iterator are both const
// iterators. This is true for unordered_map and unordered_multimap,
// false for unordered_set and unordered_multiset.
// unique_keys: bool. true if the return value of hashtable::count(k)
// is always at most one, false if it may be an arbitrary number. This
// true for unordered_set and unordered_map, false for unordered_multiset
// and unordered_multimap.
template <typename Key, typename Value,
typename Allocator,
typename ExtractKey, typename Equal,
typename H1, typename H2,
typename H, typename RehashPolicy,
bool cache_hash_code,
bool mutable_iterators,
bool unique_keys>
class hashtable
: public Internal::rehash_base<RehashPolicy, hashtable<Key, Value, Allocator, ExtractKey, Equal, H1, H2, H, RehashPolicy, cache_hash_code, mutable_iterators, unique_keys> >,
public Internal::hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H, cache_hash_code>,
public Internal::map_base<Key, Value, ExtractKey, unique_keys, hashtable<Key, Value, Allocator, ExtractKey, Equal, H1, H2, H, RehashPolicy, cache_hash_code, mutable_iterators, unique_keys> >
{
public:
typedef Allocator allocator_type;
typedef Value value_type;
typedef Key key_type;
typedef Equal key_equal;
// mapped_type, if present, comes from map_base.
// hasher, if present, comes from hash_code_base.
typedef typename Allocator::difference_type difference_type;
typedef typename Allocator::size_type size_type;
typedef typename Allocator::reference reference;
typedef typename Allocator::const_reference const_reference;
typedef Internal::node_iterator<value_type, !mutable_iterators, cache_hash_code>
local_iterator;
typedef Internal::node_iterator<value_type, false, cache_hash_code>
const_local_iterator;
typedef Internal::hashtable_iterator<value_type, !mutable_iterators, cache_hash_code>
iterator;
typedef Internal::hashtable_iterator<value_type, false, cache_hash_code>
const_iterator;
private:
typedef Internal::hash_node<Value, cache_hash_code> node;
typedef typename Allocator::template rebind<node>::other node_allocator_t;
typedef typename Allocator::template rebind<node*>::other bucket_allocator_t;
private:
node_allocator_t m_node_allocator;
node** m_buckets;
size_type m_bucket_count;
size_type m_element_count;
RehashPolicy m_rehash_policy;
node* m_allocate_node (const value_type& v);
void m_deallocate_node (node* n);
void m_deallocate_nodes (node**, size_type);
node** m_allocate_buckets (size_type n);
void m_deallocate_buckets (node**, size_type n);
public: // Constructor, destructor, assignment, swap
hashtable(size_type bucket_hint,
const H1&, const H2&, const H&,
const Equal&, const ExtractKey&,
const allocator_type&);
template <typename InIter> size_type
hashtable(InIter first, InIter last, max_size() const
size_type bucket_hint, { return m_node_allocator.max_size(); }
const H1&, const H2&, const H&,
const Equal&, const ExtractKey&, public: // Bucket operations
const allocator_type&); size_type
bucket_count() const
{ return m_bucket_count; }
hashtable(const hashtable&); size_type
hashtable& operator=(const hashtable&); max_bucket_count() const
~hashtable(); { return max_size(); }
void swap(hashtable&); size_type
bucket_size(size_type n) const
public: // Basic container operations { return std::distance(begin(n), end(n)); }
iterator begin() {
iterator i(m_buckets); size_type bucket(const key_type& k) const
if (!i.m_cur_node) {
i.m_incr_bucket(); return this->bucket_index(k, this->m_hash_code, this->m_bucket_count);
return i; }
}
const_iterator begin() const {
const_iterator i(m_buckets);
if (!i.m_cur_node)
i.m_incr_bucket();
return i;
}
iterator end() local_iterator
{ return iterator(m_buckets + m_bucket_count); } begin(size_type n)
const_iterator end() const { return local_iterator(m_buckets[n]); }
{ return const_iterator(m_buckets + m_bucket_count); }
local_iterator
size_type size() const { return m_element_count; } end(size_type n)
bool empty() const { return size() == 0; } { return local_iterator(0); }
allocator_type get_allocator() const { return m_node_allocator; } const_local_iterator
size_type max_size() const { return m_node_allocator.max_size(); } begin(size_type n) const
{ return const_local_iterator(m_buckets[n]); }
public: // Bucket operations
size_type bucket_count() const const_local_iterator
{ return m_bucket_count; } end(size_type n) const
size_type max_bucket_count() const { return const_local_iterator(0); }
{ return max_size(); }
size_type bucket_size (size_type n) const float
{ return std::distance(begin(n), end(n)); } load_factor() const
size_type bucket (const key_type& k) const {
{ return this->bucket_index (k, this->m_hash_code, this->m_bucket_count); } return static_cast<float>(size()) / static_cast<float>(bucket_count());
}
local_iterator begin(size_type n) // max_load_factor, if present, comes from rehash_base.
{ return local_iterator(m_buckets[n]); }
local_iterator end(size_type n) // Generalization of max_load_factor. Extension, not found in TR1. Only
{ return local_iterator(0); } // useful if RehashPolicy is something other than the default.
const_local_iterator begin(size_type n) const const RehashPolicy&
{ return const_local_iterator(m_buckets[n]); } rehash_policy() const
const_local_iterator end(size_type n) const { return m_rehash_policy; }
{ return const_local_iterator(0); }
void
float load_factor() const rehash_policy(const RehashPolicy&);
{ return static_cast<float>(size()) / static_cast<float>(bucket_count()); }
// max_load_factor, if present, comes from rehash_base. public: // lookup
iterator
// Generalization of max_load_factor. Extension, not found in TR1. Only find(const key_type&);
// useful if RehashPolicy is something other than the default.
const RehashPolicy& rehash_policy() const { return m_rehash_policy; } const_iterator
void rehash_policy (const RehashPolicy&); find(const key_type& k) const;
public: // lookup size_type
iterator find(const key_type&); count(const key_type& k) const;
const_iterator find(const key_type& k) const;
size_type count(const key_type& k) const; std::pair<iterator, iterator>
std::pair<iterator, iterator> equal_range(const key_type& k); equal_range(const key_type& k);
std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
std::pair<const_iterator, const_iterator>
private: // Insert and erase helper functions equal_range(const key_type& k) const;
// ??? This dispatching is a workaround for the fact that we don't
// have partial specialization of member templates; it would be private: // Insert and erase helper functions
// better to just specialize insert on unique_keys. There may be a // ??? This dispatching is a workaround for the fact that we don't
// cleaner workaround. // have partial specialization of member templates; it would be
typedef typename Internal::IF<unique_keys, std::pair<iterator, bool>, iterator>::type // better to just specialize insert on unique_keys. There may be a
Insert_Return_Type; // cleaner workaround.
typedef typename Internal::IF<unique_keys,
node* find_node (node* p, const key_type& k, typename hashtable::hash_code_t c); std::pair<iterator, bool>, iterator>::type
Insert_Return_Type;
std::pair<iterator, bool> insert (const value_type&, std::tr1::true_type);
iterator insert (const value_type&, std::tr1::false_type); node*
find_node(node* p, const key_type& k, typename hashtable::hash_code_t c);
public: // Insert and erase
Insert_Return_Type insert (const value_type& v) std::pair<iterator, bool>
{ return this->insert (v, std::tr1::integral_constant<bool, unique_keys>()); } insert(const value_type&, std::tr1::true_type);
Insert_Return_Type insert (const_iterator, const value_type& v)
{ return this->insert(v); } iterator
insert
template <typename InIter> void insert(InIter first, InIter last); (const value_type&, std::tr1::false_type);
void erase(const_iterator); public: // Insert and erase
size_type erase(const key_type&); Insert_Return_Type
void erase(const_iterator, const_iterator); insert(const value_type& v)
void clear(); {
return this->insert(v, std::tr1::integral_constant<bool,
public: unique_keys>());
// Set number of buckets to be apropriate for container of n element. }
void rehash (size_type n);
Insert_Return_Type
private: insert(const_iterator, const value_type& v)
// Unconditionally change size of bucket array to n. { return this->insert(v); }
void m_rehash (size_type n);
};
//---------------------------------------------------------------------- template<typename InIter>
// Definitions of class template hashtable's out-of-line member functions. void
insert(InIter first, InIter last);
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::node*
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::m_allocate_node (const value_type& v)
{
node* n = m_node_allocator.allocate(1);
try {
get_allocator().construct(&n->m_v, v);
n->m_next = 0;
return n;
}
catch(...) {
m_node_allocator.deallocate(n, 1);
throw;
}
}
template <typename K, typename V, void
typename A, typename Ex, typename Eq, erase(const_iterator);
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u> size_type
void erase(const key_type&);
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::m_deallocate_node (node* n)
{ void
get_allocator().destroy(&n->m_v); erase(const_iterator, const_iterator);
m_node_allocator.deallocate(n, 1);
} void
clear();
public:
// Set number of buckets to be apropriate for container of n element.
void rehash (size_type n);
private:
// Unconditionally change size of bucket array to n.
void m_rehash (size_type n);
};
//----------------------------------------------------------------------
// Definitions of class template hashtable's out-of-line member functions.
template<typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::node*
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
m_allocate_node(const value_type& v)
{
node* n = m_node_allocator.allocate(1);
try
{
get_allocator().construct(&n->m_v, v);
n->m_next = 0;
return n;
}
catch(...)
{
m_node_allocator.deallocate(n, 1);
throw;
}
}
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 m, bool u> bool c, bool m, bool u>
void void
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
::m_deallocate_nodes (node** array, size_type n) m_deallocate_node(node* n)
{ {
for (size_type i = 0; i < n; ++i) { get_allocator().destroy(&n->m_v);
node* p = array[i]; m_node_allocator.deallocate(n, 1);
while (p) {
node* tmp = p;
p = p->m_next;
m_deallocate_node (tmp);
} }
array[i] = 0;
}
}
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 m, bool u> bool c, bool m, bool u>
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::node** void
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::m_allocate_buckets (size_type n) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ m_deallocate_nodes(node** array, size_type n)
bucket_allocator_t alloc(m_node_allocator); {
for (size_type i = 0; i < n; ++i)
// We allocate one extra bucket to hold a sentinel, an arbitrary {
// non-null pointer. Iterator increment relies on this. node* p = array[i];
node** p = alloc.allocate(n+1); while (p)
std::fill(p, p+n, (node*) 0); {
p[n] = reinterpret_cast<node*>(0x1000); node* tmp = p;
return p; p = p->m_next;
} m_deallocate_node (tmp);
}
array[i] = 0;
}
}
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 m, bool u> bool c, bool m, bool u>
void typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::node**
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
::m_deallocate_buckets (node** p, size_type n) m_allocate_buckets(size_type n)
{ {
bucket_allocator_t alloc(m_node_allocator); bucket_allocator_t alloc(m_node_allocator);
alloc.deallocate(p, n+1);
} // We allocate one extra bucket to hold a sentinel, an arbitrary
// non-null pointer. Iterator increment relies on this.
node** p = alloc.allocate(n+1);
std::fill(p, p+n, (node*) 0);
p[n] = reinterpret_cast<node*>(0x1000);
return p;
}
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 m, bool u> bool c, bool m, bool u>
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> void
::hashtable(size_type bucket_hint, hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
const H1& h1, const H2& h2, const H& h, m_deallocate_buckets(node** p, size_type n)
const Eq& eq, const Ex& exk, {
const allocator_type& a) bucket_allocator_t alloc(m_node_allocator);
: Internal::rehash_base<RP,hashtable> (), alloc.deallocate(p, n+1);
Internal::hash_code_base<K,V,Ex,Eq,H1,H2,H,c> (exk, eq, h1, h2, h), }
Internal::map_base<K,V,Ex,u,hashtable> (),
m_node_allocator(a),
m_bucket_count (0),
m_element_count (0),
m_rehash_policy ()
{
m_bucket_count = m_rehash_policy.next_bkt(bucket_hint);
m_buckets = m_allocate_buckets (m_bucket_count);
}
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 m, bool u> bool c, bool m, bool u>
template <typename InIter> hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> hashtable(size_type bucket_hint,
::hashtable(InIter f, InIter l, const H1& h1, const H2& h2, const H& h,
size_type bucket_hint, const Eq& eq, const Ex& exk,
const H1& h1, const H2& h2, const H& h, const allocator_type& a)
const Eq& eq, const Ex& exk, : Internal::rehash_base<RP,hashtable>(),
const allocator_type& a) Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c>(exk, eq, h1, h2, h),
: Internal::rehash_base<RP,hashtable> (), Internal::map_base<K, V, Ex, u, hashtable>(),
Internal::hash_code_base<K,V,Ex,Eq,H1,H2,H,c> (exk, eq, h1, h2, h), m_node_allocator(a),
Internal::map_base<K,V,Ex,u,hashtable> (), m_bucket_count(0),
m_node_allocator(a), m_element_count(0),
m_bucket_count (0), m_rehash_policy()
m_element_count (0), {
m_rehash_policy () m_bucket_count = m_rehash_policy.next_bkt(bucket_hint);
{ m_buckets = m_allocate_buckets(m_bucket_count);
m_bucket_count = std::max(m_rehash_policy.next_bkt(bucket_hint), }
m_rehash_policy.bkt_for_elements(Internal::distance_fw(f, l)));
m_buckets = m_allocate_buckets (m_bucket_count);
try {
for (; f != l; ++f)
this->insert (*f);
}
catch(...) {
clear();
m_deallocate_buckets (m_buckets, m_bucket_count);
throw;
}
}
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 m, bool u> bool c, bool m, bool u>
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> template<typename InIter>
::hashtable(const hashtable& ht) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
: Internal::rehash_base<RP,hashtable> (ht), hashtable(InIter f, InIter l,
Internal::hash_code_base<K,V,Ex,Eq,H1,H2,H,c> (ht), size_type bucket_hint,
Internal::map_base<K,V,Ex,u,hashtable> (ht), const H1& h1, const H2& h2, const H& h,
m_node_allocator(ht.get_allocator()), const Eq& eq, const Ex& exk,
m_bucket_count (ht.m_bucket_count), const allocator_type& a)
m_element_count (ht.m_element_count), : Internal::rehash_base<RP,hashtable>(),
m_rehash_policy (ht.m_rehash_policy) Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c> (exk, eq,
{ h1, h2, h),
m_buckets = m_allocate_buckets (m_bucket_count); Internal::map_base<K,V,Ex,u,hashtable>(),
try { m_node_allocator(a),
for (size_t i = 0; i < ht.m_bucket_count; ++i) { m_bucket_count (0),
node* n = ht.m_buckets[i]; m_element_count(0),
node** tail = m_buckets + i; m_rehash_policy()
while (n) { {
*tail = m_allocate_node (n); m_bucket_count = std::max(m_rehash_policy.next_bkt(bucket_hint),
(*tail).copy_code_from (n); m_rehash_policy.
tail = &((*tail)->m_next); bkt_for_elements(Internal::
n = n->m_next; distance_fw(f, l)));
m_buckets = m_allocate_buckets(m_bucket_count);
try
{
for (; f != l; ++f)
this->insert(*f);
}
catch(...)
{
clear();
m_deallocate_buckets(m_buckets, m_bucket_count);
throw;
}
} }
template<typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
hashtable(const hashtable& ht)
: Internal::rehash_base<RP, hashtable>(ht),
Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c>(ht),
Internal::map_base<K, V, Ex, u, hashtable>(ht),
m_node_allocator(ht.get_allocator()),
m_bucket_count(ht.m_bucket_count),
m_element_count(ht.m_element_count),
m_rehash_policy(ht.m_rehash_policy)
{
m_buckets = m_allocate_buckets (m_bucket_count);
try
{
for (size_t i = 0; i < ht.m_bucket_count; ++i)
{
node* n = ht.m_buckets[i];
node** tail = m_buckets + i;
while (n)
{
*tail = m_allocate_node(n);
(*tail).copy_code_from(n);
tail = &((*tail)->m_next);
n = n->m_next;
}
}
}
catch (...)
{
clear();
m_deallocate_buckets (m_buckets, m_bucket_count);
throw;
}
} }
}
catch (...) {
clear();
m_deallocate_buckets (m_buckets, m_bucket_count);
throw;
}
}
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>&
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::operator= (const hashtable& ht)
{
hashtable tmp(ht);
this->swap(tmp);
return *this;
}
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::~hashtable()
{
clear();
m_deallocate_buckets(m_buckets, m_bucket_count);
}
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
void hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::swap (hashtable& x)
{
// The only base class with member variables is hash_code_base. We
// define hash_code_base::m_swap because different specializations
// have different members.
Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c>::m_swap(x);
// open LWG issue 431
// std::swap(m_node_allocator, x.m_node_allocator);
std::swap (m_rehash_policy, x.m_rehash_policy);
std::swap (m_buckets, x.m_buckets);
std::swap (m_bucket_count, x.m_bucket_count);
std::swap (m_element_count, x.m_element_count);
}
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 m, bool u> bool c, bool m, bool u>
void hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>&
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::rehash_policy (const RP& pol) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ operator=(const hashtable& ht)
m_rehash_policy = pol; {
size_type n_bkt = pol.bkt_for_elements(m_element_count); hashtable tmp(ht);
if (n_bkt > m_bucket_count) this->swap(tmp);
m_rehash (n_bkt); return *this;
} }
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::iterator
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::find (const key_type& k)
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count());
node* p = find_node (m_buckets[n], k, code);
return p ? iterator(p, m_buckets + n) : this->end();
}
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::const_iterator
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::find (const key_type& k) const
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count());
node* p = find_node (m_buckets[n], k, code);
return p ? const_iterator(p, m_buckets + n) : this->end();
}
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::size_type
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::count (const key_type& k) const
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count());
size_t result = 0;
for (node* p = m_buckets[n]; p ; p = p->m_next)
if (this->compare (k, code, p))
++result;
return result;
}
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
std::pair<typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::iterator,
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::iterator>
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::equal_range (const key_type& k)
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count());
node** head = m_buckets + n;
node* p = find_node (*head, k, code);
if (p) {
node* p1 = p->m_next;
for (; p1 ; p1 = p1->m_next)
if (!this->compare (k, code, p1))
break;
iterator first(p, head);
iterator last(p1, head);
if (!p1)
last.m_incr_bucket();
return std::make_pair(first, last);
}
else
return std::make_pair (this->end(), this->end());
}
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
std::pair<typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::const_iterator,
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::const_iterator>
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::equal_range (const key_type& k) const
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count());
node** head = m_buckets + n;
node* p = find_node (*head, k, code);
if (p) {
node* p1 = p->m_next;
for (; p1 ; p1 = p1->m_next)
if (!this->compare (k, code, p1))
break;
const_iterator first(p, head);
const_iterator last(p1, head);
if (!p1)
last.m_incr_bucket();
return std::make_pair(first, last);
}
else
return std::make_pair (this->end(), this->end());
}
// Find the node whose key compares equal to k, beginning the search
// at p (usually the head of a bucket). Return nil if no node is found.
template <typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::node*
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>
::find_node (node* p, const key_type& k, typename hashtable::hash_code_t code)
{
for ( ; p ; p = p->m_next)
if (this->compare (k, code, p))
return p;
return false;
}
// Insert v if no element with its key is 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 m, bool u>
bool c, bool m, bool u> hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
std::pair<typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::iterator, bool> ~hashtable()
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> {
::insert (const value_type& v, std::tr1::true_type) clear();
{ m_deallocate_buckets(m_buckets, m_bucket_count);
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 = find_node (m_buckets[n], k, code)) template<typename K, typename V,
return std::make_pair(iterator(p, m_buckets + n), false); typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
void
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
swap(hashtable& x)
{
// The only base class with member variables is hash_code_base. We
// define hash_code_base::m_swap because different specializations
// have different members.
Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c>::m_swap(x);
// open LWG issue 431
// std::swap(m_node_allocator, x.m_node_allocator);
std::swap(m_rehash_policy, x.m_rehash_policy);
std::swap(m_buckets, x.m_buckets);
std::swap(m_bucket_count, x.m_bucket_count);
std::swap(m_element_count, x.m_element_count);
}
std::pair<bool, size_t> do_rehash template<typename K, typename V,
= m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1); typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
void
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
rehash_policy(const RP& pol)
{
m_rehash_policy = pol;
size_type n_bkt = pol.bkt_for_elements(m_element_count);
if (n_bkt > m_bucket_count)
m_rehash (n_bkt);
}
// Allocate the new node before doing the rehash so that we don't template<typename K, typename V,
// do a rehash if the allocation throws. typename A, typename Ex, typename Eq,
node* new_node = m_allocate_node (v); typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::iterator
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
find(const key_type& k)
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index(k, code, this->bucket_count());
node* p = find_node (m_buckets[n], k, code);
return p ? iterator(p, m_buckets + n) : this->end();
}
template<typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::const_iterator
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
find(const key_type& k) const
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index(k, code, this->bucket_count());
node* p = find_node (m_buckets[n], k, code);
return p ? const_iterator(p, m_buckets + n) : this->end();
}
template<typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::size_type
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
count(const key_type& k) const
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count());
size_t result = 0;
for (node* p = m_buckets[n]; p ; p = p->m_next)
if (this->compare (k, code, p))
++result;
return result;
}
try { template<typename K, typename V,
if (do_rehash.first) { typename A, typename Ex, typename Eq,
n = this->bucket_index (k, code, do_rehash.second); typename H1, typename H2, typename H, typename RP,
m_rehash(do_rehash.second); bool c, bool m, bool u>
std::pair<typename hashtable<K, V, A, Ex, Eq, H1,
H2, H, RP, c, m, u>::iterator,
typename hashtable<K, V, A, Ex, Eq, H1,
H2, H, RP, c, m, u>::iterator>
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
equal_range(const key_type& k)
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index(k, code, this->bucket_count());
node** head = m_buckets + n;
node* p = find_node (*head, k, code);
if (p)
{
node* p1 = p->m_next;
for (; p1 ; p1 = p1->m_next)
if (!this->compare (k, code, p1))
break;
iterator first(p, head);
iterator last(p1, head);
if (!p1)
last.m_incr_bucket();
return std::make_pair(first, last);
}
else
return std::make_pair(this->end(), this->end());
} }
new_node->m_next = m_buckets[n]; template<typename K, typename V,
m_buckets[n] = new_node; typename A, typename Ex, typename Eq,
++m_element_count; typename H1, typename H2, typename H, typename RP,
return std::make_pair(iterator (new_node, m_buckets + n), true); bool c, bool m, bool u>
} std::pair<typename hashtable<K, V, A, Ex, Eq, H1,
catch (...) { H2, H, RP, c, m, u>::const_iterator,
m_deallocate_node (new_node); typename hashtable<K, V, A, Ex, Eq, H1,
throw; H2, H, RP, c, m, u>::const_iterator>
} hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
} equal_range(const key_type& k) const
{
typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index(k, code, this->bucket_count());
node** head = m_buckets + n;
node* p = find_node (*head, k, code);
if (p)
{
node* p1 = p->m_next;
for (; p1 ; p1 = p1->m_next)
if (!this->compare (k, code, p1))
break;
const_iterator first(p, head);
const_iterator last(p1, head);
if (!p1)
last.m_incr_bucket();
return std::make_pair(first, last);
}
else
return std::make_pair(this->end(), this->end());
}
// Insert v unconditionally. // Find the node whose key compares equal to k, beginning the search
template <typename K, typename V, // at p (usually the head of a bucket). Return nil if no node is found.
typename A, typename Ex, typename Eq, template<typename K, typename V,
typename H1, typename H2, typename H, typename RP, typename A, typename Ex, typename Eq,
bool c, bool m, bool u> typename H1, typename H2, typename H, typename RP,
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::iterator bool c, bool m, bool u>
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::node*
::insert (const value_type& v, std::tr1::false_type) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ find_node(node* p, const key_type& k, typename hashtable::hash_code_t code)
std::pair<bool, std::size_t> do_rehash {
= m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1); for ( ; p ; p = p->m_next)
if (do_rehash.first) if (this->compare (k, code, p))
m_rehash(do_rehash.second); return p;
return false;
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);
node* new_node = m_allocate_node (v);
node* prev = find_node (m_buckets[n], k, code);
if (prev) {
new_node->m_next = prev->m_next;
prev->m_next = new_node;
}
else {
new_node->m_next = m_buckets[n];
m_buckets[n] = new_node;
}
++m_element_count; // Insert v if no element with its key is already present.
return iterator (new_node, 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 m, bool u>
std::pair<typename hashtable<K, V, A, Ex, Eq, H1,
H2, H, RP, c, m, u>::iterator, bool>
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
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 = find_node(m_buckets[n], k, code))
return std::make_pair(iterator(p, m_buckets + n), false);
std::pair<bool, size_t> do_rehash
= 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
// do a rehash if the allocation throws.
node* new_node = m_allocate_node (v);
try
{
if (do_rehash.first)
{
n = this->bucket_index(k, code, do_rehash.second);
m_rehash(do_rehash.second);
}
new_node->m_next = m_buckets[n];
m_buckets[n] = new_node;
++m_element_count;
return std::make_pair(iterator(new_node, m_buckets + n), true);
}
catch (...)
{
m_deallocate_node (new_node);
throw;
}
}
// Insert v unconditionally.
template<typename K, typename V,
typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u>
typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::iterator
hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
insert(const value_type& v, std::tr1::false_type)
{
std::pair<bool, std::size_t> do_rehash
= m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1);
if (do_rehash.first)
m_rehash(do_rehash.second);
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);
node* new_node = m_allocate_node (v);
node* prev = find_node(m_buckets[n], k, code);
if (prev)
{
new_node->m_next = prev->m_next;
prev->m_next = new_node;
}
else
{
new_node->m_next = m_buckets[n];
m_buckets[n] = new_node;
}
++m_element_count;
return iterator(new_node, m_buckets + n);
}
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 m, bool u> bool c, bool m, bool u>
template <typename InIter> template<typename InIter>
void void
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::insert(InIter first, InIter last) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ insert(InIter first, InIter last)
size_type n_elt = Internal::distance_fw (first, last); {
std::pair<bool, std::size_t> do_rehash size_type n_elt = Internal::distance_fw (first, last);
= m_rehash_policy.need_rehash(m_bucket_count, m_element_count, n_elt); std::pair<bool, std::size_t> do_rehash
if (do_rehash.first) = m_rehash_policy.need_rehash(m_bucket_count, m_element_count, n_elt);
m_rehash(do_rehash.second); if (do_rehash.first)
m_rehash(do_rehash.second);
for (; first != last; ++first)
this->insert (*first); for (; first != last; ++first)
} this->insert (*first);
}
// XXX We're following the TR in giving this a return type of void, // XXX We're following the TR in giving this a return type of void,
// but that ought to change. The return type should be const_iterator, // but that ought to change. The return type should be const_iterator,
// and it should return the iterator following the one we've erased. // and it should return the iterator following the one we've erased.
// That would simplify range erase. // That would simplify range erase.
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 m, bool u> bool c, bool m, bool u>
void hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::erase (const_iterator i) void
{ hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
node* p = i.m_cur_node; erase(const_iterator i)
node* cur = *i.m_cur_bucket; {
if (cur == p) node* p = i.m_cur_node;
*i.m_cur_bucket = cur->m_next; node* cur = *i.m_cur_bucket;
else { if (cur == p)
node* next = cur->m_next; *i.m_cur_bucket = cur->m_next;
while (next != p) { else
cur = next; {
next = cur->m_next; 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;
} }
cur->m_next = next->m_next;
}
m_deallocate_node (p);
--m_element_count;
}
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 m, bool u> bool c, bool m, bool u>
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::size_type typename hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::size_type
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::erase(const key_type& k) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ erase(const key_type& k)
typename hashtable::hash_code_t code = this->m_hash_code (k); {
size_type n = this->bucket_index (k, code, m_bucket_count); typename hashtable::hash_code_t code = this->m_hash_code (k);
size_type n = this->bucket_index(k, code, m_bucket_count);
node** slot = m_buckets + n;
while (*slot && ! this->compare (k, code, *slot)) node** slot = m_buckets + n;
slot = &((*slot)->m_next); while (*slot && ! this->compare (k, code, *slot))
slot = &((*slot)->m_next);
while (*slot && this->compare (k, code, *slot)) {
node* n = *slot; while (*slot && this->compare (k, code, *slot))
*slot = n->m_next; {
m_deallocate_node (n); node* n = *slot;
--m_element_count; *slot = n->m_next;
} m_deallocate_node (n);
} --m_element_count;
}
}
// ??? This could be optimized by taking advantage of the bucket // ??? This could be optimized by taking advantage of the bucket
// structure, but it's not clear that it's worth doing. It probably // structure, but it's not clear that it's worth doing. It probably
// wouldn't even be an optimization unless the load factor is large. // wouldn't even be an optimization unless the load factor is large.
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 m, bool u> bool c, bool m, bool u>
void hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> void
::erase(const_iterator first, const_iterator last) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ erase(const_iterator first, const_iterator last)
while (first != last) { {
const_iterator next = first; while (first != last)
++next; {
this->erase(first); const_iterator next = first;
first = next; ++next;
} this->erase(first);
} first = next;
}
}
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 m, bool u> bool c, bool m, bool u>
void hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::clear() void
{ hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
m_deallocate_nodes (m_buckets, m_bucket_count); clear()
m_element_count = 0; {
} m_deallocate_nodes(m_buckets, m_bucket_count);
m_element_count = 0;
}
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 m, bool u> bool c, bool m, bool u>
void void
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::m_rehash (size_type N) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ m_rehash(size_type N)
node** new_array = m_allocate_buckets (N); {
try { node** new_array = m_allocate_buckets (N);
for (size_type i = 0; i < m_bucket_count; ++i) try
while (node* p = m_buckets[i]) { {
size_type new_index = this->bucket_index (p, N); for (size_type i = 0; i < m_bucket_count; ++i)
m_buckets[i] = p->m_next; while (node* p = m_buckets[i])
p->m_next = new_array[new_index]; {
new_array[new_index] = p; size_type new_index = this->bucket_index (p, N);
} m_buckets[i] = p->m_next;
m_deallocate_buckets (m_buckets, m_bucket_count); p->m_next = new_array[new_index];
m_bucket_count = N; new_array[new_index] = p;
m_buckets = new_array; }
} m_deallocate_buckets(m_buckets, m_bucket_count);
catch (...) { m_bucket_count = N;
// A failure here means that a hash function threw an exception. m_buckets = new_array;
// We can't restore the previous state without calling the hash }
// function again, so the only sensible recovery is to delete catch (...)
// everything. {
m_deallocate_nodes (new_array, N); // A failure here means that a hash function threw an exception.
m_deallocate_buckets (new_array, N); // We can't restore the previous state without calling the hash
m_deallocate_nodes (m_buckets, m_bucket_count); // function again, so the only sensible recovery is to delete
m_element_count = 0; // everything.
throw; m_deallocate_nodes(new_array, N);
} m_deallocate_buckets(new_array, N);
m_deallocate_nodes(m_buckets, m_bucket_count);
m_element_count = 0;
throw;
}
}
} }
} // Namespace std::tr1
} } // Namespace std::tr1
#endif /* GNU_LIBSTDCXX_TR1_HASHTABLE_ */ #endif /* GNU_LIBSTDCXX_TR1_HASHTABLE_ */
...@@ -40,127 +40,131 @@ ...@@ -40,127 +40,131 @@
#include <utility> #include <utility>
#include <memory> #include <memory>
namespace std { namespace tr1 { namespace std
// XXX When we get typedef templates these class definitions will be unnecessary.
template <class Key, class T,
class Hash = hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T> >,
bool cache_hash_code = false>
class unordered_map
: public hashtable <Key, std::pair<const Key, T>,
Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, true, true>
{ {
typedef hashtable <Key, std::pair<const Key, T>, namespace tr1
Alloc, {
Internal::extract1st<std::pair<const Key, T> >, Pred, // XXX When we get typedef templates these class definitions
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, // will be unnecessary.
Internal::prime_rehash_policy,
cache_hash_code, true, true> template<class Key, class T,
Base; class Hash = hash<Key>,
class Pred = std::equal_to<Key>,
public: class Alloc = std::allocator<std::pair<const Key, T> >,
typedef typename Base::size_type size_type; bool cache_hash_code = false>
typedef typename Base::hasher hasher; class unordered_map
typedef typename Base::key_equal key_equal; : public hashtable <Key, std::pair<const Key, T>,
typedef typename Base::allocator_type allocator_type; Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred,
explicit unordered_map(size_type n = 10, Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, true, true>
{
typedef hashtable <Key, std::pair<const Key, T>,
Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred,
Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, true, true>
Base;
public:
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type;
explicit
unordered_map(size_type n = 10,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: Base(n, hf, Internal::mod_range_hashing(),
Internal::default_ranged_hash(),
eql, Internal::extract1st<std::pair<const Key, T> >(), a)
{ }
template<typename InputIterator>
unordered_map(InputIterator f, InputIterator l,
size_type n = 10,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: Base (f, l, n, hf, Internal::mod_range_hashing(),
Internal::default_ranged_hash(),
eql, Internal::extract1st<std::pair<const Key, T> >(), a)
{ }
};
template<class Key, class T,
class Hash = hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T> >,
bool cache_hash_code = false>
class unordered_multimap
: public hashtable <Key, std::pair<const Key, T>,
Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred,
Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, true, false>
{
typedef hashtable <Key, std::pair<const Key, T>,
Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred,
Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, true, false>
Base;
public:
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type;
explicit
unordered_multimap(size_type n = 10,
const hasher& hf = hasher(), const hasher& hf = hasher(),
const key_equal& eql = key_equal(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type()) const allocator_type& a = allocator_type())
: Base (n, : Base (n, hf, Internal::mod_range_hashing(),
hf, Internal::mod_range_hashing(), Internal::default_ranged_hash(), Internal::default_ranged_hash(),
eql, Internal::extract1st<std::pair<const Key, T> >(), eql, Internal::extract1st<std::pair<const Key, T> >(), a)
a) { }
{ }
template <typename InputIterator> template<typename InputIterator>
unordered_map(InputIterator f, InputIterator l, unordered_multimap(InputIterator f, InputIterator l,
size_type n = 10, typename Base::size_type n = 0,
const hasher& hf = hasher(), const hasher& hf = hasher(),
const key_equal& eql = key_equal(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type()) const allocator_type& a = allocator_type())
: Base (f, l, : Base (f, l, n, hf, Internal::mod_range_hashing(),
n, Internal::default_ranged_hash(),
hf, Internal::mod_range_hashing(), Internal::default_ranged_hash(), eql, Internal::extract1st<std::pair<const Key, T> >(), a)
eql, Internal::extract1st<std::pair<const Key, T> >(), { }
a) };
{ }
}; template<class Key, class T, class Hash, class Pred, class Alloc,
bool cache_hash_code>
template <class Key, class T, inline void
class Hash = hash<Key>, swap(unordered_map<Key, T, Hash, Pred, Alloc, cache_hash_code>& x,
class Pred = std::equal_to<Key>, unordered_map<Key, T, Hash, Pred, Alloc, cache_hash_code>& y)
class Alloc = std::allocator<std::pair<const Key, T> >, { x.swap(y); }
bool cache_hash_code = false>
class unordered_multimap template<class Key, class T, class Hash, class Pred, class Alloc,
: public hashtable <Key, std::pair<const Key, T>, bool cache_hash_code>
Alloc, inline void
Internal::extract1st<std::pair<const Key, T> >, Pred, swap(unordered_multimap<Key, T, Hash, Pred, Alloc, cache_hash_code>& x,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, unordered_multimap<Key, T, Hash, Pred, Alloc, cache_hash_code>& y)
Internal::prime_rehash_policy, { x.swap(y); }
cache_hash_code, true, false>
{
typedef hashtable <Key, std::pair<const Key, T>,
Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, true, false>
Base;
public:
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type;
explicit unordered_multimap(size_type n = 10,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: Base (n,
hf, Internal::mod_range_hashing(), Internal::default_ranged_hash(),
eql, Internal::extract1st<std::pair<const Key, T> >(),
a)
{ }
template <typename InputIterator>
unordered_multimap(InputIterator f, InputIterator l,
typename Base::size_type n = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: Base (f, l,
n,
hf, Internal::mod_range_hashing(), Internal::default_ranged_hash(),
eql, Internal::extract1st<std::pair<const Key, T> >(),
a)
{ }
};
template <class Key, class T, class Hash, class Pred, class Alloc, bool cache_hash_code>
inline void swap (unordered_map<Key, T, Hash, Pred, Alloc, cache_hash_code>& x,
unordered_map<Key, T, Hash, Pred, Alloc, cache_hash_code>& y)
{
x.swap(y);
}
template <class Key, class T, class Hash, class Pred, class Alloc, bool cache_hash_code>
inline void swap (unordered_multimap<Key, T, Hash, Pred, Alloc, cache_hash_code>& x,
unordered_multimap<Key, T, Hash, Pred, Alloc, cache_hash_code>& y)
{
x.swap(y);
} }
}
} }
#endif /* GNU_LIBSTDCXX_TR1_UNORDERED_MAP_ */ #endif /* GNU_LIBSTDCXX_TR1_UNORDERED_MAP_ */
...@@ -38,123 +38,128 @@ ...@@ -38,123 +38,128 @@
#include <tr1/functional> #include <tr1/functional>
#include <memory> #include <memory>
namespace std { namespace tr1 { namespace std
{
// XXX When we get typedef templates these class definitions will be unnecessary. namespace tr1
template <class Value,
class Hash = hash<Value>,
class Pred = std::equal_to<Value>,
class Alloc = std::allocator<Value>,
bool cache_hash_code = false>
class unordered_set
: public hashtable <Value, Value, Alloc,
Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, false, true>
{ {
typedef hashtable <Value, Value, Alloc,
Internal::identity<Value>, Pred, // XXX When we get typedef templates these class definitions
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, // will be unnecessary.
Internal::prime_rehash_policy,
cache_hash_code, false, true> template<class Value,
Base; class Hash = hash<Value>,
class Pred = std::equal_to<Value>,
public: class Alloc = std::allocator<Value>,
typedef typename Base::size_type size_type; bool cache_hash_code = false>
typedef typename Base::hasher hasher; class unordered_set
typedef typename Base::key_equal key_equal; : public hashtable<Value, Value, Alloc,
typedef typename Base::allocator_type allocator_type; Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing,
explicit unordered_set(size_type n = 10, Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, false, true>
{
typedef hashtable<Value, Value, Alloc,
Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, false, true>
Base;
public:
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type;
explicit
unordered_set(size_type n = 10,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: Base (n, hf, Internal::mod_range_hashing(),
Internal::default_ranged_hash(),
eql, Internal::identity<Value>(), a)
{ }
template<typename InputIterator>
unordered_set(InputIterator f, InputIterator l,
size_type n = 10,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: Base (f, l, n, hf, Internal::mod_range_hashing(),
Internal::default_ranged_hash(),
eql, Internal::identity<Value>(), a)
{ }
};
template<class Value,
class Hash = hash<Value>,
class Pred = std::equal_to<Value>,
class Alloc = std::allocator<Value>,
bool cache_hash_code = false>
class unordered_multiset
: public hashtable <Value, Value, Alloc,
Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, false, false>
{
typedef hashtable<Value, Value, Alloc,
Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, false, false>
Base;
public:
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type;
explicit
unordered_multiset(size_type n = 10,
const hasher& hf = hasher(), const hasher& hf = hasher(),
const key_equal& eql = key_equal(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type()) const allocator_type& a = allocator_type())
: Base (n, : Base (n, hf, Internal::mod_range_hashing(),
hf, Internal::mod_range_hashing(), Internal::default_ranged_hash(), Internal::default_ranged_hash(),
eql, Internal::identity<Value>(), eql, Internal::identity<Value>(), a)
a) { }
{ }
template <typename InputIterator> template<typename InputIterator>
unordered_set(InputIterator f, InputIterator l, unordered_multiset(InputIterator f, InputIterator l,
size_type n = 10, typename Base::size_type n = 0,
const hasher& hf = hasher(), const hasher& hf = hasher(),
const key_equal& eql = key_equal(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type()) const allocator_type& a = allocator_type())
: Base (f, l, : Base (f, l, n, hf, Internal::mod_range_hashing(),
n, Internal::default_ranged_hash(), eql,
hf, Internal::mod_range_hashing(), Internal::default_ranged_hash(), Internal::identity<Value>(), a)
eql, Internal::identity<Value>(), { }
a) };
{ }
}; template<class Value, class Hash, class Pred, class Alloc,
bool cache_hash_code>
template <class Value, inline void
class Hash = hash<Value>, swap (unordered_set<Value, Hash, Pred, Alloc, cache_hash_code>& x,
class Pred = std::equal_to<Value>, unordered_set<Value, Hash, Pred, Alloc, cache_hash_code>& y)
class Alloc = std::allocator<Value>, { x.swap(y); }
bool cache_hash_code = false>
class unordered_multiset template<class Value, class Hash, class Pred, class Alloc,
: public hashtable <Value, Value, Alloc, bool cache_hash_code>
Internal::identity<Value>, Pred, inline void
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, swap(unordered_multiset<Value, Hash, Pred, Alloc, cache_hash_code>& x,
Internal::prime_rehash_policy, unordered_multiset<Value, Hash, Pred, Alloc, cache_hash_code>& y)
cache_hash_code, false, false> { x.swap(y); }
{
typedef hashtable <Value, Value, Alloc,
Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash,
Internal::prime_rehash_policy,
cache_hash_code, false, false>
Base;
public:
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type;
explicit unordered_multiset(size_type n = 10,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: Base (n,
hf, Internal::mod_range_hashing(), Internal::default_ranged_hash(),
eql, Internal::identity<Value>(),
a)
{ }
template <typename InputIterator>
unordered_multiset(InputIterator f, InputIterator l,
typename Base::size_type n = 0,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type())
: Base (f, l,
n,
hf, Internal::mod_range_hashing(), Internal::default_ranged_hash(),
eql, Internal::identity<Value>(),
a)
{ }
};
template <class Value, class Hash, class Pred, class Alloc, bool cache_hash_code>
inline void swap (unordered_set<Value, Hash, Pred, Alloc, cache_hash_code>& x,
unordered_set<Value, Hash, Pred, Alloc, cache_hash_code>& y)
{
x.swap(y);
}
template <class Value, class Hash, class Pred, class Alloc, bool cache_hash_code>
inline void swap (unordered_multiset<Value, Hash, Pred, Alloc, cache_hash_code>& x,
unordered_multiset<Value, Hash, Pred, Alloc, cache_hash_code>& y)
{
x.swap(y);
} }
}
} }
#endif /* GNU_LIBSTDCXX_TR1_UNORDERED_SET_ */ #endif /* GNU_LIBSTDCXX_TR1_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