diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 95911f47..137cc380 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -1,17 +1,15 @@ +project boost/doc ; +import boostbook : boostbook ; -# Copyright 2005 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) +boostbook doc : src/boost.xml + : -using quickbook ; + ## Build the various generated docs (Doxygen and QuickBook)... -xml unordered : unordered.qbk ; -boostbook standalone : unordered : - boost.root=../../../.. - boost.libraries=../../../libraries.htm - html.stylesheet=../../../../doc/html/boostbook.css - chunk.first.sections=1 - chunk.section.depth=2 - generate.section.toc.level=2 - toc.section.depth=1 - toc.max.depth=1 ; + ../libs/unordered/doc//unordered + ../libs/unordered/doc//unordered + #../libs/functional/hash/doc//hash + #../libs/functional/hash/doc//hash + + boost.libraries=../../libs/libraries.htm + ; diff --git a/doc/buckets.qbk b/doc/buckets.qbk index 57cabdc0..24778aaa 100644 --- a/doc/buckets.qbk +++ b/doc/buckets.qbk @@ -7,8 +7,8 @@ The containers are made up of a number of 'buckets', each of which can contain any number of elements. For example, the following diagram shows an [classref boost::unordered_set unordered_set] with 7 buckets containing 5 elements, `A`, -`B`, `C`, `D` and `E` (this is just for illustration, containers will typically -have more buckets). +`B`, `C`, `D` and `E` (this is just for illustration, in practise containers +will have more buckets). [$../../libs/unordered/doc/diagrams/buckets.png] @@ -97,10 +97,9 @@ elements into container `x`, you could first call: x.rehash((x.size() + n) / x.max_load_factor() + 1); [blurb Note: `rehash`'s argument is the number of buckets, not the number of -elements, which is why the new size is divided by the maximum load factor. The -+ 1 guarantees there is no invalidation; without it, reallocation could occur -if the number of bucket exactly divides the target size, since the container is -allowed to rehash when the load factor is equal to the maximum load factor.] +elements, which is why the new size is divided by the maximum load factor. The +`+ 1` is required because the container is allowed to resize when the load +factor is equal to the maximum load factor.] [table Methods for Controlling Bucket Size [[Method] [Description]] diff --git a/doc/comparison.qbk b/doc/comparison.qbk index 7f15d189..6703bea6 100644 --- a/doc/comparison.qbk +++ b/doc/comparison.qbk @@ -8,16 +8,19 @@ [[Associative Containers] [Unordered Associative Containers]] [ - [Parameterized by an ordering relation `Compare`] - [Parameterized by a function object `Hash` and an equivalence relation + [Parametrised by an ordering relation `Compare`] + [Parametrised by a function object `Hash` and an equivalence relation `Pred`] ] [ - [Keys can be compared using `key_compare` which is accessed by member function `key_comp()`, - values can be compared using `value_compare` which is accessed by member function `value_comp()`.] - [Keys can be hashed using `hasher` which is accessed by member function `hash_function()`, - and checked for equality using `key_equal` which is accessed by member function `key_eq()`. - There is no function object for compared or hashing values.] + [`Compare` exposed by member typedef `key_compare`, accessed by member function `key_comp()`] + [`Hash` exposed by member typedef `hasher`, accessed by member function `hash_function()`. + + `Pred` by member typedef `key_equal` and member function `key_eq()`.] + ] + [ + [Member typedef `value_compare` supplies an ordering comparison for member elements, accessed by member function `value_comp()`.] + [No equivalent. No idea why.] ] [ [Constructors have optional extra parameters for the comparison object.] @@ -102,15 +105,15 @@ ] [ [Insert a single element with a hint] - [Amortized constant if t elements inserted right after hint, + [Amortised constant if t elements inserted right after hint, logarithmic otherwise] [Average case constant, worst case linear (ie. the same as a normal insert).] ] [ [Inserting a range of /N/ elements] - [ /N/ log(`size()`+/N/) ] - [Average case O(/N/), worst case O(/N/ * `size()`)] + [/N/ log(`size()`+/N/)] + [Average case O(/N/), worst case O(/N/ * 'size()')] ] [ [Erase by key, `k`] @@ -119,7 +122,7 @@ ] [ [Erase a single element by iterator] - [Amortized constant] + [Amortised constant] [Average case: O(1), Worst case: O(`size()`)] ] [ @@ -135,7 +138,7 @@ [ [Find] [logarithmic] - [Average case: O(1), Worst case: O(`size()`)] + [Average case: O(/N/), Worst case: O(`size()`)] ] [/ TODO: Average case is probably wrong. ] [ diff --git a/doc/hash_equality.qbk b/doc/hash_equality.qbk index 11111050..4963e00e 100644 --- a/doc/hash_equality.qbk +++ b/doc/hash_equality.qbk @@ -16,7 +16,7 @@ is declared as: class ``[classref boost::unordered_set unordered_set]``; The hash function comes first as you might want to change the hash function -but not the equality predicate, while if you were to change the behavior +but not the equality predicate, while if you were to change the behaviour of the equality predicate you would have to change the hash function to match it. So, if you wanted to use the [@http://www.isthe.com/chongo/tech/comp/fnv/ FNV-1 hash] you could write: @@ -34,21 +34,59 @@ case-insensitive dictionary: [case_insensitive_functions] [case_insensitive_dictionary] -This is a simplified version of the example at: +A more generic version is available at: [@../../libs/unordered/examples/case_insensitive.hpp /libs/unordered/examples/case_insensitive.hpp] -which supports other locales and string types. [h2 Custom Types] Similarly, a custom hash function can be used for custom types: -[import src_code/point1.cpp] -[point_example1] + struct point { + int x; + int y; + }; -Although, customizing Boost.Hash is probably a better solution: + bool operator==(point const& p1, point const& p2) + { + return p1.x == p2.x && p1.y == p2.y; + } -[import src_code/point2.cpp] -[point_example2] + struct point_hash + : std::unary_function + { + std::size_t operator()(point const& p) const + { + std::size_t seed = 0; + boost::hash_combine(seed, p.x); + boost::hash_combine(seed, p.y); + return seed; + } + } + + boost::unordered_multiset, point_hash> + points; + +Although, customising Boost.Hash is probably a better solution: + + struct point { + int x; + int y; + }; + + bool operator==(point const& p1, point const& p2) + { + return p1.x == p2.x && p1.y == p2.y; + } + + std::size_t hash_value(point const& x) { + std::size_t seed = 0; + boost::hash_combine(seed, p.x); + boost::hash_combine(seed, p.y); + return seed; + } + + // Now the default functions work. + boost::unordered_multiset points; See the Boost.Hash documentation for more detail on how to do this. Remember that it relies on extensions to the draft standard - so it won't work on other diff --git a/doc/intro.qbk b/doc/intro.qbk index 5bdd2fbd..82ee5d2a 100644 --- a/doc/intro.qbk +++ b/doc/intro.qbk @@ -45,14 +45,14 @@ details). If accepted the containers should also be added to __boost-tr1__. namespace boost { template < class Key, - class Hash = ``[classref boost::hash]``, + class Hash = boost::hash, class Pred = std::equal_to, class Alloc = std::allocator > class ``[classref boost::unordered_set unordered_set]``; template< class Key, - class Hash = ``[classref boost::hash]``, + class Hash = boost::hash, class Pred = std::equal_to, class Alloc = std::allocator > class ``[classref boost::unordered_multiset unordered_multiset]``; @@ -63,15 +63,15 @@ details). If accepted the containers should also be added to __boost-tr1__. namespace boost { template < - class Key, class Mapped, - class Hash = ``[classref boost::hash]``, + class Key, class T, + class Hash = boost::hash, class Pred = std::equal_to, class Alloc = std::allocator > class ``[classref boost::unordered_map unordered_map]``; template< - class Key, class Mapped, - class Hash = ``[classref boost::hash]``, + class Key, class T, + class Hash = boost::hash, class Pred = std::equal_to, class Alloc = std::allocator > class ``[classref boost::unordered_multimap unordered_multimap]``; diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 42755d34..563b57d0 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -7,7 +7,7 @@ Thomas Wang's article on integer hash functions]] [def __n2345__ [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2345.pdf - N2345, 'Placement Insert for Containers']] + N2345, 'Placement Instert for Containers']] [def __n2369__ [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2369.pdf the August 2008 version of the working draft standard]] @@ -28,12 +28,12 @@ By specifying an interface for accessing the buckets of the container the standard pretty much requires that the hash table uses chained addressing. It would be conceivable to write a hash table that uses another method. For -example, it could use open addressing, and use the lookup chain to act as a +example, an it could use open addressing, and use the lookup chain to act as a bucket but there are a some serious problems with this: * The draft standard requires that pointers to elements aren't invalidated, so the elements can't be stored in one array, but will need a layer of - indirection instead - losing the efficiency and most of the memory gain, + indirection instead - loosing the efficiency and most of the memory gain, the main advantages of open addressing. * Local iterators would be very inefficient and may not be able to @@ -98,96 +98,35 @@ So, this implementation uses a prime number for the hash table size. [h2 Active Issues and Proposals] -[h3 Removing unused allocator functions] +[h3 [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2257.html + Removing unused allocator functions]] -In -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2257.html -N2257, removing unused allocator functions], -Matt Austern suggests removing the `construct`, `destroy` and `address` member -functions - all of which Boost.Unordered calls. Changing this will simplify the -implementation, as well as make supporting `emplace` easier, but means that the -containers won't support allocators which require these methods to be called. -Detlef Vollmann opposed this change in -[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2339.htm N2339]. +This proposal suggests removing the `construct`, `destroy` and `address` +member functions - all of which Boost.Unordered calls. It's near trivial +to replace the calls with the appropriate code - and will simplify the +implementation, as well as make supporting `emplace` easier. +[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2339.htm +N2339] opposed this change. -[h3 Swapping containers with unequal allocators] +[h3 [@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#431 + 431. Swapping containers with unequal allocators]] -It isn't clear how to swap containers when their allocators aren't equal. -This is -[@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#431 -Issue 431: Swapping containers with unequal allocators]. +I followed Howard Hinnant's advice and implemented option 3. -Howard Hinnant wrote about this in -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1599.html N1599] -and suggested swapping both the allocators and the containers' contents. -But the committee have now decided that `swap` should do a fast swap if the +There is currently a further issue - if the allocator's swap does throw there's +no guarantee what state the allocators will be in. The only solution seems to +be to double buffer the allocators. But I'm assuming that it won't throw for now. + +Update: The committee have now decided that `swap` should do a fast swap if the allocator is Swappable and a slow swap using copy construction otherwise. To -make this distinction requires concepts. +make this distinction requires concepts. For now I'm sticking with the current +implementation. -In -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2387.pdf -N2387, Omnibus Allocator Fix-up Proposals], -Pablo Halpern suggests that there are actually two distinct allocator models, -"Moves with Value" and "Scoped" which behave differently: +[h3 [@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#518 + 518. Are insert and erase stable for unordered_multiset and unordered_multimap?]] -[: -When allocators are allowed to have state, it is necessary to have a model for -determining from where an object obtains its allocator. We’ve identified two such -models: the “Moves with Value” allocator model and the “Scoped” allocator model. - -In the “Moves with Value” allocator model, the copy constructor of an allocator-aware -class will copy both the value and the allocator from its argument. This is the model -specified in the C++03 standard. With this model, inserting an object into a container -usually causes the new container item to copy the allocator from the object that was -inserted. This model can be useful in special circumstances, e.g., if the items within a -container use an allocator that is specially tuned to the item’s type. - -In the “Scoped” allocator model, the allocator used to construct an object is determined -by the context of that object, much like a storage class. With this model, inserting an -object into a container causes the new container item to use the same allocator as the -container. To avoid allocators being used in the wrong context, the allocator is never -copied during copy or move construction. Thus, it is possible using this model to use -allocators based on short-lived resources without fear that an object will transfer its -allocator to a copy that might outlive the (shared) allocator resource. This model is -reasonably safe and generally useful on a large scale. There was strong support in the -2005 Tremblant meeting for pursuing an allocator model that propagates allocators -from container to contained objects. -] - -With these models the choice becomes clearer: - -[: -I introduced the “Moves with Value” allocator model and the -“Scoped” allocator model. In the former case, the allocator is copied when the container -is copy-constructed. In the latter case it is not. Swapping the allocators is the right thing -to do if the containers conform to the “Moves with Value” allocator model and -absolutely the wrong thing to do if the containers conform to the “Scoped” allocator -model. With the two allocator models well-defined, the desired behavior becomes clear. -] - -The proposal is that allocators are swapped if the allocator follows the -"Moves with Value" model and the allocator is swappable. Otherwise a slow swap -is used. Since containers currently only support the "Moves with Value" model -this is consistent with the committee's current recommendation (although it -suggests using a trait to detect if the allocator is swappable rather than a -concept). - -Since there is currently neither have a swappable trait or concept for -allocators this implementation always performs a slow swap. - -[h3 Are insert and erase stable for unordered_multiset and unordered_multimap?] - -It is not specified if `unordered_multiset` and `unordered_multimap` preserve the order -of elements with equivalent keys (i.e. if they're stable under `insert` and `erase`). -This is [@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#518 issue 581]. The current proposal is that insert, erase and rehash are stable - so they are here. -[h3 const_local_iterator cbegin, cend missing from TR1] - -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2482.html#691 -Issue 691] is that `cbegin` and `cend` are missing for local iterators. -The current resolution is that they'll be added, so I've added them. - [h2 Future Developments] [h3 Support for `emplace`] diff --git a/doc/ref.xml b/doc/ref.xml index 58e14a95..6f8d16cb 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -128,7 +128,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A const_local_iterator object can be used to iterate through a single bucket. - + size_type implementation-defined @@ -149,7 +149,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) size() == 0 - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0. + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocatorand a maximum load factor of 1.0. @@ -263,7 +263,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The bool component of the return type is true if an insert took place. - If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent value. + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the elment with equivalent value. If an exception is thrown by an operation other than a call to hasher the function has no effect. @@ -285,7 +285,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) hint is a suggestion to where the element should be inserted. - If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent value. + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the elment with equivalent value. If an exception is thrown by an operation other than a call to hasher the function has no effect. @@ -329,8 +329,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The iterator following position before the erasure. - Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + Only throws an exception, if it is thrown by a call to hasher or key_equal. + They don't get called by the current implementation Boost.Unordered but other implementations may call them. @@ -345,7 +345,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The number of elements erased. - Only throws an exception if it is thrown by hasher or key_equal. + Only throws an exception, if it is thrown by a call to hasher or key_equal. @@ -356,15 +356,15 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) const_iterator iterator - + Erases the elements in the range from first to last. - + The iterator following the erased elements - i.e. last. - Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + Only throws an exception, if it is thrown by a call to hasher or key_equal. + They don't get called by the current implementation Boost.Unordered but other implementations may call them. @@ -385,12 +385,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. + Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. - - For a discussion of the behaviour when allocators aren't equal see - the implementation details. - @@ -443,7 +439,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& - std::pair<const_iterator, const_iterator> + std::pair<iterator, iterator> A range containing all elements with key equivalent to k. @@ -530,30 +526,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A local iterator pointing the 'one past the end' element in the bucket with index n. - - - size_type - - const_local_iterator - - n shall be in the range [0, bucket_count()). - - - A constant local iterator pointing the first element in the bucket with index n. - - - - - size_type - - const_local_iterator - - n shall be in the range [0, bucket_count()). - - - A constant local iterator pointing the 'one past the end' element in the bucket with index n. - - @@ -591,71 +563,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - - - - unordered_set<Value, Hash, Pred, Alloc> const& - - - unordered_set<Value, Hash, Pred, Alloc> const& - - bool - - This is a boost extension. - - - - - - unordered_set<Value, Hash, Pred, Alloc> const& - - - unordered_set<Value, Hash, Pred, Alloc> const& - - bool - - This is a boost extension. - - - - - - unordered_set<Value, Hash, Pred, Alloc> const& - - std::size_t - - This is a boost extension. - - - - unordered_set<Value, Hash, Pred, Alloc>& + unordered_set<Key, T, Hash, Pred, Alloc>& - unordered_set<Value, Hash, Pred, Alloc>& + unordered_set<Key, T, Hash, Pred, Alloc>& void x.swap(y) - If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. + Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. - - For a discussion of the behaviour when allocators aren't equal see - the implementation details. - @@ -805,7 +708,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A const_local_iterator object can be used to iterate through a single bucket. - + size_type implementation-defined @@ -826,7 +729,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) size() == 0 - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0. + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocatorand a maximum load factor of 1.0. @@ -1005,8 +908,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The iterator following position before the erasure. - Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + Only throws an exception, if it is thrown by a call to hasher or key_equal. + They don't get called by the current implementation Boost.Unordered but other implementations may call them. @@ -1021,7 +924,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The number of elements erased. - Only throws an exception if it is thrown by hasher or key_equal. + Only throws an exception, if it is thrown by a call to hasher or key_equal. @@ -1032,15 +935,15 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) const_iterator iterator - + Erases the elements in the range from first to last. - + The iterator following the erased elements - i.e. last. - Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + Only throws an exception, if it is thrown by a call to hasher or key_equal. + They don't get called by the current implementation Boost.Unordered but other implementations may call them. @@ -1061,12 +964,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. + Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. - - For a discussion of the behaviour when allocators aren't equal see - the implementation details. - @@ -1119,7 +1018,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& - std::pair<const_iterator, const_iterator> + std::pair<iterator, iterator> A range containing all elements with key equivalent to k. @@ -1206,30 +1105,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A local iterator pointing the 'one past the end' element in the bucket with index n. - - - size_type - - const_local_iterator - - n shall be in the range [0, bucket_count()). - - - A constant local iterator pointing the first element in the bucket with index n. - - - - - size_type - - const_local_iterator - - n shall be in the range [0, bucket_count()). - - - A constant local iterator pointing the 'one past the end' element in the bucket with index n. - - @@ -1267,71 +1142,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - - - - unordered_multiset<Value, Hash, Pred, Alloc> const& - - - unordered_multiset<Value, Hash, Pred, Alloc> const& - - bool - - This is a boost extension. - - - - - - unordered_multiset<Value, Hash, Pred, Alloc> const& - - - unordered_multiset<Value, Hash, Pred, Alloc> const& - - bool - - This is a boost extension. - - - - - - unordered_multiset<Value, Hash, Pred, Alloc> const& - - std::size_t - - This is a boost extension. - - - - unordered_multiset<Value, Hash, Pred, Alloc>& + unordered_multiset<Key, T, Hash, Pred, Alloc>& - unordered_multiset<Value, Hash, Pred, Alloc>& + unordered_multiset<Key, T, Hash, Pred, Alloc>& void x.swap(y) - If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. + Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. - - For a discussion of the behaviour when allocators aren't equal see - the implementation details. - @@ -1381,7 +1187,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An unordered associative container that associates unique keys with another value. @@ -1406,8 +1212,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Key Key must be Assignable and CopyConstructible. - Mapped - Mapped must be CopyConstructible + T + T must be CopyConstructible Hash A unary function object type that acts a hash function for a Key. It takes a single argument of type Key and returns a value of type std::size_t. @@ -1429,7 +1235,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) std::pair<Key const, Value> - Mapped + T Hash @@ -1497,7 +1303,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A const_local_iterator object can be used to iterate through a single bucket. - + size_type implementation-defined @@ -1518,7 +1324,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) size() == 0 - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0. + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocatorand a maximum load factor of 1.0. @@ -1632,7 +1438,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The bool component of the return type is true if an insert took place. - If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the elment with equivalent key. If an exception is thrown by an operation other than a call to hasher the function has no effect. @@ -1654,7 +1460,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) hint is a suggestion to where the element should be inserted. - If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the elment with equivalent key. If an exception is thrown by an operation other than a call to hasher the function has no effect. @@ -1698,8 +1504,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The iterator following position before the erasure. - Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + Only throws an exception, if it is thrown by a call to hasher or key_equal. + They don't get called by the current implementation Boost.Unordered but other implementations may call them. @@ -1714,7 +1520,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The number of elements erased. - Only throws an exception if it is thrown by hasher or key_equal. + Only throws an exception, if it is thrown by a call to hasher or key_equal. @@ -1725,15 +1531,15 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) const_iterator iterator - + Erases the elements in the range from first to last. - + The iterator following the erased elements - i.e. last. - Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + Only throws an exception, if it is thrown by a call to hasher or key_equal. + They don't get called by the current implementation Boost.Unordered but other implementations may call them. @@ -1754,12 +1560,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. + Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. - - For a discussion of the behaviour when allocators aren't equal see - the implementation details. - @@ -1812,7 +1614,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& - std::pair<const_iterator, const_iterator> + std::pair<iterator, iterator> A range containing all elements with key equivalent to k. @@ -1840,9 +1642,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - Mapped& + T& key_type const& - Mapped const& + T const& key_type const& A reference to x.second where x is the (unique) element whose key is equivalent to k. @@ -1933,30 +1735,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A local iterator pointing the 'one past the end' element in the bucket with index n. - - - size_type - - const_local_iterator - - n shall be in the range [0, bucket_count()). - - - A constant local iterator pointing the first element in the bucket with index n. - - - - - size_type - - const_local_iterator - - n shall be in the range [0, bucket_count()). - - - A constant local iterator pointing the 'one past the end' element in the bucket with index n. - - @@ -1994,83 +1772,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - - - - unordered_map<Key, Mapped, Hash, Pred, Alloc> const& - - - unordered_map<Key, Mapped, Hash, Pred, Alloc> const& - - bool - - This is a boost extension. - - - - - - unordered_map<Key, Mapped, Hash, Pred, Alloc> const& - - - unordered_map<Key, Mapped, Hash, Pred, Alloc> const& - - bool - - This is a boost extension. - - - - - - unordered_map<Key, Mapped, Hash, Pred, Alloc> const& - - std::size_t - - This is a boost extension. - - - - unordered_map<Key, Mapped, Hash, Pred, Alloc>& + unordered_map<Key, T, Hash, Pred, Alloc>& - unordered_map<Key, Mapped, Hash, Pred, Alloc>& + unordered_map<Key, T, Hash, Pred, Alloc>& void x.swap(y) - If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. + Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. - - For a discussion of the behaviour when allocators aren't equal see - the implementation details. - @@ -2108,7 +1811,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An unordered associative container that associates keys with another value. The same key can be stored multiple times. @@ -2133,8 +1836,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Key Key must be Assignable and CopyConstructible. - Mapped - Mapped must be CopyConstructible + T + T must be CopyConstructible Hash A unary function object type that acts a hash function for a Key. It takes a single argument of type Key and returns a value of type std::size_t. @@ -2156,7 +1859,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) std::pair<Key const, Value> - Mapped + T Hash @@ -2224,7 +1927,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A const_local_iterator object can be used to iterate through a single bucket. - + size_type implementation-defined @@ -2245,7 +1948,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) size() == 0 - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0. + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocatorand a maximum load factor of 1.0. @@ -2424,8 +2127,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The iterator following position before the erasure. - Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + Only throws an exception, if it is thrown by a call to hasher or key_equal. + They don't get called by the current implementation Boost.Unordered but other implementations may call them. @@ -2440,7 +2143,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The number of elements erased. - Only throws an exception if it is thrown by hasher or key_equal. + Only throws an exception, if it is thrown by a call to hasher or key_equal. @@ -2451,15 +2154,15 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) const_iterator iterator - + Erases the elements in the range from first to last. - + The iterator following the erased elements - i.e. last. - Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + Only throws an exception, if it is thrown by a call to hasher or key_equal. + They don't get called by the current implementation Boost.Unordered but other implementations may call them. @@ -2480,12 +2183,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. + Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. - - For a discussion of the behaviour when allocators aren't equal see - the implementation details. - @@ -2538,7 +2237,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& - std::pair<const_iterator, const_iterator> + std::pair<iterator, iterator> A range containing all elements with key equivalent to k. @@ -2625,30 +2324,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A local iterator pointing the 'one past the end' element in the bucket with index n. - - - size_type - - const_local_iterator - - n shall be in the range [0, bucket_count()). - - - A constant local iterator pointing the first element in the bucket with index n. - - - - - size_type - - const_local_iterator - - n shall be in the range [0, bucket_count()). - - - A constant local iterator pointing the 'one past the end' element in the bucket with index n. - - @@ -2686,83 +2361,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - - - - unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const& - - - unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const& - - bool - - This is a boost extension. - - - - - - unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const& - - - unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const& - - bool - - This is a boost extension. - - - - - - unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const& - - std::size_t - - This is a boost extension. - - - - unordered_multimap<Key, Mapped, Hash, Pred, Alloc>& + unordered_multimap<Key, T, Hash, Pred, Alloc>& - unordered_multimap<Key, Mapped, Hash, Pred, Alloc>& + unordered_multimap<Key, T, Hash, Pred, Alloc>& void x.swap(y) - If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. + Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. - - For a discussion of the behaviour when allocators aren't equal see - the implementation details. - diff --git a/doc/src/boost.xml b/doc/src/boost.xml index b0a7afcd..457d5047 100644 --- a/doc/src/boost.xml +++ b/doc/src/boost.xml @@ -5,5 +5,5 @@ The Boost C++ Unordered Containers Library Documentation - + diff --git a/doc/src_code/insensitive.cpp b/doc/src_code/insensitive.cpp index 5e344177..8cf29f1b 100644 --- a/doc/src_code/insensitive.cpp +++ b/doc/src_code/insensitive.cpp @@ -14,7 +14,7 @@ bool operator()(std::string const& x, std::string const& y) const { - return boost::algorithm::iequals(x, y, std::locale()); + return boost::algorithm::iequals(x, y); } }; @@ -24,12 +24,11 @@ std::size_t operator()(std::string const& x) const { std::size_t seed = 0; - std::locale locale; for(std::string::const_iterator it = x.begin(); it != x.end(); ++it) { - boost::hash_combine(seed, std::toupper(*it, locale)); + boost::hash_combine(seed, std::toupper(*it)); } return seed; diff --git a/examples/case_insensitive.hpp b/examples/case_insensitive.hpp index 8cd00224..fba5b941 100644 --- a/examples/case_insensitive.hpp +++ b/examples/case_insensitive.hpp @@ -27,7 +27,7 @@ namespace hash_examples template bool operator()(String1 const& x1, String2 const& x2) const { - return boost::algorithm::iequals(x1, x2, locale_); + return boost::algorithm::iequals(x1, x2); } private: std::locale locale_; diff --git a/include/boost/unordered/detail/allocator.hpp b/include/boost/unordered/detail/allocator.hpp index 671b130c..5e421ea6 100644 --- a/include/boost/unordered/detail/allocator.hpp +++ b/include/boost/unordered/detail/allocator.hpp @@ -42,9 +42,6 @@ namespace boost { #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) template inline void reset(T& x) { x = T(); } - - template - inline Ptr null_ptr() { return Ptr(); } #else template inline void reset_impl(T& x, ...) { x = T(); } @@ -52,9 +49,6 @@ namespace boost { inline void reset_impl(T*& x, int) { x = 0; } template inline void reset(T& x) { reset_impl(x); } - - template - inline Ptr null_ptr() { Ptr x; reset(x); return x; } #endif // Work around for Microsoft's ETI bug. diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 355afedf..5d373d5c 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -82,21 +82,17 @@ namespace boost { // no throw inline std::size_t next_prime(std::size_t n) { - std::size_t const* const prime_list_end = prime_list + - sizeof(prime_list) / sizeof(*prime_list); std::size_t const* bound = - std::lower_bound(prime_list,prime_list_end, n); - if(bound == prime_list_end) + std::lower_bound(prime_list,prime_list + 28, n); + if(bound == prime_list + 28) bound--; return *bound; } // no throw inline std::size_t prev_prime(std::size_t n) { - std::size_t const* const prime_list_end = prime_list + - sizeof(prime_list) / sizeof(*prime_list); std::size_t const* bound = - std::upper_bound(prime_list,prime_list_end, n); + std::upper_bound(prime_list,prime_list + 28, n); if(bound != prime_list) bound--; return *bound; diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 26152520..6d549aa2 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -5,19 +5,19 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #if BOOST_UNORDERED_HASH_EQUIVALENT -#define BOOST_UNORDERED_TABLE hash_table_equivalent_keys -#define BOOST_UNORDERED_TABLE_DATA hash_table_data_equivalent_keys -#define BOOST_UNORDERED_ITERATOR hash_iterator_equivalent_keys -#define BOOST_UNORDERED_CONST_ITERATOR hash_const_iterator_equivalent_keys -#define BOOST_UNORDERED_LOCAL_ITERATOR hash_local_iterator_equivalent_keys -#define BOOST_UNORDERED_CONST_LOCAL_ITERATOR hash_const_local_iterator_equivalent_keys +#define HASH_TABLE hash_table_equivalent_keys +#define HASH_TABLE_DATA hash_table_data_equivalent_keys +#define HASH_ITERATOR hash_iterator_equivalent_keys +#define HASH_CONST_ITERATOR hash_const_iterator_equivalent_keys +#define HASH_LOCAL_ITERATOR hash_local_iterator_equivalent_keys +#define HASH_CONST_LOCAL_ITERATOR hash_const_local_iterator_equivalent_keys #else -#define BOOST_UNORDERED_TABLE hash_table_unique_keys -#define BOOST_UNORDERED_TABLE_DATA hash_table_data_unique_keys -#define BOOST_UNORDERED_ITERATOR hash_iterator_unique_keys -#define BOOST_UNORDERED_CONST_ITERATOR hash_const_iterator_unique_keys -#define BOOST_UNORDERED_LOCAL_ITERATOR hash_local_iterator_unique_keys -#define BOOST_UNORDERED_CONST_LOCAL_ITERATOR hash_const_local_iterator_unique_keys +#define HASH_TABLE hash_table_unique_keys +#define HASH_TABLE_DATA hash_table_data_unique_keys +#define HASH_ITERATOR hash_iterator_unique_keys +#define HASH_CONST_ITERATOR hash_const_iterator_unique_keys +#define HASH_LOCAL_ITERATOR hash_local_iterator_unique_keys +#define HASH_CONST_LOCAL_ITERATOR hash_const_local_iterator_unique_keys #endif namespace boost { @@ -29,7 +29,7 @@ namespace boost { // Responsible for managing the hash buckets. template - class BOOST_UNORDERED_TABLE_DATA + class HASH_TABLE_DATA { public: struct node_base; @@ -53,28 +53,8 @@ namespace boost { typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type node_ptr; typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type bucket_ptr; typedef BOOST_DEDUCED_TYPENAME allocator_reference::type reference; - typedef BOOST_DEDUCED_TYPENAME allocator_reference::type bucket_reference; - -#if 1 typedef bucket_ptr link_ptr; -#else - // This alternative version of link_ptr is used to check that the - // implementation is type safe wrt bucket_ptr and link_ptr. - // - // It's a sort of strict typedef. - struct link_ptr { - link_ptr() : ptr_() { BOOST_HASH_MSVC_RESET_PTR(ptr_); } - explicit link_ptr(bucket_ptr p) : ptr_(p) {} - bucket_reference operator*() const { return *ptr_; } - bucket* operator->() const { return &*ptr_; } - operator bool() const { return ptr_; } - bool operator==(link_ptr const& x) const { return ptr_ == x.ptr_; } - bool operator!=(link_ptr const& x) const { return ptr_ != x.ptr_; } - private: - bucket_ptr ptr_; - }; -#endif // Hash Bucket // // all no throw @@ -238,69 +218,69 @@ namespace boost { // Methods for navigating groups of elements with equal keys. #if BOOST_UNORDERED_HASH_EQUIVALENT - static inline link_ptr& prev_in_group(link_ptr n) { + static link_ptr& prev_in_group(link_ptr n) { return static_cast(*n).group_prev_; } // pre: Must be pointing to the first node in a group. - static inline link_ptr last_in_group(link_ptr n) { + static link_ptr last_in_group(link_ptr n) { BOOST_ASSERT(BOOST_HASH_BORLAND_BOOL(n) && n != prev_in_group(n)->next_); return prev_in_group(n); } // pre: Must be pointing to the first node in a group. - static inline link_ptr& next_group(link_ptr n) { + static link_ptr& next_group(link_ptr n) { BOOST_ASSERT(BOOST_HASH_BORLAND_BOOL(n) && n != prev_in_group(n)->next_); return prev_in_group(n)->next_; } #else - static inline link_ptr last_in_group(link_ptr n) { + static link_ptr last_in_group(link_ptr n) { return n; } - static inline link_ptr& next_group(link_ptr n) { + static link_ptr& next_group(link_ptr n) { BOOST_ASSERT(n); return n->next_; } #endif // pre: Must be pointing to a node - static inline node& get_node(link_ptr p) { + static node& get_node(link_ptr p) { BOOST_ASSERT(p); return static_cast(*p); } // pre: Must be pointing to a node - static inline reference get_value(link_ptr p) { + static reference get_value(link_ptr p) { BOOST_ASSERT(p); return static_cast(*p).value_; } - class iterator_base + class local_iterator_base { public: - bucket_ptr bucket_; link_ptr node_; - iterator_base() - : bucket_(), node_() + local_iterator_base() + : node_() { - BOOST_HASH_MSVC_RESET_PTR(bucket_); BOOST_HASH_MSVC_RESET_PTR(node_); } - explicit iterator_base(bucket_ptr b) - : bucket_(b), node_(b->next_) {} + explicit local_iterator_base(link_ptr n) + : node_(n) {} - iterator_base(bucket_ptr b, link_ptr n) - : bucket_(b), node_(n) {} + bool not_finished() const + { + return node_ ? true : false; + } - bool operator==(iterator_base const& x) const + bool operator==(local_iterator_base const& x) const { return node_ == x.node_; } - bool operator!=(iterator_base const& x) const + bool operator!=(local_iterator_base const& x) const { return node_ != x.node_; } @@ -312,12 +292,57 @@ namespace boost { void increment() { - BOOST_ASSERT(bucket_); + BOOST_ASSERT(node_); node_ = node_->next_; + } - while (!node_) { + 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_; - node_ = bucket_->next_; + local_ = local_iterator_base(bucket_->next_); } } }; @@ -332,7 +357,7 @@ namespace boost { // Constructors/Deconstructor - BOOST_UNORDERED_TABLE_DATA(size_type n, value_allocator const& a) + HASH_TABLE_DATA(size_type n, value_allocator const& a) : allocators_(a), buckets_(), bucket_count_(next_prime(n)), cached_begin_bucket_(), size_(0) @@ -355,7 +380,7 @@ namespace boost { buckets_ = constructor.release(); } - BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA const& x, size_type n) + 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) @@ -379,7 +404,7 @@ namespace boost { } // no throw - ~BOOST_UNORDERED_TABLE_DATA() + ~HASH_TABLE_DATA() { if(buckets_) { bucket_ptr begin = cached_begin_bucket_; @@ -399,13 +424,13 @@ namespace boost { private: - BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA const&); - BOOST_UNORDERED_TABLE_DATA& operator=(BOOST_UNORDERED_TABLE_DATA const&); + HASH_TABLE_DATA(HASH_TABLE_DATA const&); + HASH_TABLE_DATA& operator=(HASH_TABLE_DATA const&); public: // no throw - void swap(BOOST_UNORDERED_TABLE_DATA& other) + void swap(HASH_TABLE_DATA& other) { std::swap(buckets_, other.buckets_); std::swap(bucket_count_, other.bucket_count_); @@ -437,40 +462,41 @@ namespace boost { return iterator_base(buckets_ + bucket_count_); } - link_ptr begin(size_type n) const + local_iterator_base begin(size_type n) const { - return buckets_[n].next_; + return local_iterator_base(buckets_[n].next_); } - link_ptr end(size_type) const + local_iterator_base end(size_type) const { - return unordered_detail::null_ptr(); + return local_iterator_base(); } - link_ptr begin(bucket_ptr b) const + local_iterator_base begin(bucket_ptr b) const { - return b->next_; + return local_iterator_base(b->next_); } // Bucket Size // no throw - size_type node_count(link_ptr it) const + size_type node_count(local_iterator_base it) const { size_type count = 0; - while(BOOST_HASH_BORLAND_BOOL(it)) { + while(it.not_finished()) { ++count; - it = it->next_; + it.increment(); } return count; } - size_type node_count(link_ptr it1, link_ptr it2) const + size_type node_count(local_iterator_base it1, + local_iterator_base it2) const { size_type count = 0; while(it1 != it2) { ++count; - it1 = it1->next_; + it1.increment(); } return count; } @@ -481,9 +507,10 @@ namespace boost { } #if BOOST_UNORDERED_HASH_EQUIVALENT - static size_type group_count(link_ptr it) + size_type group_count(local_iterator_base first_node) const { size_type count = 0; + link_ptr it = first_node.node_; link_ptr first = it; do { ++count; @@ -492,7 +519,7 @@ namespace boost { return count; } #else - static size_type group_count(link_ptr) + size_type group_count(local_iterator_base) const { return 1; } @@ -505,9 +532,9 @@ namespace boost { // no throw #if BOOST_UNORDERED_HASH_EQUIVALENT - static link_ptr* get_for_erase(iterator_base r) + link_ptr* get_for_erase(iterator_base r) const { - link_ptr n = r.node_; + link_ptr n = r.local_.node_; // If the element isn't the first in its group, then // the link to it will be found in the previous element @@ -518,13 +545,13 @@ namespace boost { // The element is the first in its group, so iterate // throught the groups, checking against the first element. it = &r.bucket_->next_; - while(*it != n) it = &BOOST_UNORDERED_TABLE_DATA::next_group(*it); + while(*it != n) it = &HASH_TABLE_DATA::next_group(*it); return it; } #else - static link_ptr* get_for_erase(iterator_base r) + link_ptr* get_for_erase(iterator_base r) const { - link_ptr n = r.node_; + link_ptr n = r.local_.node_; link_ptr* it = &r.bucket_->next_; while(*it != n) it = &(*it)->next_; return it; @@ -539,10 +566,10 @@ namespace boost { // no throw #if BOOST_UNORDERED_HASH_EQUIVALENT - void link_node(link_ptr n, link_ptr pos) + void link_node(link_ptr n, local_iterator_base pos) { node& node_ref = get_node(n); - node& pos_ref = get_node(pos); + node& pos_ref = get_node(pos.node_); node_ref.next_ = pos_ref.group_prev_->next_; node_ref.group_prev_ = pos_ref.group_prev_; pos_ref.group_prev_->next_ = n; @@ -550,7 +577,7 @@ namespace boost { ++size_; } - void link_node_in_bucket(link_ptr n, bucket_ptr base) + void link_node(link_ptr n, bucket_ptr base) { node& node_ref = get_node(n); node_ref.next_ = base->next_; @@ -570,7 +597,7 @@ namespace boost { if(base < cached_begin_bucket_) cached_begin_bucket_ = base; } #else - void link_node_in_bucket(link_ptr n, bucket_ptr base) + void link_node(link_ptr n, bucket_ptr base) { n->next_ = base->next_; base->next_ = n; @@ -580,7 +607,7 @@ namespace boost { void link_group(link_ptr n, bucket_ptr base, size_type) { - link_node_in_bucket(n, base); + link_node(n, base); } #endif @@ -588,7 +615,7 @@ namespace boost { void unlink_node(iterator_base it) { link_ptr* pos = get_for_erase(it); - node* n = &get_node(it.node_); + node* n = &get_node(it.local_.node_); link_ptr next = n->next_; if(n->group_prev_ == *pos) { @@ -617,7 +644,7 @@ namespace boost { size_type unlink_group(link_ptr* pos) { - size_type count = group_count(*pos); + size_type count = group_count(local_iterator_base(*pos)); size_ -= count; link_ptr last = last_in_group(*pos); *pos = last->next_; @@ -644,28 +671,31 @@ namespace boost { link_ptr* it = get_for_erase(n); split_group(*it); unordered_detail::reset(*it); - size_ -= node_count(n.node_); + size_ -= node_count(n.local_); } void unlink_nodes(iterator_base begin, iterator_base end) { BOOST_ASSERT(begin.bucket_ == end.bucket_); - size_ -= node_count(begin.node_, end.node_); + local_iterator_base local_end = end.local_; + + size_ -= node_count(begin.local_, local_end); link_ptr* it = get_for_erase(begin); - split_group(*it, end.node_); - *it = end.node_; + split_group(*it, local_end.node_); + *it = local_end.node_; } void unlink_nodes(bucket_ptr base, iterator_base end) { BOOST_ASSERT(base == end.bucket_); - split_group(end.node_); + local_iterator_base local_end = end.local_; + split_group(local_end.node_); link_ptr ptr(base->next_); - base->next_ = end.node_; + base->next_ = local_end.node_; - size_ -= node_count(ptr, end.node_); + size_ -= node_count(local_iterator_base(ptr), local_end); } #if BOOST_UNORDERED_HASH_EQUIVALENT @@ -677,7 +707,7 @@ namespace boost { // If split is at the beginning of the group then there's // nothing to split. if(prev_in_group(split)->next_ != split) - return unordered_detail::null_ptr(); + return link_ptr(); // Find the start of the group. link_ptr start = split; @@ -733,7 +763,7 @@ namespace boost { link_ptr n = construct_node(v); // Rest is no throw - link_node_in_bucket(n, base); + link_node(n, base); return iterator_base(base, n); } @@ -744,38 +774,39 @@ namespace boost { link_ptr n = construct_node(v); // Rest is no throw - link_node(n, position.node_); + link_node(n, position.local_); return iterator_base(position.bucket_, n); } iterator_base create_node(value_type const& v, - bucket_ptr base, link_ptr position) + bucket_ptr base, local_iterator_base position) { // throws, strong exception-safety: link_ptr n = construct_node(v); // Rest is no throw - if(BOOST_HASH_BORLAND_BOOL(position)) + if(position.not_finished()) link_node(n, position); else - link_node_in_bucket(n, base); + link_node(n, base); return iterator_base(base, n); } #endif #if BOOST_UNORDERED_HASH_EQUIVALENT - void copy_group(link_ptr it, bucket_ptr dst) + void copy_group(local_iterator_base it, bucket_ptr dst) { - link_ptr end = next_group(it); - iterator_base pos = create_node(get_value(it), dst); - for(it = it->next_; it != end; it = it->next_) - create_node(get_value(it), pos); + 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); } #else - void copy_group(link_ptr it, bucket_ptr dst) + void copy_group(local_iterator_base it, bucket_ptr dst) { - create_node(get_value(it), dst); + create_node(*it, dst); } #endif @@ -853,7 +884,7 @@ namespace boost { iterator_base next = r; next.increment(); unlink_node(r); - allocators_.destroy(r.node_); + allocators_.destroy(r.local_.node_); // r has been invalidated but its bucket is still valid recompute_begin_bucket(r.bucket_, next.bucket_); return next; @@ -867,7 +898,7 @@ namespace boost { if (r1.bucket_ == r2.bucket_) { unlink_nodes(r1, r2); - delete_nodes(r1.node_, r2.node_); + 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 @@ -878,17 +909,17 @@ namespace boost { BOOST_ASSERT(r1.bucket_ < r2.bucket_); unlink_nodes(r1); - delete_to_bucket_end(r1.node_); + delete_to_bucket_end(r1.local_.node_); for(bucket_ptr i = r1.bucket_ + 1; i != r2.bucket_; ++i) { - size_ -= node_count(i->next_); + 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.node_); + delete_nodes(first, r2.local_.node_); } // r1 has been invalidated but its bucket is still @@ -949,7 +980,7 @@ namespace boost { #if defined(BOOST_MPL_CFG_MSVC_ETI_BUG) template <> - class BOOST_UNORDERED_TABLE_DATA + class HASH_TABLE_DATA { public: typedef int size_type; @@ -964,10 +995,10 @@ namespace boost { template - class BOOST_UNORDERED_TABLE - : public BOOST_UNORDERED_TABLE_DATA + class HASH_TABLE + : public HASH_TABLE_DATA { - typedef BOOST_UNORDERED_TABLE_DATA data; + typedef HASH_TABLE_DATA data; typedef typename data::node_constructor node_constructor; typedef typename data::bucket_ptr bucket_ptr; @@ -988,6 +1019,7 @@ namespace boost { // iterators + typedef BOOST_DEDUCED_TYPENAME data::local_iterator_base local_iterator_base; typedef BOOST_DEDUCED_TYPENAME data::iterator_base iterator_base; private: @@ -1016,7 +1048,7 @@ namespace boost { // buffering is used to copy them. func_ points to the currently // active function objects. - typedef functions BOOST_UNORDERED_TABLE::*functions_ptr; + typedef functions HASH_TABLE::*functions_ptr; functions func1_; functions func2_; @@ -1030,15 +1062,15 @@ namespace boost { // Constructors // // In the constructors, if anything throws an exception, - // BOOST_UNORDERED_TABLE_DATA's destructor will clean up. + // HASH_TABLE_DATA's destructor will clean up. - BOOST_UNORDERED_TABLE(size_type n, + HASH_TABLE(size_type n, hasher const& hf, key_equal const& eq, value_allocator const& a) : data(n, a), // throws, cleans itself up func1_(hf, eq), // throws " " func2_(hf, eq), // throws " " - func_(&BOOST_UNORDERED_TABLE::func1_), // no throw + func_(&HASH_TABLE::func1_), // no throw mlf_(1.0f) // no throw { calculate_max_load(); // no throw @@ -1078,32 +1110,32 @@ namespace boost { } template - BOOST_UNORDERED_TABLE(I i, I j, size_type n, + HASH_TABLE(I i, I j, size_type n, hasher const& hf, key_equal const& eq, value_allocator const& a) : data(initial_size(i, j, n), a), // throws, cleans itself up func1_(hf, eq), // throws " " func2_(hf, eq), // throws " " - func_(&BOOST_UNORDERED_TABLE::func1_), // no throw + func_(&HASH_TABLE::func1_), // no throw mlf_(1.0f) // no throw { calculate_max_load(); // no throw - // This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean up. + // This can throw, but HASH_TABLE_DATA's destructor will clean up. insert(i, j); } // Copy Construct - BOOST_UNORDERED_TABLE(BOOST_UNORDERED_TABLE const& x) + HASH_TABLE(HASH_TABLE const& x) : data(x, x.min_buckets_for_size(x.size())), // throws func1_(x.current_functions()), // throws func2_(x.current_functions()), // throws - func_(&BOOST_UNORDERED_TABLE::func1_), // no throw + func_(&HASH_TABLE::func1_), // no throw mlf_(x.mlf_) // no throw { calculate_max_load(); // no throw - // This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean + // This can throw, but HASH_TABLE_DATA's destructor will clean // up. copy_buckets(x, *this, current_functions()); } @@ -1115,7 +1147,7 @@ namespace boost { // throws the container is left with whatever was successfully // copied. - BOOST_UNORDERED_TABLE& operator=(BOOST_UNORDERED_TABLE const& x) + HASH_TABLE& operator=(HASH_TABLE const& x) { if(this != &x) { @@ -1132,19 +1164,34 @@ namespace boost { // Swap // - // Swap's behaviour when allocators aren't equal is in dispute, for - // details see: - // - // http://unordered.nfshost.com/doc/html/unordered/rationale.html#swapping_containers_with_unequal_allocators + // Swap's behaviour when allocators aren't equal is in dispute, see + // this paper for full details: + // + // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1599.html + // + // It lists 3 possible behaviours: + // + // 1 - If the allocators aren't equal then throw an exception. + // 2 - Reallocate the elements in the containers with the + // appropriate allocators - messing up exception safety in + // the process. + // 3 - Swap the allocators, hoping that the allocators have a + // no-throw swap. + // + // The paper recommends #3. // // ---------------------------------------------------------------- // // Strong exception safety (might change unused function objects) // - // Can throw if hash or predicate object's copy constructor throws - // or if allocators are unequal. + // Can throw if hash or predicate object's copy constructor throws. + // If allocators are unequal: + // Can throw if allocator's swap throws + // (I'm assuming that the allocator's swap doesn't throw + // but this doesn't seem to be guaranteed. Maybe I + // could double buffer the allocators). - void swap(BOOST_UNORDERED_TABLE& x) + void swap(HASH_TABLE& x) { // This only effects the function objects that aren't in use // so it is strongly exception safe, via. double buffering. @@ -1155,18 +1202,10 @@ namespace boost { this->data::swap(x); // no throw } else { - // Create new buckets in separate HASH_TABLE_DATA objects - // which will clean up if anything throws an exception. - // (all can throw, but with no effect as these are new objects). - data new_this(*this, x.min_buckets_for_size(x.size_)); - copy_buckets(x, new_this, this->*new_func_this); - - data new_that(x, min_buckets_for_size(this->size_)); - x.copy_buckets(*this, new_that, x.*new_func_that); - - // Start updating the data here, no throw from now on. - this->data::swap(new_this); - x.data::swap(new_that); + // Note: I'm not sure that allocator swap is guaranteed to be no + // throw. + this->allocators_.swap(x.allocators_); + this->data::swap(x); } // We've made it, the rest is no throw. @@ -1192,11 +1231,11 @@ namespace boost { // // Strong exception safety (since only usued function objects are // changed). - functions_ptr copy_functions(BOOST_UNORDERED_TABLE const& x) + functions_ptr copy_functions(HASH_TABLE const& x) { // no throw: - functions_ptr ptr = func_ == &BOOST_UNORDERED_TABLE::func1_ - ? &BOOST_UNORDERED_TABLE::func2_ : &BOOST_UNORDERED_TABLE::func1_; + functions_ptr ptr = func_ == &HASH_TABLE::func1_ + ? &HASH_TABLE::func2_ : &HASH_TABLE::func1_; // throws, functions not in use, so strong this->*ptr = x.current_functions(); return ptr; @@ -1450,11 +1489,11 @@ namespace boost { // no throw: for(bucket_ptr i = src.cached_begin_bucket_; i != end; ++i) { // no throw: - for(link_ptr it = src.begin(i); - BOOST_HASH_BORLAND_BOOL(it); it = data::next_group(it)) { + for(local_iterator_base it = src.begin(i); + it.not_finished(); it.next_group()) { // hash function can throw. bucket_ptr dst_bucket = dst.buckets_ + - dst.index_from_hash(hf(extract_key(data::get_value(it)))); + dst.index_from_hash(hf(extract_key(*it))); // throws, strong dst.copy_group(it, dst_bucket); } @@ -1480,7 +1519,7 @@ namespace boost { size_type hash_value = hash_function()(k); bucket_ptr bucket = this->buckets_ + this->index_from_hash(hash_value); - link_ptr position = find_iterator(bucket, k); + local_iterator_base position = find_iterator(bucket, k); // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). @@ -1496,12 +1535,12 @@ namespace boost { link_ptr n = a.release(); - // I'm relying on link_ptr not being invalidated by + // I'm relying on local_iterator_base not being invalidated by // the rehash here. - if(BOOST_HASH_BORLAND_BOOL(position)) + if(position.not_finished()) this->link_node(n, position); else - this->link_node_in_bucket(n, bucket); + this->link_node(n, bucket); return iterator_base(bucket, n); } @@ -1522,9 +1561,9 @@ namespace boost { // Find the first node in the group - so that the node // will be inserted at the end of the group. - link_ptr start(it.node_); - while(this->prev_in_group(start)->next_ == start) - start = this->prev_in_group(start); + local_iterator_base start(it.local_); + while(this->prev_in_group(start.node_)->next_ == start.node_) + start.node_ = this->prev_in_group(start.node_); // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). @@ -1561,19 +1600,19 @@ namespace boost { else { // Only require basic exception safety here reserve_extra(size() + distance); - node_constructor a(this->allocators_); for (; i != j; ++i) { + node_constructor a(this->allocators_); a.construct(*i); key_type const& k = extract_key(a.get()->value_); bucket_ptr bucket = get_bucket(k); - link_ptr position = find_iterator(bucket, k); + local_iterator_base position = find_iterator(bucket, k); - if(BOOST_HASH_BORLAND_BOOL(position)) + if(position.not_finished()) this->link_node(a.release(), position); else - this->link_node_in_bucket(a.release(), bucket); + this->link_node(a.release(), bucket); } } } @@ -1611,10 +1650,10 @@ namespace boost { size_type hash_value = hash_function()(k); bucket_ptr bucket = this->buckets_ + this->index_from_hash(hash_value); - link_ptr pos = find_iterator(bucket, k); + local_iterator_base pos = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(pos)) - return data::get_value(pos); + if (pos.not_finished()) + return *pos; else { // Side effects only in this block. @@ -1632,9 +1671,9 @@ namespace boost { // Nothing after this point can throw. link_ptr n = a.release(); - this->link_node_in_bucket(n, bucket); + this->link_node(n, bucket); - return data::get_value(n); + return *local_iterator_base(n); } } @@ -1648,9 +1687,9 @@ namespace boost { key_type const& k = extract_key(v); size_type hash_value = hash_function()(k); bucket_ptr bucket = this->buckets_ + this->index_from_hash(hash_value); - link_ptr pos = find_iterator(bucket, k); + local_iterator_base pos = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(pos)) { + if (pos.not_finished()) { // Found an existing key, return it (no throw). return std::pair( iterator_base(bucket, pos), false); @@ -1672,7 +1711,7 @@ namespace boost { // Nothing after this point can throw. link_ptr n = a.release(); - this->link_node_in_bucket(n, bucket); + this->link_node(n, bucket); return std::pair( iterator_base(bucket, n), true); @@ -1718,21 +1757,22 @@ namespace boost { template void insert(InputIterator i, InputIterator j) { - node_constructor a(this->allocators_); - + // If only inserting 1 element, get the required + // safety since insert is only called once. for (; i != j; ++i) { // No side effects in this initial code size_type hash_value = hash_function()(extract_key(*i)); bucket_ptr bucket = this->buckets_ + this->index_from_hash(hash_value); - link_ptr pos = find_iterator(bucket, extract_key(*i)); + local_iterator_base pos = find_iterator(bucket, extract_key(*i)); - if (!BOOST_HASH_BORLAND_BOOL(pos)) { + if (!pos.not_finished()) { // Doesn't already exist, add to bucket. // Side effects only in this block. // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). + node_constructor a(this->allocators_); value_type const& v = *i; a.construct(v); @@ -1744,7 +1784,7 @@ namespace boost { } // Nothing after this point can throw. - this->link_node_in_bucket(a.release(), bucket); + this->link_node(a.release(), bucket); } } } @@ -1781,8 +1821,8 @@ namespace boost { // strong exception safety, no side effects size_type count(key_type const& k) const { - link_ptr it = find_iterator(k); // throws, strong - return BOOST_HASH_BORLAND_BOOL(it) ? data::group_count(it) : 0; + local_iterator_base it = find_iterator(k); // throws, strong + return it.not_finished() ? this->group_count(it) : 0; } // find @@ -1791,9 +1831,9 @@ namespace boost { iterator_base find(key_type const& k) const { bucket_ptr bucket = get_bucket(k); - link_ptr it = find_iterator(bucket, k); + local_iterator_base it = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(it)) + if (it.not_finished()) return iterator_base(bucket, it); else return this->end(); @@ -1802,10 +1842,10 @@ namespace boost { value_type& at(key_type const& k) const { bucket_ptr bucket = get_bucket(k); - link_ptr it = find_iterator(bucket, k); + local_iterator_base it = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(it)) - return data::get_value(it); + if (it.not_finished()) + return *it; else throw std::out_of_range("Unable to find key in unordered_map."); } @@ -1816,10 +1856,10 @@ namespace boost { std::pair equal_range(key_type const& k) const { bucket_ptr bucket = get_bucket(k); - link_ptr it = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(it)) { + local_iterator_base it = find_iterator(bucket, k); + if (it.not_finished()) { iterator_base first(iterator_base(bucket, it)); - iterator_base second(iterator_base(bucket, this->last_in_group(it))); + iterator_base second(iterator_base(bucket, this->last_in_group(it.node_))); second.increment(); return std::pair(first, second); } @@ -1829,98 +1869,6 @@ namespace boost { } } - // - // equals - // - -private: -#if BOOST_UNORDERED_HASH_EQUIVALENT - static inline bool group_equals(link_ptr it1, link_ptr it2, - type_wrapper*) - { - return data::group_count(it1) == data::group_count(it2); - } - - static inline bool group_equals(link_ptr it1, link_ptr it2, void*) - { - if(!BOOST_HASH_BORLAND_BOOL(it2)) return false; - link_ptr end1 = data::next_group(it1); - link_ptr end2 = data::next_group(it2); - do { - if(data::get_value(it1).second != data::get_value(it2).second) return false; - it1 = it1->next_; - it2 = it2->next_; - } while(it1 != end1 && it2 != end2); - return it1 == end1 && it2 == end2; - } -#else - static inline bool group_equals(link_ptr it1, link_ptr it2, - type_wrapper*) - { - return true; - } - - static inline bool group_equals(link_ptr it1, link_ptr it2, void*) - { - return data::get_value(it1).second == data::get_value(it2).second; - } -#endif - -public: - bool equals(BOOST_UNORDERED_TABLE const& other) const - { - if(this->size() != other.size()) return false; - - for(bucket_ptr i = this->cached_begin_bucket_, - j = this->buckets_ + this->bucket_count_; i != j; ++i) - { - for(link_ptr it(i->next_); BOOST_HASH_BORLAND_BOOL(it); it = data::next_group(it)) - { - link_ptr other_pos = other.find_iterator(other.extract_key(data::get_value(it))); - if(!BOOST_HASH_BORLAND_BOOL(other_pos) || - !group_equals(it, other_pos, (type_wrapper*)0)) - return false; - } - } - - return true; - } - - inline bool group_hash(link_ptr it, type_wrapper*) const - { - std::size_t seed = data::group_count(it); - boost::hash_combine(seed, hash_function()(data::get_value(it))); - return seed; - } - - inline bool group_hash(link_ptr it, void*) const - { - std::size_t seed = hash_function()(data::get_value(it).first); - - link_ptr end = data::next_group(it); - - do { - boost::hash_combine(seed, data::get_value(it).second); - it = it->next_; - } while(it != end); - - return seed; - } - - std::size_t hash_value() const - { - std::size_t seed = 0; - - for(bucket_ptr i = this->cached_begin_bucket_, - j = this->buckets_ + this->bucket_count_; i != j; ++i) - { - for(link_ptr it(i->next_); BOOST_HASH_BORLAND_BOOL(it); it = data::next_group(it)) - seed ^= group_hash(it, (type_wrapper*)0); - } - - return seed; - } - private: // strong exception safety, no side effects @@ -1930,18 +1878,18 @@ public: } // strong exception safety, no side effects - link_ptr find_iterator(key_type const& k) const + local_iterator_base find_iterator(key_type const& k) const { return find_iterator(get_bucket(k), k); } // strong exception safety, no side effects - link_ptr find_iterator(bucket_ptr bucket, + local_iterator_base find_iterator(bucket_ptr bucket, key_type const& k) const { - link_ptr it = this->begin(bucket); - while (BOOST_HASH_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) - it = data::next_group(it); + local_iterator_base it = this->begin(bucket); + while (it.not_finished() && !equal(k, *it)) + it.next_group(); return it; } @@ -1950,8 +1898,8 @@ public: link_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const { link_ptr* it = &bucket->next_; - while(BOOST_HASH_BORLAND_BOOL(*it) && !equal(k, data::get_value(*it))) - it = &data::next_group(*it); + while(BOOST_HASH_BORLAND_BOOL(*it) && !equal(k, this->get_value(*it))) + it = &this->next_group(*it); return it; } @@ -1959,10 +1907,10 @@ public: // Iterators - template class BOOST_UNORDERED_ITERATOR; - template class BOOST_UNORDERED_CONST_ITERATOR; - template class BOOST_UNORDERED_LOCAL_ITERATOR; - template class BOOST_UNORDERED_CONST_LOCAL_ITERATOR; + template class HASH_ITERATOR; + template class HASH_CONST_ITERATOR; + template class HASH_LOCAL_ITERATOR; + template class HASH_CONST_LOCAL_ITERATOR; class iterator_access; // Local Iterators @@ -1970,7 +1918,7 @@ public: // all no throw template - class BOOST_UNORDERED_LOCAL_ITERATOR + class HASH_LOCAL_ITERATOR : public boost::iterator < std::forward_iterator_tag, BOOST_DEDUCED_TYPENAME allocator_value_type::type, @@ -1982,31 +1930,28 @@ public: typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; private: - typedef BOOST_UNORDERED_TABLE_DATA data; - typedef BOOST_DEDUCED_TYPENAME data::link_ptr ptr; - typedef BOOST_UNORDERED_CONST_LOCAL_ITERATOR const_local_iterator; + typedef BOOST_DEDUCED_TYPENAME HASH_TABLE_DATA::local_iterator_base base; + typedef HASH_CONST_LOCAL_ITERATOR const_local_iterator; - friend class BOOST_UNORDERED_CONST_LOCAL_ITERATOR; - ptr ptr_; + friend class HASH_CONST_LOCAL_ITERATOR; + base base_; public: - BOOST_UNORDERED_LOCAL_ITERATOR() : ptr_() { - BOOST_HASH_MSVC_RESET_PTR(ptr_); - } - explicit BOOST_UNORDERED_LOCAL_ITERATOR(ptr x) : ptr_(x) {} + HASH_LOCAL_ITERATOR() : base_() {} + explicit HASH_LOCAL_ITERATOR(base x) : base_(x) {} BOOST_DEDUCED_TYPENAME allocator_reference::type operator*() const - { return data::get_value(ptr_); } - value_type* operator->() const { return &data::get_value(ptr_); } - BOOST_UNORDERED_LOCAL_ITERATOR& operator++() { ptr_ = ptr_->next_; return *this; } - BOOST_UNORDERED_LOCAL_ITERATOR operator++(int) { BOOST_UNORDERED_LOCAL_ITERATOR tmp(ptr_); ptr_ = ptr_->next_; return tmp; } - bool operator==(BOOST_UNORDERED_LOCAL_ITERATOR x) const { return ptr_ == x.ptr_; } - bool operator==(const_local_iterator x) const { return ptr_ == x.ptr_; } - bool operator!=(BOOST_UNORDERED_LOCAL_ITERATOR x) const { return ptr_ != x.ptr_; } - bool operator!=(const_local_iterator x) const { return ptr_ != x.ptr_; } + { return *base_; } + value_type* operator->() const { return &*base_; } + HASH_LOCAL_ITERATOR& operator++() { base_.increment(); return *this; } + HASH_LOCAL_ITERATOR operator++(int) { HASH_LOCAL_ITERATOR tmp(base_); base_.increment(); return tmp; } + bool operator==(HASH_LOCAL_ITERATOR x) const { return base_ == x.base_; } + bool operator==(const_local_iterator x) const { return base_ == x.base_; } + bool operator!=(HASH_LOCAL_ITERATOR x) const { return base_ != x.base_; } + bool operator!=(const_local_iterator x) const { return base_ != x.base_; } }; template - class BOOST_UNORDERED_CONST_LOCAL_ITERATOR + class HASH_CONST_LOCAL_ITERATOR : public boost::iterator < std::forward_iterator_tag, BOOST_DEDUCED_TYPENAME allocator_value_type::type, @@ -2018,27 +1963,24 @@ public: typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; private: - typedef BOOST_UNORDERED_TABLE_DATA data; - typedef BOOST_DEDUCED_TYPENAME data::link_ptr ptr; - typedef BOOST_UNORDERED_LOCAL_ITERATOR local_iterator; - friend class BOOST_UNORDERED_LOCAL_ITERATOR; - ptr ptr_; + typedef BOOST_DEDUCED_TYPENAME HASH_TABLE_DATA::local_iterator_base base; + typedef HASH_LOCAL_ITERATOR local_iterator; + friend class HASH_LOCAL_ITERATOR; + base base_; public: - BOOST_UNORDERED_CONST_LOCAL_ITERATOR() : ptr_() { - BOOST_HASH_MSVC_RESET_PTR(ptr_); - } - explicit BOOST_UNORDERED_CONST_LOCAL_ITERATOR(ptr x) : ptr_(x) {} - BOOST_UNORDERED_CONST_LOCAL_ITERATOR(local_iterator x) : ptr_(x.ptr_) {} + HASH_CONST_LOCAL_ITERATOR() : base_() {} + explicit HASH_CONST_LOCAL_ITERATOR(base x) : base_(x) {} + HASH_CONST_LOCAL_ITERATOR(local_iterator x) : base_(x.base_) {} BOOST_DEDUCED_TYPENAME allocator_const_reference::type - operator*() const { return data::get_value(ptr_); } - value_type const* operator->() const { return &data::get_value(ptr_); } - BOOST_UNORDERED_CONST_LOCAL_ITERATOR& operator++() { ptr_ = ptr_->next_; return *this; } - BOOST_UNORDERED_CONST_LOCAL_ITERATOR operator++(int) { BOOST_UNORDERED_CONST_LOCAL_ITERATOR tmp(ptr_); ptr_ = ptr_->next_; return tmp; } - bool operator==(local_iterator x) const { return ptr_ == x.ptr_; } - bool operator==(BOOST_UNORDERED_CONST_LOCAL_ITERATOR x) const { return ptr_ == x.ptr_; } - bool operator!=(local_iterator x) const { return ptr_ != x.ptr_; } - bool operator!=(BOOST_UNORDERED_CONST_LOCAL_ITERATOR x) const { return ptr_ != x.ptr_; } + operator*() const { return *base_; } + value_type const* operator->() const { return &*base_; } + HASH_CONST_LOCAL_ITERATOR& operator++() { base_.increment(); return *this; } + HASH_CONST_LOCAL_ITERATOR operator++(int) { HASH_CONST_LOCAL_ITERATOR tmp(base_); base_.increment(); return tmp; } + bool operator==(local_iterator x) const { return base_ == x.base_; } + bool operator==(HASH_CONST_LOCAL_ITERATOR x) const { return base_ == x.base_; } + bool operator!=(local_iterator x) const { return base_ != x.base_; } + bool operator!=(HASH_CONST_LOCAL_ITERATOR x) const { return base_ != x.base_; } }; // iterators @@ -2047,7 +1989,7 @@ public: template - class BOOST_UNORDERED_ITERATOR + class HASH_ITERATOR : public boost::iterator < std::forward_iterator_tag, BOOST_DEDUCED_TYPENAME allocator_value_type::type, @@ -2059,28 +2001,28 @@ public: typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; private: - typedef BOOST_DEDUCED_TYPENAME BOOST_UNORDERED_TABLE_DATA::iterator_base base; - typedef BOOST_UNORDERED_CONST_ITERATOR const_iterator; - friend class BOOST_UNORDERED_CONST_ITERATOR; + typedef BOOST_DEDUCED_TYPENAME HASH_TABLE_DATA::iterator_base base; + typedef HASH_CONST_ITERATOR const_iterator; + friend class HASH_CONST_ITERATOR; base base_; public: - BOOST_UNORDERED_ITERATOR() : base_() {} - explicit BOOST_UNORDERED_ITERATOR(base const& x) : base_(x) {} + HASH_ITERATOR() : base_() {} + explicit HASH_ITERATOR(base const& x) : base_(x) {} BOOST_DEDUCED_TYPENAME allocator_reference::type operator*() const { return *base_; } value_type* operator->() const { return &*base_; } - BOOST_UNORDERED_ITERATOR& operator++() { base_.increment(); return *this; } - BOOST_UNORDERED_ITERATOR operator++(int) { BOOST_UNORDERED_ITERATOR tmp(base_); base_.increment(); return tmp; } - bool operator==(BOOST_UNORDERED_ITERATOR const& x) const { return base_ == x.base_; } + HASH_ITERATOR& operator++() { base_.increment(); return *this; } + HASH_ITERATOR operator++(int) { HASH_ITERATOR tmp(base_); base_.increment(); return tmp; } + bool operator==(HASH_ITERATOR const& x) const { return base_ == x.base_; } bool operator==(const_iterator const& x) const { return base_ == x.base_; } - bool operator!=(BOOST_UNORDERED_ITERATOR const& x) const { return base_ != x.base_; } + bool operator!=(HASH_ITERATOR const& x) const { return base_ != x.base_; } bool operator!=(const_iterator const& x) const { return base_ != x.base_; } }; template - class BOOST_UNORDERED_CONST_ITERATOR + class HASH_CONST_ITERATOR : public boost::iterator < std::forward_iterator_tag, BOOST_DEDUCED_TYPENAME allocator_value_type::type, @@ -2092,34 +2034,34 @@ public: typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; private: - typedef BOOST_DEDUCED_TYPENAME BOOST_UNORDERED_TABLE_DATA::iterator_base base; - typedef BOOST_UNORDERED_ITERATOR iterator; - friend class BOOST_UNORDERED_ITERATOR; + typedef BOOST_DEDUCED_TYPENAME HASH_TABLE_DATA::iterator_base base; + typedef HASH_ITERATOR iterator; + friend class HASH_ITERATOR; friend class iterator_access; base base_; public: - BOOST_UNORDERED_CONST_ITERATOR() : base_() {} - explicit BOOST_UNORDERED_CONST_ITERATOR(base const& x) : base_(x) {} - BOOST_UNORDERED_CONST_ITERATOR(iterator const& x) : base_(x.base_) {} + HASH_CONST_ITERATOR() : base_() {} + explicit HASH_CONST_ITERATOR(base const& x) : base_(x) {} + HASH_CONST_ITERATOR(iterator const& x) : base_(x.base_) {} BOOST_DEDUCED_TYPENAME allocator_const_reference::type operator*() const { return *base_; } value_type const* operator->() const { return &*base_; } - BOOST_UNORDERED_CONST_ITERATOR& operator++() { base_.increment(); return *this; } - BOOST_UNORDERED_CONST_ITERATOR operator++(int) { BOOST_UNORDERED_CONST_ITERATOR tmp(base_); base_.increment(); return tmp; } + HASH_CONST_ITERATOR& operator++() { base_.increment(); return *this; } + HASH_CONST_ITERATOR operator++(int) { HASH_CONST_ITERATOR tmp(base_); base_.increment(); return tmp; } bool operator==(iterator const& x) const { return base_ == x.base_; } - bool operator==(BOOST_UNORDERED_CONST_ITERATOR const& x) const { return base_ == x.base_; } + bool operator==(HASH_CONST_ITERATOR const& x) const { return base_ == x.base_; } bool operator!=(iterator const& x) const { return base_ != x.base_; } - bool operator!=(BOOST_UNORDERED_CONST_ITERATOR const& x) const { return base_ != x.base_; } + bool operator!=(HASH_CONST_ITERATOR const& x) const { return base_ != x.base_; } }; } } -#undef BOOST_UNORDERED_TABLE -#undef BOOST_UNORDERED_TABLE_DATA -#undef BOOST_UNORDERED_ITERATOR -#undef BOOST_UNORDERED_CONST_ITERATOR -#undef BOOST_UNORDERED_LOCAL_ITERATOR -#undef BOOST_UNORDERED_CONST_LOCAL_ITERATOR +#undef HASH_TABLE +#undef HASH_TABLE_DATA +#undef HASH_ITERATOR +#undef HASH_CONST_ITERATOR +#undef HASH_LOCAL_ITERATOR +#undef HASH_CONST_LOCAL_ITERATOR diff --git a/include/boost/unordered_map.hpp b/include/boost/unordered_map.hpp index 7dd7b185..1fd2749c 100644 --- a/include/boost/unordered_map.hpp +++ b/include/boost/unordered_map.hpp @@ -16,8 +16,8 @@ #include #include -#include #include +#include namespace boost { @@ -294,6 +294,7 @@ namespace boost return const_local_iterator(base.end(n)); } +#if defined(BOOST_UNORDERED_LOCAL_CBEGIN) const_local_iterator cbegin(size_type n) const { return const_local_iterator(base.begin(n)); @@ -303,6 +304,7 @@ namespace boost { return const_local_iterator(base.end(n)); } +#endif // hash policy @@ -325,21 +327,6 @@ namespace boost { base.rehash(n); } - - friend bool operator==(unordered_map const& m1, unordered_map const& m2) - { - return m1.base.equals(m2.base); - } - - friend bool operator!=(unordered_map const& m1, unordered_map const& m2) - { - return !m1.base.equals(m2.base); - } - - friend std::size_t hash_value(unordered_map const& m) - { - return m.base.hash_value(); - } }; // class template unordered_map template @@ -606,6 +593,7 @@ namespace boost return const_local_iterator(base.end(n)); } +#if defined(BOOST_UNORDERED_LOCAL_CBEGIN) const_local_iterator cbegin(size_type n) const { return const_local_iterator(base.begin(n)); @@ -615,6 +603,7 @@ namespace boost { return const_local_iterator(base.end(n)); } +#endif // hash policy @@ -637,21 +626,6 @@ namespace boost { base.rehash(n); } - - friend bool operator==(unordered_multimap const& m1, unordered_multimap const& m2) - { - return m1.base.equals(m2.base); - } - - friend bool operator!=(unordered_multimap const& m1, unordered_multimap const& m2) - { - return !m1.base.equals(m2.base); - } - - friend std::size_t hash_value(unordered_multimap const& m) - { - return m.base.hash_value(); - } }; // class template unordered_multimap template diff --git a/include/boost/unordered_set.hpp b/include/boost/unordered_set.hpp index f20aef0c..15c20c15 100644 --- a/include/boost/unordered_set.hpp +++ b/include/boost/unordered_set.hpp @@ -16,8 +16,8 @@ #include #include -#include #include +#include namespace boost { @@ -264,6 +264,7 @@ namespace boost return const_local_iterator(base.end(n)); } +#if defined(BOOST_UNORDERED_LOCAL_CBEGIN) const_local_iterator cbegin(size_type n) const { return const_local_iterator(base.begin(n)); @@ -273,6 +274,7 @@ namespace boost { return const_local_iterator(base.end(n)); } +#endif // hash policy @@ -295,21 +297,6 @@ namespace boost { base.rehash(n); } - - friend bool operator==(unordered_set const& m1, unordered_set const& m2) - { - return m1.base.equals(m2.base); - } - - friend bool operator!=(unordered_set const& m1, unordered_set const& m2) - { - return !m1.base.equals(m2.base); - } - - friend std::size_t hash_value(unordered_set const& m) - { - return m.base.hash_value(); - } }; // class template unordered_set template @@ -561,6 +548,7 @@ namespace boost return const_local_iterator(base.end(n)); } +#if defined(BOOST_UNORDERED_LOCAL_CBEGIN) const_local_iterator cbegin(size_type n) const { return const_local_iterator(base.begin(n)); @@ -570,6 +558,7 @@ namespace boost { return const_local_iterator(base.end(n)); } +#endif // hash policy @@ -592,21 +581,6 @@ namespace boost { base.rehash(n); } - - friend bool operator==(unordered_multiset const& m1, unordered_multiset const& m2) - { - return m1.base.equals(m2.base); - } - - friend bool operator!=(unordered_multiset const& m1, unordered_multiset const& m2) - { - return !m1.base.equals(m2.base); - } - - friend std::size_t hash_value(unordered_multiset const& m) - { - return m.base.hash_value(); - } }; // class template unordered_multiset template diff --git a/release.sh b/release.sh index 68e33a3a..5cacfc71 100755 --- a/release.sh +++ b/release.sh @@ -16,7 +16,6 @@ mkdir $UNORDERED_DST/doc/html/images/ cp $BOOST_ROOT/doc/html/*.css $UNORDERED_DST/doc/html/ cp $BOOST_ROOT/doc/html/images/*.png $UNORDERED_DST/doc/html/images/ -rm -r $UNORDERED_DST/libs/functional rm -r $UNORDERED_DST/bin.v2 rm $UNORDERED_DST/release.sh diff --git a/test/container/compile_tests.hpp b/test/container/compile_tests.hpp index c8a22ae7..b5fe1ab3 100644 --- a/test/container/compile_tests.hpp +++ b/test/container/compile_tests.hpp @@ -111,7 +111,6 @@ void container_test(X& r, T&) (&a1)->~X(); X const a_const; - test::check_return_type::equals(a.begin()); test::check_return_type::equals(a_const.begin()); test::check_return_type::equals(a.cbegin()); @@ -120,18 +119,12 @@ void container_test(X& r, T&) test::check_return_type::equals(a_const.end()); test::check_return_type::equals(a.cend()); test::check_return_type::equals(a_const.cend()); -} -template -void equality_test(X& r, T&) -{ - X const a = r, b = r; + // No tests for ==, != since they're not required for unordered containers. - test::check_return_type::equals(a == b); - test::check_return_type::equals(a != b); -#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) - test::check_return_type::equals(boost::hash_value(a)); -#else - test::check_return_type::equals(hash_value(a)); -#endif + a.swap(b); + test::check_return_type::equals_ref(r = a); + test::check_return_type::equals(a.size()); + test::check_return_type::equals(a.max_size()); + test::check_return_type::convertible(a.empty()); } diff --git a/test/container/map_compile.cpp b/test/container/map_compile.cpp index 1ac721b4..e498a934 100644 --- a/test/container/map_compile.cpp +++ b/test/container/map_compile.cpp @@ -13,7 +13,7 @@ #include "../objects/minimal.hpp" #include "./compile_tests.hpp" -void container_tests() +int main() { typedef std::pair value_type; @@ -40,36 +40,6 @@ void container_tests() test::minimal::allocator > multimap; container_test(multimap, value); -} -void equality_tests() { - typedef std::pair value_type; - value_type value( - test::minimal::assignable::create(), - test::minimal::copy_constructible_equality_comparable::create()); - - boost::unordered_map< - test::minimal::assignable, - test::minimal::copy_constructible_equality_comparable, - test::minimal::hash, - test::minimal::equal_to, - test::minimal::allocator > map; - - equality_test(map, value); - - boost::unordered_multimap< - test::minimal::assignable, - test::minimal::copy_constructible_equality_comparable, - test::minimal::hash, - test::minimal::equal_to, - test::minimal::allocator > multimap; - - equality_test(multimap, value); -} - -int main() { - container_tests(); - equality_tests(); return boost::report_errors(); } diff --git a/test/container/set_compile.cpp b/test/container/set_compile.cpp index a557f8eb..f34de5d7 100644 --- a/test/container/set_compile.cpp +++ b/test/container/set_compile.cpp @@ -25,7 +25,6 @@ int main() test::minimal::allocator > set; container_test(set, assignable); - equality_test(set, assignable); std::cout<<"Test unordered_multiset.\n"; boost::unordered_multiset< @@ -35,7 +34,6 @@ int main() test::minimal::allocator > multiset; container_test(multiset, assignable); - equality_test(multiset, assignable); return boost::report_errors(); } diff --git a/test/exception/Jamfile.v2 b/test/exception/Jamfile.v2 index 0ec42869..e702f2c9 100644 --- a/test/exception/Jamfile.v2 +++ b/test/exception/Jamfile.v2 @@ -21,5 +21,5 @@ test-suite unordered-tests [ run erase_tests.cpp framework ] [ run rehash_tests.cpp framework ] [ run swap_tests.cpp framework : : : - BOOST_UNORDERED_SWAP_METHOD=2 ] + BOOST_UNORDERED_SWAP_METHOD=3 ] ; diff --git a/test/exception/insert_tests.cpp b/test/exception/insert_tests.cpp index 1e59f822..be498a70 100644 --- a/test/exception/insert_tests.cpp +++ b/test/exception/insert_tests.cpp @@ -73,7 +73,11 @@ struct insert_test2 : public insert_test_base template struct insert_test3 : public insert_test_base { - void run(T& x) const { + typedef typename insert_test_base::strong_type strong_type; + + void run(T& x, strong_type& strong) const { + // I don't think there's any need for this here. + //strong.store(x); x.insert(this->values.begin(), this->values.end()); } @@ -161,52 +165,7 @@ struct insert_test_rehash2 : public insert_test_rehash1 } }; -template -struct insert_test_rehash3 : public insert_test_base -{ - typename T::size_type mutable rehash_bucket_count, original_bucket_count; - - insert_test_rehash3() : insert_test_base(1000) {} - - T init() const { - typedef typename T::size_type size_type; - - T x; - x.max_load_factor(0.25); - - original_bucket_count = x.bucket_count(); - rehash_bucket_count = static_cast( - std::ceil(original_bucket_count * x.max_load_factor())) - 1; - - size_type initial_elements = rehash_bucket_count - 5; - - BOOST_REQUIRE(initial_elements < this->values.size()); - x.insert(this->values.begin(), - boost::next(this->values.begin(), initial_elements)); - BOOST_REQUIRE(original_bucket_count == x.bucket_count()); - return x; - } - - void run(T& x) const { - typename T::size_type bucket_count = x.bucket_count(); - - x.insert(boost::next(this->values.begin(), x.size()), - boost::next(this->values.begin(), x.size() + 20)); - - // This isn't actually a failure, but it means the test isn't doing its - // job. - BOOST_REQUIRE(x.bucket_count() != bucket_count); - } - - void check(T const& x) const { - if(x.size() < rehash_bucket_count) { - //BOOST_CHECK(x.bucket_count() == original_bucket_count); - } - test::check_equivalent_keys(x); - } -}; - RUN_EXCEPTION_TESTS( (insert_test1)(insert_test2)(insert_test3)(insert_test4) - (insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3), + (insert_test_rehash1)(insert_test_rehash2), CONTAINER_SEQ) diff --git a/test/helpers/input_iterator.hpp b/test/helpers/input_iterator.hpp index c45b1eb3..66f66d75 100644 --- a/test/helpers/input_iterator.hpp +++ b/test/helpers/input_iterator.hpp @@ -7,6 +7,7 @@ #define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER #include +#include namespace test { diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index f8f84445..a0312fc0 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -18,7 +18,6 @@ namespace test namespace minimal { class copy_constructible; - class copy_constructible_equality_comparable; class default_copy_constructible; class assignable; template class hash; @@ -38,29 +37,6 @@ namespace minimal copy_constructible() {} }; - class copy_constructible_equality_comparable - { - public: - static copy_constructible_equality_comparable create() { return copy_constructible_equality_comparable(); } - copy_constructible_equality_comparable(copy_constructible_equality_comparable const&) {} - ~copy_constructible_equality_comparable() {} - private: - copy_constructible_equality_comparable& operator=(copy_constructible_equality_comparable const&); - copy_constructible_equality_comparable() {} - }; - - bool operator==(copy_constructible_equality_comparable, copy_constructible_equality_comparable) { - return true; - } - - bool operator!=(copy_constructible_equality_comparable, copy_constructible_equality_comparable) { - return false; - } - - std::size_t hash_value(copy_constructible_equality_comparable) { - return 1; - } - class default_copy_constructible { public: @@ -241,8 +217,7 @@ namespace minimal size_type max_size() const { return 1000; } -#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || \ - BOOST_WORKAROUND(MSVC, <= 1300) +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) public: allocator& operator=(allocator const&) { return *this;} #else private: allocator& operator=(allocator const&); diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 29b2a47c..0f735543 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -27,5 +27,5 @@ test-suite unordered-tests [ run bucket_tests.cpp ] [ run load_factor_tests.cpp ] [ run rehash_tests.cpp ] - [ run swap_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=2 ] + [ run swap_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=3 ] ; diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index 620e16f0..ff819f4f 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -41,10 +41,8 @@ void bucket_tests(X* = 0) for(size_type i = 0; i < x.bucket_count(); ++i) { BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x.begin(i), x.end(i))); - BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x.cbegin(i), x.cend(i))); X const& x_ref = x; BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x_ref.begin(i), x_ref.end(i))); - BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x_ref.cbegin(i), x_ref.cend(i))); } } diff --git a/test/unordered/compile_tests.cpp b/test/unordered/compile_tests.cpp index 616b7423..6d3ae4ad 100644 --- a/test/unordered/compile_tests.cpp +++ b/test/unordered/compile_tests.cpp @@ -190,11 +190,6 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq) test::check_return_type::equals(a.end(0)); test::check_return_type::equals(b.end(0)); - test::check_return_type::equals(a.cbegin(0)); - test::check_return_type::equals(b.cbegin(0)); - test::check_return_type::equals(a.cend(0)); - test::check_return_type::equals(b.cend(0)); - test::check_return_type::equals(b.load_factor()); test::check_return_type::equals(b.max_load_factor()); a.max_load_factor((float) 2.0);