Add Boost.Unordered and add to the documentation. Not fully integrated yet.

[SVN r42528]
This commit is contained in:
Daniel James
2008-01-06 16:47:16 +00:00
71 changed files with 13019 additions and 0 deletions

17
doc/Jamfile.v2 Normal file
View File

@ -0,0 +1,17 @@
# 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)
using quickbook ;
xml unordered : unordered.qbk ;
boostbook standalone : unordered :
<xsl:param>boost.root=../../../..
<xsl:param>boost.libraries=../../../libraries.htm
<xsl:param>html.stylesheet=../../../../doc/html/boostbook.css
<xsl:param>chunk.first.sections=1
<xsl:param>chunk.section.depth=2
<xsl:param>generate.section.toc.level=2
<xsl:param>toc.section.depth=1
<xsl:param>toc.max.depth=1 ;

146
doc/buckets.qbk Normal file
View File

@ -0,0 +1,146 @@
[/ Copyright 2006-2007 Daniel James.
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[section:buckets The Data Structure]
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).
[$../../libs/unordered/doc/diagrams/buckets.png]
In order to decide which bucket to place an element in, the container applies
the hash function, `Hash`, to the element's key (for `unordered_set` and
`unordered_multiset` the key is the whole element, but is referred to as the key
so that the same terminology can be used for sets and maps). This returns a
value of type `std::size_t`. `std::size_t` has a much greater range of values
then the number of buckets, so that container applies another transformation to
that value to choose a bucket to place the element in.
Retreiving the elements for a given key is simple. The same process is applied
to the key to find the correct bucket. Then the key is compared with the
elements in the bucket to find any elements that match (using the equality
predicate `Pred`). If the hash function has worked well the elements will be
evenly distributed amongst the buckets so only a small number of elements will
need to be examined.
There is [link unordered.hash_equality more information on hash functions and
equality predicates in the next section].
You can see in the diagram that `A` & `D` have been placed in the same bucket.
When looking for elements in this bucket up to 2 comparisons are made, making
the search slower. This is known as a collision. To keep things fast we try to
keep collisions to a minimum.
[table Methods for Accessing Buckets
[[Method] [Description]]
[
[``size_type bucket_count() const``]
[The number of buckets.]
]
[
[``size_type max_bucket_count() const``]
[An upper bound on the number of buckets.]
]
[
[``size_type bucket_size(size_type n) const``]
[The number of elements in bucket `n`.]
]
[
[``size_type bucket(key_type const& k) const``]
[Returns the index of the bucket which would contain k]
]
[
[``
local_iterator begin(size_type n);
local_iterator end(size_type n);
const_local_iterator begin(size_type n) const;
const_local_iterator end(size_type n) const;
const_local_iterator cbegin(size_type n) const;
const_local_iterator cend(size_type n) const;
``]
[Return begin and end iterators for bucket `n`.]
]
]
[h2 Controlling the number of buckets]
As more elements are added to an unordered associative container, the number
of elements in the buckets will increase causing performance to degrade.
To combat this the containers increase the bucket count as elements are inserted.
You can also tell the container to change the bucket count (if required) by
calling `rehash`.
The standard leaves a lot of freedom to the implementor to decide how the
number of buckets are chosen, but it does make some requirements based on the
container's 'load factor', the average number of elements per bucket.
Containers also have a 'maximum load factor' which they should try to keep the
load factor below.
You can't control the bucket count directly but there are two ways to
influence it:
* Specify the minimum number of buckets when constructing a container or
when calling `rehash`.
* Suggest a maximum load factor by calling `max_load_factor`.
`max_load_factor` doesn't let you set the maximum load factor yourself, it just
lets you give a /hint/. And even then, the draft standard doesn't actually
require the container to pay much attention to this value. The only time the
load factor is /required/ to be less than the maximum is following a call to
`rehash`. But most implementations will try to keep the number of elements
below the max load factor, and set the maximum load factor to be the same as
or close to the hint - unless your hint is unreasonably small or large.
[table Methods for Controlling Bucket Size
[[Method] [Description]]
[
[``float load_factor() const``]
[The average number of elements per bucket.]
]
[
[``float max_load_factor() const``]
[Returns the current maximum load factor.]
]
[
[``float max_load_factor(float z)``]
[Changes the container's maximum load factor, using `z` as a hint.]
]
[
[``void rehash(size_type n)``]
[Changes the number of buckets so that there at least n buckets, and
so that the load factor is less than the maximum load factor.]
]
]
[h2 Iterator Invalidation]
It is not specified how member functions other than `rehash` affect
the bucket count, although `insert` is only allowed to invalidate iterators
when the insertion causes the load factor to be greater than or equal to the
maximum load factor. For most implementations this means that insert will only
change the number of buckets when this happens. While iterators can be
invalidated by calls to `insert` and `rehash`, pointers and references to the
container's elements are never invalidated.
In a similar manner to using `reserve` for `vector`s, it can be a good idea
to call `rehash` before inserting a large number of elements. This will get
the expensive rehashing out of the way and let you store iterators, safe in
the knowledge that they won't be invalidated. If you are inserting `n`
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 minimum 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.]
[endsect]

164
doc/comparison.qbk Normal file
View File

@ -0,0 +1,164 @@
[/ Copyright 2006-2007 Daniel James.
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[section:comparison Comparison with Associative Containers]
[table Interface differences.
[[Associative Containers] [Unordered Associative Containers]]
[
[Parameterized by an ordering relation `Compare`]
[Parameterized 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.]
]
[
[Constructors have optional extra parameters for the comparison object.]
[Constructors have optional extra parameters for the initial minimum
number of buckets, a hash function and an equality object.]
]
[
[Keys `k1`, `k2` are considered equivalent if
`!Compare(k1, k2) && !Compare(k2, k1)`]
[Keys `k1`, `k2` are considered equivalent if `Pred(k1, k2)`]
]
[
[Member function `lower_bound(k)` and `upper_bound(k)`]
[No equivalent. Since the elements aren't ordered `lower_bound` and
`upper_bound` would be meaningless.]
]
[
[`equal_range(k)` returns an empty range at the position that k
would be inserted if k isn't present in the container.]
[`equal_range(k)` returns a range at the end of the container if
k isn't present in the container. It can't return a positioned
range as k could be inserted into multiple place. To find out the
bucket that k would be inserted into use `bucket(k)`. But remember
that an insert can cause the container to rehash - meaning that the
element can be inserted into a different bucket.]
]
[
[`iterator`, `const_iterator` are of the bidirectional category.]
[`iterator`, `const_iterator` are of at least the forward category.]
]
[
[Iterators, pointers and references to the container's elements are
never invalidated.]
[[link unordered.buckets.iterator_invalidation Iterators can
be invalidated by calls to insert or rehash]. Pointers and
references to the container's elements are never invalidated.]
]
[
[Iterators iterate through the container in the order defined by
the comparison object.]
[Iterators iterate through the container in an arbitrary order, that
can change as elements are inserted. Although, equivalent elements
are always adjacent.]
]
[
[No equivalent]
[Local iterators can be used to iterate through individual buckets.
(I don't think that the order of local iterators and iterators are
required to have any correspondence.)]
]
[
[Can be compared using the `==`, `!=`, `<`, `<=`, `>`, `>=` operators.]
[No comparison operators are defined in the standard, although
[link unordered.rationale.equality_operator
implementations might extend the containers to support `==` and
`!=`].]
]
[
[]
[When inserting with a hint, implementations are permitted to ignore
the hint.]
]
[
[`erase` never throws an exception]
[The containers hash or predicate function can throw exceptions
from `erase`]
]
]
[table Complexity Guarantees
[[Operation] [Associative Containers] [Unordered Associative Containers]]
[
[Construction of empty container]
[constant]
[O(/n/) where /n/ is the minimum number of buckets.]
]
[
[Construction of container from a range of /N/ elements]
[O(/N/ log /N/), O(/N/) if the range is sorted with `value_comp()`]
[Average case O(/N/), worst case
O(/N/'''<superscript>2</superscript>''')]
]
[
[Insert a single element]
[logarithmic]
[Average case constant, worst case linear]
]
[
[Insert a single element with a hint]
[Amortized 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()`)]
]
[
[Erase by key, `k`]
[O(log(`size()`) + `count(k)`)]
[Average case: O(`count(k)`), Worst case: O(`size()`)]
]
[
[Erase a single element by iterator]
[Amortized constant]
[Average case: O(1), Worst case: O(`size()`)]
]
[
[Erase a range of /N/ elements]
[O(log(`size()`) + /N/)]
[Average case: O(/N/), Worst case: O(`size()`)]
]
[
[Clearing the container]
[O(`size()`)]
[O(`size()`)]
]
[
[Find]
[logarithmic]
[Average case: O(1), Worst case: O(`size()`)]
]
[/ TODO: Average case is probably wrong. ]
[
[Count]
[O(log(`size()`) + `count(k)`)]
[Average case: O(1), Worst case: O(`size()`)]
]
[
[`equal_range(k)`]
[logarithmic]
[Average case: O(`count(k)`), Worst case: O(`size()`)]
]
[
[`lower_bound`,`upper_bound`]
[logarithmic]
[n/a]
]
]
[endsect]

BIN
doc/diagrams/buckets.dia Normal file

Binary file not shown.

BIN
doc/diagrams/buckets.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

71
doc/hash_equality.qbk Normal file
View File

@ -0,0 +1,71 @@
[/ Copyright 2006-2007 Daniel James.
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[section:hash_equality Equality Predicates and Hash Functions]
While the associative containers use an ordering relation to specify how the
elements are stored, the unordered associative containers use an equality
predicate and a hash function. For example, [classref boost::unordered_set]
is declared as:
template<typename Value,
typename Hash = ``[classref boost::hash]``<Value>,
typename Pred = std::equal_to<Value>,
typename Alloc = std::allocator<Value> >
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
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:
``[classref boost::unordered_set]``<std::string, hash::fnv_1> words;
An example implementation of FNV-1, and some other hash functions are supplied
in the examples directory.
Alternatively, you might wish to use a different equality function. If you do
this you will need to use a hash function that matches it. So to implement a
case-insensitive dictionary:
[import src_code/insensitive.cpp]
[case_insensitive_functions]
[case_insensitive_dictionary]
This is a simplified version of the example 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]
Although, [link hash.custom extending boost::hash to support the type] is
probably a better solution:
[import src_code/point2.cpp]
[point_example2]
See the [link hash.custom 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 implementations of the unordered associative containers.
[table Methods for accessing the hash and equality functions.
[[Method] [Description]]
[
[``hasher hash_function() const``]
[Returns the container's hash function.]
]
[
[``key_equal key_eq() const``]
[Returns the container's key equality function.]
]
]
[endsect]

128
doc/intro.qbk Normal file
View File

@ -0,0 +1,128 @@
[/ Copyright 2006-2007 Daniel James.
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[def __tr1__
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
C++ Standard Library Technical Report]]
[def __boost-tr1__
[@http://www.boost.org/doc/html/boost_tr1.html
Boost.TR1]]
[def __draft__
[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2461.pdf
Working Draft of the C++ Standard]]
[def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table
hash table]]
[def __hash-function__ [@http://en.wikipedia.org/wiki/Hash_function
hash function]]
[section:intro Introduction]
For accessing data based on key lookup, the C++ standard library offers `std::set`,
`std::map`, `std::multiset` and `std::multimap`. These are generally
implemented using balanced binary trees so that lookup time has
logarithmic complexity. That is generally okay, but in many cases a
__hash-table__ can perform better, as accessing data has constant complexity,
on average. The worst case complexity is linear, but that occurs rarely and
with some care, can be avoided.
Also, the existing containers require a 'less than' comparison object
to order their elements. For some data types this is impossible to implement
or isn't practical. In contrast, a hash table only needs an equality function
and a hash function for the key.
With this in mind, the __tr1__ introduced the unordered associative containers,
which are implemented using hash tables, and they have now been added to the
__draft__.
This library supplies an almost complete implementation of the specification in
the __draft__, (it doesn't support `emplace` yet, see the [link
unordered.rationale.future_developments Implementation Rationale] section for more
details). If accepted the containers should also be added to __boost-tr1__.
`unordered_set` and `unordered_multiset` are defined in the header
<[headerref boost/unordered_set.hpp]>
namespace boost {
template <
class Key,
class Hash = ``[classref boost::hash]``<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key> >
class ``[classref boost::unordered_set unordered_set]``;
template<
class Key,
class Hash = ``[classref boost::hash]``<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key> >
class ``[classref boost::unordered_multiset unordered_multiset]``;
}
`unordered_map` and `unordered_multimap` are defined in the header
<[headerref boost/unordered_map.hpp]>
namespace boost {
template <
class Key, class Mapped,
class Hash = ``[classref boost::hash]``<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key> >
class ``[classref boost::unordered_map unordered_map]``;
template<
class Key, class Mapped,
class Hash = ``[classref boost::hash]``<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key> >
class ``[classref boost::unordered_multimap unordered_multimap]``;
}
When using Boost.TR1, these classes are included from `<unordered_set>` and
`<unordered_map>`, with the classes added to the `std::tr1` namespace.
The containers are used in a similar manner to the normal associative
containers:
#include <``[headerref boost/unordered_map.hpp]``>
#include <cassert>
int main()
{
boost::unordered_map<std::string, int> x;
x["one"] = 1;
x["two"] = 2;
x["three"] = 3;
assert(x["one"] == 1);
assert(x["missing"] == 0);
}
But since the elements aren't ordered, the output of:
BOOST_FOREACH(map::value_type i, x) {
std::cout<<i.first<<","<<i.second<<"\n";
}
can be in any order. For example, it might be:
two,2
one,1
three,3
missing,0
To store an object in an unordered associative container requires both an
key equality function and a hash function. The default function objects in
the standard containers support a few basic types including integer types,
floating point types, pointer types, and the standard strings. Since
Boost.Unordered uses [classref boost::hash] it also supports some other types,
including standard containers. To use any types not supported by these methods
you have to [link hash.custom extend Boost.Hash to support the type] or use
your own custom equality predicates and hash functions. See the
[link unordered.hash_equality Equality Predicates and Hash Functions] section
for more details.
There are other differences, which are listed in the
[link unordered.comparison Comparison with Associative Containers] section.
[endsect]

212
doc/rationale.qbk Normal file
View File

@ -0,0 +1,212 @@
[/ Copyright 2006-2007 Daniel James.
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[def __wang__
[@http://www.concentric.net/~Ttwang/tech/inthash.htm
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']]
[def __n2369__
[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2369.pdf
the August 2008 version of the working draft standard]]
[section:rationale Implementation Rationale]
The intent of this library is to implement the unordered
containers in the draft standard, so the interface was fixed. But there are
still some implementation decisions to make. The priorities are
conformance to the standard and portability.
The [@http://en.wikipedia.org/wiki/Hash_table wikipedia article on hash tables]
has a good summary of the implementation issues for hash tables in general.
[h2 Data Structure]
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
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,
the main advantages of open addressing.
* Local iterators would be very inefficient and may not be able to
meet the complexity requirements.
* There are also the restrictions on when iterators can be invalidated. Since
open addressing degrades badly when there are a high number of collisions the
restrictions could prevent a rehash when it's really needed. The maximum load
factor could be set to a fairly low value to work around this - but the
standard requires that it is initially set to 1.0.
* And since the standard is written with a eye towards chained
addressing, users will be surprised if the performance doesn't reflect that.
So chained addressing is used.
For containers with unique keys I store the buckets in a single-linked list.
There are other possible data structures (such as a double-linked list)
that allow for some operations to be faster (such as erasing and iteration)
but the possible gain seems small compared to the extra memory needed.
The most commonly used operations (insertion and lookup) would not be improved
at all.
But for containers with equivalent keys a single-linked list can degrade badly
when a large number of elements with equivalent keys are inserted. I think it's
reasonable to assume that users who choose to use `unordered_multiset` or
`unordered_multimap` do so because they are likely to insert elements with
equivalent keys. So I have used an alternative data structure that doesn't
degrade, at the expense of an extra pointer per node.
This works by adding storing a circular linked list for each group of equivalent
nodes in reverse order. This allows quick navigation to the end of a group (since
the first element points to the last) and can be quickly updated when elements
are inserted or erased. The main disadvantage of this approach is some hairy code
for erasing elements.
[h2 Number of Buckets]
There are two popular methods for choosing the number of buckets in a hash
table. One is to have a prime number of buckets, another is to use a power
of 2.
Using a prime number of buckets, and choosing a bucket by using the modulus
of the hash function's result will usually give a good result. The downside
is that the required modulus operation is fairly expensive.
Using a power of 2 allows for much quicker selection of the bucket
to use, but at the expense of loosing the upper bits of the hash value.
For some specially designed hash functions it is possible to do this and
still get a good result but as the containers can take arbitrary hash
functions this can't be relied on.
To avoid this a transformation could be applied to the hash function, for an
example see __wang__. Unfortunately, a transformation like Wang's requires
knowledge of the number of bits in the hash value, so it isn't portable enough.
This leaves more expensive methods, such as Knuth's Multiplicative Method
(mentioned in Wang's article). These don't tend to work as well as taking the
modulus of a prime, and the extra computation required might negate
efficiency advantage of power of 2 hash tables.
So, this implementation uses a prime number for the hash table size.
[h2 Active Issues and Proposals]
[h3 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].
[h3 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].
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
allocator is Swappable and a slow swap using copy construction otherwise. To
make this distinction requires concepts.
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:
[:
When allocators are allowed to have state, it is necessary to have a model for
determining from where an object obtains its allocator. Weve 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 items 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`]
In __n2369__ a new member function, `emplace` was added to the containers to
allow placement insert, as described in __n2345__. To fully implement this
`std::forward` is required, along with new functions in `std::allocator` and
new constructors in `std::pair`. But partial support is possible - especially
if I don't use the `construct` member of allocators.
[h3 Equality operator]
While `operator==` and `operator!=` are not included in the standard, it's
possible to implement them for all the containers - this is helped by having
stable order of elements with equivalent keys. They will need to be specified
differently to the standard associative containers, probably comparing keys
using the equality predicate rather than `operator==`. This is inconsistent
with the other containers but it is probably closer to user's expectations.
If these are added then a `hash_value` free function should also be added.
[endsect]

2537
doc/ref.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/algorithm/string/predicate.hpp>
//[case_insensitive_functions
struct iequal_to
: std::binary_function<std::string, std::string, bool>
{
bool operator()(std::string const& x,
std::string const& y) const
{
return boost::algorithm::iequals(x, y, std::locale());
}
};
struct ihash
: std::unary_function<std::string, std::size_t>
{
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));
}
return seed;
}
};
struct word_info;
//]
struct word_info {
int tag;
explicit word_info(int t = 0) : tag(t) {}
};
int main() {
//[case_insensitive_dictionary
boost::unordered_map<std::string, word_info, ihash, iequal_to>
idictionary;
//]
BOOST_TEST(idictionary.empty());
idictionary["one"] = word_info(1);
BOOST_TEST(idictionary.size() == 1);
BOOST_TEST(idictionary.find("ONE") != idictionary.end() &&
idictionary.find("ONE") == idictionary.find("one"));
idictionary.insert(std::make_pair("ONE", word_info(2)));
BOOST_TEST(idictionary.size() == 1);
BOOST_TEST(idictionary.find("ONE") != idictionary.end() &&
idictionary.find("ONE")->first == "one" &&
idictionary.find("ONE")->second.tag == 1);
idictionary["One"] = word_info(3);
BOOST_TEST(idictionary.size() == 1);
BOOST_TEST(idictionary.find("ONE") != idictionary.end() &&
idictionary.find("ONE")->first == "one" &&
idictionary.find("ONE")->second.tag == 3);
idictionary["two"] = word_info(4);
BOOST_TEST(idictionary.size() == 2);
BOOST_TEST(idictionary.find("two") != idictionary.end() &&
idictionary.find("TWO")->first == "two" &&
idictionary.find("Two")->second.tag == 4);
return boost::report_errors();
}

46
doc/src_code/point1.cpp Normal file
View File

@ -0,0 +1,46 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/detail/lightweight_test.hpp>
//[point_example1
struct point {
int x;
int y;
};
bool operator==(point const& p1, point const& p2)
{
return p1.x == p2.x && p1.y == p2.y;
}
struct point_hash
: std::unary_function<point, std::size_t>
{
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, point_hash, std::equal_to<point> >
points;
//]
int main() {
point x[] = {{1,2}, {3,4}, {1,5}, {1,2}};
for(int i = 0; i < sizeof(x) / sizeof(point); ++i)
points.insert(x[i]);
BOOST_TEST(points.count(x[0]) == 2);
BOOST_TEST(points.count(x[1]) == 1);
point y = {10, 2};
BOOST_TEST(points.count(y) == 0);
return boost::report_errors();
}

43
doc/src_code/point2.cpp Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/functional/hash.hpp>
#include <boost/detail/lightweight_test.hpp>
//[point_example2
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& p) {
std::size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);
return seed;
}
// Now the default function objects work.
boost::unordered_multiset<point> points;
//]
int main() {
point x[] = {{1,2}, {3,4}, {1,5}, {1,2}};
for(int i = 0; i < sizeof(x) / sizeof(point); ++i)
points.insert(x[i]);
BOOST_TEST(points.count(x[0]) == 2);
BOOST_TEST(points.count(x[1]) == 1);
point y = {10, 2};
BOOST_TEST(points.count(y) == 0);
return boost::report_errors();
}

26
doc/unordered.qbk Normal file
View File

@ -0,0 +1,26 @@
[/ Copyright 2006-2007 Daniel James.
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[library Unordered Associative Containers
[quickbook 1.4]
[authors [James, Daniel]]
[copyright 2003 2004 Jeremy B. Maitin-Shepard]
[copyright 2005 2006 2007 Daniel James]
[purpose std::tr1 compliant hash containers]
[id unordered]
[dirname unordered]
[license
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]
]
]
[include:unordered intro.qbk]
[include:unordered buckets.qbk]
[include:unordered hash_equality.qbk]
[include:unordered comparison.qbk]
[include:unordered rationale.qbk]
[xinclude ref.xml]

View File

@ -0,0 +1,60 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// This file implements a locale aware case insenstive equality predicate and
// hash function. Unfortunately it still falls short of full
// internationalization as it only deals with a single character at a time
// (some languages have tricky cases where the characters in an upper case
// string don't have a one-to-one correspondence with the lower case version of
// the text, eg. )
#if !defined(BOOST_HASH_EXAMPLES_CASE_INSENSITIVE_HEADER)
#define BOOST_HASH_EXAMPLES_CASE_INSENSITIVE_HEADER
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>
namespace hash_examples
{
struct iequal_to
: std::binary_function<std::string, std::string, bool>
{
iequal_to() {}
explicit iequal_to(std::locale const& l) : locale_(l) {}
template <typename String1, typename String2>
bool operator()(String1 const& x1, String2 const& x2) const
{
return boost::algorithm::iequals(x1, x2, locale_);
}
private:
std::locale locale_;
};
struct ihash
: std::unary_function<std::string, std::size_t>
{
ihash() {}
explicit ihash(std::locale const& l) : locale_(l) {}
template <typename String>
std::size_t operator()(String const& x) const
{
std::size_t seed = 0;
for(typename String::const_iterator it = x.begin();
it != x.end(); ++it)
{
boost::hash_combine(seed, std::toupper(*it, locale_));
}
return seed;
}
private:
std::locale locale_;
};
}
#endif

View File

@ -0,0 +1,82 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./case_insensitive.hpp"
#include <boost/detail/lightweight_test.hpp>
#include <boost/unordered_map.hpp>
struct word_info {
int tag;
explicit word_info(int t = 0) : tag(t) {}
};
void test1() {
boost::unordered_map<std::string, word_info,
hash_examples::ihash, hash_examples::iequal_to> idictionary;
BOOST_TEST(idictionary.empty());
idictionary["one"] = word_info(1);
BOOST_TEST(idictionary.size() == 1);
BOOST_TEST(idictionary.find("ONE") != idictionary.end() &&
idictionary.find("ONE") == idictionary.find("one"));
idictionary.insert(std::make_pair("ONE", word_info(2)));
BOOST_TEST(idictionary.size() == 1);
BOOST_TEST(idictionary.find("ONE") != idictionary.end() &&
idictionary.find("ONE")->first == "one" &&
idictionary.find("ONE")->second.tag == 1);
idictionary["One"] = word_info(3);
BOOST_TEST(idictionary.size() == 1);
BOOST_TEST(idictionary.find("ONE") != idictionary.end() &&
idictionary.find("ONE")->first == "one" &&
idictionary.find("ONE")->second.tag == 3);
idictionary["two"] = word_info(4);
BOOST_TEST(idictionary.size() == 2);
BOOST_TEST(idictionary.find("two") != idictionary.end() &&
idictionary.find("TWO")->first == "two" &&
idictionary.find("Two")->second.tag == 4);
}
void test2() {
boost::unordered_map<std::wstring, word_info,
hash_examples::ihash, hash_examples::iequal_to> idictionary;
BOOST_TEST(idictionary.empty());
idictionary[L"one"] = word_info(1);
BOOST_TEST(idictionary.size() == 1);
BOOST_TEST(idictionary.find(L"ONE") != idictionary.end() &&
idictionary.find(L"ONE") == idictionary.find(L"one"));
idictionary.insert(std::make_pair(L"ONE", word_info(2)));
BOOST_TEST(idictionary.size() == 1);
BOOST_TEST(idictionary.find(L"ONE") != idictionary.end() &&
idictionary.find(L"ONE")->first == L"one" &&
idictionary.find(L"ONE")->second.tag == 1);
idictionary[L"One"] = word_info(3);
BOOST_TEST(idictionary.size() == 1);
BOOST_TEST(idictionary.find(L"ONE") != idictionary.end() &&
idictionary.find(L"ONE")->first == L"one" &&
idictionary.find(L"ONE")->second.tag == 3);
idictionary[L"two"] = word_info(4);
BOOST_TEST(idictionary.size() == 2);
BOOST_TEST(idictionary.find(L"two") != idictionary.end() &&
idictionary.find(L"TWO")->first == L"two" &&
idictionary.find(L"Two")->second.tag == 4);
}
int main() {
test1();
test2();
return boost::report_errors();
}

View File

@ -0,0 +1,66 @@
// See: http://www.isthe.com/chongo/tech/comp/fnv/
#include <string>
namespace hash
{
template <std::size_t FnvPrime, std::size_t OffsetBias>
struct basic_fnv_1
{
std::size_t operator()(std::string const& text)
{
std::size_t hash = OffsetBias;
for(std::string::const_iterator it = text.begin(), end = text.end();
it != end; ++it)
{
hash *= FnvPrime;
hash ^= *it;
}
return hash;
}
};
template <std::size_t FnvPrime, std::size_t OffsetBias>
struct basic_fnv_1a
{
std::size_t operator()(std::string const& text)
{
std::size_t hash = OffsetBias;
for(std::string::const_iterator it = text.begin(), end = text.end();
it != end; ++it)
{
hash ^= *it;
hash *= FnvPrime;
}
return hash;
}
};
// TODO: Select Bias & Prime base on the size of std::size_t.
//
// 32 bit FNV_prime = 16777619
// 64 bit FNV_prime = 1099511628211
// 128 bit FNV_prime = 309485009821345068724781401
// 256 bit FNV_prime = 374144419156711147060143317175368453031918731002211
//
// 32 bit offset_basis = 2166136261
// 64 bit offset_basis = 14695981039346656037
// 128 bit offset_basis = 275519064689413815358837431229664493455
// 256 bit offset_basis = 100029257958052580907070968620625704837092796014241193945225284501741471925557
const std::size_t fnv_prime = 16777619;
// 64 bit FNV_prime = 1099511628211
// 128 bit FNV_prime = 309485009821345068724781401
// 256 bit FNV_prime = 374144419156711147060143317175368453031918731002211
const std::size_t fnv_offset_bias = 2166136261;
// 64 bit offset_basis = 14695981039346656037
// 128 bit offset_basis = 275519064689413815358837431229664493455
// 256 bit offset_basis = 100029257958052580907070968620625704837092796014241193945225284501741471925557
typedef basic_fnv_1<fnv_prime, fnv_offset_bias> fnv_1;
typedef basic_fnv_1a<fnv_prime, fnv_offset_bias> fnv_1a;
}

View File

@ -0,0 +1,237 @@
// Copyright 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/config.hpp>
#if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
&& !defined(__BORLANDC__)
# define BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES
#endif
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
# include <boost/detail/allocator_utilities.hpp>
#endif
#include <boost/mpl/aux_/config/eti.hpp>
namespace boost {
namespace unordered_detail {
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
template <class Alloc, class T>
struct rebind_wrap : ::boost::detail::allocator::rebind_to<Alloc, T> {};
#else
template <class Alloc, class T>
struct rebind_wrap
{
typedef BOOST_DEDUCED_TYPENAME
Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other
type;
};
#endif
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
template <class T>
inline void reset(T& x) { x = T(); }
template <class Ptr>
inline Ptr null_ptr() { return Ptr(); }
#else
template <class T>
inline void reset_impl(T& x, ...) { x = T(); }
template <class T>
inline void reset_impl(T*& x, int) { x = 0; }
template <class T>
inline void reset(T& x) { reset_impl(x); }
template <class Ptr>
inline Ptr null_ptr() { Ptr x; reset(x); return x; }
#endif
// Work around for Microsoft's ETI bug.
template <class Allocator> struct allocator_value_type
{
typedef BOOST_DEDUCED_TYPENAME Allocator::value_type type;
};
template <class Allocator> struct allocator_pointer
{
typedef BOOST_DEDUCED_TYPENAME Allocator::pointer type;
};
template <class Allocator> struct allocator_const_pointer
{
typedef BOOST_DEDUCED_TYPENAME Allocator::const_pointer type;
};
template <class Allocator> struct allocator_reference
{
typedef BOOST_DEDUCED_TYPENAME Allocator::reference type;
};
template <class Allocator> struct allocator_const_reference
{
typedef BOOST_DEDUCED_TYPENAME Allocator::const_reference type;
};
#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
template <>
struct allocator_value_type<int>
{
typedef int type;
};
template <>
struct allocator_pointer<int>
{
typedef int type;
};
template <>
struct allocator_const_pointer<int>
{
typedef int type;
};
template <>
struct allocator_reference<int>
{
typedef int type;
};
template <>
struct allocator_const_reference<int>
{
typedef int type;
};
#endif
template <class Allocator>
struct allocator_constructor
{
typedef BOOST_DEDUCED_TYPENAME allocator_value_type<Allocator>::type value_type;
typedef BOOST_DEDUCED_TYPENAME allocator_pointer<Allocator>::type pointer;
Allocator& alloc_;
pointer ptr_;
bool constructed_;
allocator_constructor(Allocator& a)
: alloc_(a), ptr_(), constructed_(false)
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(ptr_);
#endif
}
~allocator_constructor() {
if(ptr_) {
if(constructed_) alloc_.destroy(ptr_);
alloc_.deallocate(ptr_, 1);
}
}
template <class V>
void construct(V const& v) {
BOOST_ASSERT(!ptr_ && !constructed_);
ptr_ = alloc_.allocate(1);
alloc_.construct(ptr_, value_type(v));
constructed_ = true;
}
void construct(value_type const& v) {
BOOST_ASSERT(!ptr_ && !constructed_);
ptr_ = alloc_.allocate(1);
alloc_.construct(ptr_, v);
constructed_ = true;
}
pointer get() const
{
return ptr_;
}
// no throw
pointer release()
{
pointer p = ptr_;
constructed_ = false;
unordered_detail::reset(ptr_);
return p;
}
};
template <class Allocator>
struct allocator_array_constructor
{
typedef BOOST_DEDUCED_TYPENAME allocator_pointer<Allocator>::type pointer;
Allocator& alloc_;
pointer ptr_;
pointer constructed_;
std::size_t length_;
allocator_array_constructor(Allocator& a)
: alloc_(a), ptr_(), constructed_(), length_(0)
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(constructed_);
unordered_detail::reset(ptr_);
#endif
}
~allocator_array_constructor() {
if (ptr_) {
for(pointer p = ptr_; p != constructed_; ++p)
alloc_.destroy(p);
alloc_.deallocate(ptr_, length_);
}
}
template <class V>
void construct(V const& v, std::size_t l)
{
BOOST_ASSERT(!ptr_);
length_ = l;
ptr_ = alloc_.allocate(length_);
pointer end = ptr_ + length_;
for(constructed_ = ptr_; constructed_ != end; ++constructed_)
alloc_.construct(constructed_, v);
}
pointer get() const
{
return ptr_;
}
pointer release()
{
pointer p(ptr_);
unordered_detail::reset(ptr_);
return p;
}
private:
allocator_array_constructor(allocator_array_constructor const&);
allocator_array_constructor& operator=(allocator_array_constructor const&);
};
}
}
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
# undef BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES
#endif
#endif

View File

@ -0,0 +1,185 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2007 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/config.hpp>
#include <cstddef>
#include <cmath>
#include <algorithm>
#include <utility>
#include <stdexcept>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/limits.hpp>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/unordered/detail/allocator.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/mpl/aux_/config/eti.hpp>
#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551)
#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x)
#else
#define BOOST_UNORDERED_BORLAND_BOOL(x) x
#endif
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
#define BOOST_UNORDERED_MSVC_RESET_PTR(x) unordered_detail::reset(x)
#else
#define BOOST_UNORDERED_MSVC_RESET_PTR(x)
#endif
namespace boost {
namespace unordered_detail {
template <class T> struct type_wrapper {};
const static std::size_t default_initial_bucket_count = 50;
const static float minimum_max_load_factor = 1e-3f;
inline std::size_t next_prime(std::size_t n);
template <class T>
inline void hash_swap(T& x, T& y)
{
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
std::swap(x,y);
#else
using std::swap;
swap(x, y);
#endif
}
inline std::size_t float_to_size_t(float f)
{
return f > static_cast<float>((std::numeric_limits<std::size_t>::max)()) ?
(std::numeric_limits<std::size_t>::max)() :
static_cast<std::size_t>(f);
}
// prime number list, accessor
static const std::size_t prime_list[] = {
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul };
// 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)
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);
if(bound != prime_list)
bound--;
return *bound;
}
// pair_cast - used to convert between pair types.
template <class Dst1, class Dst2, class Src1, class Src2>
inline std::pair<Dst1, Dst2> pair_cast(std::pair<Src1, Src2> const& x)
{
return std::pair<Dst1, Dst2>(Dst1(x.first), Dst2(x.second));
}
}
}
#define BOOST_UNORDERED_EQUIVALENT_KEYS 1
#include <boost/unordered/detail/hash_table_impl.hpp>
#undef BOOST_UNORDERED_EQUIVALENT_KEYS
#define BOOST_UNORDERED_EQUIVALENT_KEYS 0
#include <boost/unordered/detail/hash_table_impl.hpp>
#undef BOOST_UNORDERED_EQUIVALENT_KEYS
namespace boost {
namespace unordered_detail {
class iterator_access
{
public:
template <class Iterator>
static BOOST_DEDUCED_TYPENAME Iterator::base const& get(Iterator const& it) {
return it.base_;
}
};
template <class ValueType, class KeyType,
class Hash, class Pred, class Alloc>
class hash_types_unique_keys
{
public:
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<Alloc, ValueType>::type
value_allocator;
typedef hash_table_unique_keys<ValueType, KeyType, Hash, Pred,
value_allocator> hash_table;
typedef hash_table_data_unique_keys<value_allocator> data;
typedef BOOST_DEDUCED_TYPENAME data::iterator_base iterator_base;
typedef hash_const_local_iterator_unique_keys<value_allocator> const_local_iterator;
typedef hash_local_iterator_unique_keys<value_allocator> local_iterator;
typedef hash_const_iterator_unique_keys<value_allocator> const_iterator;
typedef hash_iterator_unique_keys<value_allocator> iterator;
typedef BOOST_DEDUCED_TYPENAME data::size_type size_type;
typedef std::ptrdiff_t difference_type;
};
template <class ValueType, class KeyType,
class Hash, class Pred, class Alloc>
class hash_types_equivalent_keys
{
public:
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<Alloc, ValueType>::type
value_allocator;
typedef hash_table_equivalent_keys<ValueType, KeyType, Hash, Pred,
value_allocator> hash_table;
typedef hash_table_data_equivalent_keys<value_allocator> data;
typedef BOOST_DEDUCED_TYPENAME data::iterator_base iterator_base;
typedef hash_const_local_iterator_equivalent_keys<value_allocator> const_local_iterator;
typedef hash_local_iterator_equivalent_keys<value_allocator> local_iterator;
typedef hash_const_iterator_equivalent_keys<value_allocator> const_iterator;
typedef hash_iterator_equivalent_keys<value_allocator> iterator;
typedef BOOST_DEDUCED_TYPENAME data::size_type size_type;
typedef std::ptrdiff_t difference_type;
};
} // namespace boost::unordered_detail
} // namespace boost
#undef BOOST_UNORDERED_BORLAND_BOOL
#undef BOOST_UNORDERED_MSVC_RESET_PTR
#endif // BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,636 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_MAP_HPP_INCLUDED
#define BOOST_UNORDERED_MAP_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/config.hpp>
#include <functional>
#include <memory>
#include <boost/unordered/detail/hash_table.hpp>
#include <boost/functional/hash.hpp>
namespace boost
{
template <class Key,
class T,
class Hash = hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T> > >
class unordered_map
{
typedef boost::unordered_detail::hash_types_unique_keys<
std::pair<const Key, T>, Key, Hash, Pred, Alloc
> implementation;
BOOST_DEDUCED_TYPENAME implementation::hash_table base;
public:
// types
typedef Key key_type;
typedef std::pair<const Key, T> value_type;
typedef T mapped_type;
typedef Hash hasher;
typedef Pred key_equal;
typedef Alloc allocator_type;
typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type;
typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type;
typedef BOOST_DEDUCED_TYPENAME implementation::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::local_iterator local_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator;
// construct/destroy/copy
explicit unordered_map(
size_type n = boost::unordered_detail::default_initial_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(n, hf, eql, a)
{
}
template <class InputIterator>
unordered_map(InputIterator f, InputIterator l)
: base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
{
}
template <class InputIterator>
unordered_map(InputIterator f, InputIterator l,
size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(f, l, n, hf, eql, a)
{
}
private:
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
get(const_iterator const& it)
{
return boost::unordered_detail::iterator_access::get(it);
}
public:
allocator_type get_allocator() const
{
return base.get_allocator();
}
// size and capacity
bool empty() const
{
return base.empty();
}
size_type size() const
{
return base.size();
}
size_type max_size() const
{
return base.max_size();
}
// iterators
iterator begin()
{
return iterator(base.begin());
}
const_iterator begin() const
{
return const_iterator(base.begin());
}
iterator end()
{
return iterator(base.end());
}
const_iterator end() const
{
return const_iterator(base.end());
}
const_iterator cbegin() const
{
return const_iterator(base.begin());
}
const_iterator cend() const
{
return const_iterator(base.end());
}
// modifiers
std::pair<iterator, bool> insert(const value_type& obj)
{
return boost::unordered_detail::pair_cast<iterator, bool>(
base.insert(obj));
}
iterator insert(const_iterator hint, const value_type& obj)
{
return iterator(base.insert(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
base.insert(first, last);
}
iterator erase(const_iterator position)
{
return iterator(base.erase(get(position)));
}
size_type erase(const key_type& k)
{
return base.erase(k);
}
iterator erase(const_iterator first, const_iterator last)
{
return iterator(base.erase(get(first), get(last)));
}
void clear()
{
base.clear();
}
void swap(unordered_map& other)
{
base.swap(other.base);
}
// observers
hasher hash_function() const
{
return base.hash_function();
}
key_equal key_eq() const
{
return base.key_eq();
}
mapped_type& operator[](const key_type &k)
{
return base[k].second;
}
mapped_type& at(const key_type& k)
{
return base.at(k).second;
}
mapped_type const& at(const key_type& k) const
{
return base.at(k).second;
}
// lookup
iterator find(const key_type& k)
{
return iterator(base.find(k));
}
const_iterator find(const key_type& k) const
{
return const_iterator(base.find(k));
}
size_type count(const key_type& k) const
{
return base.count(k);
}
std::pair<iterator, iterator>
equal_range(const key_type& k)
{
return boost::unordered_detail::pair_cast<iterator, iterator>(
base.equal_range(k));
}
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
base.equal_range(k));
}
// bucket interface
size_type bucket_count() const
{
return base.bucket_count();
}
size_type max_bucket_count() const
{
return base.max_bucket_count();
}
size_type bucket_size(size_type n) const
{
return base.bucket_size(n);
}
size_type bucket(const key_type& k) const
{
return base.bucket(k);
}
local_iterator begin(size_type n)
{
return local_iterator(base.begin(n));
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(base.begin(n));
}
local_iterator end(size_type n)
{
return local_iterator(base.end(n));
}
const_local_iterator end(size_type n) const
{
return const_local_iterator(base.end(n));
}
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(base.begin(n));
}
const_local_iterator cend(size_type n) const
{
return const_local_iterator(base.end(n));
}
// hash policy
float load_factor() const
{
return base.load_factor();
}
float max_load_factor() const
{
return base.max_load_factor();
}
void max_load_factor(float m)
{
base.max_load_factor(m);
}
void rehash(size_type n)
{
base.rehash(n);
}
}; // class template unordered_map
template <class K, class T, class H, class P, class A>
void swap(unordered_map<K, T, H, P, A> &m1,
unordered_map<K, T, H, P, A> &m2)
{
m1.swap(m2);
}
template <class Key,
class T,
class Hash = hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T> > >
class unordered_multimap
{
typedef boost::unordered_detail::hash_types_equivalent_keys<
std::pair<const Key, T>, Key, Hash, Pred, Alloc
> implementation;
BOOST_DEDUCED_TYPENAME implementation::hash_table base;
public:
// types
typedef Key key_type;
typedef std::pair<const Key, T> value_type;
typedef T mapped_type;
typedef Hash hasher;
typedef Pred key_equal;
typedef Alloc allocator_type;
typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type;
typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type;
typedef BOOST_DEDUCED_TYPENAME implementation::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::local_iterator local_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator;
// construct/destroy/copy
explicit unordered_multimap(
size_type n = boost::unordered_detail::default_initial_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(n, hf, eql, a)
{
}
template <class InputIterator>
unordered_multimap(InputIterator f, InputIterator l)
: base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
{
}
template <class InputIterator>
unordered_multimap(InputIterator f, InputIterator l,
size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(f, l, n, hf, eql, a)
{
}
private:
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
get(const_iterator const& it)
{
return boost::unordered_detail::iterator_access::get(it);
}
public:
allocator_type get_allocator() const
{
return base.get_allocator();
}
// size and capacity
bool empty() const
{
return base.empty();
}
size_type size() const
{
return base.size();
}
size_type max_size() const
{
return base.max_size();
}
// iterators
iterator begin()
{
return iterator(base.begin());
}
const_iterator begin() const
{
return const_iterator(base.begin());
}
iterator end()
{
return iterator(base.end());
}
const_iterator end() const
{
return const_iterator(base.end());
}
const_iterator cbegin() const
{
return const_iterator(base.begin());
}
const_iterator cend() const
{
return const_iterator(base.end());
}
// modifiers
iterator insert(const value_type& obj)
{
return iterator(base.insert(obj));
}
iterator insert(const_iterator hint, const value_type& obj)
{
return iterator(base.insert(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
base.insert(first, last);
}
iterator erase(const_iterator position)
{
return iterator(base.erase(get(position)));
}
size_type erase(const key_type& k)
{
return base.erase(k);
}
iterator erase(const_iterator first, const_iterator last)
{
return iterator(base.erase(get(first), get(last)));
}
void clear()
{
base.clear();
}
void swap(unordered_multimap& other)
{
base.swap(other.base);
}
// observers
hasher hash_function() const
{
return base.hash_function();
}
key_equal key_eq() const
{
return base.key_eq();
}
// lookup
iterator find(const key_type& k)
{
return iterator(base.find(k));
}
const_iterator find(const key_type& k) const
{
return const_iterator(base.find(k));
}
size_type count(const key_type& k) const
{
return base.count(k);
}
std::pair<iterator, iterator>
equal_range(const key_type& k)
{
return boost::unordered_detail::pair_cast<iterator, iterator>(
base.equal_range(k));
}
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
base.equal_range(k));
}
// bucket interface
size_type bucket_count() const
{
return base.bucket_count();
}
size_type max_bucket_count() const
{
return base.max_bucket_count();
}
size_type bucket_size(size_type n) const
{
return base.bucket_size(n);
}
size_type bucket(const key_type& k) const
{
return base.bucket(k);
}
local_iterator begin(size_type n)
{
return local_iterator(base.begin(n));
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(base.begin(n));
}
local_iterator end(size_type n)
{
return local_iterator(base.end(n));
}
const_local_iterator end(size_type n) const
{
return const_local_iterator(base.end(n));
}
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(base.begin(n));
}
const_local_iterator cend(size_type n) const
{
return const_local_iterator(base.end(n));
}
// hash policy
float load_factor() const
{
return base.load_factor();
}
float max_load_factor() const
{
return base.max_load_factor();
}
void max_load_factor(float m)
{
base.max_load_factor(m);
}
void rehash(size_type n)
{
base.rehash(n);
}
}; // class template unordered_multimap
template <class K, class T, class H, class P, class A>
void swap(unordered_multimap<K, T, H, P, A> &m1,
unordered_multimap<K, T, H, P, A> &m2)
{
m1.swap(m2);
}
} // namespace boost
#endif // BOOST_UNORDERED_MAP_HPP_INCLUDED

View File

@ -0,0 +1,591 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_SET_HPP_INCLUDED
#define BOOST_UNORDERED_SET_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/config.hpp>
#include <functional>
#include <memory>
#include <boost/unordered/detail/hash_table.hpp>
#include <boost/functional/hash.hpp>
namespace boost
{
template <class Value,
class Hash = hash<Value>,
class Pred = std::equal_to<Value>,
class Alloc = std::allocator<Value> >
class unordered_set
{
typedef boost::unordered_detail::hash_types_unique_keys<
Value, Value, Hash, Pred, Alloc
> implementation;
BOOST_DEDUCED_TYPENAME implementation::hash_table base;
public:
// types
typedef Value key_type;
typedef Value value_type;
typedef Hash hasher;
typedef Pred key_equal;
typedef Alloc allocator_type;
typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type;
typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type;
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator local_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator;
// construct/destroy/copy
explicit unordered_set(
size_type n = boost::unordered_detail::default_initial_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(n, hf, eql, a)
{
}
template <class InputIterator>
unordered_set(InputIterator f, InputIterator l)
: base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
{
}
template <class InputIterator>
unordered_set(InputIterator f, InputIterator l, size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(f, l, n, hf, eql, a)
{
}
private:
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
get(const_iterator const& it)
{
return boost::unordered_detail::iterator_access::get(it);
}
public:
allocator_type get_allocator() const
{
return base.get_allocator();
}
// size and capacity
bool empty() const
{
return base.empty();
}
size_type size() const
{
return base.size();
}
size_type max_size() const
{
return base.max_size();
}
// iterators
iterator begin()
{
return iterator(base.begin());
}
const_iterator begin() const
{
return const_iterator(base.begin());
}
iterator end()
{
return iterator(base.end());
}
const_iterator end() const
{
return const_iterator(base.end());
}
const_iterator cbegin() const
{
return const_iterator(base.begin());
}
const_iterator cend() const
{
return const_iterator(base.end());
}
// modifiers
std::pair<iterator, bool> insert(const value_type& obj)
{
return boost::unordered_detail::pair_cast<iterator, bool>(
base.insert(obj));
}
iterator insert(const_iterator hint, const value_type& obj)
{
return iterator(base.insert(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
base.insert(first, last);
}
iterator erase(const_iterator position)
{
return iterator(base.erase(get(position)));
}
size_type erase(const key_type& k)
{
return base.erase(k);
}
iterator erase(const_iterator first, const_iterator last)
{
return iterator(base.erase(get(first), get(last)));
}
void clear()
{
base.clear();
}
void swap(unordered_set& other)
{
base.swap(other.base);
}
// observers
hasher hash_function() const
{
return base.hash_function();
}
key_equal key_eq() const
{
return base.key_eq();
}
// lookup
const_iterator find(const key_type& k) const
{
return const_iterator(base.find(k));
}
size_type count(const key_type& k) const
{
return base.count(k);
}
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
base.equal_range(k));
}
// bucket interface
size_type bucket_count() const
{
return base.bucket_count();
}
size_type max_bucket_count() const
{
return base.max_bucket_count();
}
size_type bucket_size(size_type n) const
{
return base.bucket_size(n);
}
size_type bucket(const key_type& k) const
{
return base.bucket(k);
}
local_iterator begin(size_type n)
{
return local_iterator(base.begin(n));
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(base.begin(n));
}
local_iterator end(size_type n)
{
return local_iterator(base.end(n));
}
const_local_iterator end(size_type n) const
{
return const_local_iterator(base.end(n));
}
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(base.begin(n));
}
const_local_iterator cend(size_type n) const
{
return const_local_iterator(base.end(n));
}
// hash policy
float load_factor() const
{
return base.load_factor();
}
float max_load_factor() const
{
return base.max_load_factor();
}
void max_load_factor(float m)
{
base.max_load_factor(m);
}
void rehash(size_type n)
{
base.rehash(n);
}
}; // class template unordered_set
template <class T, class H, class P, class A>
void swap(unordered_set<T, H, P, A> &m1,
unordered_set<T, H, P, A> &m2)
{
m1.swap(m2);
}
template <class Value,
class Hash = hash<Value>,
class Pred = std::equal_to<Value>,
class Alloc = std::allocator<Value> >
class unordered_multiset
{
typedef boost::unordered_detail::hash_types_equivalent_keys<
Value, Value, Hash, Pred, Alloc
> implementation;
BOOST_DEDUCED_TYPENAME implementation::hash_table base;
public:
//types
typedef Value key_type;
typedef Value value_type;
typedef Hash hasher;
typedef Pred key_equal;
typedef Alloc allocator_type;
typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type;
typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type;
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator local_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator;
// construct/destroy/copy
explicit unordered_multiset(
size_type n = boost::unordered_detail::default_initial_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(n, hf, eql, a)
{
}
template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l)
: base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
{
}
template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l, size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(f, l, n, hf, eql, a)
{
}
private:
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
get(const_iterator const& it)
{
return boost::unordered_detail::iterator_access::get(it);
}
public:
allocator_type get_allocator() const
{
return base.get_allocator();
}
// size and capacity
bool empty() const
{
return base.empty();
}
size_type size() const
{
return base.size();
}
size_type max_size() const
{
return base.max_size();
}
// iterators
iterator begin()
{
return iterator(base.begin());
}
const_iterator begin() const
{
return const_iterator(base.begin());
}
iterator end()
{
return iterator(base.end());
}
const_iterator end() const
{
return const_iterator(base.end());
}
const_iterator cbegin() const
{
return const_iterator(base.begin());
}
const_iterator cend() const
{
return const_iterator(base.end());
}
// modifiers
iterator insert(const value_type& obj)
{
return iterator(base.insert(obj));
}
iterator insert(const_iterator hint, const value_type& obj)
{
return iterator(base.insert(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
base.insert(first, last);
}
iterator erase(const_iterator position)
{
return iterator(base.erase(get(position)));
}
size_type erase(const key_type& k)
{
return base.erase(k);
}
iterator erase(const_iterator first, const_iterator last)
{
return iterator(base.erase(get(first), get(last)));
}
void clear()
{
base.clear();
}
void swap(unordered_multiset& other)
{
base.swap(other.base);
}
// observers
hasher hash_function() const
{
return base.hash_function();
}
key_equal key_eq() const
{
return base.key_eq();
}
// lookup
const_iterator find(const key_type& k) const
{
return const_iterator(base.find(k));
}
size_type count(const key_type& k) const
{
return base.count(k);
}
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
base.equal_range(k));
}
// bucket interface
size_type bucket_count() const
{
return base.bucket_count();
}
size_type max_bucket_count() const
{
return base.max_bucket_count();
}
size_type bucket_size(size_type n) const
{
return base.bucket_size(n);
}
size_type bucket(const key_type& k) const
{
return base.bucket(k);
}
local_iterator begin(size_type n)
{
return local_iterator(base.begin(n));
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(base.begin(n));
}
local_iterator end(size_type n)
{
return local_iterator(base.end(n));
}
const_local_iterator end(size_type n) const
{
return const_local_iterator(base.end(n));
}
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(base.begin(n));
}
const_local_iterator cend(size_type n) const
{
return const_local_iterator(base.end(n));
}
// hash policy
float load_factor() const
{
return base.load_factor();
}
float max_load_factor() const
{
return base.max_load_factor();
}
void max_load_factor(float m)
{
base.max_load_factor(m);
}
void rehash(size_type n)
{
base.rehash(n);
}
}; // class template unordered_multiset
template <class T, class H, class P, class A>
void swap(unordered_multiset<T, H, P, A> &m1,
unordered_multiset<T, H, P, A> &m2)
{
m1.swap(m2);
}
} // namespace boost
#endif // BOOST_UNORDERED_SET_HPP_INCLUDED

8
test/Jamfile.v2 Normal file
View File

@ -0,0 +1,8 @@
# Copyright 2006-2007 Daniel James.
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
build-project container ;
build-project unordered ;
build-project exception ;

21
test/container/Jamfile.v2 Normal file
View File

@ -0,0 +1,21 @@
# 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)
import testing ;
project unordered-test/container
: requirements
<toolset>intel-linux:"<cxxflags>-strict_ansi -cxxlib-icc"
<toolset>gcc:<cxxflags>-Wsign-promo
<toolset>msvc:<cxxflags>/W4
;
test-suite container-tests
:
[ run set_compile.cpp ]
[ run map_compile.cpp ]
[ run simple_tests.cpp ]
[ run link_test_1.cpp link_test_2.cpp ]
;

View File

@ -0,0 +1,130 @@
// Copyright 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
#include <boost/concept_check.hpp>
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#include <boost/mpl/assert.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <boost/limits.hpp>
#include "../helpers/check_return_type.hpp"
typedef long double comparison_type;
template <class T> void sink(T const&) {}
template <class X, class T>
void container_test(X& r, T&)
{
typedef typename X::iterator iterator;
typedef typename X::const_iterator const_iterator;
typedef typename X::difference_type difference_type;
typedef typename X::size_type size_type;
typedef typename boost::iterator_value<iterator>::type iterator_value_type;
typedef typename boost::iterator_value<const_iterator>::type const_iterator_value_type;
typedef typename boost::iterator_difference<iterator>::type iterator_difference_type;
typedef typename boost::iterator_difference<const_iterator>::type const_iterator_difference_type;
typedef typename X::value_type value_type;
typedef typename X::reference reference;
typedef typename X::const_reference const_reference;
// value_type
BOOST_MPL_ASSERT((boost::is_same<T, value_type>));
boost::function_requires<boost::CopyConstructibleConcept<X> >();
// reference_type / const_reference_type
BOOST_MPL_ASSERT((boost::is_same<T&, reference>));
BOOST_MPL_ASSERT((boost::is_same<T const&, const_reference>));
// iterator
boost::function_requires<boost::InputIteratorConcept<iterator> >();
BOOST_MPL_ASSERT((boost::is_same<T, iterator_value_type>));
BOOST_MPL_ASSERT((boost::is_convertible<iterator, const_iterator>));
// const_iterator
boost::function_requires<boost::InputIteratorConcept<const_iterator> >();
BOOST_MPL_ASSERT((boost::is_same<T, const_iterator_value_type>));
// difference_type
BOOST_MPL_ASSERT((boost::mpl::bool_<
std::numeric_limits<difference_type>::is_signed>));
BOOST_MPL_ASSERT((boost::mpl::bool_<
std::numeric_limits<difference_type>::is_integer>));
BOOST_MPL_ASSERT((boost::is_same<difference_type,
iterator_difference_type>));
BOOST_MPL_ASSERT((boost::is_same<difference_type,
const_iterator_difference_type>));
// size_type
BOOST_MPL_ASSERT_NOT((boost::mpl::bool_<
std::numeric_limits<size_type>::is_signed>));
BOOST_MPL_ASSERT((boost::mpl::bool_<
std::numeric_limits<size_type>::is_integer>));
// size_type can represent any non-negative value type of difference_type
// I'm not sure about either of these tests...
size_type max_diff((std::numeric_limits<difference_type>::max)());
difference_type converted_diff(max_diff);
BOOST_TEST((std::numeric_limits<difference_type>::max)()
== converted_diff);
BOOST_TEST(
static_cast<comparison_type>(
(std::numeric_limits<size_type>::max)()) >
static_cast<comparison_type>(
(std::numeric_limits<difference_type>::max)()));
// I don't test the runtime post-conditions here.
X u;
BOOST_TEST(u.size() == 0);
BOOST_TEST(X().size() == 0);
X a,b;
sink(X(a));
X u2(a);
X u3 = a;
X* ptr = new X();
X& a1 = *ptr;
(&a1)->~X();
X const a_const;
test::check_return_type<iterator>::equals(a.begin());
test::check_return_type<const_iterator>::equals(a_const.begin());
test::check_return_type<const_iterator>::equals(a.cbegin());
test::check_return_type<const_iterator>::equals(a_const.cbegin());
test::check_return_type<iterator>::equals(a.end());
test::check_return_type<const_iterator>::equals(a_const.end());
test::check_return_type<const_iterator>::equals(a.cend());
test::check_return_type<const_iterator>::equals(a_const.cend());
// No tests for ==, != since they're not required for unordered containers.
a.swap(b);
test::check_return_type<X>::equals_ref(r = a);
test::check_return_type<size_type>::equals(a.size());
test::check_return_type<size_type>::equals(a.max_size());
test::check_return_type<bool>::convertible(a.empty());
}

View File

@ -0,0 +1,24 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
void foo(boost::unordered_set<int>&,
boost::unordered_map<int, int>&,
boost::unordered_multiset<int>&,
boost::unordered_multimap<int, int>&);
int main()
{
boost::unordered_set<int> x1;
boost::unordered_map<int, int> x2;
boost::unordered_multiset<int> x3;
boost::unordered_multimap<int, int> x4;
foo(x1, x2, x3, x4);
return 0;
}

View File

@ -0,0 +1,18 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
void foo(boost::unordered_set<int>& x1,
boost::unordered_map<int, int>& x2,
boost::unordered_multiset<int>& x3,
boost::unordered_multimap<int, int>& x4)
{
x1.insert(1);
x2[2] = 2;
x3.insert(3);
x4.insert(std::make_pair(4, 5));
}

View File

@ -0,0 +1,45 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// This test creates the containers with members that meet their minimum
// requirements. Makes sure everything compiles and is defined correctly.
#include <boost/unordered_map.hpp>
#include <iostream>
#include <boost/detail/lightweight_test.hpp>
#include "../objects/minimal.hpp"
#include "./compile_tests.hpp"
int main()
{
typedef std::pair<test::minimal::assignable const,
test::minimal::copy_constructible> value_type;
value_type value(
test::minimal::assignable::create(),
test::minimal::copy_constructible::create());
std::cout<<"Test unordered_map.\n";
boost::unordered_map<
test::minimal::assignable,
test::minimal::copy_constructible,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<value_type> > map;
container_test(map, value);
std::cout<<"Test unordered_multimap.\n";
boost::unordered_multimap<
test::minimal::assignable,
test::minimal::copy_constructible,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<value_type> > multimap;
container_test(multimap, value);
return boost::report_errors();
}

View File

@ -0,0 +1,39 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// This test creates the containers with members that meet their minimum
// requirements. Makes sure everything compiles and is defined correctly.
#include <boost/unordered_set.hpp>
#include <iostream>
#include <boost/detail/lightweight_test.hpp>
#include "../objects/minimal.hpp"
#include "./compile_tests.hpp"
int main()
{
test::minimal::assignable assignable = test::minimal::assignable::create();
std::cout<<"Test unordered_set.\n";
boost::unordered_set<
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<test::minimal::assignable> > set;
container_test(set, assignable);
std::cout<<"Test unordered_multiset.\n";
boost::unordered_multiset<
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<test::minimal::assignable> > multiset;
container_test(multiset, assignable);
return boost::report_errors();
}

View File

@ -0,0 +1,104 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// This test checks the runtime requirements of containers.
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <algorithm>
#include "../helpers/equivalent.hpp"
template <class X>
void simple_test(X const& a)
{
test::unordered_equivalence_tester<X> equivalent(a);
{
X u;
BOOST_TEST(u.size() == 0);
BOOST_TEST(X().size() == 0);
}
{
BOOST_TEST(equivalent(X(a)));
}
{
X u(a);
BOOST_TEST(equivalent(u));
}
{
X u = a;
BOOST_TEST(equivalent(u));
}
{
X b(a);
BOOST_TEST(b.begin() == const_cast<X const&>(b).cbegin());
BOOST_TEST(b.end() == const_cast<X const&>(b).cend());
}
{
X b(a);
X c;
BOOST_TEST(equivalent(b));
BOOST_TEST(c.empty());
b.swap(c);
BOOST_TEST(b.empty());
BOOST_TEST(equivalent(c));
b.swap(c);
BOOST_TEST(b.empty());
BOOST_TEST(equivalent(c));
}
{
X u;
X& r = u;
BOOST_TEST(&(r = r) == &r);
BOOST_TEST(r.empty());
BOOST_TEST(&(r = a) == &r);
BOOST_TEST(equivalent(r));
BOOST_TEST(&(r = r) == &r);
BOOST_TEST(equivalent(r));
}
{
BOOST_TEST(a.size() ==
(typename X::size_type) std::distance(a.begin(), a.end()));
}
{
BOOST_TEST(a.empty() == (a.size() == 0));
}
{
BOOST_TEST(a.empty() == (a.begin() == a.end()));
X u;
BOOST_TEST(u.begin() == u.end());
}
}
int main()
{
std::cout<<"Test unordered_set.\n";
boost::unordered_set<int> set;
simple_test(set);
std::cout<<"Test unordered_multiset.\n";
boost::unordered_multiset<int> multiset;
simple_test(multiset);
std::cout<<"Test unordered_map.\n";
boost::unordered_map<int, int> map;
simple_test(map);
std::cout<<"Test unordered_multimap.\n";
boost::unordered_multimap<int, int> multimap;
simple_test(multimap);
return boost::report_errors();
}

26
test/exception/Jamfile.v2 Normal file
View File

@ -0,0 +1,26 @@
# Copyright 2006-2007 Daniel James.
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
import testing ;
alias framework : /boost/test//boost_unit_test_framework ;
project unordered-test/exception-tests
: requirements
<toolset>intel-linux:"<cxxflags>-strict_ansi -cxxlib-icc"
<toolset>gcc:<cxxflags>-Wsign-promo
;
test-suite unordered-tests
:
[ run constructor_tests.cpp framework ]
[ run copy_tests.cpp framework ]
[ run assign_tests.cpp framework ]
[ run insert_tests.cpp framework ]
[ run erase_tests.cpp framework ]
[ run rehash_tests.cpp framework ]
[ run swap_tests.cpp framework : : :
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
;

View File

@ -0,0 +1,81 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./containers.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/test/exception_safety.hpp>
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
test::seed_t seed(12847);
template <class T>
struct self_assign_base : public test::exception_base
{
test::random_values<T> values;
self_assign_base(int count = 0) : values(count) {}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
void run(T& x) const { x = x; }
void check(T const& x) const { test::check_equivalent_keys(x); }
};
template <class T>
struct self_assign_test1 : self_assign_base<T> {};
template <class T>
struct self_assign_test2 : self_assign_base<T>
{
self_assign_test2() : self_assign_base<T>(100) {}
};
template <class T>
struct assign_base : public test::exception_base
{
const test::random_values<T> x_values, y_values;
const T x,y;
assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
: x_values(count1), y_values(count2),
x(x_values.begin(), x_values.end(), 0, typename T::hasher(tag1), typename T::key_equal(tag1), typename T::allocator_type(tag1)),
y(y_values.begin(), y_values.end(), 0, typename T::hasher(tag2), typename T::key_equal(tag2), typename T::allocator_type(tag2)) {}
typedef T data_type;
T init() const { return T(x); }
void run(T& x1) const { x1 = y; }
void check(T const& x1) const { test::check_equivalent_keys(x1); }
};
template <class T>
struct assign_test1 : assign_base<T>
{
assign_test1() : assign_base<T>(0, 0, 0, 0) {}
};
template <class T>
struct assign_test2 : assign_base<T>
{
assign_test2() : assign_base<T>(60, 0, 0, 0) {}
};
template <class T>
struct assign_test3 : assign_base<T>
{
assign_test3() : assign_base<T>(0, 60, 0, 0) {}
};
template <class T>
struct assign_test4 : assign_base<T>
{
assign_test4() : assign_base<T>(10, 10, 1, 2) {}
};
RUN_EXCEPTION_TESTS(
(self_assign_test1)(self_assign_test2)
(assign_test1)(assign_test2)(assign_test3)(assign_test4),
CONTAINER_SEQ)

View File

@ -0,0 +1,133 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./containers.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/test/exception_safety.hpp>
#include "../helpers/random_values.hpp"
#include "../helpers/input_iterator.hpp"
test::seed_t seed(91274);
struct objects
{
test::exception::object obj;
test::exception::hash hash;
test::exception::equal_to equal_to;
test::exception::allocator<test::exception::object> allocator;
};
template <class T>
struct construct_test1 : public objects, test::exception_base
{
void run() const {
T x;
}
};
template <class T>
struct construct_test2 : public objects, test::exception_base
{
void run() const {
T x(300);
}
};
template <class T>
struct construct_test3 : public objects, test::exception_base
{
void run() const {
T x(0, hash);
}
};
template <class T>
struct construct_test4 : public objects, test::exception_base
{
void run() const {
T x(0, hash, equal_to);
}
};
template <class T>
struct construct_test5 : public objects, test::exception_base
{
void run() const {
T x(50, hash, equal_to, allocator);
}
};
template <class T>
struct range : public test::exception_base
{
test::random_values<T> values;
range() : values(5) {}
range(unsigned int count) : values(count) {}
};
template <class T>
struct range_construct_test1 : public range<T>, objects
{
void run() const {
T x(this->values.begin(), this->values.end());
}
};
template <class T>
struct range_construct_test2 : public range<T>, objects
{
void run() const {
T x(this->values.begin(), this->values.end(), 0);
}
};
template <class T>
struct range_construct_test3 : public range<T>, objects
{
void run() const {
T x(this->values.begin(), this->values.end(), 0, hash);
}
};
template <class T>
struct range_construct_test4 : public range<T>, objects
{
void run() const {
T x(this->values.begin(), this->values.end(), 100, hash, equal_to);
}
};
// Need to run at least one test with a fairly large number
// of objects in case it triggers a rehash.
template <class T>
struct range_construct_test5 : public range<T>, objects
{
range_construct_test5() : range<T>(60) {}
void run() const {
T x(this->values.begin(), this->values.end(), 0, hash, equal_to, allocator);
}
};
template <class T>
struct input_range_construct_test : public range<T>, objects
{
input_range_construct_test() : range<T>(60) {}
void run() const {
T x(test::input_iterator(this->values.begin()),
test::input_iterator(this->values.end()),
0, hash, equal_to, allocator);
}
};
RUN_EXCEPTION_TESTS(
(construct_test1)(construct_test2)(construct_test3)(construct_test4)(construct_test5)
(range_construct_test1)(range_construct_test2)(range_construct_test3)(range_construct_test4)(range_construct_test5)
(input_range_construct_test),
CONTAINER_SEQ)

View File

@ -0,0 +1,33 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "../objects/exception.hpp"
typedef boost::unordered_set<
test::exception::object,
test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> > test_set;
typedef boost::unordered_multiset<
test::exception::object,
test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> > test_multiset;
typedef boost::unordered_map<
test::exception::object,
test::exception::object,
test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> > test_map;
typedef boost::unordered_multimap<
test::exception::object,
test::exception::object,
test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> > test_multimap;
#define CONTAINER_SEQ (test_set)(test_multiset)(test_map)(test_multimap)

View File

@ -0,0 +1,53 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./containers.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/test/exception_safety.hpp>
#include "../helpers/random_values.hpp"
test::seed_t seed(73041);
template <class T>
struct copy_test1 : public test::exception_base
{
T x;
void run() const {
T y(x);
}
};
template <class T>
struct copy_test2 : public test::exception_base
{
test::random_values<T> values;
T x;
copy_test2() : values(5), x(values.begin(), values.end()) {}
void run() const {
T y(x);
}
};
template <class T>
struct copy_test3 : public test::exception_base
{
test::random_values<T> values;
T x;
copy_test3() : values(100), x(values.begin(), values.end()) {}
void run() const {
T y(x);
}
};
RUN_EXCEPTION_TESTS(
(copy_test1)(copy_test2)(copy_test3),
CONTAINER_SEQ)

View File

@ -0,0 +1,57 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./containers.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/test/exception_safety.hpp>
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/helpers.hpp"
test::seed_t seed(835193);
template <class T>
struct erase_test_base : public test::exception_base
{
test::random_values<T> values;
erase_test_base(unsigned int count = 5) : values(count) {}
typedef T data_type;
data_type init() const {
return T(values.begin(), values.end());
}
void check(T const& x) const {
std::string scope(test::scope);
HASH_CHECK(scope.find("hash::") != std::string::npos ||
scope.find("equal_to::") != std::string::npos ||
scope == "operator==(object, object)");
test::check_equivalent_keys(x);
}
};
template <class T>
struct erase_by_key_test1 : public erase_test_base<T>
{
void run(T& x) const
{
typedef typename test::random_values<T>::const_iterator iterator;
for(iterator it = this->values.begin(), end = this->values.end();
it != end; ++it)
{
x.erase(test::get_key<T>(*it));
}
}
};
RUN_EXCEPTION_TESTS(
(erase_by_key_test1),
CONTAINER_SEQ)

View File

@ -0,0 +1,212 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./containers.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/test/exception_safety.hpp>
#include <string>
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/strong.hpp"
#include "../helpers/input_iterator.hpp"
#include <cmath>
test::seed_t seed(747373);
template <class T>
struct insert_test_base : public test::exception_base
{
test::random_values<T> values;
insert_test_base(unsigned int count = 5) : values(count) {}
typedef T data_type;
typedef test::strong<T> strong_type;
data_type init() const {
return T();
}
void check(T const& x, strong_type const& strong) const {
std::string scope(test::scope);
if(scope.find("hash::operator()") == std::string::npos)
strong.test(x);
test::check_equivalent_keys(x);
}
};
template <class T>
struct insert_test1 : public insert_test_base<T>
{
typedef typename insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const {
for(typename test::random_values<T>::const_iterator
it = this->values.begin(), end = this->values.end(); it != end; ++it)
{
strong.store(x);
x.insert(*it);
}
}
};
template <class T>
struct insert_test2 : public insert_test_base<T>
{
typedef typename insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const {
for(typename test::random_values<T>::const_iterator
it = this->values.begin(), end = this->values.end(); it != end; ++it)
{
strong.store(x);
x.insert(x.begin(), *it);
}
}
};
template <class T>
struct insert_test3 : public insert_test_base<T>
{
void run(T& x) const {
x.insert(this->values.begin(), this->values.end());
}
void check(T const& x) const {
test::check_equivalent_keys(x);
}
};
template <class T>
struct insert_test4 : public insert_test_base<T>
{
typedef typename insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const {
for(typename test::random_values<T>::const_iterator
it = this->values.begin(), end = this->values.end(); it != end; ++it)
{
strong.store(x);
x.insert(it, boost::next(it));
}
}
};
template <class T>
struct insert_test_rehash1 : public insert_test_base<T>
{
typedef typename insert_test_base<T>::strong_type strong_type;
insert_test_rehash1() : insert_test_base<T>(1000) {}
T init() const {
typedef typename T::size_type size_type;
T x;
x.max_load_factor(0.25);
size_type bucket_count = x.bucket_count();
size_type initial_elements = static_cast<size_type>(
std::ceil(bucket_count * x.max_load_factor()) - 1);
BOOST_REQUIRE(initial_elements < this->values.size());
x.insert(this->values.begin(),
boost::next(this->values.begin(), initial_elements));
BOOST_REQUIRE(bucket_count == x.bucket_count());
return x;
}
void run(T& x, strong_type& strong) const {
typename T::size_type bucket_count = x.bucket_count();
int count = 0;
typename T::const_iterator pos = x.cbegin();
for(typename test::random_values<T>::const_iterator
it = boost::next(this->values.begin(), x.size()), end = this->values.end();
it != end && count < 10; ++it, ++count)
{
strong.store(x);
pos = x.insert(pos, *it);
}
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_REQUIRE(x.bucket_count() != bucket_count);
}
};
template <class T>
struct insert_test_rehash2 : public insert_test_rehash1<T>
{
typedef typename insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const {
typename T::size_type bucket_count = x.bucket_count();
int count = 0;
for(typename test::random_values<T>::const_iterator
it = boost::next(this->values.begin(), x.size()), end = this->values.end();
it != end && count < 10; ++it, ++count)
{
strong.store(x);
x.insert(*it);
}
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_REQUIRE(x.bucket_count() != bucket_count);
}
};
template <class T>
struct insert_test_rehash3 : public insert_test_base<T>
{
typename T::size_type mutable rehash_bucket_count, original_bucket_count;
insert_test_rehash3() : insert_test_base<T>(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<size_type>(
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),
CONTAINER_SEQ)

View File

@ -0,0 +1,85 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./containers.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/test/exception_safety.hpp>
#include <string>
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/strong.hpp"
#include <iostream>
test::seed_t seed(3298597);
template <class T>
struct rehash_test_base : public test::exception_base
{
test::random_values<T> values;
unsigned int n;
rehash_test_base(unsigned int count = 100, unsigned int n = 0) : values(count), n(n) {}
typedef T data_type;
typedef test::strong<T> strong_type;
data_type init() const {
T x(values.begin(), values.end(), n);
return x;
}
void check(T const& x, strong_type const& strong) const {
std::string scope(test::scope);
if(scope.find("hash::operator()") == std::string::npos &&
scope.find("equal_to::operator()") == std::string::npos &&
scope != "operator==(object, object)")
strong.test(x);
test::check_equivalent_keys(x);
}
};
template <class T>
struct rehash_test0 : rehash_test_base<T>
{
rehash_test0() : rehash_test_base<T>(0) {}
void run(T& x) const { x.rehash(0); }
};
template <class T>
struct rehash_test1 : rehash_test_base<T>
{
rehash_test1() : rehash_test_base<T>(0) {}
void run(T& x) const { x.rehash(200); }
};
template <class T>
struct rehash_test2 : rehash_test_base<T>
{
rehash_test2() : rehash_test_base<T>(0, 200) {}
void run(T& x) const { x.rehash(0); }
};
template <class T>
struct rehash_test3 : rehash_test_base<T>
{
rehash_test3() : rehash_test_base<T>(10, 0) {}
void run(T& x) const { x.rehash(200); }
};
template <class T>
struct rehash_test4 : rehash_test_base<T>
{
rehash_test4() : rehash_test_base<T>(10, 200) {}
void run(T& x) const { x.rehash(0); }
};
RUN_EXCEPTION_TESTS(
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4),
CONTAINER_SEQ)

View File

@ -0,0 +1,119 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./containers.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/test/exception_safety.hpp>
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
test::seed_t seed(9387);
template <class T>
struct self_swap_base : public test::exception_base
{
test::random_values<T> values;
self_swap_base(int count = 0) : values(count) {}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
void run(T& x) const { x.swap(x); }
void check(T const& x) const {
std::string scope(test::scope);
#if BOOST_UNORDERED_SWAP_METHOD != 2
HASH_CHECK(
scope == "hash::operator(hash)" ||
scope == "hash::operator=(hash)" ||
scope == "equal_to::operator(equal_to)" ||
scope == "equal_to::operator=(equal_to)");
#endif
test::check_equivalent_keys(x);
}
};
template <class T>
struct self_swap_test1 : self_swap_base<T> {};
template <class T>
struct self_swap_test2 : self_swap_base<T>
{
self_swap_test2() : self_swap_base<T>(100) {}
};
template <class T>
struct swap_base : public test::exception_base
{
const test::random_values<T> x_values, y_values;
const T initial_x, initial_y;
swap_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
: x_values(count1), y_values(count2),
initial_x(x_values.begin(), x_values.end(), 0, typename T::hasher(tag1),
typename T::key_equal(tag1), typename T::allocator_type(tag1)),
initial_y(y_values.begin(), y_values.end(), 0, typename T::hasher(tag2),
typename T::key_equal(tag2), typename T::allocator_type(tag2))
{}
struct data_type {
data_type(T const& x, T const& y)
: x(x), y(y) {}
T x, y;
};
data_type init() const { return data_type(initial_x, initial_y); }
void run(data_type& d) const {
try {
d.x.swap(d.y);
} catch (std::runtime_error) {}
}
void check(data_type const& d) const {
std::string scope(test::scope);
#if BOOST_UNORDERED_SWAP_METHOD != 2
HASH_CHECK(
scope == "hash::operator(hash)" ||
scope == "hash::operator=(hash)" ||
scope == "equal_to::operator(equal_to)" ||
scope == "equal_to::operator=(equal_to)");
#endif
test::check_equivalent_keys(d.x);
test::check_equivalent_keys(d.y);
}
};
template <class T>
struct swap_test1 : swap_base<T>
{
swap_test1() : swap_base<T>(0, 0, 0, 0) {}
};
template <class T>
struct swap_test2 : swap_base<T>
{
swap_test2() : swap_base<T>(60, 0, 0, 0) {}
};
template <class T>
struct swap_test3 : swap_base<T>
{
swap_test3() : swap_base<T>(0, 60, 0, 0) {}
};
template <class T>
struct swap_test4 : swap_base<T>
{
swap_test4() : swap_base<T>(10, 10, 1, 2) {}
};
RUN_EXCEPTION_TESTS(
(self_swap_test1)(self_swap_test2)
(swap_test1)(swap_test2)(swap_test3)(swap_test4),
CONTAINER_SEQ)

View File

@ -0,0 +1,72 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_MALLOC_ALLOCATOR_HEADER)
#define BOOST_UNORDERED_TEST_MALLOC_ALLOCATOR_HEADER
#include <cstddef>
#include <cstdlib>
#include <boost/limits.hpp>
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
namespace test
{
template <class T>
struct malloc_allocator
{
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef malloc_allocator<U> other; };
malloc_allocator() {}
template <class Y> malloc_allocator(malloc_allocator<Y> const&) {}
malloc_allocator(malloc_allocator const&) {}
pointer address(reference r) { return &r; }
const_pointer address(const_reference r) { return &r; }
pointer allocate(size_type n) {
return static_cast<T*>(malloc(n * sizeof(T)));
}
pointer allocate(size_type n, const_pointer u) { return allocate(n); }
void deallocate(pointer p, size_type) { free(p); }
void construct(pointer p, T const& t) { new(p) T(t); }
void destroy(pointer p) { p->~T(); }
size_type max_size() const {
return (std::numeric_limits<size_type>::max)();
}
bool operator==(malloc_allocator const& x) const { return true; }
bool operator!=(malloc_allocator const& x) const { return false; }
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
template <class T> void deallocate(T* p, size_type) {
free(p);
}
char* _Charalloc(size_type n) {
return static_cast<char*>(malloc(n * sizeof(char)));
}
#endif
};
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
#endif

View File

@ -0,0 +1,38 @@
// Copyright 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_convertible.hpp>
namespace test
{
template <class T1>
struct check_return_type
{
template <class T2>
static void equals(T2)
{
BOOST_MPL_ASSERT((boost::is_same<T1, T2>));
}
template <class T2>
static void equals_ref(T2&)
{
BOOST_MPL_ASSERT((boost::is_same<T1, T2>));
}
template <class T2>
static void convertible(T2)
{
BOOST_MPL_ASSERT((boost::is_convertible<T2, T1>));
}
};
}
#endif

View File

@ -0,0 +1,94 @@
// Copyright 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER)
#define BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <vector>
#include <algorithm>
#include "./metafunctions.hpp"
#include "./fwd.hpp"
namespace test
{
template <class T1, class T2>
bool equivalent_impl(T1 const& x, T2 const& y, base_type) {
return x == y;
}
template <class T>
bool equivalent_impl(boost::hash<T> const&, boost::hash<T> const&, derived_type) {
return true;
}
template <class T>
bool equivalent_impl(std::equal_to<T> const&, std::equal_to<T> const&, derived_type) {
return true;
}
template <class T1, class T2, class T3, class T4>
bool equivalent_impl(std::pair<T1, T2> const& x1,
std::pair<T3, T4> const& x2, derived_type) {
return equivalent_impl(x1.first, x2.first, derived) &&
equivalent_impl(x1.second, x2.second, derived);
}
struct equivalent_type {
template <class T1, class T2>
bool operator()(T1 const& x, T2 const& y) {
return equivalent_impl(x, y, derived);
}
};
namespace {
equivalent_type equivalent;
}
template <class Container>
class unordered_equivalence_tester
{
typename Container::size_type size_;
typename Container::hasher hasher_;
typename Container::key_equal key_equal_;
float max_load_factor_;
typedef typename non_const_value_type<Container>::type value_type;
std::vector<value_type> values_;
public:
unordered_equivalence_tester(Container const &x)
: size_(x.size()),
hasher_(x.hash_function()), key_equal_(x.key_eq()),
max_load_factor_(x.max_load_factor()),
values_()
{
// Can't initialise values_ straight from x because of Visual C++ 6
values_.reserve(x.size());
std::copy(x.begin(), x.end(), std::back_inserter(values_));
std::sort(values_.begin(), values_.end());
}
bool operator()(Container const& x) const
{
if(!((size_ == x.size()) &&
(test::equivalent(hasher_, x.hash_function())) &&
(test::equivalent(key_equal_, x.key_eq())) &&
(max_load_factor_ == x.max_load_factor()) &&
(values_.size() == x.size()))) return false;
std::vector<value_type> copy;
copy.reserve(x.size());
std::copy(x.begin(), x.end(), std::back_inserter(copy));
std::sort(copy.begin(), copy.end());
return(std::equal(values_.begin(), values_.end(), copy.begin()));
}
private:
unordered_equivalence_tester();
};
}
#endif

26
test/helpers/fwd.hpp Normal file
View File

@ -0,0 +1,26 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER
#include <string>
namespace test
{
int generate(int const*);
char generate(char const*);
signed char generate(signed char const*);
std::string generate(std::string*);
float generate(float const*);
template <class T1, class T2>
std::pair<T1, T2> generate(std::pair<T1, T2>*);
struct base_type {} base;
struct derived_type : base_type {} derived;
}
#endif

View File

@ -0,0 +1,91 @@
// Copyright 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// This uses std::rand to generate random values for tests.
// Which is not good as different platforms will be running different tests.
// It would be much better to use Boost.Random, but it doesn't
// support all the compilers that I want to test on.
#if !defined(BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER
#include <string>
#include <utility>
#include <stdexcept>
#include <cstdlib>
#include "./fwd.hpp"
namespace test
{
struct seed_t {
seed_t(unsigned int x) {
using namespace std;
srand(x);
}
};
template <class T>
struct generator;
template <class T1, class T2> std::pair<T1, T2> generate(
std::pair<T1, T2> const*)
{
static generator<T1> g1;
static generator<T2> g2;
return std::pair<T1, T2>(g1(), g2());
}
template <class T>
struct generator
{
typedef T value_type;
value_type operator()()
{
return generate((T const*) 0);
}
};
inline int generate(int const*)
{
using namespace std;
return rand();
}
inline char generate(char const*)
{
using namespace std;
return static_cast<char>((rand() >> 1) % (128-32) + 32);
}
inline signed char generate(signed char const*)
{
using namespace std;
return static_cast<signed char>(rand());
}
inline std::string generate(std::string const*)
{
using namespace std;
static test::generator<char> char_gen;
std::string result;
int length = rand() % 10;
for(int i = 0; i < length; ++i)
result += char_gen();
return result;
}
float generate(float const*)
{
return (float) rand() / (float) RAND_MAX;
}
}
#endif

41
test/helpers/helpers.hpp Normal file
View File

@ -0,0 +1,41 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_HELPERS_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_HEADER
namespace test
{
template <class Container>
struct get_key_impl
{
typedef typename Container::key_type key_type;
static key_type const& get_key(key_type const& x)
{
return x;
}
template <class T>
static key_type const& get_key(std::pair<key_type, T> const& x, char = 0)
{
return x.first;
}
template <class T>
static key_type const& get_key(std::pair<key_type const, T> const& x, unsigned char = 0)
{
return x.first;
}
};
template <class Container, class T>
inline typename Container::key_type const& get_key(T const& x)
{
return get_key_impl<Container>::get_key(x);
}
}
#endif

View File

@ -0,0 +1,35 @@
// Copyright 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER
#include <boost/iterator_adaptors.hpp>
namespace test
{
template <class Iterator>
struct input_iterator_adaptor
: boost::iterator_adaptor<
input_iterator_adaptor<Iterator>, Iterator,
boost::use_default, std::input_iterator_tag>
{
typedef boost::iterator_adaptor<
input_iterator_adaptor<Iterator>, Iterator,
boost::use_default, std::input_iterator_tag> base;
explicit input_iterator_adaptor(Iterator it = Iterator())
: base(it) {}
};
template <class Iterator>
input_iterator_adaptor<Iterator> input_iterator(Iterator it)
{
return input_iterator_adaptor<Iterator>(it);
}
}
#endif

105
test/helpers/invariants.hpp Normal file
View File

@ -0,0 +1,105 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// This header contains metafunctions/functions to get the equivalent
// associative container for an unordered container, and compare the contents.
#if !defined(BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER
#include <set>
#include <cmath>
#include "./metafunctions.hpp"
#include "./helpers.hpp"
#include "./allocator.hpp"
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4127) // conditional expression is constant
#endif
namespace test
{
template <class X>
void check_equivalent_keys(X const& x1)
{
typename X::key_equal eq = x1.key_eq();
typedef typename X::key_type key_type;
// Boost.Test was reporting memory leaks for std::set on g++-3.3.
// So I work around it by using malloc.
std::set<key_type, std::less<key_type>, test::malloc_allocator<key_type> > found_;
typename X::const_iterator it = x1.begin(), end = x1.end();
typename X::size_type size = 0;
while(it != end) {
// First test that the current key has not occured before, required
// to test either that keys are unique or that equivalent keys are
// adjacent. (6.3.1/6)
key_type key = get_key<X>(*it);
if(!found_.insert(key).second)
BOOST_ERROR("Elements with equivalent keys aren't adjacent.");
// Iterate over equivalent keys, counting them.
unsigned int count = 0;
do {
++it;
++count;
++size;
} while(it != end && eq(get_key<X>(*it), key));
// If the container has unique keys, test that there's only one.
// Since the previous test makes sure that all equivalent keys are
// adjacent, this is all the equivalent keys - so the test is
// sufficient. (6.3.1/6 again).
if(test::has_unique_keys<X>::value && count != 1)
BOOST_ERROR("Non-unique key.");
if(x1.count(key) != count) {
BOOST_ERROR("Incorrect output of count.");
std::cerr<<x1.count(key)<<","<<count<<"\n";
}
// I'm not bothering with the following test for now, as the
// previous test is probably more enough to catch the kind of
// errors that this would catch (if an element was in the wrong
// bucket it not be found by the call to count, if elements are not
// adjacent then they would be caught when checking against
// found_.
// // Check that the keys are in the correct bucket and are
// // adjacent in the bucket.
// typename X::size_type bucket = x1.bucket(key);
// typename X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket);
// for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
// if(lit == lend)
// BOOST_ERROR("Unable to find element with a local_iterator");
// unsigned int count2 = 0;
// for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
// if(count != count2)
// BOOST_ERROR("Element count doesn't match local_iterator.");
// for(; lit != lend; ++lit) {
// if(eq(get_key<X>(*lit), key)) {
// BOOST_ERROR("Non-adjacent element with equivalent key in bucket.");
// break;
// }
// }
};
// Finally, check that size matches up.
if(x1.size() != size)
BOOST_ERROR("x1.size() doesn't match actual size.");
float load_factor = static_cast<float>(size) / static_cast<float>(x1.bucket_count());
using namespace std;
if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)
BOOST_ERROR("x1.load_factor() doesn't match actual load_factor.");
}
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#endif

View File

@ -0,0 +1,103 @@
// Copyright 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_HELPERS_METAFUNCTIONS_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_METAFUNCTIONS_HEADER
#include <boost/config.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
namespace test
{
/*
struct unordered_set_type { char x[100]; };
struct unordered_multiset_type { char x[200]; };
struct unordered_map_type { char x[300]; };
struct unordered_multimap_type { char x[400]; };
template <class V, class H, class P, class A>
unordered_set_type container_type(
boost::unordered_set<V, H, P, A> const*);
template <class V, class H, class P, class A>
unordered_multiset_type container_type(
boost::unordered_multiset<V, H, P, A> const*);
template <class K, class M, class H, class P, class A>
unordered_map_type container_type(
boost::unordered_map<K, M, H, P, A> const*);
template <class K, class M, class H, class P, class A>
unordered_multimap_type container_type(
boost::unordered_multimap<K, M, H, P, A> const*);
*/
template <class Container>
struct is_set
: public boost::is_same<
typename Container::key_type,
typename Container::value_type> {};
template <class Container>
struct is_map
: public boost::mpl::not_<is_set<Container> > {};
struct yes_type { char x[100]; };
struct no_type { char x[200]; };
template <class V, class H, class P, class A>
yes_type has_unique_key_impl(
boost::unordered_set<V, H, P, A> const*);
template <class V, class H, class P, class A>
no_type has_unique_key_impl(
boost::unordered_multiset<V, H, P, A> const*);
template <class K, class M, class H, class P, class A>
yes_type has_unique_key_impl(
boost::unordered_map<K, M, H, P, A> const*);
template <class K, class M, class H, class P, class A>
no_type has_unique_key_impl(
boost::unordered_multimap<K, M, H, P, A> const*);
template <class Container>
struct has_unique_keys
{
BOOST_STATIC_CONSTANT(bool, value =
sizeof(has_unique_key_impl((Container const*)0))
== sizeof(yes_type));
};
template <class Container>
struct has_equivalent_keys
{
BOOST_STATIC_CONSTANT(bool, value =
sizeof(has_unique_key_impl((Container const*)0))
== sizeof(no_type));
};
// Non Const Value Type
template <class Container>
struct map_non_const_value_type
{
typedef std::pair<
typename Container::key_type,
typename Container::mapped_type> type;
};
template <class Container>
struct non_const_value_type
: boost::mpl::eval_if<is_map<Container>,
map_non_const_value_type<Container>,
boost::mpl::identity<typename Container::value_type> >
{
};
}
#endif

View File

@ -0,0 +1,27 @@
// Copyright 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER
#include <list>
#include <algorithm>
#include "./generators.hpp"
namespace test
{
template <class X>
struct random_values
: public std::list<typename X::value_type>
{
random_values(int count) {
typedef typename X::value_type value_type;
static test::generator<value_type> gen;
std::generate_n(std::back_inserter(*this), count, gen);
}
};
}
#endif

39
test/helpers/strong.hpp Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2005-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER
#include <boost/config.hpp>
#include <vector>
#include <iterator>
#include "./metafunctions.hpp"
#include "./equivalent.hpp"
#include "../objects/exception.hpp"
namespace test
{
template <class X>
class strong
{
typedef std::vector<typename non_const_value_type<X>::type> values_type;
values_type values_;
public:
void store(X const& x) {
DISABLE_EXCEPTIONS;
values_.clear();
values_.reserve(x.size());
std::copy(x.cbegin(), x.cend(), std::back_inserter(values_));
}
void test(X const& x) const {
if(!(x.size() == values_.size() &&
std::equal(x.cbegin(), x.cend(), values_.begin(), test::equivalent)))
BOOST_ERROR("Strong exception safety failure.");
}
};
}
#endif

163
test/helpers/tracker.hpp Normal file
View File

@ -0,0 +1,163 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// This header contains metafunctions/functions to get the equivalent
// associative container for an unordered container, and compare the contents.
#if !defined(BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER
#include <set>
#include <map>
#include <vector>
#include <iterator>
#include <algorithm>
#include <boost/mpl/if.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/is_same.hpp>
#include "../objects/fwd.hpp"
#include "./metafunctions.hpp"
#include "./helpers.hpp"
#include "./equivalent.hpp"
namespace test
{
template <class X>
struct equals_to_compare2
: public boost::mpl::identity<std::less<typename X::first_argument_type> >
{
};
template <class X>
struct equals_to_compare
: public boost::mpl::eval_if<
boost::is_same<X, test::equal_to>,
boost::mpl::identity<test::less>,
equals_to_compare2<X>
>
{
};
template <class X1, class X2>
void compare_range(X1 const& x1, X2 const& x2)
{
typedef typename non_const_value_type<X1>::type value_type;
std::vector<value_type> values1, values2;
values1.reserve(x1.size());
values2.reserve(x2.size());
std::copy(x1.begin(), x1.end(), std::back_inserter(values1));
std::copy(x2.begin(), x2.end(), std::back_inserter(values2));
std::sort(values1.begin(), values1.end());
std::sort(values2.begin(), values2.end());
BOOST_TEST(values1.size() == values2.size() &&
std::equal(values1.begin(), values1.end(), values2.begin(), test::equivalent));
}
template <class X1, class X2, class T>
void compare_pairs(X1 const& x1, X2 const& x2, T*)
{
std::vector<T> values1, values2;
values1.reserve(std::distance(x1.first, x1.second));
values2.reserve(std::distance(x2.first, x2.second));
std::copy(x1.first, x1.second, std::back_inserter(values1));
std::copy(x2.first, x2.second, std::back_inserter(values2));
std::sort(values1.begin(), values1.end());
std::sort(values2.begin(), values2.end());
BOOST_TEST(values1.size() == values2.size() &&
std::equal(values1.begin(), values1.end(), values2.begin(), test::equivalent));
}
template <class X>
struct ordered_set
: public boost::mpl::if_<
test::has_unique_keys<X>,
std::set<typename X::value_type,
typename equals_to_compare<typename X::key_equal>::type>,
std::multiset<typename X::value_type,
typename equals_to_compare<typename X::key_equal>::type>
> {};
template <class X>
struct ordered_map
: public boost::mpl::if_<
test::has_unique_keys<X>,
std::map<typename X::key_type, typename X::mapped_type,
typename equals_to_compare<typename X::key_equal>::type>,
std::multimap<typename X::key_type, typename X::mapped_type,
typename equals_to_compare<typename X::key_equal>::type>
> {};
template <class X>
struct ordered_base
: public boost::mpl::eval_if<
test::is_set<X>,
test::ordered_set<X>,
test::ordered_map<X> >
{
};
template <class X>
class ordered : public ordered_base<X>::type
{
typedef typename ordered_base<X>::type base;
public:
typedef typename base::key_compare key_compare;
ordered()
: base()
{}
explicit ordered(key_compare const& compare)
: base(compare)
{}
void compare(X const& x)
{
compare_range(x, *this);
}
void compare_key(X const& x, typename X::value_type const& val)
{
compare_pairs(
x.equal_range(get_key<X>(val)),
this->equal_range(get_key<X>(val)),
(typename non_const_value_type<X>::type*) 0
);
}
template <class It>
void insert_range(It begin, It end) {
while(begin != end) {
this->insert(*begin);
++begin;
}
}
};
template <class Equals>
typename equals_to_compare<Equals>::type create_compare(Equals const&)
{
typename equals_to_compare<Equals>::type x;
return x;
}
template <class X>
ordered<X> create_ordered(X const& container)
{
return ordered<X>(create_compare(container.key_eq()));
}
template <class X1, class X2>
void check_container(X1 const& container, X2 const& values)
{
ordered<X1> tracker = create_ordered(container);
tracker.insert_range(values.begin(), values.end());
tracker.compare(container);
}
}
#endif

659
test/objects/exception.hpp Normal file
View File

@ -0,0 +1,659 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_OBJECTS_HEADER)
#define BOOST_UNORDERED_TEST_OBJECTS_HEADER
#include <cstddef>
#include <boost/limits.hpp>
#include <boost/test/test_tools.hpp>
#include <boost/test/exception_safety.hpp>
#include <boost/preprocessor/seq/for_each_product.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/cat.hpp>
#include <iostream>
#include "../helpers/fwd.hpp"
#include "../helpers/allocator.hpp"
#include <map>
#define RUN_EXCEPTION_TESTS(test_seq, param_seq) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP, (test_seq)(param_seq))
#define RUN_EXCEPTION_TESTS_OP(r, product) \
RUN_EXCEPTION_TESTS_OP2( \
BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(1, product)) \
), \
BOOST_PP_SEQ_ELEM(0, product), \
BOOST_PP_SEQ_ELEM(1, product) \
)
#define RUN_EXCEPTION_TESTS_OP2(name, test_func, type) \
BOOST_AUTO_TEST_CASE(name) \
{ \
test_func< type > fixture; \
::test::exception_safety(fixture, BOOST_STRINGIZE(test_func<type>)); \
}
#define SCOPE(scope_name) \
for(::test::scope_guard unordered_test_guard( \
BOOST_STRINGIZE(scope_name)); \
!unordered_test_guard.dismissed(); \
unordered_test_guard.dismiss())
#define EPOINT(name) \
if(::test::exceptions_enabled) { \
BOOST_ITEST_EPOINT(name); \
}
#define ENABLE_EXCEPTIONS \
::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(true)
#define DISABLE_EXCEPTIONS \
::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(false)
#define HASH_CHECK(test) if(!(test)) BOOST_ERROR(BOOST_STRINGIZE(test))
namespace test {
static char const* scope = "";
bool exceptions_enabled = false;
class scope_guard {
scope_guard& operator=(scope_guard const&);
scope_guard(scope_guard const&);
char const* old_scope_;
char const* scope_;
bool dismissed_;
public:
scope_guard(char const* name)
: old_scope_(scope),
scope_(name),
dismissed_(false)
{
scope = scope_;
}
~scope_guard() {
if(dismissed_) scope = old_scope_;
}
void dismiss() {
dismissed_ = true;
}
bool dismissed() const {
return dismissed_;
}
};
class exceptions_enable
{
exceptions_enable& operator=(exceptions_enable const&);
exceptions_enable(exceptions_enable const&);
bool old_value_;
public:
exceptions_enable(bool enable)
: old_value_(exceptions_enabled)
{
exceptions_enabled = enable;
}
~exceptions_enable()
{
exceptions_enabled = old_value_;
}
};
struct exception_base {
struct data_type {};
struct strong_type {
template <class T> void store(T const&) {}
template <class T> void test(T const&) const {}
};
data_type init() const { return data_type(); }
void check() const {}
};
template <class T, class P1, class P2, class T2>
inline void call_ignore_extra_parameters(void (T::*fn)() const, T2 const& obj,
P1&, P2&)
{
(obj.*fn)();
}
template <class T, class P1, class P2, class T2>
inline void call_ignore_extra_parameters(void (T::*fn)(P1&) const, T2 const& obj,
P1& p1, P2&)
{
(obj.*fn)(p1);
}
template <class T, class P1, class P2, class T2>
inline void call_ignore_extra_parameters(void (T::*fn)(P1&, P2&) const, T2 const& obj,
P1& p1, P2& p2)
{
(obj.*fn)(p1, p2);
}
template <class T>
T const& constant(T const& x) {
return x;
}
template <class Test>
class test_runner
{
Test const& test_;
public:
test_runner(Test const& t) : test_(t) {}
void operator()() const {
DISABLE_EXCEPTIONS;
typename Test::data_type x(test_.init());
typename Test::strong_type strong;
strong.store(x);
try {
ENABLE_EXCEPTIONS;
call_ignore_extra_parameters(&Test::run, test_, x, strong);
}
catch(...) {
call_ignore_extra_parameters(&Test::check, test_,
constant(x), constant(strong));
throw;
}
}
};
template <class Test>
void exception_safety(Test const& f, char const* name) {
test_runner<Test> runner(f);
::boost::itest::exception_safety(runner, name);
}
}
namespace test
{
namespace exception
{
namespace detail
{
// This annoymous namespace won't cause ODR violations as I won't
// be linking multiple translation units together. I'll probably
// move this into a cpp file before a full release, but for now it's
// the most convenient way.
namespace
{
struct memory_area {
void const* start;
void const* end;
memory_area(void const* s, void const* e)
: start(s), end(e)
{
}
// This is a bit dodgy as it defines overlapping
// areas as 'equal', so this isn't a total ordering.
// But it is for non-overlapping memory regions - which
// is what'll be stored.
//
// All searches will be for areas entirely contained by
// a member of the set - so it should find the area that contains
// the region that is searched for.
bool operator<(memory_area const& other) const {
return end < other.start;
}
};
struct memory_track {
explicit memory_track(int tag = -1) :
tag_(tag) {}
int tag_;
};
typedef std::map<memory_area, memory_track, std::less<memory_area>,
test::malloc_allocator<std::pair<memory_area const, memory_track> > >
allocated_memory_type;
allocated_memory_type allocated_memory;
unsigned int count_allocators = 0;
unsigned int count_allocations = 0;
unsigned int count_constructions = 0;
}
void allocator_ref()
{
if(count_allocators == 0) {
count_allocations = 0;
count_constructions = 0;
allocated_memory.clear();
}
++count_allocators;
}
void allocator_unref()
{
HASH_CHECK(count_allocators > 0);
if(count_allocators > 0) {
--count_allocators;
if(count_allocators == 0) {
bool no_allocations_left = (count_allocations == 0);
bool no_constructions_left = (count_constructions == 0);
bool allocated_memory_empty = allocated_memory.empty();
// Clearing the data before the checks terminate the tests.
count_allocations = 0;
count_constructions = 0;
allocated_memory.clear();
HASH_CHECK(no_allocations_left);
HASH_CHECK(no_constructions_left);
HASH_CHECK(allocated_memory_empty);
}
}
}
void track_allocate(void *ptr, std::size_t n, std::size_t size, int tag)
{
if(n == 0) {
BOOST_ERROR("Allocating 0 length array.");
}
else {
++count_allocations;
allocated_memory[memory_area(ptr, (char*) ptr + n * size)] =
memory_track(tag);
}
}
void track_deallocate(void* ptr, std::size_t n, std::size_t size, int tag)
{
allocated_memory_type::iterator pos
= allocated_memory.find(memory_area(ptr, ptr));
if(pos == allocated_memory.end()) {
BOOST_ERROR("Deallocating unknown pointer.");
} else {
HASH_CHECK(pos->first.start == ptr);
HASH_CHECK(pos->first.end == (char*) ptr + n * size);
HASH_CHECK(pos->second.tag_ == tag);
allocated_memory.erase(pos);
}
HASH_CHECK(count_allocations > 0);
if(count_allocations > 0) --count_allocations;
}
void track_construct(void* ptr, std::size_t /*size*/, int tag)
{
++count_constructions;
}
void track_destroy(void* ptr, std::size_t /*size*/, int tag)
{
HASH_CHECK(count_constructions > 0);
if(count_constructions > 0) --count_constructions;
}
}
class object;
class hash;
class equal_to;
template <class T> class allocator;
class object
{
public:
int tag1_, tag2_;
explicit object() : tag1_(0), tag2_(0)
{
SCOPE(object::object()) {
EPOINT("Mock object default constructor.");
}
}
explicit object(int t1, int t2 = 0) : tag1_(t1), tag2_(t2)
{
SCOPE(object::object(int)) {
EPOINT("Mock object constructor by value.");
}
}
object(object const& x)
: tag1_(x.tag1_), tag2_(x.tag2_)
{
SCOPE(object::object(object)) {
EPOINT("Mock object copy constructor.");
}
}
~object() {
tag1_ = -1;
tag2_ = -1;
}
object& operator=(object const& x)
{
SCOPE(object::operator=(object)) {
tag1_ = x.tag1_;
EPOINT("Mock object assign operator 1.");
tag2_ = x.tag2_;
//EPOINT("Mock object assign operator 2.");
}
return *this;
}
friend bool operator==(object const& x1, object const& x2) {
SCOPE(operator==(object, object)) {
EPOINT("Mock object equality operator.");
}
return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
}
friend bool operator!=(object const& x1, object const& x2) {
SCOPE(operator!=(object, object)) {
EPOINT("Mock object inequality operator.");
}
return !(x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_);
}
// None of the last few functions are used by the unordered associative
// containers - so there aren't any exception points.
friend bool operator<(object const& x1, object const& x2) {
return x1.tag1_ < x2.tag1_ ||
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
}
friend object generate(object const*) {
int* x = 0;
return object(::test::generate(x), ::test::generate(x));
}
friend std::ostream& operator<<(std::ostream& out, object const& o)
{
return out<<"("<<o.tag1_<<","<<o.tag2_<<")";
}
};
class hash
{
int tag_;
public:
hash(int t = 0) : tag_(t)
{
SCOPE(hash::object()) {
EPOINT("Mock hash default constructor.");
}
}
hash(hash const& x)
: tag_(x.tag_)
{
SCOPE(hash::hash(hash)) {
EPOINT("Mock hash copy constructor.");
}
}
hash& operator=(hash const& x)
{
SCOPE(hash::operator=(hash)) {
EPOINT("Mock hash assign operator 1.");
tag_ = x.tag_;
EPOINT("Mock hash assign operator 2.");
}
return *this;
}
std::size_t operator()(object const& x) const {
SCOPE(hash::operator()(object)) {
EPOINT("Mock hash function.");
}
switch(tag_) {
case 1:
return x.tag1_;
case 2:
return x.tag2_;
default:
return x.tag1_ + x.tag2_;
}
}
friend bool operator==(hash const& x1, hash const& x2) {
SCOPE(operator==(hash, hash)) {
EPOINT("Mock hash equality function.");
}
return x1.tag_ == x2.tag_;
}
friend bool operator!=(hash const& x1, hash const& x2) {
SCOPE(hash::operator!=(hash, hash)) {
EPOINT("Mock hash inequality function.");
}
return x1.tag_ != x2.tag_;
}
};
class equal_to
{
int tag_;
public:
equal_to(int t = 0) : tag_(t)
{
SCOPE(equal_to::equal_to()) {
EPOINT("Mock equal_to default constructor.");
}
}
equal_to(equal_to const& x)
: tag_(x.tag_)
{
SCOPE(equal_to::equal_to(equal_to)) {
EPOINT("Mock equal_to copy constructor.");
}
}
equal_to& operator=(equal_to const& x)
{
SCOPE(equal_to::operator=(equal_to)) {
EPOINT("Mock equal_to assign operator 1.");
tag_ = x.tag_;
EPOINT("Mock equal_to assign operator 2.");
}
return *this;
}
bool operator()(object const& x1, object const& x2) const {
SCOPE(equal_to::operator()(object, object)) {
EPOINT("Mock equal_to function.");
}
switch(tag_) {
case 1:
return x1.tag1_ == x2.tag1_;
case 2:
return x1.tag2_ == x2.tag2_;
default:
return x1 == x2;
}
}
friend bool operator==(equal_to const& x1, equal_to const& x2) {
SCOPE(operator==(equal_to, equal_to)) {
EPOINT("Mock equal_to equality function.");
}
return x1.tag_ == x2.tag_;
}
friend bool operator!=(equal_to const& x1, equal_to const& x2) {
SCOPE(operator!=(equal_to, equal_to)) {
EPOINT("Mock equal_to inequality function.");
}
return x1.tag_ != x2.tag_;
}
};
template <class T>
class allocator
{
public:
int tag_;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef allocator<U> other; };
explicit allocator(int t = 0) : tag_(t)
{
SCOPE(allocator::allocator()) {
EPOINT("Mock allocator default constructor.");
}
detail::allocator_ref();
}
template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_)
{
SCOPE(allocator::allocator()) {
EPOINT("Mock allocator template copy constructor.");
}
detail::allocator_ref();
}
allocator(allocator const& x) : tag_(x.tag_)
{
SCOPE(allocator::allocator()) {
EPOINT("Mock allocator copy constructor.");
}
detail::allocator_ref();
}
~allocator() {
detail::allocator_unref();
}
allocator& operator=(allocator const& x) {
SCOPE(allocator::allocator()) {
EPOINT("Mock allocator assignment operator.");
tag_ = x.tag_;
}
return *this;
}
// If address throws, then it can't be used in erase or the
// destructor, which is very limiting. I need to check up on
// this.
pointer address(reference r) {
//SCOPE(allocator::address(reference)) {
// EPOINT("Mock allocator address function.");
//}
return pointer(&r);
}
const_pointer address(const_reference r) {
//SCOPE(allocator::address(const_reference)) {
// EPOINT("Mock allocator const address function.");
//}
return const_pointer(&r);
}
pointer allocate(size_type n) {
T* ptr = 0;
SCOPE(allocator::allocate(size_type)) {
EPOINT("Mock allocator allocate function.");
using namespace std;
ptr = (T*) malloc(n * sizeof(T));
if(!ptr) throw std::bad_alloc();
}
detail::track_allocate((void*) ptr, n, sizeof(T), tag_);
return pointer(ptr);
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
}
pointer allocate(size_type n, const_pointer u)
{
T* ptr = 0;
SCOPE(allocator::allocate(size_type, const_pointer)) {
EPOINT("Mock allocator allocate function.");
using namespace std;
ptr = (T*) malloc(n * sizeof(T));
if(!ptr) throw std::bad_alloc();
}
detail::track_allocate((void*) ptr, n, sizeof(T), tag_);
return pointer(ptr);
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
}
void deallocate(pointer p, size_type n)
{
//::operator delete((void*) p);
if(p) {
detail::track_deallocate((void*) p, n, sizeof(T), tag_);
using namespace std;
free(p);
}
}
void construct(pointer p, T const& t) {
SCOPE(allocator::construct(pointer, T)) {
EPOINT("Mock allocator construct function.");
new(p) T(t);
}
detail::track_construct((void*) p, sizeof(T), tag_);
}
void destroy(pointer p) {
detail::track_destroy((void*) p, sizeof(T), tag_);
p->~T();
}
size_type max_size() const {
SCOPE(allocator::construct(pointer, T)) {
EPOINT("Mock allocator max_size function.");
}
return (std::numeric_limits<std::size_t>::max)();
}
};
template <class T>
void swap(allocator<T>& x, allocator<T>& y)
{
std::swap(x.tag_, y.tag_);
}
// It's pretty much impossible to write a compliant swap when these
// two can throw. So they don't.
template <class T>
inline bool operator==(allocator<T> const& x, allocator<T> const& y)
{
//SCOPE(operator==(allocator, allocator)) {
// EPOINT("Mock allocator equality operator.");
//}
return x.tag_ == y.tag_;
}
template <class T>
inline bool operator!=(allocator<T> const& x, allocator<T> const& y)
{
//SCOPE(operator!=(allocator, allocator)) {
// EPOINT("Mock allocator inequality operator.");
//}
return x.tag_ != y.tag_;
}
}
}
#endif

18
test/objects/fwd.hpp Normal file
View File

@ -0,0 +1,18 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER)
#define BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER
namespace test
{
class object;
class hash;
class less;
class equal_to;
template <class T> class allocator;
}
#endif

251
test/objects/minimal.hpp Normal file
View File

@ -0,0 +1,251 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER)
#define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER
#include <cstddef>
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
namespace test
{
namespace minimal
{
class copy_constructible;
class default_copy_constructible;
class assignable;
template <class T> class hash;
template <class T> class equal_to;
template <class T> class ptr;
template <class T> class const_ptr;
template <class T> class allocator;
class copy_constructible
{
public:
static copy_constructible create() { return copy_constructible(); }
copy_constructible(copy_constructible const&) {}
~copy_constructible() {}
private:
copy_constructible& operator=(copy_constructible const&);
copy_constructible() {}
};
class default_copy_constructible
{
public:
static default_copy_constructible create() { return default_copy_constructible(); }
default_copy_constructible() {}
default_copy_constructible(default_copy_constructible const&) {}
~default_copy_constructible() {}
private:
default_copy_constructible& operator=(default_copy_constructible const&);
};
class assignable
{
public:
static assignable create() { return assignable(); }
assignable(assignable const&) {}
assignable& operator=(assignable const&) { return *this; }
~assignable() {}
private:
assignable() {}
};
template <class T>
class hash
{
public:
static hash create() { return hash<T>(); }
hash() {}
hash(hash const&) {}
hash& operator=(hash const&) { return *this; }
~hash() {}
std::size_t operator()(T const&) const { return 0; }
};
template <class T>
class equal_to
{
public:
static equal_to create() { return equal_to<T>(); }
equal_to() {}
equal_to(equal_to const&) {}
equal_to& operator=(equal_to const&) { return *this; }
~equal_to() {}
bool operator()(T const&, T const&) const { return true; }
};
template <class T> class ptr;
template <class T> class const_ptr;
template <class T>
class ptr
{
friend class allocator<T>;
friend class const_ptr<T>;
T* ptr_;
ptr(T* x) : ptr_(x) {}
public:
ptr() : ptr_(0) {}
typedef void (ptr::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
ptr& operator++() { ++ptr_; return *this; }
ptr operator++(int) { ptr tmp(*this); ++ptr_; return tmp; }
ptr operator+(int s) const { return ptr<T>(ptr_ + s); }
T& operator[](int s) const { return ptr_[s]; }
bool operator!() const { return !ptr_; }
operator bool_type() const {
return ptr_ ?
&ptr::this_type_does_not_support_comparisons
: 0;
}
bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
bool operator==(const_ptr<T> const& x) const { return ptr_ == x.ptr_; }
bool operator!=(const_ptr<T> const& x) const { return ptr_ != x.ptr_; }
bool operator<(const_ptr<T> const& x) const { return ptr_ < x.ptr_; }
bool operator>(const_ptr<T> const& x) const { return ptr_ > x.ptr_; }
bool operator<=(const_ptr<T> const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(const_ptr<T> const& x) const { return ptr_ >= x.ptr_; }
};
template <class T>
class const_ptr
{
friend class allocator<T>;
T const* ptr_;
const_ptr(T const* ptr) : ptr_(ptr) {}
public:
const_ptr() : ptr_(0) {}
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
typedef void (const_ptr::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
T const& operator*() const { return *ptr_; }
T const* operator->() const { return ptr_; }
const_ptr& operator++() { ++ptr_; return *this; }
const_ptr operator++(int) { const_ptr tmp(*this); ++ptr_; return tmp; }
const_ptr operator+(int s) const { return const_ptr(ptr_ + s); }
T const& operator[](int s) const { return ptr_[s]; }
bool operator!() const { return !ptr_; }
operator bool_type() const {
return ptr_ ?
&const_ptr::this_type_does_not_support_comparisons
: 0;
}
bool operator==(ptr<T> const& x) const { return ptr_ == x.ptr_; }
bool operator!=(ptr<T> const& x) const { return ptr_ != x.ptr_; }
bool operator<(ptr<T> const& x) const { return ptr_ < x.ptr_; }
bool operator>(ptr<T> const& x) const { return ptr_ > x.ptr_; }
bool operator<=(ptr<T> const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(ptr<T> const& x) const { return ptr_ >= x.ptr_; }
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
};
template <class T>
class allocator
{
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef ptr<T> pointer;
typedef const_ptr<T> const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef allocator<U> other; };
allocator() {}
template <class Y> allocator(allocator<Y> const&) {}
allocator(allocator const&) {}
~allocator() {}
pointer address(reference r) { return pointer(&r); }
const_pointer address(const_reference r) { return const_pointer(&r); }
pointer allocate(size_type n) {
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
}
pointer allocate(size_type n, const_pointer u)
{
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
}
void deallocate(pointer p, size_type)
{
::operator delete((void*) p.ptr_);
}
void construct(pointer p, T const& t) { new((void*)p.ptr_) T(t); }
void destroy(pointer p) { ((T*)p.ptr_)->~T(); }
size_type max_size() const { return 1000; }
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || \
BOOST_WORKAROUND(MSVC, <= 1300)
public: allocator& operator=(allocator const&) { return *this;}
#else
private: allocator& operator=(allocator const&);
#endif
};
template <class T>
inline bool operator==(allocator<T> const&, allocator<T> const&)
{
return true;
}
template <class T>
inline bool operator!=(allocator<T> const&, allocator<T> const&)
{
return false;
}
template <class T>
void swap(allocator<T>&, allocator<T>&)
{
}
}
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#endif

458
test/objects/test.hpp Normal file
View File

@ -0,0 +1,458 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_TEST_OBJECTS_HEADER)
#define BOOST_UNORDERED_TEST_OBJECTS_HEADER
#include <boost/config.hpp>
#include <boost/limits.hpp>
#include <cstddef>
#include "../helpers/fwd.hpp"
#include <iostream>
#include <map>
namespace test
{
// Note that the default hash function will work for any equal_to (but not
// very well).
class object;
class hash;
class less;
class equal_to;
template <class T> class allocator;
class object
{
friend class hash;
friend class equal_to;
friend class less;
int tag1_, tag2_;
public:
explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
~object() {
tag1_ = -1;
tag2_ = -1;
}
friend bool operator==(object const& x1, object const& x2) {
return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
}
friend bool operator!=(object const& x1, object const& x2) {
return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
}
friend bool operator<(object const& x1, object const& x2) {
return x1.tag1_ < x2.tag1_ ||
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
}
friend object generate(object const*) {
int* x = 0;
return object(generate(x), generate(x));
}
friend std::ostream& operator<<(std::ostream& out, object const& o)
{
return out<<"("<<o.tag1_<<","<<o.tag2_<<")";
}
};
// This object is usd to test how well the containers cope with equivalent keys.
class equivalent_object
{
friend class hash;
friend class equal_to;
friend class less;
int tag1_, tag2_;
public:
explicit equivalent_object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
~equivalent_object() {
tag1_ = -1;
tag2_ = -1;
}
friend bool operator==(equivalent_object const& x1, equivalent_object const& x2) {
return x1.tag1_ == x2.tag1_;
}
friend bool operator!=(equivalent_object const& x1, equivalent_object const& x2) {
return x1.tag1_ != x2.tag1_;
}
friend bool operator<(equivalent_object const& x1, equivalent_object const& x2) {
return x1.tag1_ < x2.tag1_;
}
friend equivalent_object generate(equivalent_object const*) {
signed char* x = 0;
return equivalent_object(generate(x), generate(x));
}
friend std::ostream& operator<<(std::ostream& out, equivalent_object const& o)
{
return out<<"("<<o.tag1_<<","<<o.tag2_<<")";
}
};
class hash
{
int type_;
public:
explicit hash(int t = 0) : type_(t) {}
std::size_t operator()(object const& x) const {
switch(type_) {
case 1:
return x.tag1_;
case 2:
return x.tag2_;
default:
return x.tag1_ + x.tag2_;
}
}
std::size_t operator()(equivalent_object const& x) const {
return x.tag1_;
}
std::size_t operator()(int x) const {
return x;
}
friend bool operator==(hash const& x1, hash const& x2) {
return x1.type_ == x2.type_;
}
friend bool operator!=(hash const& x1, hash const& x2) {
return x1.type_ != x2.type_;
}
};
class less
{
int type_;
public:
explicit less(int t = 0) : type_(t) {}
bool operator()(object const& x1, object const& x2) const {
switch(type_) {
case 1:
return x1.tag1_ < x2.tag1_;
case 2:
return x1.tag2_ < x2.tag2_;
default:
return x1 < x2;
}
}
bool operator()(equivalent_object const& x1, equivalent_object const& x2) const {
return x1 < x2;
}
std::size_t operator()(int x1, int x2) const {
return x1 < x2;
}
friend bool operator==(less const& x1, less const& x2) {
return x1.type_ == x2.type_;
}
};
class equal_to
{
int type_;
public:
explicit equal_to(int t = 0) : type_(t) {}
bool operator()(object const& x1, object const& x2) const {
switch(type_) {
case 1:
return x1.tag1_ == x2.tag1_;
case 2:
return x1.tag2_ == x2.tag2_;
default:
return x1 == x2;
}
}
bool operator()(equivalent_object const& x1, equivalent_object const& x2) const {
return x1 == x2;
}
std::size_t operator()(int x1, int x2) const {
return x1 == x2;
}
friend bool operator==(equal_to const& x1, equal_to const& x2) {
return x1.type_ == x2.type_;
}
friend bool operator!=(equal_to const& x1, equal_to const& x2) {
return x1.type_ != x2.type_;
}
friend less create_compare(equal_to x) {
return less(x.type_);
}
};
namespace detail
{
// This annoymous namespace won't cause ODR violations as I won't
// be linking multiple translation units together. I'll probably
// move this into a cpp file before a full release, but for now it's
// the most convenient way.
namespace {
struct memory_area {
void const* start;
void const* end;
memory_area(void const* s, void const* e)
: start(s), end(e)
{
}
// This is a bit dodgy as it defines overlapping
// areas as 'equal', so this isn't a total ordering.
// But it is for non-overlapping memory regions - which
// is what'll be stored.
//
// All searches will be for areas entirely contained by
// a member of the set - so it should find the area that contains
// the region that is searched for.
bool operator<(memory_area const& other) const {
return end < other.start;
}
};
struct memory_track {
explicit memory_track(int tag = -1) :
constructed_(0),
tag_(tag) {}
int constructed_;
int tag_;
};
typedef std::map<memory_area, memory_track> allocated_memory_type;
allocated_memory_type allocated_memory;
unsigned int count_allocators = 0;
unsigned int count_allocations = 0;
unsigned int count_constructions = 0;
}
void allocator_ref()
{
if(count_allocators == 0) {
count_allocations = 0;
count_constructions = 0;
allocated_memory.clear();
}
++count_allocators;
}
void allocator_unref()
{
BOOST_TEST(count_allocators > 0);
if(count_allocators > 0) {
--count_allocators;
if(count_allocators == 0) {
bool no_allocations_left = (count_allocations == 0);
bool no_constructions_left = (count_constructions == 0);
bool allocated_memory_empty = allocated_memory.empty();
// Clearing the data before the checks terminate the tests.
count_allocations = 0;
count_constructions = 0;
allocated_memory.clear();
BOOST_TEST(no_allocations_left);
BOOST_TEST(no_constructions_left);
BOOST_TEST(allocated_memory_empty);
}
}
}
void track_allocate(void *ptr, std::size_t n, std::size_t size, int tag)
{
if(n == 0) {
BOOST_ERROR("Allocating 0 length array.");
}
else {
++count_allocations;
allocated_memory[memory_area(ptr, (char*) ptr + n * size)] =
memory_track(tag);
}
}
void track_deallocate(void* ptr, std::size_t n, std::size_t size, int tag)
{
allocated_memory_type::iterator pos
= allocated_memory.find(memory_area(ptr, ptr));
if(pos == allocated_memory.end()) {
BOOST_ERROR("Deallocating unknown pointer.");
} else {
BOOST_TEST(pos->first.start == ptr);
BOOST_TEST(pos->first.end == (char*) ptr + n * size);
BOOST_TEST(pos->second.tag_ == tag);
BOOST_TEST(pos->second.constructed_ == 0);
allocated_memory.erase(pos);
}
BOOST_TEST(count_allocations > 0);
if(count_allocations > 0) --count_allocations;
}
void track_construct(void* ptr, std::size_t /*size*/, int tag)
{
allocated_memory_type::iterator pos
= allocated_memory.find(memory_area(ptr, ptr));
if(pos == allocated_memory.end())
BOOST_ERROR("Constructing unknown pointer.");
BOOST_TEST(pos->second.tag_ == tag);
++count_constructions;
++pos->second.constructed_;
}
void track_destroy(void* ptr, std::size_t /*size*/, int tag)
{
allocated_memory_type::iterator pos
= allocated_memory.find(memory_area(ptr, ptr));
if(pos == allocated_memory.end())
BOOST_ERROR("Destroying unknown pointer.");
BOOST_TEST(count_constructions > 0);
BOOST_TEST(pos->second.tag_ == tag);
BOOST_TEST(pos->second.constructed_ > 0);
if(count_constructions > 0) --count_constructions;
if(pos->second.constructed_ > 0) --pos->second.constructed_;
}
}
template <class T>
class allocator
{
# ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
public:
# else
template <class> friend class allocator;
# endif
int tag_;
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef allocator<U> other; };
explicit allocator(int t = 0) : tag_(t) { detail::allocator_ref(); }
template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_) { detail::allocator_ref(); }
allocator(allocator const& x) : tag_(x.tag_) { detail::allocator_ref(); }
~allocator() { detail::allocator_unref(); }
pointer address(reference r) { return pointer(&r); }
const_pointer address(const_reference r) { return const_pointer(&r); }
pointer allocate(size_type n) {
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
detail::track_allocate((void*) ptr, n, sizeof(T), tag_);
return ptr;
}
pointer allocate(size_type n, const_pointer u)
{
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
detail::track_allocate((void*) ptr, n, sizeof(T), tag_);
return ptr;
}
void deallocate(pointer p, size_type n)
{
detail::track_deallocate((void*) p, n, sizeof(T), tag_);
::operator delete((void*) p);
}
void construct(pointer p, T const& t) {
detail::track_construct((void*) p, sizeof(T), tag_);
new(p) T(t);
}
void destroy(pointer p) {
detail::track_destroy((void*) p, sizeof(T), tag_);
p->~T();
}
size_type max_size() const {
return (std::numeric_limits<size_type>::max)();
}
bool operator==(allocator const& x) const
{
return tag_ == x.tag_;
}
bool operator!=(allocator const& x) const
{
return tag_ != x.tag_;
}
};
template <class T>
bool equivalent_impl(allocator<T> const& x, allocator<T> const& y, test::derived_type) {
return x == y;
}
#if BOOST_WORKAROUND(__GNUC__, < 3)
void swap(test::object& x, test::object& y) {
test::object tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::equivalent_object& x, test::equivalent_object& y) {
test::equivalent_object tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::hash& x, test::hash& y) {
test::hash tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::less& x, test::less& y) {
test::less tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::equal_to& x, test::equal_to& y) {
test::equal_to tmp;
tmp = x;
x = y;
y = tmp;
}
template <class T>
void swap(test::allocator<T>& x, test::allocator<T>& y) {
test::allocator<T> tmp;
tmp = x;
x = y;
y = tmp;
}
#endif
}
#endif

33
test/unordered/Jamfile.v2 Normal file
View File

@ -0,0 +1,33 @@
# Copyright 2006-2007 Daniel James.
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
import testing ;
project unordered-test/unordered
: requirements
<toolset>intel-linux:"<cxxflags>-strict_ansi -cxxlib-icc"
<toolset>gcc:<cxxflags>-Wsign-promo
<toolset>msvc:<cxxflags>/W4
;
test-suite unordered-tests
:
[ run equivalent_keys_tests.cpp ]
[ run compile_tests.cpp ]
[ run constructor_tests.cpp ]
[ run copy_tests.cpp ]
[ run assign_tests.cpp ]
[ run insert_tests.cpp ]
[ run insert_stable_tests.cpp ]
[ run unnecessary_copy_tests.cpp ]
[ run erase_tests.cpp ]
[ run erase_equiv_tests.cpp ]
[ run find_tests.cpp ]
[ run at_tests.cpp ]
[ run bucket_tests.cpp ]
[ run load_factor_tests.cpp ]
[ run rehash_tests.cpp ]
[ run swap_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=2 ]
;

View File

@ -0,0 +1,109 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include <iostream>
test::seed_t seed(96785);
template <class T>
void assign_tests1(T* = 0)
{
typename T::hasher hf;
typename T::key_equal eq;
std::cerr<<"assign_tests1.1\n";
{
T x;
x = x;
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
}
std::cerr<<"assign_tests1.2\n";
{
test::random_values<T> v(1000);
T x(v.begin(), v.end());
test::ordered<T> tracker = test::create_ordered(x);
tracker.insert_range(v.begin(), v.end());
x = x;
tracker.compare(x);
T y;
y.max_load_factor(x.max_load_factor() / 20);
y = x;
tracker.compare(y);
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
}
}
template <class T>
void assign_tests2(T* = 0)
{
typename T::hasher hf1(1);
typename T::hasher hf2(2);
typename T::key_equal eq1(1);
typename T::key_equal eq2(2);
typename T::allocator_type al1(1);
typename T::allocator_type al2(2);
std::cerr<<"assign_tests2.1\n";
{
test::random_values<T> v(1000);
T x1(v.begin(), v.end(), 0, hf1, eq1);
T x2(0, hf2, eq2);
x2 = x1;
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
test::check_container(x2, v);
}
std::cerr<<"assign_tests2.2\n";
{
test::random_values<T> v1(100), v2(100);
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
x2 = x1;
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
test::check_container(x2, v1);
}
}
int main()
{
assign_tests1((boost::unordered_set<int>*) 0);
assign_tests1((boost::unordered_multiset<int>*) 0);
assign_tests1((boost::unordered_map<int, int>*) 0);
assign_tests1((boost::unordered_multimap<int, int>*) 0);
assign_tests1((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
assign_tests1((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
assign_tests1((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
assign_tests1((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
assign_tests1((boost::unordered_set<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
assign_tests1((boost::unordered_multiset<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
assign_tests1((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
assign_tests1((boost::unordered_multimap<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
assign_tests2((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
assign_tests2((boost::unordered_multiset<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
assign_tests2((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
assign_tests2((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
return boost::report_errors();
}

View File

@ -0,0 +1,28 @@
// Copyright 2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <string>
int main() {
boost::unordered_map<std::string, int> x;
typedef boost::unordered_map<std::string, int>::iterator iterator;
x["one"] = 1;
x["two"] = 2;
BOOST_TEST(x.at("one") == 1);
BOOST_TEST(x.at("two") == 2);
try {
x.at("three");
BOOST_ERROR("Should have thrown.");
}
catch(std::out_of_range) {
}
return boost::report_errors();
}

View File

@ -0,0 +1,64 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <algorithm>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/helpers.hpp"
test::seed_t seed(54635);
template <class X>
void bucket_tests(X* = 0)
{
typedef typename X::size_type size_type;
typedef typename X::const_local_iterator const_local_iterator;
test::random_values<X> v(1000);
X x(v.begin(), v.end());
BOOST_TEST(x.bucket_count() < x.max_bucket_count());
std::cerr<<x.bucket_count()<<"<"<<x.max_bucket_count()<<"\n";
for(typename test::random_values<X>::const_iterator
it = v.begin(), end = v.end(); it != end; ++it)
{
size_type bucket = x.bucket(test::get_key<X>(*it));
BOOST_TEST(bucket < x.bucket_count());
if(bucket < x.max_bucket_count()) {
// lit? lend?? I need a new naming scheme.
const_local_iterator lit = x.begin(bucket), lend = x.end(bucket);
while(lit != lend && test::get_key<X>(*it) != test::get_key<X>(*lit)) ++lit;
BOOST_TEST(lit != lend);
}
}
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)));
}
}
int main()
{
bucket_tests((boost::unordered_set<int>*) 0);
bucket_tests((boost::unordered_multiset<int>*) 0);
bucket_tests((boost::unordered_map<int, int>*) 0);
bucket_tests((boost::unordered_multimap<int, int>*) 0);
bucket_tests((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
bucket_tests((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
bucket_tests((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
bucket_tests((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
return boost::report_errors();
}

View File

@ -0,0 +1,328 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
#include <boost/concept_check.hpp>
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#include <boost/mpl/assert.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include "../helpers/check_return_type.hpp"
#include <iostream>
#include <boost/detail/lightweight_test.hpp>
#include "../objects/minimal.hpp"
template <class T> void sink(T const&) {}
template <class X, class Key>
void unordered_set_test(X&, Key const&)
{
typedef typename X::value_type value_type;
typedef typename X::key_type key_type;
BOOST_MPL_ASSERT((boost::is_same<value_type, key_type>));
}
template <class X, class Key, class T>
void unordered_map_test(X&, Key const&, T const&)
{
typedef typename X::value_type value_type;
typedef typename X::key_type key_type;
BOOST_MPL_ASSERT((boost::is_same<value_type, std::pair<key_type const, T> >));
}
template <class X, class T>
void unordered_unique_test(X& r, T const& t)
{
typedef typename X::iterator iterator;
test::check_return_type<std::pair<iterator, bool> >::equals(r.insert(t));
}
template <class X, class T>
void unordered_equivalent_test(X& r, T const& t)
{
typedef typename X::iterator iterator;
test::check_return_type<iterator>::equals(r.insert(t));
}
template <class X, class Key, class T>
void unordered_map_functions(X&, Key const& k, T const&)
{
typedef typename X::mapped_type mapped_type;
X a;
test::check_return_type<mapped_type>::equals_ref(a[k]);
test::check_return_type<mapped_type>::equals_ref(a.at(k));
X const b = a;
test::check_return_type<mapped_type const>::equals_ref(b.at(k));
}
template <class X, class Key, class T, class Hash, class Pred>
void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
{
typedef typename X::key_type key_type;
typedef typename X::hasher hasher;
typedef typename X::key_equal key_equal;
typedef typename X::size_type size_type;
typedef typename X::iterator iterator;
typedef typename X::const_iterator const_iterator;
typedef typename X::local_iterator local_iterator;
typedef typename X::const_local_iterator const_local_iterator;
typedef typename boost::BOOST_ITERATOR_CATEGORY<iterator>::type iterator_category;
typedef typename boost::iterator_difference<iterator>::type iterator_difference;
typedef typename boost::iterator_pointer<iterator>::type iterator_pointer;
typedef typename boost::iterator_reference<iterator>::type iterator_reference;
typedef typename boost::BOOST_ITERATOR_CATEGORY<local_iterator>::type local_iterator_category;
typedef typename boost::iterator_difference<local_iterator>::type local_iterator_difference;
typedef typename boost::iterator_pointer<local_iterator>::type local_iterator_pointer;
typedef typename boost::iterator_reference<local_iterator>::type local_iterator_reference;
typedef typename boost::BOOST_ITERATOR_CATEGORY<const_iterator>::type const_iterator_category;
typedef typename boost::iterator_difference<const_iterator>::type const_iterator_difference;
typedef typename boost::iterator_pointer<const_iterator>::type const_iterator_pointer;
typedef typename boost::iterator_reference<const_iterator>::type const_iterator_reference;
typedef typename boost::BOOST_ITERATOR_CATEGORY<const_local_iterator>::type const_local_iterator_category;
typedef typename boost::iterator_difference<const_local_iterator>::type const_local_iterator_difference;
typedef typename boost::iterator_pointer<const_local_iterator>::type const_local_iterator_pointer;
typedef typename boost::iterator_reference<const_local_iterator>::type const_local_iterator_reference;
BOOST_MPL_ASSERT((boost::is_same<Key, key_type>));
boost::function_requires<boost::CopyConstructibleConcept<key_type> >();
boost::function_requires<boost::AssignableConcept<key_type> >();
BOOST_MPL_ASSERT((boost::is_same<Hash, hasher>));
test::check_return_type<std::size_t>::equals(hf(k));
BOOST_MPL_ASSERT((boost::is_same<Pred, key_equal>));
test::check_return_type<bool>::convertible(eq(k, k));
boost::function_requires<boost::InputIteratorConcept<local_iterator> >();
BOOST_MPL_ASSERT((boost::is_same<local_iterator_category, iterator_category>));
BOOST_MPL_ASSERT((boost::is_same<local_iterator_difference, iterator_difference>));
BOOST_MPL_ASSERT((boost::is_same<local_iterator_pointer, iterator_pointer>));
BOOST_MPL_ASSERT((boost::is_same<local_iterator_reference, iterator_reference>));
boost::function_requires<boost::InputIteratorConcept<const_local_iterator> >();
BOOST_MPL_ASSERT((boost::is_same<const_local_iterator_category, const_iterator_category>));
BOOST_MPL_ASSERT((boost::is_same<const_local_iterator_difference, const_iterator_difference>));
BOOST_MPL_ASSERT((boost::is_same<const_local_iterator_pointer, const_iterator_pointer>));
BOOST_MPL_ASSERT((boost::is_same<const_local_iterator_reference, const_iterator_reference>));
X(10, hf, eq);
X a(10, hf, eq);
X(10, hf);
X a2(10, hf);
X(10);
X a3(10);
X();
X a4;
typename X::value_type* i = 0;
typename X::value_type* j = 0;
X(i, j, 10, hf, eq);
X a5(i, j, 10, hf, eq);
X(i, j, 10, hf);
X a6(i, j, 10, hf);
X(i, j, 10);
X a7(i, j, 10);
X(i, j);
X a8(i, j);
X const b;
sink(X(b));
X a9(b);
a = b;
test::check_return_type<hasher>::equals(b.hash_function());
test::check_return_type<key_equal>::equals(b.key_eq());
const_iterator q = a.cbegin();
test::check_return_type<iterator>::equals(a.insert(q, t));
a.insert(i, j);
test::check_return_type<size_type>::equals(a.erase(k));
BOOST_TEST(a.empty());
if(a.empty()) {
a.insert(t);
q = a.cbegin();
test::check_return_type<iterator>::equals(a.erase(q));
}
const_iterator q1 = a.cbegin(), q2 = a.cend();
test::check_return_type<iterator>::equals(a.erase(q1, q2));
a.clear();
test::check_return_type<iterator>::equals(a.find(k));
test::check_return_type<const_iterator>::equals(b.find(k));
test::check_return_type<size_type>::equals(b.count(k));
test::check_return_type<std::pair<iterator, iterator> >::equals(
a.equal_range(k));
test::check_return_type<std::pair<const_iterator, const_iterator> >::equals(
b.equal_range(k));
test::check_return_type<size_type>::equals(b.bucket_count());
test::check_return_type<size_type>::equals(b.max_bucket_count());
test::check_return_type<size_type>::equals(b.bucket(k));
test::check_return_type<size_type>::equals(b.bucket_size(0));
test::check_return_type<local_iterator>::equals(a.begin(0));
test::check_return_type<const_local_iterator>::equals(b.begin(0));
test::check_return_type<local_iterator>::equals(a.end(0));
test::check_return_type<const_local_iterator>::equals(b.end(0));
test::check_return_type<const_local_iterator>::equals(a.cbegin(0));
test::check_return_type<const_local_iterator>::equals(b.cbegin(0));
test::check_return_type<const_local_iterator>::equals(a.cend(0));
test::check_return_type<const_local_iterator>::equals(b.cend(0));
test::check_return_type<float>::equals(b.load_factor());
test::check_return_type<float>::equals(b.max_load_factor());
a.max_load_factor((float) 2.0);
a.rehash(100);
}
void test1()
{
boost::hash<int> hash;
std::equal_to<int> equal_to;
int value = 0;
std::pair<int const, int> map_value(0, 0);
std::cout<<"Test unordered_set.\n";
boost::unordered_set<int> set;
unordered_unique_test(set, value);
unordered_set_test(set, value);
unordered_test(set, value, value, hash, equal_to);
std::cout<<"Test unordered_multiset.\n";
boost::unordered_multiset<int> multiset;
unordered_equivalent_test(multiset, value);
unordered_set_test(multiset, value);
unordered_test(multiset, value, value, hash, equal_to);
std::cout<<"Test unordered_map.\n";
boost::unordered_map<int, int> map;
unordered_unique_test(map, map_value);
unordered_map_test(map, value, value);
unordered_test(map, value, map_value, hash, equal_to);
unordered_map_functions(map, value, value);
std::cout<<"Test unordered_multimap.\n";
boost::unordered_multimap<int, int> multimap;
unordered_equivalent_test(multimap, map_value);
unordered_map_test(multimap, value, value);
unordered_test(multimap, value, map_value, hash, equal_to);
}
void test2()
{
test::minimal::assignable assignable
= test::minimal::assignable::create();
test::minimal::copy_constructible copy_constructible
= test::minimal::copy_constructible::create();
test::minimal::hash<test::minimal::assignable> hash
= test::minimal::hash<test::minimal::assignable>::create();
test::minimal::equal_to<test::minimal::assignable> equal_to
= test::minimal::equal_to<test::minimal::assignable>::create();
typedef std::pair<test::minimal::assignable const,
test::minimal::copy_constructible> map_value_type;
map_value_type map_value(assignable, copy_constructible);
std::cout<<"Test unordered_set.\n";
boost::unordered_set<
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<test::minimal::assignable> > set;
unordered_unique_test(set, assignable);
unordered_set_test(set, assignable);
unordered_test(set, assignable, assignable, hash, equal_to);
std::cout<<"Test unordered_multiset.\n";
boost::unordered_multiset<
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<test::minimal::assignable> > multiset;
unordered_equivalent_test(multiset, assignable);
unordered_set_test(multiset, assignable);
unordered_test(multiset, assignable, assignable, hash, equal_to);
std::cout<<"Test unordered_map.\n";
boost::unordered_map<
test::minimal::assignable,
test::minimal::copy_constructible,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<map_value_type> > map;
unordered_unique_test(map, map_value);
unordered_map_test(map, assignable, copy_constructible);
unordered_test(map, assignable, map_value, hash, equal_to);
boost::unordered_map<
test::minimal::assignable,
test::minimal::default_copy_constructible,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<map_value_type> > map2;
test::minimal::default_copy_constructible default_copy_constructible;
unordered_map_functions(map2, assignable, default_copy_constructible);
std::cout<<"Test unordered_multimap.\n";
boost::unordered_multimap<
test::minimal::assignable,
test::minimal::copy_constructible,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<map_value_type> > multimap;
unordered_equivalent_test(multimap, map_value);
unordered_map_test(multimap, assignable, copy_constructible);
unordered_test(multimap, assignable, map_value, hash, equal_to);
}
int main() {
test1();
test2();
return boost::report_errors();
}

View File

@ -0,0 +1,311 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/input_iterator.hpp"
#include "../helpers/invariants.hpp"
#include <iostream>
test::seed_t seed(356730);
template <class T>
void constructor_tests1(T* = 0)
{
typename T::hasher hf;
typename T::key_equal eq;
typename T::allocator_type al;
std::cerr<<"Construct 1\n";
{
T x(0, hf, eq);
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 2\n";
{
T x(100, hf);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 100);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 3\n";
{
T x(2000);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 2000);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 4\n";
{
T x;
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 5\n";
{
test::random_values<T> v(1000);
T x(v.begin(), v.end(), 10000, hf, eq);
BOOST_TEST(x.bucket_count() >= 10000);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 6\n";
{
test::random_values<T> v(10);
T x(v.begin(), v.end(), 10000, hf);
BOOST_TEST(x.bucket_count() >= 10000);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 7\n";
{
test::random_values<T> v(100);
T x(v.begin(), v.end(), 100);
BOOST_TEST(x.bucket_count() >= 100);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 8\n";
{
test::random_values<T> v(1);
T x(v.begin(), v.end());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 9\n";
{
T x(0, hf, eq, al);
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 10\n";
{
test::random_values<T> v(1000);
T x(v.begin(), v.end(), 10000, hf, eq, al);
BOOST_TEST(x.bucket_count() >= 10000);
BOOST_TEST(test::equivalent(x.hash_function(), hf));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
}
template <class T>
void constructor_tests2(T* = 0)
{
typename T::hasher hf;
typename T::hasher hf1(1);
typename T::hasher hf2(2);
typename T::key_equal eq;
typename T::key_equal eq1(1);
typename T::key_equal eq2(2);
typename T::allocator_type al;
typename T::allocator_type al1(1);
typename T::allocator_type al2(2);
std::cerr<<"Construct 1\n";
{
T x(10000, hf1, eq1);
BOOST_TEST(x.bucket_count() >= 10000);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 2\n";
{
T x(100, hf1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 100);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 3\n";
{
test::random_values<T> v(100);
T x(v.begin(), v.end(), 0, hf1, eq1);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 4\n";
{
test::random_values<T> v(5);
T x(v.begin(), v.end(), 1000, hf1);
BOOST_TEST(x.bucket_count() >= 1000);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
BOOST_TEST(test::equivalent(x.key_eq(), eq));
BOOST_TEST(test::equivalent(x.get_allocator(), al));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
std::cerr<<"Construct 5\n";
{
test::random_values<T> v(100);
T x(v.begin(), v.end(), 0, hf, eq, al1);
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
test::check_container(x, v);
test::check_container(y, x);
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
}
std::cerr<<"Construct 6\n";
{
test::random_values<T> v(100);
T x(v.begin(), v.end(), 0, hf1, eq1);
T y(x.begin(), x.end(), 0, hf, eq);
test::check_container(x, v);
test::check_container(y, x);
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
}
std::cerr<<"Construct 7\n";
{
test::random_values<T> v(100);
T x(v.begin(), v.end(), 0, hf1, eq1);
T y(x.begin(), x.end(), 0, hf2, eq2);
test::check_container(x, v);
test::check_container(y, x);
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
}
std::cerr<<"Construct 8 - from input iterator\n";
{
test::random_values<T> v(100);
T x(test::input_iterator(v.begin()), test::input_iterator(v.end()), 0, hf1, eq1);
T y(test::input_iterator(x.begin()), test::input_iterator(x.end()), 0, hf2, eq2);
test::check_container(x, v);
test::check_container(y, x);
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
}
}
template <class T>
void map_constructor_test(T* = 0)
{
std::cerr<<"map_constructor_test\n";
typedef std::list<std::pair<BOOST_DEDUCED_TYPENAME T::key_type, BOOST_DEDUCED_TYPENAME T::mapped_type> > list;
test::random_values<T> v(1000);
list l;
std::copy(v.begin(), v.end(), std::back_inserter(l));
T x(l.begin(), l.end());
test::check_container(x, v);
test::check_equivalent_keys(x);
}
int main()
{
std::cerr<<"Test1 unordered_set<int>\n";
constructor_tests1((boost::unordered_set<int>*) 0);
std::cerr<<"Test1 unordered_multiset<int>\n";
constructor_tests1((boost::unordered_multiset<int>*) 0);
std::cerr<<"Test1 unordered_map<int, int>\n";
constructor_tests1((boost::unordered_map<int, int>*) 0);
std::cerr<<"Test1 unordered_multimap<int, int>\n";
constructor_tests1((boost::unordered_multimap<int, int>*) 0);
std::cerr<<"Test1 unordered_set<test::object>\n";
constructor_tests1((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Test1 unordered_multiset<test::object>\n";
constructor_tests1((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Test1 unordered_map<test::object, test::object>\n";
constructor_tests1((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Test1 unordered_multimap<test::object, test::object>\n";
constructor_tests1((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Test1 unordered_set<test::equivalent_object>\n";
constructor_tests1((boost::unordered_set<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"Test1 unordered_multiset<test::equivalent_object>\n";
constructor_tests1((boost::unordered_multiset<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"Test1 unordered_map<test::equivalent_object, test::equivalent_object>\n";
constructor_tests1((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"Test1 unordered_multimap<test::equivalent_object, test::equivalent_object>\n";
constructor_tests1((boost::unordered_multimap<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"Test2 unordered_set<test::object>\n";
constructor_tests2((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Test2 unordered_multiset<test::object>\n";
constructor_tests2((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Test2 unordered_map<test::object, test::object>\n";
constructor_tests2((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Test2 unordered_multimap<test::object, test::object>\n";
constructor_tests2((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Test2 unordered_set<test::equivalent_object>\n";
constructor_tests2((boost::unordered_set<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"Test2 unordered_multiset<test::equivalent_object>\n";
constructor_tests2((boost::unordered_multiset<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"Test2 unordered_map<test::equivalent_object, test::equivalent_object>\n";
constructor_tests2((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"Test2 unordered_multimap<test::equivalent_object, test::equivalent_object>\n";
constructor_tests2((boost::unordered_multimap<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"Map Test unordered_map<test::object, test::object>\n";
map_constructor_test((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"Map Test unordered_multimap<test::object, test::object>\n";
map_constructor_test((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
return boost::report_errors();
}

View File

@ -0,0 +1,111 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/invariants.hpp"
test::seed_t seed(9063);
template <class T>
void copy_construct_tests1(T* = 0)
{
typename T::hasher hf;
typename T::key_equal eq;
typename T::allocator_type al;
{
T x;
T y(x);
BOOST_TEST(y.empty());
BOOST_TEST(test::equivalent(y.hash_function(), hf));
BOOST_TEST(test::equivalent(y.key_eq(), eq));
BOOST_TEST(test::equivalent(y.get_allocator(), al));
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
test::check_equivalent_keys(y);
}
{
test::random_values<T> v(1000);
T x(v.begin(), v.end());
T y(x);
test::unordered_equivalence_tester<T> equivalent(x);
equivalent(y);
test::check_equivalent_keys(y);
}
{
// In this test I drop the original containers max load factor, so it
// is much lower than the load factor. The hash table is not allowed
// to rehash, but the destination container should probably allocate
// enough buckets to decrease the load factor appropriately.
test::random_values<T> v(1000);
T x(v.begin(), v.end());
x.max_load_factor(x.load_factor() / 4);
T y(x);
test::unordered_equivalence_tester<T> equivalent(x);
equivalent(y);
// This isn't guaranteed:
BOOST_TEST(y.load_factor() < y.max_load_factor());
test::check_equivalent_keys(y);
}
}
template <class T>
void copy_construct_tests2(T* ptr = 0)
{
copy_construct_tests1(ptr);
typename T::hasher hf(1);
typename T::key_equal eq(1);
typename T::allocator_type al(1);
{
T x(10000, hf, eq, al);
T y(x);
BOOST_TEST(y.empty());
BOOST_TEST(test::equivalent(y.hash_function(), hf));
BOOST_TEST(test::equivalent(y.key_eq(), eq));
BOOST_TEST(test::equivalent(y.get_allocator(), al));
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
test::check_equivalent_keys(y);
}
{
test::random_values<T> v(1000);
T x(v.begin(), v.end(), 0, hf, eq, al);
T y(x);
test::unordered_equivalence_tester<T> equivalent(x);
equivalent(y);
test::check_equivalent_keys(y);
}
}
int main()
{
copy_construct_tests1((boost::unordered_set<int>*) 0);
copy_construct_tests1((boost::unordered_multiset<int>*) 0);
copy_construct_tests1((boost::unordered_map<int, int>*) 0);
copy_construct_tests1((boost::unordered_multimap<int, int>*) 0);
copy_construct_tests2((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
copy_construct_tests2((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
copy_construct_tests2((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
copy_construct_tests2((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
copy_construct_tests2((boost::unordered_set<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
copy_construct_tests2((boost::unordered_multiset<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
copy_construct_tests2((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
copy_construct_tests2((boost::unordered_multimap<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
return boost::report_errors();
}

View File

@ -0,0 +1,85 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <algorithm>
#include <map>
#include <deque>
#include "../helpers/tracker.hpp"
#include "../helpers/invariants.hpp"
#include <iostream>
template <class Container, class Iterator>
void test_equal_insertion(Iterator begin, Iterator end)
{
typedef test::ordered<Container> tracker;
Container x1;
tracker x2 = test::create_ordered(x1);
for(Iterator it = begin; it != end; ++it) {
x1.insert(*it);
x2.insert(*it);
x2.compare_key(x1, *it);
}
x2.compare(x1);
test::check_equivalent_keys(x1);
}
void set_tests()
{
int values[][5] = {
{1},
{54, 23},
{-13, 65},
{77, 77},
{986, 25, 986}
};
test_equal_insertion<boost::unordered_set<int> >(values[0], values[0] + 1);
test_equal_insertion<boost::unordered_set<int> >(values[1], values[1] + 2);
test_equal_insertion<boost::unordered_set<int> >(values[2], values[2] + 2);
test_equal_insertion<boost::unordered_set<int> >(values[3], values[3] + 2);
test_equal_insertion<boost::unordered_set<int> >(values[4], values[4] + 3);
test_equal_insertion<boost::unordered_multiset<int> >(values[0], values[0] + 1);
test_equal_insertion<boost::unordered_multiset<int> >(values[1], values[1] + 2);
test_equal_insertion<boost::unordered_multiset<int> >(values[2], values[2] + 2);
test_equal_insertion<boost::unordered_multiset<int> >(values[3], values[3] + 2);
test_equal_insertion<boost::unordered_multiset<int> >(values[4], values[4] + 3);
}
void map_tests()
{
typedef std::deque<std::pair<int const, int> > values_type;
values_type v[5];
v[0].push_back(std::pair<int const, int>(1,1));
v[1].push_back(std::pair<int const, int>(28,34));
v[1].push_back(std::pair<int const, int>(16,58));
v[1].push_back(std::pair<int const, int>(-124, 62));
v[2].push_back(std::pair<int const, int>(432,12));
v[2].push_back(std::pair<int const, int>(9,13));
v[2].push_back(std::pair<int const, int>(432,24));
for(int i = 0; i < 5; ++i)
test_equal_insertion<boost::unordered_map<int, int> >(
v[i].begin(), v[i].end());
for(int i2 = 0; i2 < 5; ++i2)
test_equal_insertion<boost::unordered_multimap<int, int> >(
v[i2].begin(), v[i2].end());
}
int main()
{
set_tests();
map_tests();
return boost::report_errors();
}

View File

@ -0,0 +1,199 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// The code for erasing elements from containers with equivalent keys is very
// hairy with several tricky edge cases - so explicitly test each one.
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <list>
#include <set>
#include <iostream>
#include <iterator>
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
struct write_pair_type
{
template <class X1, class X2>
void operator()(std::pair<X1, X2> const& x) const
{
std::cout<<"("<<x.first<<","<<x.second<<")";
}
} write_pair;
template <class Container>
void write_container(Container const& x)
{
std::for_each(x.begin(), x.end(), write_pair);
std::cout<<"\n";
}
// Make everything collide - for testing erase in a single bucket.
struct collision_hash
{
int operator()(int) const { return 0; }
};
// For testing erase in 2 buckets.
struct collision2_hash
{
int operator()(int x) const { return x & 1; }
};
typedef boost::unordered_multimap<int, int,
collision_hash, std::equal_to<int>,
test::allocator<std::pair<int const, int> > > collide_map;
typedef boost::unordered_multimap<int, int,
collision2_hash, std::equal_to<int>,
test::allocator<std::pair<int const, int> > > collide_map2;
typedef collide_map::value_type collide_value;
typedef std::list<collide_value> collide_list;
void empty_range_tests()
{
collide_map x;
x.erase(x.begin(), x.end());
x.erase(x.begin(), x.begin());
x.erase(x.end(), x.end());
}
void single_item_tests()
{
collide_list init;
init.push_back(collide_value(1,1));
collide_map x(init.begin(), init.end());
x.erase(x.begin(), x.begin());
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
x.erase(x.end(), x.end());
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
x.erase(x.begin(), x.end());
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
}
void two_equivalent_item_tests()
{
collide_list init;
init.push_back(collide_value(1,1));
init.push_back(collide_value(1,2));
{
collide_map x(init.begin(), init.end());
x.erase(x.begin(), x.end());
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
}
{
collide_map x(init.begin(), init.end());
int value = boost::next(x.begin())->second;
x.erase(x.begin(), boost::next(x.begin()));
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
x.begin()->first == 1 && x.begin()->second == value);
}
{
collide_map x(init.begin(), init.end());
int value = x.begin()->second;
x.erase(boost::next(x.begin()), x.end());
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
x.begin()->first == 1 && x.begin()->second == value);
}
}
// More automated tests...
template<class Range1, class Range2>
bool compare(Range1 const& x, Range2 const& y)
{
collide_list a;
collide_list b;
std::copy(x.begin(), x.end(), std::back_inserter(a));
std::copy(y.begin(), y.end(), std::back_inserter(b));
a.sort();
b.sort();
return a == b;
}
template <class Container>
bool general_erase_range_test(Container& x, int start, int end)
{
collide_list l;
std::copy(x.begin(), x.end(), std::back_inserter(l));
l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end));
x.erase(boost::next(x.begin(), start), boost::next(x.begin(), end));
return compare(l, x);
}
template <class Container>
void erase_subrange_tests(Container const& x)
{
for(std::size_t length = 0; length < x.size(); ++length) {
for(std::size_t position = 0; position < x.size() - length; ++position) {
Container y(x);
collide_list init;
std::copy(y.begin(), y.end(), std::back_inserter(init));
if(!general_erase_range_test(y, position, position + length)) {
BOOST_ERROR("general_erase_range_test failed.");
std::cout<<"Erase: ["<<position<<","<<position + length<<")\n";
write_container(init);
write_container(y);
}
}
}
}
template <class Container>
void x_by_y_erase_range_tests(Container*, int values, int duplicates)
{
Container y;
for(int i = 0; i < values; ++i) {
for(int j = 0; j < duplicates; ++j) {
y.insert(collide_value(i, j));
}
}
std::cout<<"Values: "<<values<<", Duplicates: "<<duplicates<<"\n";
erase_subrange_tests(y);
}
template <class Container>
void exhaustive_erase_tests(Container* x, int num_values,
int num_duplicated)
{
for(int i = 0; i < num_values; ++i) {
for(int j = 0; j < num_duplicated; ++j) {
x_by_y_erase_range_tests(x, i, j);
}
}
}
void exhaustive_collide_tests()
{
std::cout<<"exhaustive_collide_tests:\n";
collide_map m;
exhaustive_erase_tests((collide_map*) 0, 4, 4);
std::cout<<"\n";
}
void exhaustive_collide2_tests()
{
std::cout<<"exhaustive_collide2_tests:\n";
exhaustive_erase_tests((collide_map2*) 0, 8, 4);
std::cout<<"\n";
}
int main()
{
empty_range_tests();
single_item_tests();
two_equivalent_item_tests();
exhaustive_collide_tests();
exhaustive_collide2_tests();
return boost::report_errors();
}

View File

@ -0,0 +1,150 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/helpers.hpp"
#include <iostream>
test::seed_t seed(85638);
template <class Container>
void erase_tests1(Container* = 0)
{
std::cerr<<"Erase by key.\n";
{
test::random_values<Container> v(1000);
Container x(v.begin(), v.end());
for(typename test::random_values<Container>::iterator it = v.begin();
it != v.end(); ++it)
{
std::size_t count = x.count(test::get_key<Container>(*it));
std::size_t old_size = x.size();
BOOST_TEST(count == x.erase(test::get_key<Container>(*it)));
BOOST_TEST(x.size() == old_size - count);
BOOST_TEST(x.count(test::get_key<Container>(*it)) == 0);
BOOST_TEST(x.find(test::get_key<Container>(*it)) == x.end());
}
}
std::cerr<<"erase(begin()).\n";
{
test::random_values<Container> v(1000);
Container x(v.begin(), v.end());
std::size_t size = x.size();
while(size > 0 && !x.empty())
{
typename Container::key_type key = test::get_key<Container>(*x.begin());
std::size_t count = x.count(key);
typename Container::iterator pos = x.erase(x.begin());
--size;
BOOST_TEST(pos == x.begin());
BOOST_TEST(x.count(key) == count - 1);
BOOST_TEST(x.size() == size);
}
BOOST_TEST(x.empty());
}
std::cerr<<"erase(random position).\n";
{
test::random_values<Container> v(1000);
Container x(v.begin(), v.end());
std::size_t size = x.size();
while(size > 0 && !x.empty())
{
using namespace std;
int index = rand() % x.size();
typename Container::const_iterator prev, pos, next;
if(index == 0) {
prev = pos = x.begin();
}
else {
prev = boost::next(x.begin(), index - 1);
pos = boost::next(prev);
}
next = boost::next(pos);
typename Container::key_type key = test::get_key<Container>(*pos);
std::size_t count = x.count(key);
BOOST_TEST(next == x.erase(pos));
--size;
if(size > 0)
BOOST_TEST(next ==
(index == 0 ? x.begin() : boost::next(prev)));
BOOST_TEST(x.count(key) == count - 1);
BOOST_TEST(x.size() == size);
}
BOOST_TEST(x.empty());
}
std::cerr<<"erase(ranges).\n";
{
test::random_values<Container> v(500);
Container x(v.begin(), v.end());
std::size_t size = x.size();
// I'm actually stretching it a little here, as the standard says it
// returns 'the iterator immediately following the erase elements'
// and if nothing is erased, then there's nothing to follow. But I
// think this is the only sensible option...
BOOST_TEST(x.erase(x.end(), x.end()) == x.end());
BOOST_TEST(x.erase(x.begin(), x.begin()) == x.begin());
BOOST_TEST(x.size() == size);
BOOST_TEST(x.erase(x.begin(), x.end()) == x.end());
BOOST_TEST(x.empty());
BOOST_TEST(x.begin() == x.end());
BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin());
}
std::cerr<<"clear().\n";
{
test::random_values<Container> v(500);
Container x(v.begin(), v.end());
x.clear();
BOOST_TEST(x.empty());
BOOST_TEST(x.begin() == x.end());
}
}
int main()
{
std::cerr<<"Erase unordered_set<int>.\n";
erase_tests1((boost::unordered_set<int>*) 0);
std::cerr<<"\nErase unordered_multiset<int>.\n";
erase_tests1((boost::unordered_multiset<int>*) 0);
std::cerr<<"\nErase unordered_map<int>.\n";
erase_tests1((boost::unordered_map<int, int>*) 0);
std::cerr<<"\nErase unordered_multimap<int>.\n";
erase_tests1((boost::unordered_multimap<int, int>*) 0);
std::cerr<<"\nErase unordered_set<test::object,..>.\n";
erase_tests1((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"\nErase unordered_multiset<test::object,..>.\n";
erase_tests1((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"\nErase unordered_map<test::object,..>.\n";
erase_tests1((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"\nErase unordered_multimap<test::object,..>.\n";
erase_tests1((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"\nErase unordered_set<test::equivalent_object,..>.\n";
erase_tests1((boost::unordered_set<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"\nErase unordered_multiset<test::equivalent_object,..>.\n";
erase_tests1((boost::unordered_multiset<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"\nErase unordered_map<test::equivalent_object,..>.\n";
erase_tests1((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
std::cerr<<"\nErase unordered_multimap<test::equivalent_object,..>.\n";
erase_tests1((boost::unordered_multimap<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
return boost::report_errors();
}

View File

@ -0,0 +1,99 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/helpers.hpp"
test::seed_t seed(78937);
template <class X>
void find_tests1(X*)
{
typedef typename X::iterator iterator;
{
test::random_values<X> v(500);
X x(v.begin(), v.end());
X const& x_const = x;
test::ordered<X> tracker = test::create_ordered(x);
tracker.insert_range(v.begin(), v.end());
for(typename test::ordered<X>::const_iterator it1 =
tracker.begin(); it1 != tracker.end(); ++it1)
{
typename X::key_type key = test::get_key<X>(*it1);
iterator pos = x.find(key);
typename X::const_iterator const_pos = x_const.find(key);
BOOST_TEST(pos != x.end() &&
x.key_eq()(key, test::get_key<X>(*pos)));
BOOST_TEST(const_pos != x_const.end() &&
x_const.key_eq()(key, test::get_key<X>(*const_pos)));
BOOST_TEST(x.count(key) == tracker.count(key));
test::compare_pairs(x.equal_range(key),
tracker.equal_range(key),
(typename test::non_const_value_type<X>::type*) 0);
test::compare_pairs(x_const.equal_range(key),
tracker.equal_range(key),
(typename test::non_const_value_type<X>::type*) 0);
}
test::random_values<X> v2(500);
for(typename test::random_values<X>::const_iterator it2 =
v2.begin(); it2 != v2.end(); ++it2)
{
typename X::key_type key = test::get_key<X>(*it2);
if(tracker.find(test::get_key<X>(key)) == tracker.end())
{
BOOST_TEST(x.find(key) == x.end());
BOOST_TEST(x_const.find(key) == x_const.end());
BOOST_TEST(x.count(key) == 0);
std::pair<iterator, iterator> range = x.equal_range(key);
BOOST_TEST(range.first == range.second);
}
}
}
{
X x;
test::random_values<X> v2(5);
for(typename test::random_values<X>::const_iterator it3 =
v2.begin(); it3 != v2.end(); ++it3)
{
typename X::key_type key = test::get_key<X>(*it3);
BOOST_TEST(x.find(key) == x.end());
BOOST_TEST(x.count(key) == 0);
std::pair<iterator, iterator> range = x.equal_range(key);
BOOST_TEST(range.first == range.second);
}
}
}
int main()
{
find_tests1((boost::unordered_set<int>*) 0);
find_tests1((boost::unordered_multiset<int>*) 0);
find_tests1((boost::unordered_map<int, int>*) 0);
find_tests1((boost::unordered_multimap<int, int>*) 0);
find_tests1((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
find_tests1((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
find_tests1((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
find_tests1((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
find_tests1((boost::unordered_set<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
find_tests1((boost::unordered_multiset<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
find_tests1((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
find_tests1((boost::unordered_multimap<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
return 0;
}

View File

@ -0,0 +1,84 @@
// Copyright 2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
namespace insert_stable
{
struct member {
int tag1_;
int tag2_;
member() : tag1_(0), tag2_(0) {}
member(int t1, int t2) : tag1_(t1), tag2_(t2) {}
friend bool operator==(member const& x, member const& y) {
return x.tag1_ == y.tag1_;
}
friend bool operator!=(member const& x, member const& y) {
return x.tag1_ != y.tag1_;
}
};
}
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
namespace boost
#else
namespace insert_stable
#endif
{
std::size_t hash_value(insert_stable::member const& x) {
return static_cast<std::size_t>(x.tag1_);
}
}
void stable_insert_test1() {
boost::unordered_multiset<insert_stable::member> x;
x.insert(insert_stable::member(1,1));
x.insert(insert_stable::member(1,2));
x.insert(insert_stable::member(1,3));
boost::unordered_multiset<insert_stable::member>::const_iterator it = x.begin(), end = x.end();
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->tag2_ == 1); ++it; }
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->tag2_ == 2); ++it; }
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->tag2_ == 3); ++it; }
BOOST_TEST(it == end);
}
void stable_insert_test2() {
boost::unordered_multimap<insert_stable::member, int> x;
typedef boost::unordered_multimap<insert_stable::member, int>::const_iterator iterator;
iterator it = x.insert(x.end(), std::make_pair(insert_stable::member(1,1), 1));
it = x.insert(it, std::make_pair(insert_stable::member(1,2), 2));
it = x.insert(it, std::make_pair(insert_stable::member(1,3), 3));
it = x.begin();
iterator end = x.end();
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->first.tag2_ == 1 && it->second == 1); ++it; }
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->first.tag2_ == 2 && it->second == 2); ++it; }
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->first.tag2_ == 3 && it->second == 3); ++it; }
BOOST_TEST(it == end);
}
int main()
{
stable_insert_test1();
stable_insert_test2();
return boost::report_errors();
}

View File

@ -0,0 +1,301 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/input_iterator.hpp"
#include <iostream>
test::seed_t seed(243432);
template <class X>
void unique_insert_tests1(X* = 0)
{
typedef typename X::iterator iterator;
typedef test::ordered<X> ordered;
typedef typename test::ordered<X>::iterator ordered_iterator;
std::cerr<<"insert(value) tests for containers with unique keys.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
test::random_values<X> v(1000);
for(typename test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it)
{
typename X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
std::pair<iterator, bool> r1 = x.insert(*it);
std::pair<ordered_iterator, bool> r2 = tracker.insert(*it);
BOOST_TEST(r1.second == r2.second);
BOOST_TEST(*r1.first == *r2.first);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
template <class X>
void equivalent_insert_tests1(X* = 0)
{
std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
test::random_values<X> v(1000);
for(typename test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it)
{
typename X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
typename X::iterator r1 = x.insert(*it);
typename test::ordered<X>::iterator r2 = tracker.insert(*it);
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
template <class X>
void insert_tests2(X* = 0)
{
typedef typename test::ordered<X> tracker_type;
typedef typename X::iterator iterator;
typedef typename X::const_iterator const_iterator;
typedef typename tracker_type::iterator tracker_iterator;
std::cerr<<"insert(begin(), value) tests.\n";
{
X x;
tracker_type tracker = test::create_ordered(x);
test::random_values<X> v(1000);
for(typename test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it)
{
typename X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
iterator r1 = x.insert(x.begin(), *it);
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
std::cerr<<"insert(end(), value) tests.\n";
{
X x;
X const& x_const = x;
tracker_type tracker = test::create_ordered(x);
test::random_values<X> v(100);
for(typename test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it)
{
typename X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
const_iterator r1 = x.insert(x_const.end(), *it);
tracker_iterator r2 = tracker.insert(tracker.end(), *it);
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
std::cerr<<"insert(pos, value) tests.\n";
{
X x;
const_iterator pos = x.begin();
tracker_type tracker = test::create_ordered(x);
test::random_values<X> v(1000);
for(typename test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it)
{
typename X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
pos = x.insert(pos, *it);
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
BOOST_TEST(*pos == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
std::cerr<<"insert single item range tests.\n";
{
X x;
tracker_type tracker = test::create_ordered(x);
test::random_values<X> v(1000);
for(typename test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it)
{
typename X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
x.insert(it, boost::next(it));
tracker.insert(*it);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
std::cerr<<"insert range tests.\n";
{
X x;
test::random_values<X> v(1000);
x.insert(v.begin(), v.end());
test::check_container(x, v);
test::check_equivalent_keys(x);
}
std::cerr<<"insert input iterator range tests.\n";
{
X x;
test::random_values<X> v(1000);
x.insert(test::input_iterator(v.begin()), test::input_iterator(v.end()));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
}
template <class X>
void map_tests(X* = 0)
{
std::cerr<<"map tests.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
test::random_values<X> v(1000);
for(typename test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it)
{
typename X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
x[it->first] = it->second;
tracker[it->first] = it->second;
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
template <class X>
void associative_insert_range_test(X* = 0)
{
std::cerr<<"associative_insert_range_test\n";
typedef std::list<std::pair<BOOST_DEDUCED_TYPENAME X::key_type, BOOST_DEDUCED_TYPENAME X::mapped_type> > list;
test::random_values<X> v(1000);
list l;
std::copy(v.begin(), v.end(), std::back_inserter(l));
X x; x.insert(l.begin(), l.end());
test::check_equivalent_keys(x);
}
int main()
{
unique_insert_tests1((boost::unordered_set<int>*) 0);
equivalent_insert_tests1((boost::unordered_multiset<int>*) 0);
unique_insert_tests1((boost::unordered_map<int, int>*) 0);
equivalent_insert_tests1((boost::unordered_multimap<int, int>*) 0);
unique_insert_tests1((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
equivalent_insert_tests1((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
unique_insert_tests1((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
equivalent_insert_tests1((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
unique_insert_tests1((boost::unordered_set<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
equivalent_insert_tests1((boost::unordered_multiset<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
unique_insert_tests1((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
equivalent_insert_tests1((boost::unordered_multimap<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
insert_tests2((boost::unordered_set<int>*) 0);
insert_tests2((boost::unordered_multiset<int>*) 0);
insert_tests2((boost::unordered_map<int, int>*) 0);
insert_tests2((boost::unordered_multimap<int, int>*) 0);
insert_tests2((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
insert_tests2((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
insert_tests2((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
insert_tests2((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
insert_tests2((boost::unordered_set<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
insert_tests2((boost::unordered_multiset<test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
insert_tests2((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
insert_tests2((boost::unordered_multimap<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
map_tests((boost::unordered_map<int, int>*) 0);
map_tests((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
map_tests((boost::unordered_map<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
associative_insert_range_test((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
associative_insert_range_test((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
associative_insert_range_test((boost::unordered_multimap<test::equivalent_object, test::equivalent_object, test::hash, test::equal_to, test::allocator<test::equivalent_object> >*) 0);
return boost::report_errors();
}

View File

@ -0,0 +1,84 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/limits.hpp>
#include "../helpers/random_values.hpp"
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4127) // conditional expression is constant
#endif
test::seed_t seed(783656);
template <class X>
void load_factor_tests(X* = 0)
{
X x;
BOOST_TEST(x.max_load_factor() == 1.0);
BOOST_TEST(x.load_factor() == 0);
// A valid implementation could fail these tests, but I think they're
// reasonable.
x.max_load_factor(2.0); BOOST_TEST(x.max_load_factor() == 2.0);
x.max_load_factor(0.5); BOOST_TEST(x.max_load_factor() == 0.5);
}
template <class X>
void insert_test(X*, float mlf)
{
X x;
x.max_load_factor(mlf);
float b = x.max_load_factor();
test::random_values<X> values(1000);
for(typename test::random_values<X>::const_iterator
it = values.begin(), end = values.end(); it != end; ++it)
{
typename X::size_type old_size = x.size(),
old_bucket_count = x.bucket_count();
x.insert(*it);
if(old_size + 1 < b * old_bucket_count)
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
}
template <class X>
void load_factor_insert_tests(X* ptr = 0)
{
insert_test(ptr, 1.0f);
insert_test(ptr, 0.1f);
insert_test(ptr, 100.0f);
insert_test(ptr, (std::numeric_limits<float>::min)());
if(std::numeric_limits<float>::has_infinity)
insert_test(ptr, std::numeric_limits<float>::infinity());
}
int main()
{
load_factor_tests((boost::unordered_set<int>*) 0);
load_factor_tests((boost::unordered_multiset<int>*) 0);
load_factor_tests((boost::unordered_map<int, int>*) 0);
load_factor_tests((boost::unordered_multimap<int, int>*) 0);
load_factor_insert_tests((boost::unordered_set<int>*) 0);
load_factor_insert_tests((boost::unordered_multiset<int>*) 0);
load_factor_insert_tests((boost::unordered_map<int, int>*) 0);
load_factor_insert_tests((boost::unordered_multimap<int, int>*) 0);
return boost::report_errors();
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#pragma warning(disable:4127) // conditional expression is constant
#endif

View File

@ -0,0 +1,69 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
test::seed_t seed(2974);
template <class X>
bool postcondition(X const& x, typename X::size_type n)
{
return x.bucket_count() > x.size() / x.max_load_factor() && x.bucket_count() >= n;
}
template <class X>
void rehash_empty_test1(X* = 0)
{
X x;
x.rehash(10000);
BOOST_TEST(postcondition(x, 10000));
x.rehash(0);
BOOST_TEST(postcondition(x, 0));
}
template <class X>
void rehash_test1(X* = 0)
{
test::random_values<X> v(1000);
test::ordered<X> tracker;
tracker.insert_range(v.begin(), v.end());
X x(v.begin(), v.end());
x.rehash(0); BOOST_TEST(postcondition(x, 0));
tracker.compare(x);
x.max_load_factor(0.25);
x.rehash(0); BOOST_TEST(postcondition(x, 0));
tracker.compare(x);
x.max_load_factor(50.0);
x.rehash(0); BOOST_TEST(postcondition(x, 0));
tracker.compare(x);
x.rehash(1000); BOOST_TEST(postcondition(x, 1000));
tracker.compare(x);
}
template <class X>
void rehash_tests(X* ptr = 0)
{
rehash_empty_test1(ptr);
rehash_test1(ptr);
}
int main() {
rehash_tests((boost::unordered_set<int>*) 0);
rehash_tests((boost::unordered_multiset<int>*) 0);
rehash_tests((boost::unordered_map<int, int>*) 0);
rehash_tests((boost::unordered_multimap<int, int>*) 0);
return boost::report_errors();
}

View File

@ -0,0 +1,138 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#include <algorithm>
#include <iterator>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/invariants.hpp"
test::seed_t seed(783472);
template <class X>
void swap_test_impl(X& x1, X& x2)
{
test::ordered<X> tracker1 = test::create_ordered(x1);
test::ordered<X> tracker2 = test::create_ordered(x2);
tracker1.insert_range(x1.begin(), x1.end());
tracker2.insert_range(x2.begin(), x2.end());
x1.swap(x2);
tracker1.compare(x2);
tracker2.compare(x1);
}
template <class X>
void swap_tests1(X* = 0)
{
{
X x;
swap_test_impl(x, x);
}
{
X x,y;
swap_test_impl(x, y);
}
{
test::random_values<X> v(1000);
X x, y(v.begin(), v.end());
swap_test_impl(x, y);
swap_test_impl(x, y);
}
{
test::random_values<X> vx(1000), vy(1000);
X x(vx.begin(), vx.end()), y(vy.begin(), vy.end());
swap_test_impl(x, y);
swap_test_impl(x, y);
}
}
template <class X>
void swap_tests2(X* ptr = 0)
{
swap_tests1(ptr);
typedef typename X::hasher hasher;
typedef typename X::key_equal key_equal;
typedef typename X::allocator_type allocator_type;
{
X x(0, hasher(1), key_equal(1));
X y(0, hasher(2), key_equal(2));
swap_test_impl(x, y);
}
{
test::random_values<X> v(1000);
X x(v.begin(), v.end(), 0, hasher(1), key_equal(1));
X y(0, hasher(2), key_equal(2));
swap_test_impl(x, y);
}
{
test::random_values<X> vx(100), vy(50);
X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1));
X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2));
swap_test_impl(x, y);
swap_test_impl(x, y);
}
#if BOOST_UNORDERED_SWAP_METHOD == 1
{
test::random_values<X> vx(100), vy(50);
X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
try {
swap_test_impl(x, y);
BOOST_ERROR("Using swap method 1, swapping with unequal allocators didn't throw.");
} catch (std::runtime_error) {}
}
#else
{
test::random_values<X> vx(50), vy(100);
X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
swap_test_impl(x, y);
}
{
test::random_values<X> vx(100), vy(100);
X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1), allocator_type(1));
X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2), allocator_type(2));
swap_test_impl(x, y);
swap_test_impl(x, y);
}
#endif
}
int main()
{
std::cerr<<"Erase unordered_set<int>.\n";
swap_tests1((boost::unordered_set<int>*) 0);
std::cerr<<"\nErase unordered_multiset<int>.\n";
swap_tests1((boost::unordered_multiset<int>*) 0);
std::cerr<<"\nErase unordered_map<int>.\n";
swap_tests1((boost::unordered_map<int, int>*) 0);
std::cerr<<"\nErase unordered_multimap<int>.\n";
swap_tests1((boost::unordered_multimap<int, int>*) 0);
std::cerr<<"\nErase unordered_set<test::object,..>.\n";
swap_tests2((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"\nErase unordered_multiset<test::object,..>.\n";
swap_tests2((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"\nErase unordered_map<test::object,..>.\n";
swap_tests2((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
std::cerr<<"\nErase unordered_multimap<test::object,..>.\n";
swap_tests2((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
return boost::report_errors();
}

View File

@ -0,0 +1,57 @@
// Copyright 2006-2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
struct count_copies
{
static int count;
count_copies() { ++count; }
count_copies(count_copies const&) { ++count; }
private:
count_copies& operator=(count_copies const&);
};
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace boost {
#endif
std::size_t hash_value(count_copies const&) {
return 0;
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
}
#endif
bool operator==(count_copies const&, count_copies const&) {
return true;
}
int count_copies::count;
template <class T>
void unnecessary_copy_test(T*)
{
count_copies::count = 0;
T x;
typename T::value_type a;
BOOST_TEST(count_copies::count == 1);
x.insert(a);
BOOST_TEST(count_copies::count == 2);
}
int main()
{
unnecessary_copy_test((boost::unordered_set<count_copies>*) 0);
unnecessary_copy_test((boost::unordered_multiset<count_copies>*) 0);
unnecessary_copy_test((boost::unordered_map<int, count_copies>*) 0);
unnecessary_copy_test((boost::unordered_multimap<int, count_copies>*) 0);
return boost::report_errors();
}