More comments describing the unordered internals.

And fix a couple of small mistakes in the existing comments.

[SVN r66555]
This commit is contained in:
Daniel James
2010-11-13 12:30:06 +00:00
parent eb04f68351
commit a49c76c69c

View File

@ -21,14 +21,14 @@
// This header defines most of the classes used to implement the unordered // This header defines most of the classes used to implement the unordered
// containers. It doesn't include the insert methods as they require a lot // containers. It doesn't include the insert methods as they require a lot
// of preprocessor metaprogramming - they are in insert.hpp // of preprocessor metaprogramming - they are in unique.hpp and equivalent.hpp.
// Template parameters: // Template parameters:
// //
// H = Hash Function // H = Hash Function
// P = Predicate // P = Predicate
// A = Value Allocator // A = Value Allocator
// G = Grouped/Ungrouped // G = Bucket group policy, 'grouped' or 'ungrouped'
// E = Key Extractor // E = Key Extractor
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) #if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
@ -90,7 +90,37 @@ namespace boost { namespace unordered_detail {
#pragma warning(pop) #pragma warning(pop)
#endif #endif
////////////////////////////////////////////////////////////////////////////
//
// This section implements buckets and nodes. Here's a rough
// inheritance diagram, to show how they pull together.
//
// For unordered_set/unordered_map:
//
// hash_bucket<A>
// |
// ungrouped_node_base<A> value_base<A::value_type>
// | |
// +--------------+-------------+
// |
// hash_node<A, ungrouped>
//
// For unordered_multiset/unordered_multimap:
//
// hash_bucket<A>
// |
// grouped_node_base<A> value_base<A::value_type>
// | |
// +--------------+-------------+
// |
// hash_node<A, grouped>
// hash_bucket // hash_bucket
//
// hash_bucket is used for both the buckets and as a base class for
// nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point
// to either a bucket or a node. This is used later to implement a
// sentinel at the end of the bucket array.
template <class A> template <class A>
class hash_bucket class hash_bucket
@ -109,6 +139,16 @@ namespace boost { namespace unordered_detail {
hash_bucket() : next_() {} hash_bucket() : next_() {}
}; };
// In containers with equivalent keys (unordered_multimap and
// unordered_multiset) equivalent nodes are grouped together, in
// containers with unique keys (unordered_map and unordered_set)
// individual nodes are treated as groups of one. The following two
// classes implement the data structure.
// This is used for containers with unique keys. There are no groups
// so it doesn't add any extra members, and just treats individual
// nodes as groups of one.
template <class A> template <class A>
struct ungrouped_node_base : hash_bucket<A> { struct ungrouped_node_base : hash_bucket<A> {
typedef hash_bucket<A> bucket; typedef hash_bucket<A> bucket;
@ -125,6 +165,10 @@ namespace boost { namespace unordered_detail {
static void unlink_nodes(bucket& b, node_ptr end); static void unlink_nodes(bucket& b, node_ptr end);
}; };
// This is used for containers with equivalent keys. It implements a
// circular list running in the opposite direction to the linked
// list through the nodes.
template <class A> template <class A>
struct grouped_node_base : hash_bucket<A> struct grouped_node_base : hash_bucket<A>
{ {
@ -151,6 +195,10 @@ namespace boost { namespace unordered_detail {
} }
}; };
// These two classes implement an easy way to pass around the node
// group policy classes without the messy template parameters.
// Whenever you see the template parameter 'G' it's one of these.
struct ungrouped struct ungrouped
{ {
template <class A> template <class A>
@ -167,6 +215,8 @@ namespace boost { namespace unordered_detail {
}; };
}; };
// The space used to store values in a node.
template <class ValueType> template <class ValueType>
struct value_base struct value_base
{ {
@ -203,7 +253,13 @@ namespace boost { namespace unordered_detail {
hash_node& operator=(hash_node const&); hash_node& operator=(hash_node const&);
}; };
////////////////////////////////////////////////////////////////////////////
//
// Iterator Base // Iterator Base
//
// This is the iterator used internally, the external iterators are
// provided by lightweight wrappers (hash_iterator and
// hast_const_iterator) which provide the full iterator interface.
template <class A, class G> template <class A, class G>
class hash_iterator_base class hash_iterator_base
@ -248,12 +304,24 @@ namespace boost { namespace unordered_detail {
} }
}; };
////////////////////////////////////////////////////////////////////////////
//
// Now the main data structure:
//
// hash_buckets<A, G> hash_buffered_functions<H, P>
// | |
// +-------------+--------------+
// |
// hash_table<T>
//
// T is a class which contains typedefs for all the types we need.
// hash_buckets // hash_buckets
// //
// This is responsible for allocating and deallocating buckets and nodes. // This is responsible for allocating and deallocating buckets and nodes.
// //
// Notes: // Notes:
// 1. For the sake exception safety the allocators themselves don't allocate // 1. For the sake exception safety the consturctors don't allocate
// anything. // anything.
// 2. It's the callers responsibility to allocate the buckets before calling // 2. It's the callers responsibility to allocate the buckets before calling
// any of the methods (other than getters and setters). // any of the methods (other than getters and setters).
@ -327,6 +395,17 @@ namespace boost { namespace unordered_detail {
std::size_t delete_to_bucket_end(node_ptr begin); std::size_t delete_to_bucket_end(node_ptr begin);
}; };
// Assigning and swapping the equality and hash function objects
// needs strong exception safety. To implement that normally we'd
// require one of them to be known to not throw and the other to
// guarantee strong exception safety. Unfortunately they both only
// have basic exception safety. So to acheive strong exception
// safety we have storage space for two copies, and assign the new
// copies to the unused space. Then switch to using that to use
// them. This is implemented in 'set_hash_functions' which
// atomically assigns the new function objects in a strongly
// exception safe manner.
template <class H, class P> class set_hash_functions; template <class H, class P> class set_hash_functions;
template <class H, class P> template <class H, class P>
@ -429,6 +508,12 @@ namespace boost { namespace unordered_detail {
} }
}; };
// This implements almost all of the required functionality, apart
// from some things that are specific to containers with unique and
// equivalent keys which is implemented in hash_unique_table and
// hash_equivalent_table. See unique.hpp and equivalent.hpp for
// their declaration and implementation.
template <class T> template <class T>
class hash_table : public T::buckets, public T::buffered_functions class hash_table : public T::buckets, public T::buffered_functions
{ {
@ -569,7 +654,12 @@ namespace boost { namespace unordered_detail {
node_constructor&, std::size_t); node_constructor&, std::size_t);
}; };
// Iterator Access ///////////////////////////////////////////////////////////////////
//
// Iterators
// iterator_access is used to access the internal iterator without
// making it publicly available.
#if !defined(__clang__) #if !defined(__clang__)
class iterator_access class iterator_access
@ -605,7 +695,6 @@ namespace boost { namespace unordered_detail {
}; };
#endif #endif
// Iterators
template <class A, class G> class hash_iterator; template <class A, class G> class hash_iterator;
template <class A, class G> class hash_const_iterator; template <class A, class G> class hash_const_iterator;
@ -716,7 +805,7 @@ namespace boost { namespace unordered_detail {
} }
}; };
// iterators // Iterators
// //
// all no throw // all no throw
@ -823,7 +912,12 @@ namespace boost { namespace unordered_detail {
} }
}; };
////////////////////////////////////////////////////////////////////////////
//
// types // types
//
// This is used to convieniently pass around a container's typedefs
// without having 7 template parameters.
template <class K, class V, class H, class P, class A, class E, class G> template <class K, class V, class H, class P, class A, class E, class G>
struct types struct types