From a49c76c69c6e5adf53a089110965854d3e1c0a2d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 13 Nov 2010 12:30:06 +0000 Subject: [PATCH] More comments describing the unordered internals. And fix a couple of small mistakes in the existing comments. [SVN r66555] --- include/boost/unordered/detail/fwd.hpp | 106 +++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index be4d5e1a..4f347355 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -21,14 +21,14 @@ // 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 -// of preprocessor metaprogramming - they are in insert.hpp +// of preprocessor metaprogramming - they are in unique.hpp and equivalent.hpp. // Template parameters: // // H = Hash Function // P = Predicate // A = Value Allocator -// G = Grouped/Ungrouped +// G = Bucket group policy, 'grouped' or 'ungrouped' // E = Key Extractor #if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) @@ -90,7 +90,37 @@ namespace boost { namespace unordered_detail { #pragma warning(pop) #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 + // | + // ungrouped_node_base value_base + // | | + // +--------------+-------------+ + // | + // hash_node + // + // For unordered_multiset/unordered_multimap: + // + // hash_bucket + // | + // grouped_node_base value_base + // | | + // +--------------+-------------+ + // | + // hash_node + // 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 hash_bucket @@ -109,6 +139,16 @@ namespace boost { namespace unordered_detail { 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 struct ungrouped_node_base : hash_bucket { typedef hash_bucket bucket; @@ -125,6 +165,10 @@ namespace boost { namespace unordered_detail { 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 struct grouped_node_base : hash_bucket { @@ -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 { template @@ -167,6 +215,8 @@ namespace boost { namespace unordered_detail { }; }; + // The space used to store values in a node. + template struct value_base { @@ -203,7 +253,13 @@ namespace boost { namespace unordered_detail { hash_node& operator=(hash_node const&); }; + //////////////////////////////////////////////////////////////////////////// + // // 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 hash_iterator_base @@ -248,12 +304,24 @@ namespace boost { namespace unordered_detail { } }; + //////////////////////////////////////////////////////////////////////////// + // + // Now the main data structure: + // + // hash_buckets hash_buffered_functions + // | | + // +-------------+--------------+ + // | + // hash_table + // + // T is a class which contains typedefs for all the types we need. + // hash_buckets // // This is responsible for allocating and deallocating buckets and nodes. // // 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. // 2. It's the callers responsibility to allocate the buckets before calling // 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); }; + // 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 set_hash_functions; template @@ -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 hash_table : public T::buckets, public T::buffered_functions { @@ -569,7 +654,12 @@ namespace boost { namespace unordered_detail { 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__) class iterator_access @@ -605,7 +695,6 @@ namespace boost { namespace unordered_detail { }; #endif - // Iterators template class hash_iterator; template class hash_const_iterator; @@ -716,7 +805,7 @@ namespace boost { namespace unordered_detail { } }; - // iterators + // Iterators // // all no throw @@ -823,7 +912,12 @@ namespace boost { namespace unordered_detail { } }; + //////////////////////////////////////////////////////////////////////////// + // // types + // + // This is used to convieniently pass around a container's typedefs + // without having 7 template parameters. template struct types