Boost logo

Boost-Commit :

From: daniel_james_at_[hidden]
Date: 2007-12-08 13:06:13


Author: danieljames
Date: 2007-12-08 13:06:12 EST (Sat, 08 Dec 2007)
New Revision: 41900
URL: http://svn.boost.org/trac/boost/changeset/41900

Log:
Move hash_table_data into hash_table.hpp
Removed:
   sandbox-branches/unordered-refactor/boost/unordered/detail/hash_table_impl.hpp
Text files modified:
   sandbox-branches/unordered-refactor/boost/unordered/detail/hash_table.hpp | 765 +++++++++++++++++++++++++++++++++++++++
   1 files changed, 760 insertions(+), 5 deletions(-)

Modified: sandbox-branches/unordered-refactor/boost/unordered/detail/hash_table.hpp
==============================================================================
--- sandbox-branches/unordered-refactor/boost/unordered/detail/hash_table.hpp (original)
+++ sandbox-branches/unordered-refactor/boost/unordered/detail/hash_table.hpp 2007-12-08 13:06:12 EST (Sat, 08 Dec 2007)
@@ -357,13 +357,768 @@
             static void split_group(link_ptr) {}
             static void split_group(link_ptr, link_ptr) {}
         };
- }
-}
 
-#include <boost/unordered/detail/hash_table_impl.hpp>
+ template <typename Alloc, typename EquivKeys>
+ struct select_node_base
+ : public boost::mpl::if_<
+ EquivKeys,
+ node_base_equivalent_keys<Alloc>,
+ node_base_unique_keys<Alloc> > {};
+
+ //
+ // Hash Table Data
+ //
+ // Responsible for managing the hash buckets.
+
+ template <typename Alloc, typename EquivKeys>
+ class hash_table_data
+ {
+ public:
+ typedef bucket<Alloc> bucket;
+ typedef typename bucket::bucket_allocator bucket_allocator;
+ typedef typename bucket::bucket_ptr bucket_ptr;
+ typedef typename bucket::link_ptr link_ptr;
+
+ struct node;
+ typedef std::size_t size_type;
+
+ typedef Alloc value_allocator;
+
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::unordered_detail::rebind_wrap<Alloc, node>::type
+ node_allocator;
+
+ typedef BOOST_DEDUCED_TYPENAME allocator_value_type<Alloc>::type value_type;
+ typedef BOOST_DEDUCED_TYPENAME allocator_pointer<node_allocator>::type node_ptr;
+ typedef BOOST_DEDUCED_TYPENAME allocator_reference<value_allocator>::type reference;
+
+ typedef typename select_node_base<Alloc, EquivKeys>::type node_base;
+
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::unordered_detail::rebind_wrap<Alloc, node_base>::type
+ node_base_allocator;
+
+ struct node : node_base
+ {
+ public:
+ node(value_type const& v) : node_base(), value_(v) {}
+
+ value_type value_;
+ };
+
+ // node_constructor
+ //
+ // Used to construct nodes in an exception safe manner.
+
+ struct allocators
+ {
+ node_allocator node_alloc_;
+ bucket_allocator bucket_alloc_;
+ value_allocator value_alloc_;
+ node_base_allocator node_base_alloc_;
+
+ allocators(value_allocator const& a)
+ : node_alloc_(a), bucket_alloc_(a),
+ value_alloc_(a), node_base_alloc_(a)
+ {}
+
+ void destroy(link_ptr ptr)
+ {
+ node_ptr n(node_alloc_.address(static_cast<node&>(*ptr)));
+ value_alloc_.destroy(value_alloc_.address(n->value_));
+ node_base_alloc_.destroy(node_base_alloc_.address(*n));
+ node_alloc_.deallocate(n, 1);
+ }
+
+ void swap(allocators& x)
+ {
+ hash_swap(node_alloc_, x.node_alloc_);
+ hash_swap(bucket_alloc_, x.bucket_alloc_);
+ hash_swap(value_alloc_, x.value_alloc_);
+ hash_swap(node_base_alloc_, x.node_base_alloc_);
+ }
+
+ bool operator==(allocators const& x)
+ {
+ return value_alloc_ == x.value_alloc_;
+ }
+ };
+
+ class node_constructor
+ {
+ allocators& allocators_;
+
+ node_ptr node_;
+ bool value_constructed_;
+ bool node_base_constructed_;
+
+ public:
+
+ node_constructor(allocators& a)
+ : allocators_(a),
+ node_(), value_constructed_(false), node_base_constructed_(false)
+ {
+ BOOST_HASH_MSVC_RESET_PTR(node_);
+ }
+
+ ~node_constructor()
+ {
+ if (node_) {
+ if (value_constructed_)
+ allocators_.value_alloc_.destroy(
+ allocators_.value_alloc_.address(node_->value_));
+ if (node_base_constructed_)
+ allocators_.node_base_alloc_.destroy(
+ allocators_.node_base_alloc_.address(*node_));
+
+ allocators_.node_alloc_.deallocate(node_, 1);
+ }
+ }
+
+ template <typename V>
+ void construct(V const& v)
+ {
+ BOOST_ASSERT(!node_);
+ value_constructed_ = false;
+ node_base_constructed_ = false;
+
+ node_ = allocators_.node_alloc_.allocate(1);
+
+ allocators_.node_base_alloc_.construct(
+ allocators_.node_base_alloc_.address(*node_),
+ node_base());
+ node_base_constructed_ = true;
+
+ allocators_.value_alloc_.construct(
+ allocators_.value_alloc_.address(node_->value_), v);
+ value_constructed_ = true;
+ }
+
+ node_ptr get() const
+ {
+ BOOST_ASSERT(node_);
+ return node_;
+ }
+
+ // no throw
+ link_ptr release()
+ {
+ node_ptr p = node_;
+ unordered_detail::reset(node_);
+ return link_ptr(allocators_.bucket_alloc_.address(*p));
+ }
+
+ private:
+ node_constructor(node_constructor const&);
+ node_constructor& operator=(node_constructor const&);
+ };
+
+ // Methods for navigating groups of elements with equal keys.
+
+ static link_ptr& prev_in_group(link_ptr n) {
+ return node_base::prev_in_group(n);
+ }
+
+ // pre: Must be pointing to the first node in a group.
+ static link_ptr last_in_group(link_ptr n) {
+ return node_base::last_in_group(n);
+ }
+
+ // pre: Must be pointing to the first node in a group.
+ static link_ptr& next_group(link_ptr n) {
+ return node_base::next_group(n);
+ }
+
+ // pre: Must be pointing to a node
+ static reference get_value(link_ptr p) {
+ BOOST_ASSERT(p);
+ return static_cast<node&>(*p).value_;
+ }
+
+ class local_iterator_base
+ {
+ public:
+ link_ptr node_;
+
+ local_iterator_base()
+ : node_()
+ {
+ BOOST_HASH_MSVC_RESET_PTR(node_);
+ }
+
+ explicit local_iterator_base(link_ptr n)
+ : node_(n) {}
+
+ bool not_finished() const
+ {
+ return node_ ? true : false;
+ }
+
+ bool operator==(local_iterator_base const& x) const
+ {
+ return node_ == x.node_;
+ }
+
+ bool operator!=(local_iterator_base const& x) const
+ {
+ return node_ != x.node_;
+ }
+
+ reference operator*() const
+ {
+ return get_value(node_);
+ }
+
+ void increment()
+ {
+ BOOST_ASSERT(node_);
+ node_ = node_->next_;
+ }
+
+ void next_group()
+ {
+ node_ = hash_table_data::next_group(node_);
+ }
+ };
+
+ class iterator_base
+ {
+ public:
+ bucket_ptr bucket_;
+ local_iterator_base local_;
+
+ iterator_base()
+ : bucket_(), local_() {}
+
+ explicit iterator_base(bucket_ptr b)
+ : bucket_(b), local_(b->next_) {}
+
+ iterator_base(bucket_ptr b, link_ptr n)
+ : bucket_(b), local_(n) {}
+
+ iterator_base(bucket_ptr b, local_iterator_base const& it)
+ : bucket_(b), local_(it) {}
+
+ bool operator==(iterator_base const& x) const
+ {
+ return local_ == x.local_;
+ }
+
+ bool operator!=(iterator_base const& x) const
+ {
+ return local_ != x.local_;
+ }
+
+ reference operator*() const
+ {
+ return *local_;
+ }
+
+ void increment()
+ {
+ BOOST_ASSERT(bucket_);
+ local_.increment();
+
+ while (!local_.node_) {
+ ++bucket_;
+ local_ = local_iterator_base(bucket_->next_);
+ }
+ }
+ };
+
+ // Member Variables
+
+ allocators allocators_;
+ bucket_ptr buckets_;
+ size_type bucket_count_;
+ bucket_ptr cached_begin_bucket_;
+ size_type size_;
+
+ // Constructors/Deconstructor
+
+ hash_table_data(size_type n, value_allocator const& a)
+ : allocators_(a),
+ buckets_(), bucket_count_(next_prime(n)),
+ cached_begin_bucket_(), size_(0)
+ {
+ // The array constructor will clean up in the event of an
+ // exception.
+ allocator_array_constructor<bucket_allocator>
+ constructor(allocators_.bucket_alloc_);
+
+ // Creates an extra bucket to act as a sentinel.
+ constructor.construct(bucket(), bucket_count_ + 1);
+
+ cached_begin_bucket_ = constructor.get() + bucket_count_;
+
+ // Set up the sentinel.
+ cached_begin_bucket_->next_ = link_ptr(cached_begin_bucket_);
+
+ // Only release the buckets once everything is successfully
+ // done.
+ buckets_ = constructor.release();
+ }
+
+ hash_table_data(hash_table_data const& x, size_type n)
+ : allocators_(x.allocators_),
+ buckets_(), bucket_count_(next_prime(n)),
+ cached_begin_bucket_(), size_(0)
+ {
+ // The array constructor will clean up in the event of an
+ // exception.
+ allocator_array_constructor<bucket_allocator>
+ constructor(allocators_.bucket_alloc_);
+
+ // Creates an extra bucket to act as a sentinel.
+ constructor.construct(bucket(), bucket_count_ + 1);
+
+ cached_begin_bucket_ = constructor.get() + bucket_count_;
+
+ // Set up the sentinel
+ cached_begin_bucket_->next_ = link_ptr(cached_begin_bucket_);
+
+ // Only release the buckets once everything is successfully
+ // done.
+ buckets_ = constructor.release();
+ }
+
+ // no throw
+ ~hash_table_data()
+ {
+ if(buckets_) {
+ bucket_ptr begin = cached_begin_bucket_;
+ bucket_ptr end = buckets_ + bucket_count_;
+ while(begin != end) {
+ clear_bucket(begin);
+ ++begin;
+ }
+
+ // Destroy an extra bucket for the sentinels.
+ for(size_type i2 = 0; i2 < bucket_count_ + 1; ++i2)
+ allocators_.bucket_alloc_.destroy(buckets_ + i2);
+
+ allocators_.bucket_alloc_.deallocate(buckets_, bucket_count_ + 1);
+ }
+ }
+
+ private:
+
+ hash_table_data(hash_table_data const&);
+ hash_table_data& operator=(hash_table_data const&);
+
+ public:
+
+ // no throw
+ void swap(hash_table_data& other)
+ {
+ std::swap(buckets_, other.buckets_);
+ std::swap(bucket_count_, other.bucket_count_);
+ std::swap(cached_begin_bucket_, other.cached_begin_bucket_);
+ std::swap(size_, other.size_);
+ }
+
+ // Return the bucket index for a hashed value.
+ //
+ // no throw
+ size_type index_from_hash(size_type hashed) const
+ {
+ return hashed % bucket_count_;
+ }
+
+ // Begin & End
+ //
+ // no throw
+
+ iterator_base begin() const
+ {
+ return size_
+ ? iterator_base(cached_begin_bucket_)
+ : end();
+ }
+
+ iterator_base end() const
+ {
+ return iterator_base(buckets_ + bucket_count_);
+ }
+
+ local_iterator_base begin(size_type n) const
+ {
+ return local_iterator_base(buckets_[n].next_);
+ }
 
-namespace boost {
- namespace unordered_detail {
+ local_iterator_base end(size_type) const
+ {
+ return local_iterator_base();
+ }
+
+ local_iterator_base begin(bucket_ptr b) const
+ {
+ return local_iterator_base(b->next_);
+ }
+
+ // Bucket Size
+
+ // no throw
+ size_type node_count(local_iterator_base it) const
+ {
+ size_type count = 0;
+ while(it.not_finished()) {
+ ++count;
+ it.increment();
+ }
+ return count;
+ }
+
+ size_type node_count(local_iterator_base it1,
+ local_iterator_base it2) const
+ {
+ size_type count = 0;
+ while(it1 != it2) {
+ ++count;
+ it1.increment();
+ }
+ return count;
+ }
+
+ size_type bucket_size(size_type n) const
+ {
+ return node_count(begin(n));
+ }
+
+ size_type group_count(local_iterator_base first_node) const
+ {
+ return node_base::group_count(first_node.node_);
+ }
+
+ // get_for_erase
+ //
+ // Find the pointer to a node, for use when erasing.
+ //
+ // no throw
+
+ link_ptr* get_for_erase(iterator_base r) const
+ {
+ return node_base::get_for_erase(r.bucket_, r.local_.node_);
+ }
+
+ // Link/Unlink/Move Node
+ //
+ // For adding nodes to buckets, removing them and moving them to a
+ // new bucket.
+ //
+ // no throw
+
+ void link_node(link_ptr n, local_iterator_base pos)
+ {
+ node_base::link_node(n, pos.node_);
+ ++size_;
+ }
+
+ void link_node(link_ptr n, bucket_ptr base)
+ {
+ node_base::link_node_in_bucket(n, base);
+ ++size_;
+ if(base < cached_begin_bucket_) cached_begin_bucket_ = base;
+ }
+
+ void link_group(link_ptr n, bucket_ptr base, size_type count)
+ {
+ node_base::link_group(n, base);
+ size_ += count;
+ if(base < cached_begin_bucket_) cached_begin_bucket_ = base;
+ }
+
+ void unlink_node(iterator_base it)
+ {
+ node_base::unlink_node(get_for_erase(it));
+ --size_;
+ }
+
+ size_type unlink_group(link_ptr* pos)
+ {
+ size_type count = group_count(local_iterator_base(*pos));
+ size_ -= count;
+ *pos = next_group(*pos);
+ return count;
+ }
+
+ void unlink_nodes(iterator_base n)
+ {
+ link_ptr* it = get_for_erase(n);
+ split_group(*it);
+ unordered_detail::reset(*it);
+ size_ -= node_count(n.local_);
+ }
+
+ void unlink_nodes(iterator_base begin, iterator_base end)
+ {
+ BOOST_ASSERT(begin.bucket_ == end.bucket_);
+ local_iterator_base local_end = end.local_;
+
+ size_ -= node_count(begin.local_, local_end);
+ link_ptr* it = get_for_erase(begin);
+ split_group(*it, local_end.node_);
+ *it = local_end.node_;
+ }
+
+ void unlink_nodes(bucket_ptr base, iterator_base end)
+ {
+ BOOST_ASSERT(base == end.bucket_);
+
+ local_iterator_base local_end = end.local_;
+ split_group(local_end.node_);
+
+ link_ptr ptr(base->next_);
+ base->next_ = local_end.node_;
+
+ size_ -= node_count(local_iterator_base(ptr), local_end);
+ }
+
+ // Break a ciruclar list into two, with split as the beginning
+ // of the second group (if split is at the beginning then don't
+ // split).
+ void split_group(link_ptr split)
+ {
+ node_base::split_group(split);
+ }
+
+ void split_group(link_ptr split1, link_ptr split2)
+ {
+ node_base::split_group(split1, split2);
+ }
+
+ // throws, strong exception-safety:
+ link_ptr construct_node(value_type const& v)
+ {
+ node_constructor a(allocators_);
+ a.construct(v);
+ return a.release();
+ }
+
+ // Create Node
+ //
+ // Create a node and add it to the buckets in the given position.
+ //
+ // strong exception safety.
+
+ iterator_base create_node(value_type const& v, bucket_ptr base)
+ {
+ // throws, strong exception-safety:
+ link_ptr n = construct_node(v);
+
+ // Rest is no throw
+ link_node(n, base);
+ return iterator_base(base, n);
+ }
+
+ iterator_base create_node(value_type const& v, iterator_base position)
+ {
+ BOOST_ASSERT(EquivKeys::value);
+
+ // throws, strong exception-safety:
+ link_ptr n = construct_node(v);
+
+ // Rest is no throw
+ link_node(n, position.local_);
+ return iterator_base(position.bucket_, n);
+ }
+
+ iterator_base create_node(value_type const& v,
+ bucket_ptr base, local_iterator_base position)
+ {
+ BOOST_ASSERT(EquivKeys::value);
+
+ // throws, strong exception-safety:
+ link_ptr n = construct_node(v);
+
+ // Rest is no throw
+ if(position.not_finished())
+ link_node(n, position);
+ else
+ link_node(n, base);
+
+ return iterator_base(base, n);
+ }
+
+ void copy_group(local_iterator_base it, bucket_ptr dst)
+ {
+ local_iterator_base end = it;
+ end.next_group();
+ iterator_base pos = create_node(*it, dst);
+ for(it.increment(); it != end; it.increment())
+ create_node(*it, pos);
+ }
+
+ // Delete Node
+ //
+ // Remove a node, or a range of nodes, from a bucket, and destroy
+ // them.
+ //
+ // no throw
+
+ void delete_to_bucket_end(link_ptr begin)
+ {
+ while(begin) {
+ link_ptr node = begin;
+ begin = begin->next_;
+ allocators_.destroy(node);
+ }
+ }
+
+ void delete_nodes(link_ptr begin, link_ptr end)
+ {
+ while(begin != end) {
+ link_ptr node = begin;
+ begin = begin->next_;
+ allocators_.destroy(node);
+ }
+ }
+
+ void delete_group(link_ptr first_node)
+ {
+ delete_nodes(first_node, next_group(first_node));
+ }
+
+ // Clear
+ //
+ // Remove all the nodes.
+ //
+ // no throw
+
+ void clear_bucket(bucket_ptr b)
+ {
+ link_ptr first_node = b->next_;
+ unordered_detail::reset(b->next_);
+ delete_to_bucket_end(first_node);
+ }
+
+ void clear()
+ {
+ bucket_ptr begin = buckets_;
+ bucket_ptr end = buckets_ + bucket_count_;
+
+ size_ = 0;
+ cached_begin_bucket_ = end;
+
+ while(begin != end) {
+ clear_bucket(begin);
+ ++begin;
+ }
+ }
+
+ // Erase
+ //
+ // no throw
+
+ iterator_base erase(iterator_base r)
+ {
+ BOOST_ASSERT(r != end());
+ iterator_base next = r;
+ next.increment();
+ unlink_node(r);
+ allocators_.destroy(r.local_.node_);
+ // r has been invalidated but its bucket is still valid
+ recompute_begin_bucket(r.bucket_, next.bucket_);
+ return next;
+ }
+
+ iterator_base erase(iterator_base r1, iterator_base r2)
+ {
+ if(r1 != r2)
+ {
+ BOOST_ASSERT(r1 != end());
+
+ if (r1.bucket_ == r2.bucket_) {
+ unlink_nodes(r1, r2);
+ delete_nodes(r1.local_.node_, r2.local_.node_);
+
+ // No need to call recompute_begin_bucket because
+ // the nodes are only deleted from one bucket, which
+ // still contains r2 after the erase.
+ BOOST_ASSERT(!r1.bucket_->empty());
+ }
+ else {
+ BOOST_ASSERT(r1.bucket_ < r2.bucket_);
+
+ unlink_nodes(r1);
+ delete_to_bucket_end(r1.local_.node_);
+
+ for(bucket_ptr i = r1.bucket_ + 1; i != r2.bucket_; ++i) {
+ size_ -= node_count(local_iterator_base(i->next_));
+ clear_bucket(i);
+ }
+
+ if(r2 != end()) {
+ link_ptr first = r2.bucket_->next_;
+ unlink_nodes(r2.bucket_, r2);
+ delete_nodes(first, r2.local_.node_);
+ }
+
+ // r1 has been invalidated but its bucket is still
+ // valid.
+ recompute_begin_bucket(r1.bucket_, r2.bucket_);
+ }
+ }
+
+ return r2;
+ }
+
+ // recompute_begin_bucket
+ //
+ // After an erase cached_begin_bucket_ might be left pointing to
+ // an empty bucket, so this is called to update it
+ //
+ // no throw
+
+ void recompute_begin_bucket(bucket_ptr b)
+ {
+ BOOST_ASSERT(!(b < cached_begin_bucket_));
+
+ if(b == cached_begin_bucket_)
+ {
+ if (size_ != 0) {
+ while (cached_begin_bucket_->empty())
+ ++cached_begin_bucket_;
+ } else {
+ cached_begin_bucket_ = buckets_ + bucket_count_;
+ }
+ }
+ }
+
+ // This is called when a range has been erased
+ //
+ // no throw
+
+ void recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2)
+ {
+ BOOST_ASSERT(!(b1 < cached_begin_bucket_) && !(b2 < b1));
+ BOOST_ASSERT(b2 == buckets_ + bucket_count_ || !b2->empty());
+
+ if(b1 == cached_begin_bucket_ && b1->empty())
+ cached_begin_bucket_ = b2;
+ }
+
+ size_type erase_group(link_ptr* it, bucket_ptr bucket)
+ {
+ link_ptr pos = *it;
+ size_type count = unlink_group(it);
+ delete_group(pos);
+
+ this->recompute_begin_bucket(bucket);
+
+ return count;
+ }
+ };
+
+#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
+ template <>
+ class hash_table_data<int, int>
+ {
+ public:
+ typedef int size_type;
+ typedef int iterator_base;
+ };
+#endif
 
         //
         // Hash Table

Deleted: sandbox-branches/unordered-refactor/boost/unordered/detail/hash_table_impl.hpp
==============================================================================
--- sandbox-branches/unordered-refactor/boost/unordered/detail/hash_table_impl.hpp 2007-12-08 13:06:12 EST (Sat, 08 Dec 2007)
+++ (empty file)
@@ -1,773 +0,0 @@
-
-// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
-// Copyright (C) 2005-2007 Daniel James
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-
-namespace boost {
- namespace unordered_detail {
-
- template <typename Alloc, typename EquivKeys>
- struct select_node_base
- : public boost::mpl::if_<
- EquivKeys,
- node_base_equivalent_keys<Alloc>,
- node_base_unique_keys<Alloc> > {};
-
- //
- // Hash Table Data
- //
- // Responsible for managing the hash buckets.
-
- template <typename Alloc, typename EquivKeys>
- class hash_table_data
- {
- public:
- typedef bucket<Alloc> bucket;
- typedef typename bucket::bucket_allocator bucket_allocator;
- typedef typename bucket::bucket_ptr bucket_ptr;
- typedef typename bucket::link_ptr link_ptr;
-
- struct node;
- typedef std::size_t size_type;
-
- typedef Alloc value_allocator;
-
- typedef BOOST_DEDUCED_TYPENAME
- boost::unordered_detail::rebind_wrap<Alloc, node>::type
- node_allocator;
-
- typedef BOOST_DEDUCED_TYPENAME allocator_value_type<Alloc>::type value_type;
- typedef BOOST_DEDUCED_TYPENAME allocator_pointer<node_allocator>::type node_ptr;
- typedef BOOST_DEDUCED_TYPENAME allocator_reference<value_allocator>::type reference;
-
- typedef typename select_node_base<Alloc, EquivKeys>::type node_base;
-
- typedef BOOST_DEDUCED_TYPENAME
- boost::unordered_detail::rebind_wrap<Alloc, node_base>::type
- node_base_allocator;
-
- struct node : node_base
- {
- public:
- node(value_type const& v) : node_base(), value_(v) {}
-
- value_type value_;
- };
-
- // node_constructor
- //
- // Used to construct nodes in an exception safe manner.
-
- struct allocators
- {
- node_allocator node_alloc_;
- bucket_allocator bucket_alloc_;
- value_allocator value_alloc_;
- node_base_allocator node_base_alloc_;
-
- allocators(value_allocator const& a)
- : node_alloc_(a), bucket_alloc_(a),
- value_alloc_(a), node_base_alloc_(a)
- {}
-
- void destroy(link_ptr ptr)
- {
- node_ptr n(node_alloc_.address(static_cast<node&>(*ptr)));
- value_alloc_.destroy(value_alloc_.address(n->value_));
- node_base_alloc_.destroy(node_base_alloc_.address(*n));
- node_alloc_.deallocate(n, 1);
- }
-
- void swap(allocators& x)
- {
- hash_swap(node_alloc_, x.node_alloc_);
- hash_swap(bucket_alloc_, x.bucket_alloc_);
- hash_swap(value_alloc_, x.value_alloc_);
- hash_swap(node_base_alloc_, x.node_base_alloc_);
- }
-
- bool operator==(allocators const& x)
- {
- return value_alloc_ == x.value_alloc_;
- }
- };
-
- class node_constructor
- {
- allocators& allocators_;
-
- node_ptr node_;
- bool value_constructed_;
- bool node_base_constructed_;
-
- public:
-
- node_constructor(allocators& a)
- : allocators_(a),
- node_(), value_constructed_(false), node_base_constructed_(false)
- {
- BOOST_HASH_MSVC_RESET_PTR(node_);
- }
-
- ~node_constructor()
- {
- if (node_) {
- if (value_constructed_)
- allocators_.value_alloc_.destroy(
- allocators_.value_alloc_.address(node_->value_));
- if (node_base_constructed_)
- allocators_.node_base_alloc_.destroy(
- allocators_.node_base_alloc_.address(*node_));
-
- allocators_.node_alloc_.deallocate(node_, 1);
- }
- }
-
- template <typename V>
- void construct(V const& v)
- {
- BOOST_ASSERT(!node_);
- value_constructed_ = false;
- node_base_constructed_ = false;
-
- node_ = allocators_.node_alloc_.allocate(1);
-
- allocators_.node_base_alloc_.construct(
- allocators_.node_base_alloc_.address(*node_),
- node_base());
- node_base_constructed_ = true;
-
- allocators_.value_alloc_.construct(
- allocators_.value_alloc_.address(node_->value_), v);
- value_constructed_ = true;
- }
-
- node_ptr get() const
- {
- BOOST_ASSERT(node_);
- return node_;
- }
-
- // no throw
- link_ptr release()
- {
- node_ptr p = node_;
- unordered_detail::reset(node_);
- return link_ptr(allocators_.bucket_alloc_.address(*p));
- }
-
- private:
- node_constructor(node_constructor const&);
- node_constructor& operator=(node_constructor const&);
- };
-
- // Methods for navigating groups of elements with equal keys.
-
- static link_ptr& prev_in_group(link_ptr n) {
- return node_base::prev_in_group(n);
- }
-
- // pre: Must be pointing to the first node in a group.
- static link_ptr last_in_group(link_ptr n) {
- return node_base::last_in_group(n);
- }
-
- // pre: Must be pointing to the first node in a group.
- static link_ptr& next_group(link_ptr n) {
- return node_base::next_group(n);
- }
-
- // pre: Must be pointing to a node
- static reference get_value(link_ptr p) {
- BOOST_ASSERT(p);
- return static_cast<node&>(*p).value_;
- }
-
- class local_iterator_base
- {
- public:
- link_ptr node_;
-
- local_iterator_base()
- : node_()
- {
- BOOST_HASH_MSVC_RESET_PTR(node_);
- }
-
- explicit local_iterator_base(link_ptr n)
- : node_(n) {}
-
- bool not_finished() const
- {
- return node_ ? true : false;
- }
-
- bool operator==(local_iterator_base const& x) const
- {
- return node_ == x.node_;
- }
-
- bool operator!=(local_iterator_base const& x) const
- {
- return node_ != x.node_;
- }
-
- reference operator*() const
- {
- return get_value(node_);
- }
-
- void increment()
- {
- BOOST_ASSERT(node_);
- node_ = node_->next_;
- }
-
- void next_group()
- {
- node_ = hash_table_data::next_group(node_);
- }
- };
-
- class iterator_base
- {
- public:
- bucket_ptr bucket_;
- local_iterator_base local_;
-
- iterator_base()
- : bucket_(), local_() {}
-
- explicit iterator_base(bucket_ptr b)
- : bucket_(b), local_(b->next_) {}
-
- iterator_base(bucket_ptr b, link_ptr n)
- : bucket_(b), local_(n) {}
-
- iterator_base(bucket_ptr b, local_iterator_base const& it)
- : bucket_(b), local_(it) {}
-
- bool operator==(iterator_base const& x) const
- {
- return local_ == x.local_;
- }
-
- bool operator!=(iterator_base const& x) const
- {
- return local_ != x.local_;
- }
-
- reference operator*() const
- {
- return *local_;
- }
-
- void increment()
- {
- BOOST_ASSERT(bucket_);
- local_.increment();
-
- while (!local_.node_) {
- ++bucket_;
- local_ = local_iterator_base(bucket_->next_);
- }
- }
- };
-
- // Member Variables
-
- allocators allocators_;
- bucket_ptr buckets_;
- size_type bucket_count_;
- bucket_ptr cached_begin_bucket_;
- size_type size_;
-
- // Constructors/Deconstructor
-
- hash_table_data(size_type n, value_allocator const& a)
- : allocators_(a),
- buckets_(), bucket_count_(next_prime(n)),
- cached_begin_bucket_(), size_(0)
- {
- // The array constructor will clean up in the event of an
- // exception.
- allocator_array_constructor<bucket_allocator>
- constructor(allocators_.bucket_alloc_);
-
- // Creates an extra bucket to act as a sentinel.
- constructor.construct(bucket(), bucket_count_ + 1);
-
- cached_begin_bucket_ = constructor.get() + bucket_count_;
-
- // Set up the sentinel.
- cached_begin_bucket_->next_ = link_ptr(cached_begin_bucket_);
-
- // Only release the buckets once everything is successfully
- // done.
- buckets_ = constructor.release();
- }
-
- hash_table_data(hash_table_data const& x, size_type n)
- : allocators_(x.allocators_),
- buckets_(), bucket_count_(next_prime(n)),
- cached_begin_bucket_(), size_(0)
- {
- // The array constructor will clean up in the event of an
- // exception.
- allocator_array_constructor<bucket_allocator>
- constructor(allocators_.bucket_alloc_);
-
- // Creates an extra bucket to act as a sentinel.
- constructor.construct(bucket(), bucket_count_ + 1);
-
- cached_begin_bucket_ = constructor.get() + bucket_count_;
-
- // Set up the sentinel
- cached_begin_bucket_->next_ = link_ptr(cached_begin_bucket_);
-
- // Only release the buckets once everything is successfully
- // done.
- buckets_ = constructor.release();
- }
-
- // no throw
- ~hash_table_data()
- {
- if(buckets_) {
- bucket_ptr begin = cached_begin_bucket_;
- bucket_ptr end = buckets_ + bucket_count_;
- while(begin != end) {
- clear_bucket(begin);
- ++begin;
- }
-
- // Destroy an extra bucket for the sentinels.
- for(size_type i2 = 0; i2 < bucket_count_ + 1; ++i2)
- allocators_.bucket_alloc_.destroy(buckets_ + i2);
-
- allocators_.bucket_alloc_.deallocate(buckets_, bucket_count_ + 1);
- }
- }
-
- private:
-
- hash_table_data(hash_table_data const&);
- hash_table_data& operator=(hash_table_data const&);
-
- public:
-
- // no throw
- void swap(hash_table_data& other)
- {
- std::swap(buckets_, other.buckets_);
- std::swap(bucket_count_, other.bucket_count_);
- std::swap(cached_begin_bucket_, other.cached_begin_bucket_);
- std::swap(size_, other.size_);
- }
-
- // Return the bucket index for a hashed value.
- //
- // no throw
- size_type index_from_hash(size_type hashed) const
- {
- return hashed % bucket_count_;
- }
-
- // Begin & End
- //
- // no throw
-
- iterator_base begin() const
- {
- return size_
- ? iterator_base(cached_begin_bucket_)
- : end();
- }
-
- iterator_base end() const
- {
- return iterator_base(buckets_ + bucket_count_);
- }
-
- local_iterator_base begin(size_type n) const
- {
- return local_iterator_base(buckets_[n].next_);
- }
-
- local_iterator_base end(size_type) const
- {
- return local_iterator_base();
- }
-
- local_iterator_base begin(bucket_ptr b) const
- {
- return local_iterator_base(b->next_);
- }
-
- // Bucket Size
-
- // no throw
- size_type node_count(local_iterator_base it) const
- {
- size_type count = 0;
- while(it.not_finished()) {
- ++count;
- it.increment();
- }
- return count;
- }
-
- size_type node_count(local_iterator_base it1,
- local_iterator_base it2) const
- {
- size_type count = 0;
- while(it1 != it2) {
- ++count;
- it1.increment();
- }
- return count;
- }
-
- size_type bucket_size(size_type n) const
- {
- return node_count(begin(n));
- }
-
- size_type group_count(local_iterator_base first_node) const
- {
- return node_base::group_count(first_node.node_);
- }
-
- // get_for_erase
- //
- // Find the pointer to a node, for use when erasing.
- //
- // no throw
-
- link_ptr* get_for_erase(iterator_base r) const
- {
- return node_base::get_for_erase(r.bucket_, r.local_.node_);
- }
-
- // Link/Unlink/Move Node
- //
- // For adding nodes to buckets, removing them and moving them to a
- // new bucket.
- //
- // no throw
-
- void link_node(link_ptr n, local_iterator_base pos)
- {
- node_base::link_node(n, pos.node_);
- ++size_;
- }
-
- void link_node(link_ptr n, bucket_ptr base)
- {
- node_base::link_node_in_bucket(n, base);
- ++size_;
- if(base < cached_begin_bucket_) cached_begin_bucket_ = base;
- }
-
- void link_group(link_ptr n, bucket_ptr base, size_type count)
- {
- node_base::link_group(n, base);
- size_ += count;
- if(base < cached_begin_bucket_) cached_begin_bucket_ = base;
- }
-
- void unlink_node(iterator_base it)
- {
- node_base::unlink_node(get_for_erase(it));
- --size_;
- }
-
- size_type unlink_group(link_ptr* pos)
- {
- size_type count = group_count(local_iterator_base(*pos));
- size_ -= count;
- *pos = next_group(*pos);
- return count;
- }
-
- void unlink_nodes(iterator_base n)
- {
- link_ptr* it = get_for_erase(n);
- split_group(*it);
- unordered_detail::reset(*it);
- size_ -= node_count(n.local_);
- }
-
- void unlink_nodes(iterator_base begin, iterator_base end)
- {
- BOOST_ASSERT(begin.bucket_ == end.bucket_);
- local_iterator_base local_end = end.local_;
-
- size_ -= node_count(begin.local_, local_end);
- link_ptr* it = get_for_erase(begin);
- split_group(*it, local_end.node_);
- *it = local_end.node_;
- }
-
- void unlink_nodes(bucket_ptr base, iterator_base end)
- {
- BOOST_ASSERT(base == end.bucket_);
-
- local_iterator_base local_end = end.local_;
- split_group(local_end.node_);
-
- link_ptr ptr(base->next_);
- base->next_ = local_end.node_;
-
- size_ -= node_count(local_iterator_base(ptr), local_end);
- }
-
- // Break a ciruclar list into two, with split as the beginning
- // of the second group (if split is at the beginning then don't
- // split).
- void split_group(link_ptr split)
- {
- node_base::split_group(split);
- }
-
- void split_group(link_ptr split1, link_ptr split2)
- {
- node_base::split_group(split1, split2);
- }
-
- // throws, strong exception-safety:
- link_ptr construct_node(value_type const& v)
- {
- node_constructor a(allocators_);
- a.construct(v);
- return a.release();
- }
-
- // Create Node
- //
- // Create a node and add it to the buckets in the given position.
- //
- // strong exception safety.
-
- iterator_base create_node(value_type const& v, bucket_ptr base)
- {
- // throws, strong exception-safety:
- link_ptr n = construct_node(v);
-
- // Rest is no throw
- link_node(n, base);
- return iterator_base(base, n);
- }
-
- iterator_base create_node(value_type const& v, iterator_base position)
- {
- BOOST_ASSERT(EquivKeys::value);
-
- // throws, strong exception-safety:
- link_ptr n = construct_node(v);
-
- // Rest is no throw
- link_node(n, position.local_);
- return iterator_base(position.bucket_, n);
- }
-
- iterator_base create_node(value_type const& v,
- bucket_ptr base, local_iterator_base position)
- {
- BOOST_ASSERT(EquivKeys::value);
-
- // throws, strong exception-safety:
- link_ptr n = construct_node(v);
-
- // Rest is no throw
- if(position.not_finished())
- link_node(n, position);
- else
- link_node(n, base);
-
- return iterator_base(base, n);
- }
-
- void copy_group(local_iterator_base it, bucket_ptr dst)
- {
- local_iterator_base end = it;
- end.next_group();
- iterator_base pos = create_node(*it, dst);
- for(it.increment(); it != end; it.increment())
- create_node(*it, pos);
- }
-
- // Delete Node
- //
- // Remove a node, or a range of nodes, from a bucket, and destroy
- // them.
- //
- // no throw
-
- void delete_to_bucket_end(link_ptr begin)
- {
- while(begin) {
- link_ptr node = begin;
- begin = begin->next_;
- allocators_.destroy(node);
- }
- }
-
- void delete_nodes(link_ptr begin, link_ptr end)
- {
- while(begin != end) {
- link_ptr node = begin;
- begin = begin->next_;
- allocators_.destroy(node);
- }
- }
-
- void delete_group(link_ptr first_node)
- {
- delete_nodes(first_node, next_group(first_node));
- }
-
- // Clear
- //
- // Remove all the nodes.
- //
- // no throw
-
- void clear_bucket(bucket_ptr b)
- {
- link_ptr first_node = b->next_;
- unordered_detail::reset(b->next_);
- delete_to_bucket_end(first_node);
- }
-
- void clear()
- {
- bucket_ptr begin = buckets_;
- bucket_ptr end = buckets_ + bucket_count_;
-
- size_ = 0;
- cached_begin_bucket_ = end;
-
- while(begin != end) {
- clear_bucket(begin);
- ++begin;
- }
- }
-
- // Erase
- //
- // no throw
-
- iterator_base erase(iterator_base r)
- {
- BOOST_ASSERT(r != end());
- iterator_base next = r;
- next.increment();
- unlink_node(r);
- allocators_.destroy(r.local_.node_);
- // r has been invalidated but its bucket is still valid
- recompute_begin_bucket(r.bucket_, next.bucket_);
- return next;
- }
-
- iterator_base erase(iterator_base r1, iterator_base r2)
- {
- if(r1 != r2)
- {
- BOOST_ASSERT(r1 != end());
-
- if (r1.bucket_ == r2.bucket_) {
- unlink_nodes(r1, r2);
- delete_nodes(r1.local_.node_, r2.local_.node_);
-
- // No need to call recompute_begin_bucket because
- // the nodes are only deleted from one bucket, which
- // still contains r2 after the erase.
- BOOST_ASSERT(!r1.bucket_->empty());
- }
- else {
- BOOST_ASSERT(r1.bucket_ < r2.bucket_);
-
- unlink_nodes(r1);
- delete_to_bucket_end(r1.local_.node_);
-
- for(bucket_ptr i = r1.bucket_ + 1; i != r2.bucket_; ++i) {
- size_ -= node_count(local_iterator_base(i->next_));
- clear_bucket(i);
- }
-
- if(r2 != end()) {
- link_ptr first = r2.bucket_->next_;
- unlink_nodes(r2.bucket_, r2);
- delete_nodes(first, r2.local_.node_);
- }
-
- // r1 has been invalidated but its bucket is still
- // valid.
- recompute_begin_bucket(r1.bucket_, r2.bucket_);
- }
- }
-
- return r2;
- }
-
- // recompute_begin_bucket
- //
- // After an erase cached_begin_bucket_ might be left pointing to
- // an empty bucket, so this is called to update it
- //
- // no throw
-
- void recompute_begin_bucket(bucket_ptr b)
- {
- BOOST_ASSERT(!(b < cached_begin_bucket_));
-
- if(b == cached_begin_bucket_)
- {
- if (size_ != 0) {
- while (cached_begin_bucket_->empty())
- ++cached_begin_bucket_;
- } else {
- cached_begin_bucket_ = buckets_ + bucket_count_;
- }
- }
- }
-
- // This is called when a range has been erased
- //
- // no throw
-
- void recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2)
- {
- BOOST_ASSERT(!(b1 < cached_begin_bucket_) && !(b2 < b1));
- BOOST_ASSERT(b2 == buckets_ + bucket_count_ || !b2->empty());
-
- if(b1 == cached_begin_bucket_ && b1->empty())
- cached_begin_bucket_ = b2;
- }
-
- size_type erase_group(link_ptr* it, bucket_ptr bucket)
- {
- link_ptr pos = *it;
- size_type count = unlink_group(it);
- delete_group(pos);
-
- this->recompute_begin_bucket(bucket);
-
- return count;
- }
- };
-
-#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
- template <>
- class hash_table_data<int>
- {
- public:
- typedef int size_type;
- typedef int iterator_base;
- };
-#endif
-
- }
-}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk