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,39 +64,38 @@ ...@@ -64,39 +64,38 @@
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// 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)
{ {
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; typedef typename std::iterator_traits<Iterator>::iterator_category tag;
return distance_fw(first, last, 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, bool cache_hash_code>
struct hash_node;
template <typename Value> template<typename Value>
struct hash_node<Value, true> { struct hash_node<Value, true>
{
Value m_v; Value m_v;
std::size_t hash_code; std::size_t hash_code;
hash_node* m_next; hash_node* m_next;
}; };
template <typename Value> template<typename Value>
struct hash_node<Value, false> { struct hash_node<Value, false>
{
Value m_v; Value m_v;
hash_node* m_next; hash_node* m_next;
}; };
// Local iterators, used to iterate within a bucket but not between // Local iterators, used to iterate within a bucket but not between
// buckets. // buckets.
template<typename Value, bool cache>
struct node_iterator_base
{
node_iterator_base(hash_node<Value, cache>* p)
: m_cur(p) { }
template <typename Value, bool cache> void
struct node_iterator_base { incr()
node_iterator_base(hash_node<Value, cache>* p) : m_cur(p) { } { m_cur = m_cur->m_next; }
void incr() { m_cur = m_cur->m_next; }
hash_node<Value, cache>* m_cur; hash_node<Value, cache>* m_cur;
}; };
template <typename Value, bool cache> template<typename Value, bool cache>
inline bool operator== (const node_iterator_base<Value, cache>& x, inline bool
operator==(const node_iterator_base<Value, cache>& x,
const node_iterator_base<Value, cache>& y) const node_iterator_base<Value, cache>& y)
{ { return x.m_cur == y.m_cur; }
return x.m_cur == y.m_cur;
}
template <typename Value, bool cache> template<typename Value, bool cache>
inline bool operator!= (const node_iterator_base<Value, cache>& x, inline bool
operator!=(const node_iterator_base<Value, cache>& x,
const node_iterator_base<Value, cache>& y) const node_iterator_base<Value, cache>& y)
{ { return x.m_cur != y.m_cur; }
return x.m_cur != y.m_cur;
}
template <typename Value, bool is_const, bool cache> template<typename Value, bool is_const, bool cache>
struct node_iterator : public node_iterator_base<Value, cache> { struct node_iterator
: public node_iterator_base<Value, cache>
{
typedef Value value_type; typedef Value value_type;
typedef typename IF<is_const, const Value*, Value*>::type pointer; typedef typename IF<is_const, const Value*, Value*>::type pointer;
typedef typename IF<is_const, const Value&, Value&>::type reference; typedef typename IF<is_const, const Value&, Value&>::type reference;
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category; typedef std::forward_iterator_tag iterator_category;
explicit node_iterator (hash_node<Value, cache>* p = 0) explicit
node_iterator(hash_node<Value, cache>* p = 0)
: node_iterator_base<Value, cache>(p) { } : node_iterator_base<Value, cache>(p) { }
node_iterator (const node_iterator<Value, true, cache>& x)
node_iterator(const node_iterator<Value, true, cache>& x)
: node_iterator_base<Value, cache>(x.m_cur) { } : node_iterator_base<Value, cache>(x.m_cur) { }
reference operator*() const { return this->m_cur->m_v; } reference
pointer operator->() const { return &this->m_cur->m_v; } 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++() { this->incr(); return *this; } node_iterator
node_iterator operator++(int) operator++(int)
{ node_iterator tmp(*this); this->incr(); return tmp; } {
}; node_iterator tmp(*this);
this->incr();
return tmp;
}
};
template <typename Value, bool cache> template<typename Value, bool cache>
struct hashtable_iterator_base { struct hashtable_iterator_base
{
hashtable_iterator_base(hash_node<Value, cache>* node, hashtable_iterator_base(hash_node<Value, cache>* node,
hash_node<Value, cache>** bucket) hash_node<Value, cache>** bucket)
: m_cur_node (node), m_cur_bucket (bucket) : m_cur_node(node), m_cur_bucket(bucket)
{ } { }
void incr() { void
incr()
{
m_cur_node = m_cur_node->m_next; m_cur_node = m_cur_node->m_next;
if (!m_cur_node) if (!m_cur_node)
m_incr_bucket(); m_incr_bucket();
} }
void m_incr_bucket(); void
m_incr_bucket();
hash_node<Value, cache>* m_cur_node; hash_node<Value, cache>* m_cur_node;
hash_node<Value, cache>** m_cur_bucket; hash_node<Value, cache>** m_cur_bucket;
}; };
// Global iterators, used for arbitrary iteration within a hash
// table. Larger and more expensive than local iterators.
template <typename Value, bool cache> // Global iterators, used for arbitrary iteration within a hash
void hashtable_iterator_base<Value, cache>::m_incr_bucket() // table. Larger and more expensive than local iterators.
{ template<typename Value, bool cache>
void
hashtable_iterator_base<Value, cache>::
m_incr_bucket()
{
++m_cur_bucket; ++m_cur_bucket;
// This loop requires the bucket array to have a non-null sentinel // This loop requires the bucket array to have a non-null sentinel.
while (!*m_cur_bucket) while (!*m_cur_bucket)
++m_cur_bucket; ++m_cur_bucket;
m_cur_node = *m_cur_bucket; m_cur_node = *m_cur_bucket;
} }
template <typename Value, bool cache> template<typename Value, bool cache>
inline bool operator== (const hashtable_iterator_base<Value, cache>& x, inline bool
operator==(const hashtable_iterator_base<Value, cache>& x,
const hashtable_iterator_base<Value, cache>& y) 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> template<typename Value, bool cache>
inline bool operator!= (const hashtable_iterator_base<Value, cache>& x, inline bool
operator!=(const hashtable_iterator_base<Value, cache>& x,
const hashtable_iterator_base<Value, cache>& y) 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 is_const, bool cache> template<typename Value, bool is_const, bool cache>
struct hashtable_iterator : public hashtable_iterator_base<Value, cache> struct hashtable_iterator
{ : public hashtable_iterator_base<Value, cache>
{
typedef Value value_type; typedef Value value_type;
typedef typename IF<is_const, const Value*, Value*>::type pointer; typedef typename IF<is_const, const Value*, Value*>::type pointer;
typedef typename IF<is_const, const Value&, Value&>::type reference; typedef typename IF<is_const, const Value&, Value&>::type reference;
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category; typedef std::forward_iterator_tag iterator_category;
hashtable_iterator (hash_node<Value, cache>* p, hash_node<Value, cache>** b) hashtable_iterator(hash_node<Value, cache>* p,
hash_node<Value, cache>** b)
: hashtable_iterator_base<Value, cache>(p, b) { } : hashtable_iterator_base<Value, cache>(p, b) { }
hashtable_iterator (hash_node<Value, cache>** b)
hashtable_iterator(hash_node<Value, cache>** b)
: hashtable_iterator_base<Value, cache>(*b, b) { } : hashtable_iterator_base<Value, cache>(*b, b) { }
hashtable_iterator (const hashtable_iterator<Value, true, cache>& x)
hashtable_iterator(const hashtable_iterator<Value, true, cache>& x)
: hashtable_iterator_base<Value, cache>(x.m_cur_node, x.m_cur_bucket) { } : hashtable_iterator_base<Value, cache>(x.m_cur_node, x.m_cur_bucket) { }
reference operator*() const { return this->m_cur_node->m_v; } reference
pointer operator->() const { return &this->m_cur_node->m_v; } operator*() const
{ return this->m_cur_node->m_v; }
pointer
operator->() const
{ return &this->m_cur_node->m_v; }
hashtable_iterator&
operator++()
{
this->incr();
return *this;
}
hashtable_iterator& operator++() { this->incr(); return *this; } hashtable_iterator
hashtable_iterator operator++(int) operator++(int)
{ hashtable_iterator tmp(*this); this->incr(); return tmp; } {
}; hashtable_iterator tmp(*this);
this->incr();
return tmp; }
};
} // namespace Internal } // namespace Internal
...@@ -250,87 +296,101 @@ struct hashtable_iterator : public hashtable_iterator_base<Value, cache> ...@@ -250,87 +296,101 @@ 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. // The two key extraction policies used by the *set and *map variants.
template <typename T> template<typename T>
struct identity { struct identity
T operator()(const T& t) const { return t; } {
}; T
operator()(const T& t) const
{ return t; }
};
template <typename Pair> template<typename Pair>
struct extract1st { struct extract1st
typename Pair::first_type operator()(const Pair& p) const { return p.first; } {
}; typename Pair::first_type
operator()(const Pair& p) const
{ return p.first; }
};
// Default range hashing function: use division to fold a large number // Default range hashing function: use division to fold a large number
// into the range [0, N). // into the range [0, N).
struct mod_range_hashing struct mod_range_hashing
{ {
typedef std::size_t first_argument_type; typedef std::size_t first_argument_type;
typedef std::size_t second_argument_type; typedef std::size_t second_argument_type;
typedef std::size_t result_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
{
prime_rehash_policy(float z = 1.0);
float max_load_factor() const; float
max_load_factor() const;
// Return a bucket size no smaller than n. // Return a bucket size no smaller than n.
std::size_t next_bkt (std::size_t n) const; std::size_t
next_bkt(std::size_t n) const;
// Return a bucket count appropriate for n elements // Return a bucket count appropriate for n elements
std::size_t bkt_for_elements (std::size_t n) const; std::size_t
bkt_for_elements(std::size_t n) const;
// n_bkt is current bucket count, n_elt is current element count, // 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 // 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 // increase bucket count? If so, return make_pair(true, n), where n
// is the new bucket count. If not, return make_pair(false, 0). // is the new bucket count. If not, return make_pair(false, 0).
std::pair<bool, std::size_t> std::pair<bool, std::size_t>
need_rehash (std::size_t n_bkt, std::size_t n_elt, std::size_t n_ins) const; 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_max_load_factor;
float m_growth_factor; float m_growth_factor;
mutable std::size_t m_next_resize; mutable std::size_t m_next_resize;
}; };
// XXX This is a hack. prime_rehash_policy's member functions, and // XXX This is a hack. prime_rehash_policy's member functions, and
// certainly the list of primes, should be defined in a .cc file. // 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 // 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 // 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 // prime_rehash_policy's member functions to be inline, and there's
// certainly no good reason for X<> to exist at all. // certainly no good reason for X<> to exist at all.
struct lt { struct lt
template <typename X, typename Y> bool operator()(X x, Y y) { return x < y; } {
}; template<typename X, typename Y>
bool
operator()(X x, Y y)
{ return x < y; }
};
template <int dummy> template<int dummy>
struct X { struct X
{
static const int n_primes = 256; static const int n_primes = 256;
static const unsigned long primes[n_primes + 1]; static const unsigned long primes[n_primes + 1];
}; };
template <int dummy> template<int dummy>
const int X<dummy>::n_primes; const int X<dummy>::n_primes;
template <int dummy> template<int dummy>
const unsigned long X<dummy>::primes[n_primes + 1] = const unsigned long X<dummy>::primes[n_primes + 1] =
{ {
2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul, 2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul,
37ul, 41ul, 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul, 37ul, 41ul, 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul,
...@@ -376,67 +436,78 @@ const unsigned long X<dummy>::primes[n_primes + 1] = ...@@ -376,67 +436,78 @@ const unsigned long X<dummy>::primes[n_primes + 1] =
4294967291ul // sentinel so we don't have to test result of lower_bound 4294967291ul // sentinel so we don't have to test result of lower_bound
}; };
inline prime_rehash_policy::prime_rehash_policy (float z) inline
: m_max_load_factor(z), prime_rehash_policy::
m_growth_factor (2.f), prime_rehash_policy(float z)
m_next_resize (0) : m_max_load_factor(z), m_growth_factor(2.f), m_next_resize(0)
{ } { }
inline float prime_rehash_policy::max_load_factor() const inline float
{ prime_rehash_policy::
return m_max_load_factor; max_load_factor() const
} { return m_max_load_factor; }
// Return a prime no smaller than n. // Return a prime no smaller than n.
inline std::size_t prime_rehash_policy::next_bkt (std::size_t n) const inline std::size_t
{ prime_rehash_policy::
next_bkt(std::size_t n) const
{
const unsigned long* const last = X<0>::primes + X<0>::n_primes; const unsigned long* const last = X<0>::primes + X<0>::n_primes;
const unsigned long* p = std::lower_bound (X<0>::primes, last, n); 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)); m_next_resize = static_cast<std::size_t>(std::ceil(*p * m_max_load_factor));
return *p; return *p;
} }
// Return the smallest prime p such that alpha p >= n, where alpha // Return the smallest prime p such that alpha p >= n, where alpha
// is the load factor. // is the load factor.
inline std::size_t prime_rehash_policy::bkt_for_elements (std::size_t n) const 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 unsigned long* const last = X<0>::primes + X<0>::n_primes;
const float min_bkts = n / m_max_load_factor; const float min_bkts = n / m_max_load_factor;
const unsigned long* p = std::lower_bound (X<0>::primes, last, min_bkts, lt()); 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)); m_next_resize = static_cast<std::size_t>(std::ceil(*p * m_max_load_factor));
return *p; return *p;
} }
// Finds the smallest prime p such that alpha p > n_elt + n_ins. // Finds the smallest prime p such that alpha p > n_elt + n_ins.
// If p > n_bkt, return make_pair(true, p); otherwise return // If p > n_bkt, return make_pair(true, p); otherwise return
// make_pair(false, 0). In principle this isn't very different from // make_pair(false, 0). In principle this isn't very different from
// bkt_for_elements. // bkt_for_elements.
// The only tricky part is that we're caching the element count at // The only tricky part is that we're caching the element count at
// which we need to rehash, so we don't have to do a floating-point // which we need to rehash, so we don't have to do a floating-point
// multiply for every insertion. // multiply for every insertion.
inline std::pair<bool, std::size_t> inline std::pair<bool, std::size_t>
prime_rehash_policy prime_rehash_policy::
::need_rehash (std::size_t n_bkt, std::size_t n_elt, std::size_t n_ins) const need_rehash(std::size_t n_bkt, std::size_t n_elt, std::size_t n_ins) const
{ {
if (n_elt + n_ins > m_next_resize) { if (n_elt + n_ins > m_next_resize)
{
float min_bkts = (float(n_ins) + float(n_elt)) / m_max_load_factor; float min_bkts = (float(n_ins) + float(n_elt)) / m_max_load_factor;
if (min_bkts > n_bkt) { if (min_bkts > n_bkt)
{
min_bkts = std::max (min_bkts, m_growth_factor * 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* const last = X<0>::primes + X<0>::n_primes;
const unsigned long* p = std::lower_bound (X<0>::primes, last, min_bkts, lt()); const unsigned long* p = std::lower_bound (X<0>::primes, last,
m_next_resize = static_cast<std::size_t>(std::ceil(*p * m_max_load_factor)); min_bkts, lt());
m_next_resize =
static_cast<std::size_t>(std::ceil(*p * m_max_load_factor));
return std::make_pair(true, *p); return std::make_pair(true, *p);
} }
else { else
m_next_resize = static_cast<std::size_t>(std::ceil(n_bkt * m_max_load_factor)); {
m_next_resize =
static_cast<std::size_t>(std::ceil(n_bkt * m_max_load_factor));
return std::make_pair(false, 0); return std::make_pair(false, 0);
} }
} }
else else
return std::make_pair(false, 0); return std::make_pair(false, 0);
} }
} // namespace Internal } // namespace Internal
...@@ -449,276 +520,326 @@ prime_rehash_policy ...@@ -449,276 +520,326 @@ 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 // 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 // form pair<T1, T2> and a key extraction policy that returns the
// first part of the pair, the hashtable gets a mapped_type typedef. // first part of the pair, the hashtable gets a mapped_type typedef.
// If it satisfies those criteria and also has unique keys, then it // If it satisfies those criteria and also has unique keys, then it
// also gets an operator[]. // also gets an operator[].
template <typename K, typename V, typename Ex, bool unique, typename Hashtable> template<typename K, typename V, typename Ex, bool unique, typename Hashtable>
struct map_base { }; struct map_base { };
template <typename K, typename Pair, typename Hashtable> template<typename K, typename Pair, typename Hashtable>
struct map_base<K, Pair, extract1st<Pair>, false, Hashtable> struct map_base<K, Pair, extract1st<Pair>, false, Hashtable>
{ {
typedef typename Pair::second_type mapped_type; typedef typename Pair::second_type mapped_type;
}; };
template <typename K, typename Pair, typename Hashtable> template<typename K, typename Pair, typename Hashtable>
struct map_base<K, Pair, extract1st<Pair>, true, Hashtable> struct map_base<K, Pair, extract1st<Pair>, true, Hashtable>
{ {
typedef typename Pair::second_type mapped_type; typedef typename Pair::second_type mapped_type;
mapped_type& operator[](const K& k) {
mapped_type&
operator[](const K& k)
{
Hashtable* h = static_cast<Hashtable*>(this); Hashtable* h = static_cast<Hashtable*>(this);
typename Hashtable::iterator it = h->insert(std::make_pair(k, mapped_type())).first; typename Hashtable::iterator it =
h->insert(std::make_pair(k, mapped_type())).first;
return it->second; return it->second;
} }
}; };
// class template rehash_base. Give hashtable the max_load_factor // class template rehash_base. Give hashtable the max_load_factor
// functions iff the rehash policy is prime_rehash_policy. // functions iff the rehash policy is prime_rehash_policy.
template <typename RehashPolicy, typename Hashtable> template<typename RehashPolicy, typename Hashtable>
struct rehash_base { }; struct rehash_base { };
template <typename Hashtable> template<typename Hashtable>
struct rehash_base<prime_rehash_policy, Hashtable> struct rehash_base<prime_rehash_policy, Hashtable>
{ {
float max_load_factor() const { float
max_load_factor() const
{
const Hashtable* This = static_cast<const Hashtable*>(this); const Hashtable* This = static_cast<const Hashtable*>(this);
return This->rehash_policy()->max_load_factor(); return This->rehash_policy()->max_load_factor();
} }
void max_load_factor(float z) { void
max_load_factor(float z)
{
Hashtable* This = static_cast<Hashtable*>(this); Hashtable* This = static_cast<Hashtable*>(this);
This->rehash_policy(prime_rehash_policy(z)); This->rehash_policy(prime_rehash_policy(z));
} }
}; };
// Class template hash_code_base. Encapsulates two policy issues that // Class template hash_code_base. Encapsulates two policy issues that
// aren't quite orthogonal. // aren't quite orthogonal.
// (1) the difference between using a ranged hash function and using // (1) the difference between using a ranged hash function and using
// the combination of a hash function and a range-hashing function. // 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 // In the former case we don't have such things as hash codes, so
// we have a dummy type as placeholder. // we have a dummy type as placeholder.
// (2) Whether or not we cache hash codes. Caching hash codes is // (2) Whether or not we cache hash codes. Caching hash codes is
// meaningless if we have a ranged hash function. // meaningless if we have a ranged hash function.
// We also put the key extraction and equality comparison function // We also put the key extraction and equality comparison function
// objects here, for convenience. // objects here, for convenience.
// Primary template: unused except as a hook for specializations. // Primary template: unused except as a hook for specializations.
template <typename Key, typename Value, template<typename Key, typename Value,
typename ExtractKey, typename Equal, typename ExtractKey, typename Equal,
typename H1, typename H2, typename H, typename H1, typename H2, typename H,
bool cache_hash_code> bool cache_hash_code>
struct hash_code_base; struct hash_code_base;
// Specialization: ranged hash function, no caching hash codes. H1 // Specialization: ranged hash function, no caching hash codes. H1
// and H2 are provided but ignored. We define a dummy hash code type. // and H2 are provided but ignored. We define a dummy hash code type.
template <typename Key, typename Value, template<typename Key, typename Value,
typename ExtractKey, typename Equal, typename ExtractKey, typename Equal,
typename H1, typename H2, typename H> typename H1, typename H2, typename H>
struct hash_code_base <Key, Value, ExtractKey, Equal, H1, H2, H, false> struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H, false>
{ {
protected: protected:
hash_code_base (const ExtractKey& ex, const Equal& eq, hash_code_base(const ExtractKey& ex, const Equal& eq,
const H1&, const H2&, const H& h) const H1&, const H2&, const H& h)
: m_extract(ex), m_eq(eq), m_ranged_hash(h) { } : m_extract(ex), m_eq(eq), m_ranged_hash(h) { }
typedef void* hash_code_t; 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 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); } { 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 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
{ return m_eq (k, m_extract(n->m_v)); } { return m_eq (k, m_extract(n->m_v)); }
void copy_code (hash_node<Value, false>*, const hash_node<Value, false>*) const { } void
copy_code(hash_node<Value, false>*, const hash_node<Value, false>*) const
{ }
void m_swap(hash_code_base& x) { void
m_swap(hash_code_base& x)
{
m_extract.m_swap(x); m_extract.m_swap(x);
m_eq.m_swap(x); m_eq.m_swap(x);
m_ranged_hash.m_swap(x); m_ranged_hash.m_swap(x);
} }
protected: protected:
ExtractKey m_extract; ExtractKey m_extract;
Equal m_eq; Equal m_eq;
H m_ranged_hash; H m_ranged_hash;
}; };
// No specialization for ranged hash function while caching hash codes. // No specialization for ranged hash function while caching hash codes.
// That combination is meaningless, and trying to do it is an error. // That combination is meaningless, and trying to do it is an error.
// Specialization: ranged hash function, cache hash codes. This // Specialization: ranged hash function, cache hash codes. This
// combination is meaningless, so we provide only a declaration // combination is meaningless, so we provide only a declaration
// and no definition. // and no definition.
template <typename Key, typename Value, template<typename Key, typename Value,
typename ExtractKey, typename Equal, typename ExtractKey, typename Equal,
typename H1, typename H2, typename H> typename H1, typename H2, typename H>
struct hash_code_base <Key, Value, ExtractKey, Equal, H1, H2, H, true>; struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H, true>;
// Specialization: hash function and range-hashing function, no // Specialization: hash function and range-hashing function, no
// caching of hash codes. H is provided but ignored. Provides // caching of hash codes. H is provided but ignored. Provides
// typedef and accessor required by TR1. // typedef and accessor required by TR1.
template <typename Key, typename Value, template<typename Key, typename Value,
typename ExtractKey, typename Equal, typename ExtractKey, typename Equal,
typename H1, typename H2> typename H1, typename H2>
struct hash_code_base <Key, Value, ExtractKey, Equal, H1, H2, default_ranged_hash, false> struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2,
{ default_ranged_hash, false>
{
typedef H1 hasher; typedef H1 hasher;
hasher hash_function() const { return m_h1; }
protected: hasher
hash_code_base (const ExtractKey& ex, const Equal& eq, 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&) const H1& h1, const H2& h2, const default_ranged_hash&)
: m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { } : m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { }
typedef std::size_t hash_code_t; 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 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); } { 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 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)); } { return m_eq (k, m_extract(n->m_v)); }
void copy_code (hash_node<Value, false>*, const hash_node<Value, false>*) const { } void
copy_code(hash_node<Value, false>*, const hash_node<Value, false>*) const
{ }
void m_swap(hash_code_base& x) { void
m_swap(hash_code_base& x)
{
m_extract.m_swap(x); m_extract.m_swap(x);
m_eq.m_swap(x); m_eq.m_swap(x);
m_h1.m_swap(x); m_h1.m_swap(x);
m_h2.m_swap(x); m_h2.m_swap(x);
} }
protected: protected:
ExtractKey m_extract; ExtractKey m_extract;
Equal m_eq; Equal m_eq;
H1 m_h1; H1 m_h1;
H2 m_h2; H2 m_h2;
}; };
// Specialization: hash function and range-hashing function, // Specialization: hash function and range-hashing function,
// caching hash codes. H is provided but ignored. Provides // caching hash codes. H is provided but ignored. Provides
// typedef and accessor required by TR1. // typedef and accessor required by TR1.
template <typename Key, typename Value, template<typename Key, typename Value,
typename ExtractKey, typename Equal, typename ExtractKey, typename Equal,
typename H1, typename H2> typename H1, typename H2>
struct hash_code_base <Key, Value, ExtractKey, Equal, H1, H2, default_ranged_hash, true> struct hash_code_base<Key, Value, ExtractKey, Equal, H1, H2,
{ default_ranged_hash, true>
{
typedef H1 hasher; typedef H1 hasher;
hasher hash_function() const { return m_h1; }
protected: hasher
hash_code_base (const ExtractKey& ex, const Equal& eq, 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&) const H1& h1, const H2& h2, const default_ranged_hash&)
: m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { } : m_extract(ex), m_eq(eq), m_h1(h1), m_h2(h2) { }
typedef std::size_t hash_code_t; 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 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); } { return m_h2 (c, N); }
std::size_t bucket_index (const hash_node<Value, true>* p, std::size_t N) const { std::size_t
return m_h2 (p->hash_code, N); 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 bool
{ return c == n->hash_code && m_eq (k, m_extract(n->m_v)); } 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 void
copy_code(hash_node<Value, true>* to,
const hash_node<Value, true>* from) const
{ to->hash_code = from->hash_code; } { to->hash_code = from->hash_code; }
void m_swap(hash_code_base& x) { void
m_swap(hash_code_base& x)
{
m_extract.m_swap(x); m_extract.m_swap(x);
m_eq.m_swap(x); m_eq.m_swap(x);
m_h1.m_swap(x); m_h1.m_swap(x);
m_h2.m_swap(x); m_h2.m_swap(x);
} }
protected: protected:
ExtractKey m_extract; ExtractKey m_extract;
Equal m_eq; Equal m_eq;
H1 m_h1; H1 m_h1;
H2 m_h2; H2 m_h2;
}; };
} // namespace internal } // namespace internal
namespace std { namespace tr1 { namespace std
{
//---------------------------------------------------------------------- namespace tr1
// Class template hashtable, class definition. {
//----------------------------------------------------------------------
// Class template hashtable, class definition.
// Meaning of class template hashtable's template parameters // Meaning of class template hashtable's template parameters
// Key and Value: arbitrary CopyConstructible types. // Key and Value: arbitrary CopyConstructible types.
// Allocator: an allocator type ([lib.allocator.requirements]) whose // Allocator: an allocator type ([lib.allocator.requirements]) whose
// value type is Value. // value type is Value.
// ExtractKey: function object that takes a object of type Value // ExtractKey: function object that takes a object of type Value
// and returns a value of type Key. // and returns a value of type Key.
// Equal: function object that takes two objects of type k and returns // 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. // 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 // H1: the hash function. A unary function object with argument type
// Key and result type size_t. Return values should be distributed // Key and result type size_t. Return values should be distributed
// over the entire range [0, numeric_limits<size_t>:::max()]. // over the entire range [0, numeric_limits<size_t>:::max()].
// H2: the range-hashing function (in the terminology of Tavori and // H2: the range-hashing function (in the terminology of Tavori and
// Dreizin). A binary function object whose argument types and result // Dreizin). A binary function object whose argument types and result
// type are all size_t. Given arguments r and N, the return value is // type are all size_t. Given arguments r and N, the return value is
// in the range [0, N). // in the range [0, N).
// H: the ranged hash function (Tavori and Dreizin). A binary function // H: the ranged hash function (Tavori and Dreizin). A binary function
// whose argument types are Key and size_t and whose result type is // 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 // 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 // [0, N). Default: h(k, N) = h2(h1(k), N). If H is anything other
// than the default, H1 and H2 are ignored. // than the default, H1 and H2 are ignored.
// RehashPolicy: Policy class with three members, all of which govern // RehashPolicy: Policy class with three members, all of which govern
// the bucket count. n_bkt(n) returns a bucket count no smaller // the bucket count. n_bkt(n) returns a bucket count no smaller
// than n. bkt_for_elements(n) returns a bucket count appropriate // 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) // 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 // determines whether, if the current bucket count is n_bkt and the
// current element count is n_elt, we need to increase the bucket // 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 // count. If so, returns make_pair(true, n), where n is the new
// bucket count. If not, returns make_pair(false, <anything>). // bucket count. If not, returns make_pair(false, <anything>).
// ??? Right now it is hard-wired that the number of buckets never // ??? Right now it is hard-wired that the number of buckets never
// shrinks. Should we allow RehashPolicy to change that? // shrinks. Should we allow RehashPolicy to change that?
// cache_hash_code: bool. true if we store the value of the hash // cache_hash_code: bool. true if we store the value of the hash
// function along with the value. This is a time-space tradeoff. // function along with the value. This is a time-space tradeoff.
// Storing it may improve lookup speed by reducing the number of times // Storing it may improve lookup speed by reducing the number of times
// we need to call the Equal function. // we need to call the Equal function.
// mutable_iterators: bool. true if hashtable::iterator is a mutable // mutable_iterators: bool. true if hashtable::iterator is a mutable
// iterator, false if iterator and const_iterator are both const // iterator, false if iterator and const_iterator are both const
// iterators. This is true for unordered_map and unordered_multimap, // iterators. This is true for unordered_map and unordered_multimap,
// false for unordered_set and unordered_multiset. // false for unordered_set and unordered_multiset.
// unique_keys: bool. true if the return value of hashtable::count(k) // 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 // 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 // true for unordered_set and unordered_map, false for unordered_multiset
// and unordered_multimap. // and unordered_multimap.
template <typename Key, typename Value, template<typename Key, typename Value,
typename Allocator, typename Allocator,
typename ExtractKey, typename Equal, typename ExtractKey, typename Equal,
typename H1, typename H2, typename H1, typename H2,
...@@ -726,12 +847,21 @@ template <typename Key, typename Value, ...@@ -726,12 +847,21 @@ template <typename Key, typename Value,
bool cache_hash_code, bool cache_hash_code,
bool mutable_iterators, bool mutable_iterators,
bool unique_keys> bool unique_keys>
class hashtable 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::rehash_base<RehashPolicy,
public Internal::hash_code_base<Key, Value, ExtractKey, Equal, H1, H2, H, cache_hash_code>, hashtable<Key, Value, Allocator, ExtractKey,
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> > Equal, H1, H2, H, RehashPolicy,
{ cache_hash_code, mutable_iterators,
public: 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 Allocator allocator_type;
typedef Value value_type; typedef Value value_type;
typedef Key key_type; typedef Key key_type;
...@@ -743,42 +873,54 @@ public: ...@@ -743,42 +873,54 @@ public:
typedef typename Allocator::reference reference; typedef typename Allocator::reference reference;
typedef typename Allocator::const_reference const_reference; typedef typename Allocator::const_reference const_reference;
typedef Internal::node_iterator<value_type, !mutable_iterators, cache_hash_code> typedef Internal::node_iterator<value_type, !mutable_iterators,
cache_hash_code>
local_iterator; local_iterator;
typedef Internal::node_iterator<value_type, false, cache_hash_code> typedef Internal::node_iterator<value_type, false, cache_hash_code>
const_local_iterator; const_local_iterator;
typedef Internal::hashtable_iterator<value_type, !mutable_iterators, cache_hash_code> typedef Internal::hashtable_iterator<value_type, !mutable_iterators,
cache_hash_code>
iterator; iterator;
typedef Internal::hashtable_iterator<value_type, false, cache_hash_code> typedef Internal::hashtable_iterator<value_type, false, cache_hash_code>
const_iterator; const_iterator;
private: private:
typedef Internal::hash_node<Value, cache_hash_code> node; typedef Internal::hash_node<Value, cache_hash_code> node;
typedef typename Allocator::template rebind<node>::other node_allocator_t; typedef typename Allocator::template rebind<node>::other
typedef typename Allocator::template rebind<node*>::other bucket_allocator_t; node_allocator_t;
typedef typename Allocator::template rebind<node*>::other
bucket_allocator_t;
private: private:
node_allocator_t m_node_allocator; node_allocator_t m_node_allocator;
node** m_buckets; node** m_buckets;
size_type m_bucket_count; size_type m_bucket_count;
size_type m_element_count; size_type m_element_count;
RehashPolicy m_rehash_policy; RehashPolicy m_rehash_policy;
node* m_allocate_node (const value_type& v); node*
void m_deallocate_node (node* n); m_allocate_node(const value_type& v);
void m_deallocate_nodes (node**, size_type);
void
m_deallocate_node(node* n);
void
m_deallocate_nodes(node**, size_type);
node**
m_allocate_buckets(size_type n);
node** m_allocate_buckets (size_type n); void
void m_deallocate_buckets (node**, size_type n); m_deallocate_buckets(node**, size_type n);
public: // Constructor, destructor, assignment, swap public: // Constructor, destructor, assignment, swap
hashtable(size_type bucket_hint, hashtable(size_type bucket_hint,
const H1&, const H2&, const H&, const H1&, const H2&, const H&,
const Equal&, const ExtractKey&, const Equal&, const ExtractKey&,
const allocator_type&); const allocator_type&);
template <typename InIter> template<typename InIter>
hashtable(InIter first, InIter last, hashtable(InIter first, InIter last,
size_type bucket_hint, size_type bucket_hint,
const H1&, const H2&, const H&, const H1&, const H2&, const H&,
...@@ -786,166 +928,245 @@ public: // Constructor, destructor, assignment, swap ...@@ -786,166 +928,245 @@ public: // Constructor, destructor, assignment, swap
const allocator_type&); const allocator_type&);
hashtable(const hashtable&); hashtable(const hashtable&);
hashtable& operator=(const hashtable&);
hashtable&
operator=(const hashtable&);
~hashtable(); ~hashtable();
void swap(hashtable&); void swap(hashtable&);
public: // Basic container operations public: // Basic container operations
iterator begin() { iterator
begin()
{
iterator i(m_buckets); iterator i(m_buckets);
if (!i.m_cur_node) if (!i.m_cur_node)
i.m_incr_bucket(); i.m_incr_bucket();
return i; return i;
} }
const_iterator begin() const { const_iterator
begin() const
{
const_iterator i(m_buckets); const_iterator i(m_buckets);
if (!i.m_cur_node) if (!i.m_cur_node)
i.m_incr_bucket(); i.m_incr_bucket();
return i; return i;
} }
iterator end() iterator
end()
{ return iterator(m_buckets + m_bucket_count); } { return iterator(m_buckets + m_bucket_count); }
const_iterator end() const
const_iterator
end() const
{ return const_iterator(m_buckets + m_bucket_count); } { return const_iterator(m_buckets + m_bucket_count); }
size_type size() const { return m_element_count; } size_type
bool empty() const { return size() == 0; } size() const
{ return m_element_count; }
allocator_type get_allocator() const { return m_node_allocator; } bool
size_type max_size() const { return m_node_allocator.max_size(); } empty() const
{ return size() == 0; }
public: // Bucket operations allocator_type
size_type bucket_count() const get_allocator() const
{ return m_node_allocator; }
size_type
max_size() const
{ return m_node_allocator.max_size(); }
public: // Bucket operations
size_type
bucket_count() const
{ return m_bucket_count; } { return m_bucket_count; }
size_type max_bucket_count() const
size_type
max_bucket_count() const
{ return max_size(); } { return max_size(); }
size_type bucket_size (size_type n) const
size_type
bucket_size(size_type n) const
{ return std::distance(begin(n), end(n)); } { return std::distance(begin(n), end(n)); }
size_type bucket (const key_type& k) const
{ return this->bucket_index (k, this->m_hash_code, this->m_bucket_count); }
local_iterator begin(size_type n) size_type bucket(const key_type& k) const
{
return this->bucket_index(k, this->m_hash_code, this->m_bucket_count);
}
local_iterator
begin(size_type n)
{ return local_iterator(m_buckets[n]); } { return local_iterator(m_buckets[n]); }
local_iterator end(size_type n)
local_iterator
end(size_type n)
{ return local_iterator(0); } { return local_iterator(0); }
const_local_iterator begin(size_type n) const
const_local_iterator
begin(size_type n) const
{ return const_local_iterator(m_buckets[n]); } { return const_local_iterator(m_buckets[n]); }
const_local_iterator end(size_type n) const
const_local_iterator
end(size_type n) const
{ return const_local_iterator(0); } { return const_local_iterator(0); }
float load_factor() const float
{ return static_cast<float>(size()) / static_cast<float>(bucket_count()); } load_factor() const
{
return static_cast<float>(size()) / static_cast<float>(bucket_count());
}
// max_load_factor, if present, comes from rehash_base. // max_load_factor, if present, comes from rehash_base.
// Generalization of max_load_factor. Extension, not found in TR1. Only // Generalization of max_load_factor. Extension, not found in TR1. Only
// useful if RehashPolicy is something other than the default. // useful if RehashPolicy is something other than the default.
const RehashPolicy& rehash_policy() const { return m_rehash_policy; } const RehashPolicy&
void rehash_policy (const RehashPolicy&); rehash_policy() const
{ return m_rehash_policy; }
void
rehash_policy(const RehashPolicy&);
public: // lookup
iterator
find(const key_type&);
const_iterator
find(const key_type& k) const;
size_type
count(const key_type& k) const;
public: // lookup std::pair<iterator, iterator>
iterator find(const key_type&); equal_range(const key_type& k);
const_iterator find(const key_type& k) const;
size_type count(const key_type& k) const;
std::pair<iterator, iterator> equal_range(const key_type& k);
std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
private: // Insert and erase helper functions std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const;
private: // Insert and erase helper functions
// ??? This dispatching is a workaround for the fact that we don't // ??? This dispatching is a workaround for the fact that we don't
// have partial specialization of member templates; it would be // have partial specialization of member templates; it would be
// better to just specialize insert on unique_keys. There may be a // better to just specialize insert on unique_keys. There may be a
// cleaner workaround. // cleaner workaround.
typedef typename Internal::IF<unique_keys, std::pair<iterator, bool>, iterator>::type typedef typename Internal::IF<unique_keys,
std::pair<iterator, bool>, iterator>::type
Insert_Return_Type; Insert_Return_Type;
node* find_node (node* p, const key_type& k, typename hashtable::hash_code_t c); node*
find_node(node* p, const key_type& k, typename hashtable::hash_code_t c);
std::pair<iterator, bool>
insert(const value_type&, std::tr1::true_type);
iterator
insert
(const value_type&, std::tr1::false_type);
std::pair<iterator, bool> insert (const value_type&, std::tr1::true_type); public: // Insert and erase
iterator insert (const value_type&, std::tr1::false_type); Insert_Return_Type
insert(const value_type& v)
{
return this->insert(v, std::tr1::integral_constant<bool,
unique_keys>());
}
public: // Insert and erase Insert_Return_Type
Insert_Return_Type insert (const value_type& v) insert(const_iterator, const value_type& v)
{ return this->insert (v, std::tr1::integral_constant<bool, unique_keys>()); }
Insert_Return_Type insert (const_iterator, const value_type& v)
{ return this->insert(v); } { return this->insert(v); }
template <typename InIter> void insert(InIter first, InIter last); template<typename InIter>
void
insert(InIter first, InIter last);
void erase(const_iterator); void
size_type erase(const key_type&); erase(const_iterator);
void erase(const_iterator, const_iterator);
void clear();
public: size_type
erase(const key_type&);
void
erase(const_iterator, const_iterator);
void
clear();
public:
// Set number of buckets to be apropriate for container of n element. // Set number of buckets to be apropriate for container of n element.
void rehash (size_type n); void rehash (size_type n);
private: private:
// Unconditionally change size of bucket array to n. // Unconditionally change size of bucket array to n.
void m_rehash (size_type n); void m_rehash (size_type n);
}; };
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// Definitions of class template hashtable's out-of-line member functions. // Definitions of class template hashtable's out-of-line member functions.
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* 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) 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); node* n = m_node_allocator.allocate(1);
try { try
{
get_allocator().construct(&n->m_v, v); get_allocator().construct(&n->m_v, v);
n->m_next = 0; n->m_next = 0;
return n; return n;
} }
catch(...) { catch(...)
{
m_node_allocator.deallocate(n, 1); m_node_allocator.deallocate(n, 1);
throw; 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>::m_deallocate_node (node* n) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ m_deallocate_node(node* n)
{
get_allocator().destroy(&n->m_v); get_allocator().destroy(&n->m_v);
m_node_allocator.deallocate(n, 1); m_node_allocator.deallocate(n, 1);
} }
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_nodes(node** array, size_type n)
{ {
for (size_type i = 0; i < n; ++i) { for (size_type i = 0; i < n; ++i)
{
node* p = array[i]; node* p = array[i];
while (p) { while (p)
{
node* tmp = p; node* tmp = p;
p = p->m_next; p = p->m_next;
m_deallocate_node (tmp); m_deallocate_node (tmp);
} }
array[i] = 0; 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** 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_buckets (size_type n) hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ m_allocate_buckets(size_type n)
{
bucket_allocator_t alloc(m_node_allocator); bucket_allocator_t alloc(m_node_allocator);
// We allocate one extra bucket to hold a sentinel, an arbitrary // We allocate one extra bucket to hold a sentinel, an arbitrary
...@@ -954,136 +1175,149 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::m_allocate_buckets (size_type n) ...@@ -954,136 +1175,149 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::m_allocate_buckets (size_type n)
std::fill(p, p+n, (node*) 0); std::fill(p, p+n, (node*) 0);
p[n] = reinterpret_cast<node*>(0x1000); p[n] = reinterpret_cast<node*>(0x1000);
return p; 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>
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_buckets (node** p, size_type n) m_deallocate_buckets(node** p, size_type n)
{ {
bucket_allocator_t alloc(m_node_allocator); bucket_allocator_t alloc(m_node_allocator);
alloc.deallocate(p, n+1); alloc.deallocate(p, n+1);
} }
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> hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
::hashtable(size_type bucket_hint, hashtable(size_type bucket_hint,
const H1& h1, const H2& h2, const H& h, const H1& h1, const H2& h2, const H& h,
const Eq& eq, const Ex& exk, const Eq& eq, const Ex& exk,
const allocator_type& a) const allocator_type& a)
: Internal::rehash_base<RP,hashtable> (), : Internal::rehash_base<RP,hashtable>(),
Internal::hash_code_base<K,V,Ex,Eq,H1,H2,H,c> (exk, eq, h1, h2, h), 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> (), Internal::map_base<K, V, Ex, u, hashtable>(),
m_node_allocator(a), m_node_allocator(a),
m_bucket_count (0), m_bucket_count(0),
m_element_count (0), m_element_count(0),
m_rehash_policy () m_rehash_policy()
{ {
m_bucket_count = m_rehash_policy.next_bkt(bucket_hint); m_bucket_count = m_rehash_policy.next_bkt(bucket_hint);
m_buckets = m_allocate_buckets (m_bucket_count); 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> 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(InIter f, InIter l, hashtable(InIter f, InIter l,
size_type bucket_hint, size_type bucket_hint,
const H1& h1, const H2& h2, const H& h, const H1& h1, const H2& h2, const H& h,
const Eq& eq, const Ex& exk, const Eq& eq, const Ex& exk,
const allocator_type& a) const allocator_type& a)
: Internal::rehash_base<RP,hashtable> (), : Internal::rehash_base<RP,hashtable>(),
Internal::hash_code_base<K,V,Ex,Eq,H1,H2,H,c> (exk, eq, h1, h2, h), Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c> (exk, eq,
Internal::map_base<K,V,Ex,u,hashtable> (), h1, h2, h),
Internal::map_base<K,V,Ex,u,hashtable>(),
m_node_allocator(a), m_node_allocator(a),
m_bucket_count (0), m_bucket_count (0),
m_element_count (0), m_element_count(0),
m_rehash_policy () m_rehash_policy()
{ {
m_bucket_count = std::max(m_rehash_policy.next_bkt(bucket_hint), m_bucket_count = std::max(m_rehash_policy.next_bkt(bucket_hint),
m_rehash_policy.bkt_for_elements(Internal::distance_fw(f, l))); m_rehash_policy.
m_buckets = m_allocate_buckets (m_bucket_count); bkt_for_elements(Internal::
try { distance_fw(f, l)));
m_buckets = m_allocate_buckets(m_bucket_count);
try
{
for (; f != l; ++f) for (; f != l; ++f)
this->insert (*f); this->insert(*f);
} }
catch(...) { catch(...)
{
clear(); clear();
m_deallocate_buckets (m_buckets, m_bucket_count); m_deallocate_buckets(m_buckets, m_bucket_count);
throw; 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> hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
::hashtable(const hashtable& ht) hashtable(const hashtable& ht)
: Internal::rehash_base<RP,hashtable> (ht), : Internal::rehash_base<RP, hashtable>(ht),
Internal::hash_code_base<K,V,Ex,Eq,H1,H2,H,c> (ht), Internal::hash_code_base<K, V, Ex, Eq, H1, H2, H, c>(ht),
Internal::map_base<K,V,Ex,u,hashtable> (ht), Internal::map_base<K, V, Ex, u, hashtable>(ht),
m_node_allocator(ht.get_allocator()), m_node_allocator(ht.get_allocator()),
m_bucket_count (ht.m_bucket_count), m_bucket_count(ht.m_bucket_count),
m_element_count (ht.m_element_count), m_element_count(ht.m_element_count),
m_rehash_policy (ht.m_rehash_policy) m_rehash_policy(ht.m_rehash_policy)
{ {
m_buckets = m_allocate_buckets (m_bucket_count); m_buckets = m_allocate_buckets (m_bucket_count);
try { try
for (size_t i = 0; i < ht.m_bucket_count; ++i) { {
for (size_t i = 0; i < ht.m_bucket_count; ++i)
{
node* n = ht.m_buckets[i]; node* n = ht.m_buckets[i];
node** tail = m_buckets + i; node** tail = m_buckets + i;
while (n) { while (n)
*tail = m_allocate_node (n); {
(*tail).copy_code_from (n); *tail = m_allocate_node(n);
(*tail).copy_code_from(n);
tail = &((*tail)->m_next); tail = &((*tail)->m_next);
n = n->m_next; n = n->m_next;
} }
} }
} }
catch (...) { catch (...)
{
clear(); clear();
m_deallocate_buckets (m_buckets, m_bucket_count); m_deallocate_buckets (m_buckets, m_bucket_count);
throw; 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>& 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<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ operator=(const hashtable& ht)
{
hashtable tmp(ht); hashtable tmp(ht);
this->swap(tmp); this->swap(tmp);
return *this; return *this;
} }
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>::~hashtable() hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
{ ~hashtable()
{
clear(); clear();
m_deallocate_buckets(m_buckets, m_bucket_count); m_deallocate_buckets(m_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>
void hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::swap (hashtable& x) 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 // The only base class with member variables is hash_code_base. We
// define hash_code_base::m_swap because different specializations // define hash_code_base::m_swap because different specializations
// have different members. // have different members.
...@@ -1091,58 +1325,62 @@ void hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::swap (hashtable& x) ...@@ -1091,58 +1325,62 @@ void hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::swap (hashtable& x)
// open LWG issue 431 // open LWG issue 431
// std::swap(m_node_allocator, x.m_node_allocator); // std::swap(m_node_allocator, x.m_node_allocator);
std::swap (m_rehash_policy, x.m_rehash_policy); std::swap(m_rehash_policy, x.m_rehash_policy);
std::swap (m_buckets, x.m_buckets); std::swap(m_buckets, x.m_buckets);
std::swap (m_bucket_count, x.m_bucket_count); std::swap(m_bucket_count, x.m_bucket_count);
std::swap (m_element_count, x.m_element_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 void
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>::
{ rehash_policy(const RP& pol)
{
m_rehash_policy = pol; m_rehash_policy = pol;
size_type n_bkt = pol.bkt_for_elements(m_element_count); size_type n_bkt = pol.bkt_for_elements(m_element_count);
if (n_bkt > m_bucket_count) if (n_bkt > m_bucket_count)
m_rehash (n_bkt); m_rehash (n_bkt);
} }
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>::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>::find (const key_type& k) 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); typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count()); std::size_t n = this->bucket_index(k, code, this->bucket_count());
node* p = find_node (m_buckets[n], k, code); node* p = find_node (m_buckets[n], k, code);
return p ? iterator(p, m_buckets + n) : this->end(); return p ? iterator(p, m_buckets + n) : this->end();
} }
template <typename K, typename V, template<typename K, typename V,
typename A, typename Ex, typename Eq, typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP, typename H1, typename H2, typename H, typename RP,
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>::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>::find (const key_type& k) const 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); typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count()); std::size_t n = this->bucket_index(k, code, this->bucket_count());
node* p = find_node (m_buckets[n], k, code); node* p = find_node (m_buckets[n], k, code);
return p ? const_iterator(p, m_buckets + n) : this->end(); return p ? const_iterator(p, m_buckets + n) : this->end();
} }
template <typename K, typename V, template<typename K, typename V,
typename A, typename Ex, typename Eq, typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP, typename H1, typename H2, typename H, typename RP,
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>::count (const key_type& k) const 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); typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count()); std::size_t n = this->bucket_index (k, code, this->bucket_count());
size_t result = 0; size_t result = 0;
...@@ -1150,26 +1388,31 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::count (const key_type& k) const ...@@ -1150,26 +1388,31 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::count (const key_type& k) const
if (this->compare (k, code, p)) if (this->compare (k, code, p))
++result; ++result;
return result; return result;
} }
template <typename K, typename V, template<typename K, typename V,
typename A, typename Ex, typename Eq, typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP, typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u> bool c, bool m, bool u>
std::pair<typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::iterator, std::pair<typename hashtable<K, V, A, Ex, Eq, H1,
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::iterator> 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<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); typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count()); std::size_t n = this->bucket_index(k, code, this->bucket_count());
node** head = m_buckets + n; node** head = m_buckets + n;
node* p = find_node (*head, k, code); node* p = find_node (*head, k, code);
if (p) { if (p)
{
node* p1 = p->m_next; node* p1 = p->m_next;
for (; p1 ; p1 = p1->m_next) for (; p1 ; p1 = p1->m_next)
if (!this->compare (k, code, p1)) if (!this->compare (k, code, p1))
break; break;
iterator first(p, head); iterator first(p, head);
iterator last(p1, head); iterator last(p1, head);
if (!p1) if (!p1)
...@@ -1177,27 +1420,32 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::equal_range (const key_type& k) ...@@ -1177,27 +1420,32 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::equal_range (const key_type& k)
return std::make_pair(first, last); return std::make_pair(first, last);
} }
else else
return std::make_pair (this->end(), this->end()); return std::make_pair(this->end(), this->end());
} }
template <typename K, typename V, template<typename K, typename V,
typename A, typename Ex, typename Eq, typename A, typename Ex, typename Eq,
typename H1, typename H2, typename H, typename RP, typename H1, typename H2, typename H, typename RP,
bool c, bool m, bool u> bool c, bool m, bool u>
std::pair<typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::const_iterator, std::pair<typename hashtable<K, V, A, Ex, Eq, H1,
typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::const_iterator> 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<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); typename hashtable::hash_code_t code = this->m_hash_code (k);
std::size_t n = this->bucket_index (k, code, this->bucket_count()); std::size_t n = this->bucket_index(k, code, this->bucket_count());
node** head = m_buckets + n; node** head = m_buckets + n;
node* p = find_node (*head, k, code); node* p = find_node (*head, k, code);
if (p) { if (p)
{
node* p1 = p->m_next; node* p1 = p->m_next;
for (; p1 ; p1 = p1->m_next) for (; p1 ; p1 = p1->m_next)
if (!this->compare (k, code, p1)) if (!this->compare (k, code, p1))
break; break;
const_iterator first(p, head); const_iterator first(p, head);
const_iterator last(p1, head); const_iterator last(p1, head);
if (!p1) if (!p1)
...@@ -1205,39 +1453,40 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::equal_range (const key_type& k) const ...@@ -1205,39 +1453,40 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::equal_range (const key_type& k) const
return std::make_pair(first, last); return std::make_pair(first, last);
} }
else else
return std::make_pair (this->end(), this->end()); return std::make_pair(this->end(), this->end());
} }
// Find the node whose key compares equal to k, beginning the search // 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. // at p (usually the head of a bucket). Return nil if no node is found.
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* 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>::
::find_node (node* p, const key_type& k, typename hashtable::hash_code_t code) find_node(node* p, const key_type& k, typename hashtable::hash_code_t code)
{ {
for ( ; p ; p = p->m_next) for ( ; p ; p = p->m_next)
if (this->compare (k, code, p)) if (this->compare (k, code, p))
return p; return p;
return false; return false;
} }
// Insert v if no element with its key is already present. // 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>
std::pair<typename hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::iterator, bool> std::pair<typename hashtable<K, V, A, Ex, Eq, H1,
hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> H2, H, RP, c, m, u>::iterator, bool>
::insert (const value_type& v, std::tr1::true_type) 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); const key_type& k = this->m_extract(v);
typename hashtable::hash_code_t code = this->m_hash_code (k); typename hashtable::hash_code_t code = this->m_hash_code (k);
size_type n = this->bucket_index (k, code, m_bucket_count); size_type n = this->bucket_index(k, code, m_bucket_count);
if (node* p = find_node (m_buckets[n], k, code)) if (node* p = find_node(m_buckets[n], k, code))
return std::make_pair(iterator(p, m_buckets + n), false); return std::make_pair(iterator(p, m_buckets + n), false);
std::pair<bool, size_t> do_rehash std::pair<bool, size_t> do_rehash
...@@ -1247,32 +1496,35 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> ...@@ -1247,32 +1496,35 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>
// do a rehash if the allocation throws. // do a rehash if the allocation throws.
node* new_node = m_allocate_node (v); node* new_node = m_allocate_node (v);
try { try
if (do_rehash.first) { {
n = this->bucket_index (k, code, do_rehash.second); if (do_rehash.first)
{
n = this->bucket_index(k, code, do_rehash.second);
m_rehash(do_rehash.second); m_rehash(do_rehash.second);
} }
new_node->m_next = m_buckets[n]; new_node->m_next = m_buckets[n];
m_buckets[n] = new_node; m_buckets[n] = new_node;
++m_element_count; ++m_element_count;
return std::make_pair(iterator (new_node, m_buckets + n), true); return std::make_pair(iterator(new_node, m_buckets + n), true);
} }
catch (...) { catch (...)
{
m_deallocate_node (new_node); m_deallocate_node (new_node);
throw; throw;
} }
} }
// Insert v unconditionally. // Insert v unconditionally.
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>::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> hashtable<K, V, A, Ex, Eq, H1, H2, H, RP, c, m, u>::
::insert (const value_type& v, std::tr1::false_type) insert(const value_type& v, std::tr1::false_type)
{ {
std::pair<bool, std::size_t> do_rehash std::pair<bool, std::size_t> do_rehash
= m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1); = m_rehash_policy.need_rehash(m_bucket_count, m_element_count, 1);
if (do_rehash.first) if (do_rehash.first)
...@@ -1280,31 +1532,34 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u> ...@@ -1280,31 +1532,34 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>
const key_type& k = this->m_extract(v); const key_type& k = this->m_extract(v);
typename hashtable::hash_code_t code = this->m_hash_code (k); typename hashtable::hash_code_t code = this->m_hash_code (k);
size_type n = this->bucket_index (k, code, m_bucket_count); size_type n = this->bucket_index(k, code, m_bucket_count);
node* new_node = m_allocate_node (v); node* new_node = m_allocate_node (v);
node* prev = find_node (m_buckets[n], k, code); node* prev = find_node(m_buckets[n], k, code);
if (prev) { if (prev)
{
new_node->m_next = prev->m_next; new_node->m_next = prev->m_next;
prev->m_next = new_node; prev->m_next = new_node;
} }
else { else
{
new_node->m_next = m_buckets[n]; new_node->m_next = m_buckets[n];
m_buckets[n] = new_node; m_buckets[n] = new_node;
} }
++m_element_count; ++m_element_count;
return iterator (new_node, m_buckets + n); 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); size_type n_elt = Internal::distance_fw (first, last);
std::pair<bool, std::size_t> do_rehash std::pair<bool, std::size_t> do_rehash
= m_rehash_policy.need_rehash(m_bucket_count, m_element_count, n_elt); = m_rehash_policy.need_rehash(m_bucket_count, m_element_count, n_elt);
...@@ -1313,25 +1568,29 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::insert(InIter first, InIter last) ...@@ -1313,25 +1568,29 @@ hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::insert(InIter first, InIter last)
for (; first != last; ++first) for (; first != last; ++first)
this->insert (*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>::
erase(const_iterator i)
{
node* p = i.m_cur_node; node* p = i.m_cur_node;
node* cur = *i.m_cur_bucket; node* cur = *i.m_cur_bucket;
if (cur == p) if (cur == p)
*i.m_cur_bucket = cur->m_next; *i.m_cur_bucket = cur->m_next;
else { else
{
node* next = cur->m_next; node* next = cur->m_next;
while (next != p) { while (next != p)
{
cur = next; cur = next;
next = cur->m_next; next = cur->m_next;
} }
...@@ -1340,92 +1599,103 @@ void hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::erase (const_iterator i) ...@@ -1340,92 +1599,103 @@ void hashtable<K,V,A,Ex,Eq,H1,H2,H,RP,c,m,u>::erase (const_iterator i)
m_deallocate_node (p); m_deallocate_node (p);
--m_element_count; --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); typename hashtable::hash_code_t code = this->m_hash_code (k);
size_type n = this->bucket_index (k, code, m_bucket_count); size_type n = this->bucket_index(k, code, m_bucket_count);
node** slot = m_buckets + n; node** slot = m_buckets + n;
while (*slot && ! this->compare (k, code, *slot)) while (*slot && ! this->compare (k, code, *slot))
slot = &((*slot)->m_next); slot = &((*slot)->m_next);
while (*slot && this->compare (k, code, *slot)) { while (*slot && this->compare (k, code, *slot))
{
node* n = *slot; node* n = *slot;
*slot = n->m_next; *slot = n->m_next;
m_deallocate_node (n); m_deallocate_node (n);
--m_element_count; --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) { {
while (first != last)
{
const_iterator next = first; const_iterator next = first;
++next; ++next;
this->erase(first); this->erase(first);
first = next; 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_deallocate_nodes(m_buckets, m_bucket_count);
m_element_count = 0; 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); node** new_array = m_allocate_buckets (N);
try { try
{
for (size_type i = 0; i < m_bucket_count; ++i) for (size_type i = 0; i < m_bucket_count; ++i)
while (node* p = m_buckets[i]) { while (node* p = m_buckets[i])
{
size_type new_index = this->bucket_index (p, N); size_type new_index = this->bucket_index (p, N);
m_buckets[i] = p->m_next; m_buckets[i] = p->m_next;
p->m_next = new_array[new_index]; p->m_next = new_array[new_index];
new_array[new_index] = p; new_array[new_index] = p;
} }
m_deallocate_buckets (m_buckets, m_bucket_count); m_deallocate_buckets(m_buckets, m_bucket_count);
m_bucket_count = N; m_bucket_count = N;
m_buckets = new_array; m_buckets = new_array;
} }
catch (...) { catch (...)
{
// A failure here means that a hash function threw an exception. // A failure here means that a hash function threw an exception.
// We can't restore the previous state without calling the hash // We can't restore the previous state without calling the hash
// function again, so the only sensible recovery is to delete // function again, so the only sensible recovery is to delete
// everything. // everything.
m_deallocate_nodes (new_array, N); m_deallocate_nodes(new_array, N);
m_deallocate_buckets (new_array, N); m_deallocate_buckets(new_array, N);
m_deallocate_nodes (m_buckets, m_bucket_count); m_deallocate_nodes(m_buckets, m_bucket_count);
m_element_count = 0; m_element_count = 0;
throw; 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. namespace tr1
{
// XXX When we get typedef templates these class definitions
// will be unnecessary.
template <class Key, class T, template<class Key, class T,
class Hash = hash<Key>, class Hash = hash<Key>,
class Pred = std::equal_to<Key>, class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T> >, class Alloc = std::allocator<std::pair<const Key, T> >,
bool cache_hash_code = false> bool cache_hash_code = false>
class unordered_map class unordered_map
: public hashtable <Key, std::pair<const Key, T>, : public hashtable <Key, std::pair<const Key, T>,
Alloc, Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred, Internal::extract1st<std::pair<const Key, T> >, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy, Internal::prime_rehash_policy,
cache_hash_code, true, true> cache_hash_code, true, true>
{ {
typedef hashtable <Key, std::pair<const Key, T>, typedef hashtable <Key, std::pair<const Key, T>,
Alloc, Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred, Internal::extract1st<std::pair<const Key, T> >, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy, Internal::prime_rehash_policy,
cache_hash_code, true, true> cache_hash_code, true, true>
Base; Base;
public: public:
typedef typename Base::size_type size_type; typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher; typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal; typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type; typedef typename Base::allocator_type allocator_type;
explicit unordered_map(size_type n = 10, explicit
unordered_map(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_map(InputIterator f, InputIterator l,
size_type n = 10, 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 (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, template<class Key, class T,
class Hash = hash<Key>, class Hash = hash<Key>,
class Pred = std::equal_to<Key>, class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T> >, class Alloc = std::allocator<std::pair<const Key, T> >,
bool cache_hash_code = false> bool cache_hash_code = false>
class unordered_multimap class unordered_multimap
: public hashtable <Key, std::pair<const Key, T>, : public hashtable <Key, std::pair<const Key, T>,
Alloc, Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred, Internal::extract1st<std::pair<const Key, T> >, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy, Internal::prime_rehash_policy,
cache_hash_code, true, false> cache_hash_code, true, false>
{ {
typedef hashtable <Key, std::pair<const Key, T>, typedef hashtable <Key, std::pair<const Key, T>,
Alloc, Alloc,
Internal::extract1st<std::pair<const Key, T> >, Pred, Internal::extract1st<std::pair<const Key, T> >, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy, Internal::prime_rehash_policy,
cache_hash_code, true, false> cache_hash_code, true, false>
Base; Base;
public: public:
typedef typename Base::size_type size_type; typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher; typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal; typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type; typedef typename Base::allocator_type allocator_type;
explicit unordered_multimap(size_type n = 10, 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_multimap(InputIterator f, InputIterator l, unordered_multimap(InputIterator f, InputIterator l,
typename Base::size_type n = 0, 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, class Hash, class Pred, class Alloc,
inline void swap (unordered_map<Key, T, Hash, Pred, Alloc, cache_hash_code>& x, 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) unordered_map<Key, T, Hash, Pred, Alloc, cache_hash_code>& y)
{ { x.swap(y); }
x.swap(y);
}
template <class Key, class T, class Hash, class Pred, class Alloc, bool cache_hash_code> template<class Key, class T, class Hash, class Pred, class Alloc,
inline void swap (unordered_multimap<Key, T, Hash, Pred, Alloc, cache_hash_code>& x, 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) unordered_multimap<Key, T, Hash, Pred, Alloc, cache_hash_code>& y)
{ { x.swap(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
{
namespace tr1
{
// XXX When we get typedef templates these class definitions will be unnecessary. // XXX When we get typedef templates these class definitions
// will be unnecessary.
template <class Value, template<class Value,
class Hash = hash<Value>, class Hash = hash<Value>,
class Pred = std::equal_to<Value>, class Pred = std::equal_to<Value>,
class Alloc = std::allocator<Value>, class Alloc = std::allocator<Value>,
bool cache_hash_code = false> bool cache_hash_code = false>
class unordered_set class unordered_set
: public hashtable <Value, Value, Alloc, : public hashtable<Value, Value, Alloc,
Internal::identity<Value>, Pred, Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy, Internal::prime_rehash_policy,
cache_hash_code, false, true> cache_hash_code, false, true>
{ {
typedef hashtable <Value, Value, Alloc, typedef hashtable<Value, Value, Alloc,
Internal::identity<Value>, Pred, Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy, Internal::prime_rehash_policy,
cache_hash_code, false, true> cache_hash_code, false, true>
Base; Base;
public: public:
typedef typename Base::size_type size_type; typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher; typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal; typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type; typedef typename Base::allocator_type allocator_type;
explicit unordered_set(size_type n = 10, explicit
unordered_set(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_set(InputIterator f, InputIterator l,
size_type n = 10, 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 (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::identity<Value>(), a)
eql, Internal::identity<Value>(),
a)
{ } { }
}; };
template <class Value, template<class Value,
class Hash = hash<Value>, class Hash = hash<Value>,
class Pred = std::equal_to<Value>, class Pred = std::equal_to<Value>,
class Alloc = std::allocator<Value>, class Alloc = std::allocator<Value>,
bool cache_hash_code = false> bool cache_hash_code = false>
class unordered_multiset class unordered_multiset
: public hashtable <Value, Value, Alloc, : public hashtable <Value, Value, Alloc,
Internal::identity<Value>, Pred, Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy, Internal::prime_rehash_policy,
cache_hash_code, false, false> cache_hash_code, false, false>
{ {
typedef hashtable <Value, Value, Alloc, typedef hashtable<Value, Value, Alloc,
Internal::identity<Value>, Pred, Internal::identity<Value>, Pred,
Hash, Internal::mod_range_hashing, Internal::default_ranged_hash, Hash, Internal::mod_range_hashing,
Internal::default_ranged_hash,
Internal::prime_rehash_policy, Internal::prime_rehash_policy,
cache_hash_code, false, false> cache_hash_code, false, false>
Base; Base;
public: public:
typedef typename Base::size_type size_type; typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher; typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal; typedef typename Base::key_equal key_equal;
typedef typename Base::allocator_type allocator_type; typedef typename Base::allocator_type allocator_type;
explicit unordered_multiset(size_type n = 10, 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_multiset(InputIterator f, InputIterator l, unordered_multiset(InputIterator f, InputIterator l,
typename Base::size_type n = 0, 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, class Hash, class Pred, class Alloc,
inline void swap (unordered_set<Value, Hash, Pred, Alloc, cache_hash_code>& x, 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) unordered_set<Value, Hash, Pred, Alloc, cache_hash_code>& y)
{ { x.swap(y); }
x.swap(y);
}
template <class Value, class Hash, class Pred, class Alloc, bool cache_hash_code> template<class Value, class Hash, class Pred, class Alloc,
inline void swap (unordered_multiset<Value, Hash, Pred, Alloc, cache_hash_code>& x, 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) unordered_multiset<Value, Hash, Pred, Alloc, cache_hash_code>& y)
{ { x.swap(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