mirror of
https://github.com/boostorg/unordered.git
synced 2025-06-25 11:51:33 +02:00
Compare commits
56 Commits
svn-trunk
...
boost-1.44
Author | SHA1 | Date | |
---|---|---|---|
392029c246 | |||
8b4c480d47 | |||
70ca44b503 | |||
795d9f0aa7 | |||
ec97640b1b | |||
d3ca85bdbd | |||
fe2a6c521b | |||
958738c7af | |||
3fb7d15f5b | |||
2b212d7c49 | |||
aa0e8eedd2 | |||
f962857e68 | |||
02bf8f288e | |||
144d8963a3 | |||
f709c16d70 | |||
a3e57838ed | |||
2221c8334e | |||
584eaad67a | |||
14e09a5456 | |||
06b0b1d31c | |||
3529bc00dc | |||
1e7fe6a2d0 | |||
df1dad5cb6 | |||
1bc3ae3d9d | |||
60ecf12779 | |||
241316e0d9 | |||
9c43533655 | |||
ae09b0dd24 | |||
b018f8b173 | |||
0b4241833d | |||
e911a8011b | |||
f02cc7775d | |||
4e6b5de196 | |||
fb71e0618d | |||
694398f0e1 | |||
ab62d33495 | |||
b475ba05c0 | |||
60e3e96b48 | |||
c0e472755e | |||
6f45d36d97 | |||
2e9cf20cd0 | |||
f7c664a359 | |||
0921f8076d | |||
b8e8ffa242 | |||
07e715fceb | |||
89ab17cce5 | |||
517e39fc23 | |||
93141c26b9 | |||
dd2a994874 | |||
6571648bac | |||
f20f72bade | |||
4e4f99d51f | |||
56b9e0da1a | |||
4f27a146ef | |||
c8d0cb88ad | |||
5a898f2419 |
@ -8,11 +8,6 @@ path-constant admonishment_location : ../../../../doc/src/images ;
|
||||
|
||||
xml unordered : unordered.qbk ;
|
||||
boostbook standalone : unordered :
|
||||
<xsl:param>admon.graphics.path=images/
|
||||
<xsl:param>navig.graphics.path=images/
|
||||
<xsl:param>html.stylesheet=boostbook.css
|
||||
<xsl:param>boost.root=../../../..
|
||||
<xsl:param>boost.libraries=../../../libraries.htm
|
||||
<xsl:param>chunk.first.sections=1
|
||||
<xsl:param>chunk.section.depth=2
|
||||
<xsl:param>generate.section.toc.level=2
|
||||
@ -23,10 +18,15 @@ boostbook standalone : unordered :
|
||||
<xsl:param>boost.compact.function=0
|
||||
<xsl:param>boost.compact.enum=0
|
||||
|
||||
<dependency>css
|
||||
<dependency>images
|
||||
# HTML Options:
|
||||
|
||||
<format>html:<xsl:param>boost.root=../../../..
|
||||
<format>html:<xsl:param>img.src.path=../../../../doc/html/
|
||||
<format>xhtml:<xsl:param>boost.root=../../../..
|
||||
<format>xhtml:<xsl:param>img.src.path=../../../../doc/html/
|
||||
|
||||
# PDF Options:
|
||||
|
||||
# TOC Generation: this is needed for FOP-0.9 and later:
|
||||
<xsl:param>fop1.extensions=0
|
||||
<format>pdf:<xsl:param>xep.extensions=1
|
||||
@ -51,11 +51,6 @@ boostbook standalone : unordered :
|
||||
<format>pdf:<xsl:param>img.src.path=$(images_location)/
|
||||
#<format>pdf:<xsl:param>admon.graphics.path=$(admonishment_location)
|
||||
<format>pdf:<xsl:param>draft.mode="no"
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/libs/unordered/doc/html
|
||||
;
|
||||
|
||||
install css : [ glob $(BOOST_ROOT)/doc/src/*.css ]
|
||||
: <location>html ;
|
||||
install images : [ glob $(BOOST_ROOT)/doc/src/images/*.png ]
|
||||
: <location>html/images ;
|
||||
explicit css ;
|
||||
explicit images ;
|
||||
|
@ -1,3 +1,8 @@
|
||||
<!--
|
||||
Copyright Daniel James 2008-2009
|
||||
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 id="unordered.bibliography">
|
||||
<title>Bibliography</title>
|
||||
<bibliography>
|
||||
|
@ -115,6 +115,15 @@ or close to the hint - unless your hint is unreasonably small or large.
|
||||
[table Methods for Controlling Bucket Size
|
||||
[[Method] [Description]]
|
||||
|
||||
[
|
||||
[`X(size_type n)`]
|
||||
[Construct an empty container with at least `n` buckets (`X` is the container type).]
|
||||
]
|
||||
[
|
||||
[`X(InputIterator i, InputIterator j, size_type n)`]
|
||||
[Construct an empty container with at least `n` buckets and insert elements
|
||||
from the range \[`i`, `j`) (`X` is the container type).]
|
||||
]
|
||||
[
|
||||
[`float load_factor() const`]
|
||||
[The average number of elements per bucket.]
|
||||
|
101
doc/changes.qbk
101
doc/changes.qbk
@ -10,7 +10,7 @@
|
||||
Initial review version, for the review conducted from 7th December 2007 to
|
||||
16th December 2007.
|
||||
|
||||
[h2 1.35.0 Add-on - 31st Match 2008]
|
||||
[h2 1.35.0 Add-on - 31st March 2008]
|
||||
|
||||
Unofficial release uploaded to vault, to be used with Boost 1.35.0. Incorporated
|
||||
many of the suggestions from the review.
|
||||
@ -31,7 +31,102 @@ First official release.
|
||||
* Emplace support when rvalue references and variadic template are available.
|
||||
* More efficient node allocation when rvalue references and variadic template
|
||||
are available.
|
||||
* Added equality operators and hash functions
|
||||
([@http://svn.boost.org/trac/boost/ticket/1557 Ticket 1557]).
|
||||
* Added equality operators.
|
||||
|
||||
[h2 Boost 1.37.0]
|
||||
|
||||
* Rename overload of `emplace` with hint, to `emplace_hint` as specified in
|
||||
[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2691.pdf n2691].
|
||||
* Provide forwarding headers at `<boost/unordered/unordered_map_fwd.hpp>` and
|
||||
`<boost/unordered/unordered_set_fwd.hpp>`.
|
||||
* Move all the implementation inside `boost/unordered`, to assist
|
||||
modularization and hopefully make it easier to track changes in subversion.
|
||||
|
||||
[h2 Boost 1.38.0]
|
||||
|
||||
* Use [@boost:/libs/utility/swap.html `boost::swap`].
|
||||
* [@https://svn.boost.org/trac/boost/ticket/2237 Ticket 2237]:
|
||||
Document that the equality and inequality operators are undefined for two
|
||||
objects if their equality predicates aren't equivalent. Thanks to Daniel
|
||||
Krügler.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/1710 Ticket 1710]:
|
||||
Use a larger prime number list. Thanks to Thorsten Ottosen and Hervé
|
||||
Brönnimann.
|
||||
* Use
|
||||
[@boost:/libs/type_traits/doc/html/boost_typetraits/category/alignment.html
|
||||
aligned storage] to store the types. This changes the way the allocator is
|
||||
used to construct nodes. It used to construct the node with two calls to
|
||||
the allocator's `construct` method - once for the pointers and once for the
|
||||
value. It now constructs the node with a single call to construct and
|
||||
then constructs the value using in place construction.
|
||||
* Add support for C++0x initializer lists where they're available (currently
|
||||
only g++ 4.4 in C++0x mode).
|
||||
|
||||
[h2 Boost 1.39.0]
|
||||
|
||||
* [@https://svn.boost.org/trac/boost/ticket/2756 Ticket 2756]: Avoid a warning
|
||||
on Visual C++ 2009.
|
||||
* Some other minor internal changes to the implementation, tests and
|
||||
documentation.
|
||||
* Avoid an unnecessary copy in `operator[]`.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/2975 Ticket 2975]: Fix length of
|
||||
prime number list.
|
||||
|
||||
[h2 Boost 1.40.0]
|
||||
|
||||
* [@https://svn.boost.org/trac/boost/ticket/2975 Ticket 2975]:
|
||||
Store the prime list as a preprocessor sequence - so that it will always get
|
||||
the length right if it changes again in the future.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/1978 Ticket 1978]:
|
||||
Implement `emplace` for all compilers.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/2908 Ticket 2908],
|
||||
[@https://svn.boost.org/trac/boost/ticket/3096 Ticket 3096]:
|
||||
Some workarounds for old versions of borland, including adding explicit
|
||||
destructors to all containers.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/3082 Ticket 3082]:
|
||||
Disable incorrect Visual C++ warnings.
|
||||
* Better configuration for C++0x features when the headers aren't available.
|
||||
* Create less buckets by default.
|
||||
|
||||
[h2 Boost 1.41.0 - Major update]
|
||||
|
||||
* The original version made heavy use of macros to sidestep some of the older
|
||||
compilers' poor template support. But since I no longer support those
|
||||
compilers and the macro use was starting to become a maintenance burden it
|
||||
has been rewritten to use templates instead of macros for the implementation
|
||||
classes.
|
||||
|
||||
* The container objcet is now smaller thanks to using `boost::compressed_pair`
|
||||
for EBO and a slightly different function buffer - now using a bool instead
|
||||
of a member pointer.
|
||||
|
||||
* Buckets are allocated lazily which means that constructing an empty container
|
||||
will not allocate any memory.
|
||||
|
||||
[h2 Boost 1.42.0]
|
||||
|
||||
* Support instantiating the containers with incomplete value types.
|
||||
* Reduced the number of warnings (mostly in tests).
|
||||
* Improved codegear compatibility.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3693 Ticket 3693]:
|
||||
Add `erase_return_void` as a temporary workaround for the current
|
||||
`erase` which can be inefficient because it has to find the next
|
||||
element to return an iterator.
|
||||
* Add templated find overload for compatible keys.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3773 Ticket 3773]:
|
||||
Add missing `std` qualifier to `ptrdiff_t`.
|
||||
* Some code formatting changes to fit almost all lines into 80 characters.
|
||||
|
||||
[h2 Boost 1.43.0]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3966 Ticket 3966]:
|
||||
`erase_return_void` is now `quick_erase`, which is the
|
||||
[@http://home.roadrunner.com/~hinnant/issue_review/lwg-active.html#579
|
||||
current forerunner for resolving the slow erase by iterator], although
|
||||
there's a strong possibility that this may change in the future. The old
|
||||
method name remains for backwards compatibility but is considered deprecated
|
||||
and will be removed in a future release.
|
||||
* Use Boost.Exception.
|
||||
* Stop using deprecated `BOOST_HAS_*` macros.
|
||||
|
||||
[endsect]
|
||||
|
@ -72,7 +72,7 @@
|
||||
[
|
||||
[Can be compared using the `==`, `!=`, `<`, `<=`, `>`, `>=` operators.]
|
||||
[No comparison operators are defined in the standard, although
|
||||
[link unordered.rationale.equality_operator
|
||||
[link unordered.rationale.equality_operators
|
||||
implementations might extend the containers to support `==` and
|
||||
`!=`].]
|
||||
]
|
||||
|
@ -13,7 +13,7 @@ is declared as:
|
||||
class Key, class Mapped,
|
||||
class Hash = ``[classref boost::hash]``<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<Key> >
|
||||
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
||||
class ``[classref boost::unordered_map unordered_map]``;
|
||||
|
||||
The hash function comes first as you might want to change the hash function
|
||||
@ -23,8 +23,8 @@ but not the equality predicate. For example, if you wanted to use the
|
||||
[import src_code/dictionary.cpp]
|
||||
[case_sensitive_dictionary_fnv]
|
||||
|
||||
An example implementation of FNV-1, and some other hash functions are supplied
|
||||
in the examples directory.
|
||||
There is an [@boost:/libs/unordered/examples/fnv1.hpp implementation
|
||||
of FNV-1] in the examples directory.
|
||||
|
||||
If you wish to use a different equality function,
|
||||
you will also need to use a matching hash function. For
|
||||
@ -38,9 +38,19 @@ Which you can then use in a case insensitive dictionary:
|
||||
[case_insensitive_dictionary]
|
||||
|
||||
This is a simplified version of the example at
|
||||
[@../../libs/unordered/examples/case_insensitive.hpp /libs/unordered/examples/case_insensitive.hpp]
|
||||
[@boost:/libs/unordered/examples/case_insensitive.hpp /libs/unordered/examples/case_insensitive.hpp]
|
||||
which supports other locales and string types.
|
||||
|
||||
[caution
|
||||
Be careful when using the equality (`==`) operator with custom equality
|
||||
predicates, especially if you're using a function pointer. If you compare two
|
||||
containers with different equality predicates then the result is undefined.
|
||||
For most stateless function objects this is impossible - since you can only
|
||||
compare objects with the same equality predicate you know the equality
|
||||
predicates must be equal. But if you're using function pointers or a stateful
|
||||
equality predicate (e.g. boost::function) then you can get into trouble.
|
||||
]
|
||||
|
||||
[h2 Custom Types]
|
||||
|
||||
Similarly, a custom hash function can be used for custom types:
|
||||
|
@ -9,7 +9,7 @@
|
||||
[@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
|
||||
[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2960.pdf
|
||||
Working Draft of the C++ Standard]]
|
||||
[def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table
|
||||
hash table]]
|
||||
@ -36,9 +36,7 @@ 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__.
|
||||
the __draft__.
|
||||
|
||||
`unordered_set` and `unordered_multiset` are defined in the header
|
||||
<[headerref boost/unordered_set.hpp]>
|
||||
|
@ -5,12 +5,6 @@
|
||||
[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 2007 version of the working draft standard]]
|
||||
|
||||
[section:rationale Implementation Rationale]
|
||||
|
||||
@ -96,117 +90,52 @@ efficiency advantage of power of 2 hash tables.
|
||||
|
||||
So, this implementation uses a prime number for the hash table size.
|
||||
|
||||
[h2 Equality operators]
|
||||
|
||||
`operator==` and `operator!=` are not included in the standard, but I've
|
||||
added them as I think they could be useful and can be implemented
|
||||
fairly efficiently. They are specified differently to the other standard
|
||||
containers, comparing keys using the equality predicate rather than
|
||||
`operator==`.
|
||||
|
||||
It's also different to the proposal
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2944.pdf n2944].
|
||||
which uses the equality operators for the whole of `value_type`. This
|
||||
implementation just uses the key equality function for the key,
|
||||
and `mapped_type`'s equality operator in `unordered_map` and
|
||||
`unordered_multimap` for the mapped part of the element.
|
||||
|
||||
Also, in `unordered_multimap`, the mapped values for a group of elements with
|
||||
equivalent keys are only considered equal if they are in the same order,
|
||||
in n2944 they just need to be a permutation of each other. Since the
|
||||
order of elements with equal keys is now defined to be stable, it seems to me
|
||||
that their order can be considered part of the container's value.
|
||||
|
||||
[h2 Active Issues and Proposals]
|
||||
|
||||
[h3 Removing unused allocator functions]
|
||||
[h3 C++0x allocators]
|
||||
|
||||
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].
|
||||
Recent drafts have included an overhaul of the allocators, but this was
|
||||
dependent on concepts which are no longer in the standard.
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2946.pdf n2946]
|
||||
attempts to respecify them without concepts. I'll try to implement this (or
|
||||
an appropriate later version) in a future version of boost, possibly changed
|
||||
a little to accomodate non-C++0x compilers.
|
||||
|
||||
[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. We’ve identified two such
|
||||
models: the “Moves with Value” allocator model and the “Scoped” allocator model.
|
||||
|
||||
In the “Moves with Value” allocator model, the copy constructor of an allocator-aware
|
||||
class will copy both the value and the allocator from its argument. This is the model
|
||||
specified in the C++03 standard. With this model, inserting an object into a container
|
||||
usually causes the new container item to copy the allocator from the object that was
|
||||
inserted. This model can be useful in special circumstances, e.g., if the items within a
|
||||
container use an allocator that is specially tuned to the item’s type.
|
||||
|
||||
In the “Scoped” allocator model, the allocator used to construct an object is determined
|
||||
by the context of that object, much like a storage class. With this model, inserting an
|
||||
object into a container causes the new container item to use the same allocator as the
|
||||
container. To avoid allocators being used in the wrong context, the allocator is never
|
||||
copied during copy or move construction. Thus, it is possible using this model to use
|
||||
allocators based on short-lived resources without fear that an object will transfer its
|
||||
allocator to a copy that might outlive the (shared) allocator resource. This model is
|
||||
reasonably safe and generally useful on a large scale. There was strong support in the
|
||||
2005 Tremblant meeting for pursuing an allocator model that propagates allocators
|
||||
from container to contained objects.
|
||||
]
|
||||
|
||||
With these models the choice becomes clearer:
|
||||
|
||||
[:
|
||||
I introduced the “Moves with Value” allocator model and the
|
||||
“Scoped” allocator model. In the former case, the allocator is copied when the container
|
||||
is copy-constructed. In the latter case it is not. Swapping the allocators is the right thing
|
||||
to do if the containers conform to the “Moves with Value” allocator model and
|
||||
absolutely the wrong thing to do if the containers conform to the “Scoped” allocator
|
||||
model. With the two allocator models well-defined, the desired behavior becomes clear.
|
||||
]
|
||||
|
||||
The proposal is that allocators are swapped if the allocator follows the
|
||||
"Moves with Value" model and the allocator is swappable. Otherwise a slow swap
|
||||
is used. Since containers currently only support the "Moves with Value" model
|
||||
this is consistent with the committee's current recommendation (although it
|
||||
suggests using a trait to detect if the allocator is swappable rather than a
|
||||
concept).
|
||||
|
||||
Since there is currently neither have a swappable trait or concept for
|
||||
allocators this implementation always performs a slow swap.
|
||||
Issue 431: Swapping containers with unequal allocators]. This has been resolved
|
||||
with the new allocator specification, so this should be fixed when
|
||||
support is added.
|
||||
|
||||
[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
|
||||
It wan't 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.
|
||||
Since [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2691.pdf
|
||||
n2691] it's been specified that they do and this implementation follows that.
|
||||
|
||||
[endsect]
|
||||
|
824
doc/ref.xml
824
doc/ref.xml
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "../../examples/hash_functions/fnv-1.hpp"
|
||||
#include "../../examples/fnv1.hpp"
|
||||
|
||||
//[case_insensitive_functions
|
||||
struct iequal_to
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
[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]
|
||||
[@http://www.boost.org/LICENSE_1_0.txt])
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
|
69
examples/fnv1.hpp
Normal file
69
examples/fnv1.hpp
Normal file
@ -0,0 +1,69 @@
|
||||
|
||||
// Copyright 2008-2009 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 code is also released into the public domain.
|
||||
|
||||
// Algorithm from: http://www.isthe.com/chongo/tech/comp/fnv/
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace hash
|
||||
{
|
||||
template <std::size_t FnvPrime, std::size_t OffsetBasis>
|
||||
struct basic_fnv_1
|
||||
{
|
||||
std::size_t operator()(std::string const& text) const
|
||||
{
|
||||
std::size_t hash = OffsetBasis;
|
||||
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 OffsetBasis>
|
||||
struct basic_fnv_1a
|
||||
{
|
||||
std::size_t operator()(std::string const& text) const
|
||||
{
|
||||
std::size_t hash = OffsetBasis;
|
||||
for(std::string::const_iterator it = text.begin(), end = text.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
hash ^= *it;
|
||||
hash *= FnvPrime;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
// For 32 bit machines:
|
||||
const std::size_t fnv_prime = 16777619u;
|
||||
const std::size_t fnv_offset_basis = 2166136261u;
|
||||
|
||||
// For 64 bit machines:
|
||||
// const std::size_t fnv_prime = 1099511628211u;
|
||||
// const std::size_t fnv_offset_basis = 14695981039346656037u;
|
||||
|
||||
// For 128 bit machines:
|
||||
// const std::size_t fnv_prime = 309485009821345068724781401u;
|
||||
// const std::size_t fnv_offset_basis =
|
||||
// 275519064689413815358837431229664493455u;
|
||||
|
||||
// For 256 bit machines:
|
||||
// const std::size_t fnv_prime =
|
||||
// 374144419156711147060143317175368453031918731002211u;
|
||||
// const std::size_t fnv_offset_basis =
|
||||
// 100029257958052580907070968620625704837092796014241193945225284501741471925557u;
|
||||
|
||||
typedef basic_fnv_1<fnv_prime, fnv_offset_basis> fnv_1;
|
||||
typedef basic_fnv_1a<fnv_prime, fnv_offset_basis> fnv_1a;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
// 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) const
|
||||
{
|
||||
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) const
|
||||
{
|
||||
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 = 2166136261u;
|
||||
// 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;
|
||||
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Copyright 2005-2009 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)
|
||||
|
||||
// A couple of templates to make using allocators easier.
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
||||
|
||||
@ -21,214 +23,86 @@
|
||||
# include <boost/detail/allocator_utilities.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/mpl/aux_/config/eti.hpp>
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
namespace boost {
|
||||
namespace unordered_detail {
|
||||
// rebind_wrap
|
||||
//
|
||||
// Rebind allocators. For some problematic libraries, use rebind_to
|
||||
// from <boost/detail/allocator_utilities.hpp>.
|
||||
|
||||
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
|
||||
template <class Alloc, class T>
|
||||
struct rebind_wrap : ::boost::detail::allocator::rebind_to<Alloc, T> {};
|
||||
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;
|
||||
};
|
||||
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(); }
|
||||
// allocator_array_constructor
|
||||
//
|
||||
// Allocate and construct an array in an exception safe manner, and
|
||||
// clean up if an exception is thrown before the container takes charge
|
||||
// of it.
|
||||
|
||||
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 Allocator>
|
||||
struct allocator_array_constructor
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Allocator::pointer pointer;
|
||||
|
||||
template <class Ptr>
|
||||
inline Ptr null_ptr() { Ptr x; reset(x); return x; }
|
||||
#endif
|
||||
Allocator& alloc_;
|
||||
pointer ptr_;
|
||||
pointer constructed_;
|
||||
std::size_t length_;
|
||||
|
||||
// Work around for Microsoft's ETI bug.
|
||||
|
||||
template <class Allocator> struct allocator_value_type
|
||||
allocator_array_constructor(Allocator& a)
|
||||
: alloc_(a), ptr_(), constructed_(), length_(0)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Allocator::value_type type;
|
||||
};
|
||||
constructed_ = pointer();
|
||||
ptr_ = pointer();
|
||||
}
|
||||
|
||||
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)
|
||||
~allocator_array_constructor() {
|
||||
if (ptr_) {
|
||||
for(pointer p = ptr_; p != constructed_; ++p)
|
||||
alloc_.destroy(p);
|
||||
|
||||
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
|
||||
alloc_.deallocate(ptr_, length_);
|
||||
}
|
||||
}
|
||||
|
||||
~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
|
||||
template <class V>
|
||||
void construct(V const& v, std::size_t l)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME allocator_pointer<Allocator>::type pointer;
|
||||
BOOST_ASSERT(!ptr_);
|
||||
length_ = l;
|
||||
ptr_ = alloc_.allocate(length_);
|
||||
pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
|
||||
for(constructed_ = ptr_; constructed_ != end; ++constructed_)
|
||||
alloc_.construct(constructed_, v);
|
||||
}
|
||||
|
||||
Allocator& alloc_;
|
||||
pointer ptr_;
|
||||
pointer constructed_;
|
||||
std::size_t length_;
|
||||
pointer get() const
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
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_ + static_cast<std::ptrdiff_t>(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&);
|
||||
};
|
||||
}
|
||||
}
|
||||
pointer release()
|
||||
{
|
||||
pointer p(ptr_);
|
||||
ptr_ = pointer();
|
||||
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
|
||||
|
183
include/boost/unordered/detail/buckets.hpp
Normal file
183
include/boost/unordered/detail/buckets.hpp
Normal file
@ -0,0 +1,183 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2009 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_MANAGER_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered/detail/node.hpp>
|
||||
#include <boost/unordered/detail/util.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Buckets
|
||||
|
||||
template <class A, class G>
|
||||
inline std::size_t hash_buckets<A, G>::max_bucket_count() const {
|
||||
// -1 to account for the sentinel.
|
||||
return prev_prime(this->bucket_alloc().max_size() - 1);
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
|
||||
hash_buckets<A, G>::get_bucket(std::size_t num) const
|
||||
{
|
||||
return buckets_ + static_cast<std::ptrdiff_t>(num);
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
|
||||
hash_buckets<A, G>::bucket_ptr_from_hash(std::size_t hashed) const
|
||||
{
|
||||
return get_bucket(hashed % bucket_count_);
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
std::size_t hash_buckets<A, G>::bucket_size(std::size_t index) const
|
||||
{
|
||||
if(!buckets_) return 0;
|
||||
bucket_ptr ptr = get_bucket(index)->next_;
|
||||
std::size_t count = 0;
|
||||
while(ptr) {
|
||||
++count;
|
||||
ptr = ptr->next_;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::node_ptr
|
||||
hash_buckets<A, G>::bucket_begin(std::size_t num) const
|
||||
{
|
||||
return buckets_ ? get_bucket(num)->next_ : node_ptr();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Delete
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::delete_node(node_ptr b)
|
||||
{
|
||||
node* raw_ptr = static_cast<node*>(&*b);
|
||||
boost::unordered_detail::destroy(&raw_ptr->value());
|
||||
real_node_ptr n(node_alloc().address(*raw_ptr));
|
||||
node_alloc().destroy(n);
|
||||
node_alloc().deallocate(n, 1);
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::clear_bucket(bucket_ptr b)
|
||||
{
|
||||
node_ptr node_it = b->next_;
|
||||
b->next_ = node_ptr();
|
||||
|
||||
while(node_it) {
|
||||
node_ptr node_to_delete = node_it;
|
||||
node_it = node_it->next_;
|
||||
delete_node(node_to_delete);
|
||||
}
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::delete_buckets()
|
||||
{
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
|
||||
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
||||
clear_bucket(begin);
|
||||
}
|
||||
|
||||
// Destroy the buckets (including the sentinel bucket).
|
||||
++end;
|
||||
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
||||
bucket_alloc().destroy(begin);
|
||||
}
|
||||
|
||||
bucket_alloc().deallocate(this->buckets_, this->bucket_count_ + 1);
|
||||
|
||||
this->buckets_ = bucket_ptr();
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline std::size_t hash_buckets<A, G>::delete_nodes(
|
||||
node_ptr begin, node_ptr end)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
while(begin != end) {
|
||||
node_ptr n = begin;
|
||||
begin = begin->next_;
|
||||
delete_node(n);
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors and Destructors
|
||||
|
||||
template <class A, class G>
|
||||
inline hash_buckets<A, G>::hash_buckets(
|
||||
node_allocator const& a, std::size_t bucket_count)
|
||||
: buckets_(),
|
||||
bucket_count_(bucket_count),
|
||||
allocators_(a,a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline hash_buckets<A, G>::~hash_buckets()
|
||||
{
|
||||
if(this->buckets_) { this->delete_buckets(); }
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::create_buckets()
|
||||
{
|
||||
// The array constructor will clean up in the event of an
|
||||
// exception.
|
||||
allocator_array_constructor<bucket_allocator>
|
||||
constructor(bucket_alloc());
|
||||
|
||||
// Creates an extra bucket to act as a sentinel.
|
||||
constructor.construct(bucket(), this->bucket_count_ + 1);
|
||||
|
||||
// Set up the sentinel (node_ptr cast)
|
||||
bucket_ptr sentinel = constructor.get() +
|
||||
static_cast<std::ptrdiff_t>(this->bucket_count_);
|
||||
sentinel->next_ = sentinel;
|
||||
|
||||
// Only release the buckets once everything is successfully
|
||||
// done.
|
||||
this->buckets_ = constructor.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors and Destructors
|
||||
|
||||
// no throw
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::move(hash_buckets& other)
|
||||
{
|
||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||
if(this->buckets_) { this->delete_buckets(); }
|
||||
this->buckets_ = other.buckets_;
|
||||
this->bucket_count_ = other.bucket_count_;
|
||||
other.buckets_ = bucket_ptr();
|
||||
other.bucket_count_ = 0;
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::swap(hash_buckets<A, G>& other)
|
||||
{
|
||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||
std::swap(buckets_, other.buckets_);
|
||||
std::swap(bucket_count_, other.bucket_count_);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
@ -1,22 +0,0 @@
|
||||
|
||||
// Copyright 2008 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_DETAIL_CONFIG_HEADER)
|
||||
#define BOOST_UNORDERED_DETAIL_CONFIG_HEADER
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(BOOST_NO_SFINAE)
|
||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
#elif defined(__GNUC__) && \
|
||||
(__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
|
||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \
|
||||
BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \
|
||||
BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593))
|
||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
#endif
|
||||
|
||||
#endif
|
304
include/boost/unordered/detail/equivalent.hpp
Normal file
304
include/boost/unordered/detail/equivalent.hpp
Normal file
@ -0,0 +1,304 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2009 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_EQUIVALENT_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
||||
|
||||
#include <boost/unordered/detail/table.hpp>
|
||||
#include <boost/unordered/detail/extract_key.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
template <class T>
|
||||
class hash_equivalent_table : public T::table
|
||||
{
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::table table;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node node;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
|
||||
|
||||
// Constructors
|
||||
|
||||
hash_equivalent_table(std::size_t n,
|
||||
hasher const& hf, key_equal const& eq, value_allocator const& a)
|
||||
: table(n, hf, eq, a) {}
|
||||
hash_equivalent_table(hash_equivalent_table const& x)
|
||||
: table(x, x.node_alloc()) {}
|
||||
hash_equivalent_table(hash_equivalent_table const& x,
|
||||
value_allocator const& a)
|
||||
: table(x, a) {}
|
||||
hash_equivalent_table(hash_equivalent_table& x, move_tag m)
|
||||
: table(x, m) {}
|
||||
hash_equivalent_table(hash_equivalent_table& x,
|
||||
value_allocator const& a, move_tag m)
|
||||
: table(x, a, m) {}
|
||||
~hash_equivalent_table() {}
|
||||
|
||||
// Insert methods
|
||||
|
||||
iterator_base emplace_impl(node_constructor& a);
|
||||
void emplace_impl_no_rehash(node_constructor& a);
|
||||
|
||||
// equals
|
||||
|
||||
bool equals(hash_equivalent_table const&) const;
|
||||
|
||||
inline node_ptr add_node(node_constructor& a,
|
||||
bucket_ptr bucket, node_ptr pos);
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
template <class... Args>
|
||||
iterator_base emplace(Args&&... args);
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
||||
iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n));
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
||||
#endif
|
||||
|
||||
template <class I>
|
||||
void insert_for_range(I i, I j, forward_traversal_tag);
|
||||
template <class I>
|
||||
void insert_for_range(I i, I j, boost::incrementable_traversal_tag);
|
||||
template <class I>
|
||||
void insert_range(I i, I j);
|
||||
};
|
||||
|
||||
template <class H, class P, class A>
|
||||
struct multiset : public types<
|
||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
H, P, A,
|
||||
set_extractor<BOOST_DEDUCED_TYPENAME A::value_type>,
|
||||
grouped>
|
||||
{
|
||||
typedef hash_equivalent_table<multiset<H, P, A> > impl;
|
||||
typedef hash_table<multiset<H, P, A> > table;
|
||||
};
|
||||
|
||||
template <class K, class H, class P, class A>
|
||||
struct multimap : public types<
|
||||
K, BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
H, P, A,
|
||||
map_extractor<K, BOOST_DEDUCED_TYPENAME A::value_type>,
|
||||
grouped>
|
||||
{
|
||||
typedef hash_equivalent_table<multimap<K, H, P, A> > impl;
|
||||
typedef hash_table<multimap<K, H, P, A> > table;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Equality
|
||||
|
||||
template <class T>
|
||||
bool hash_equivalent_table<T>
|
||||
::equals(hash_equivalent_table<T> const& other) const
|
||||
{
|
||||
if(this->size_ != other.size_) return false;
|
||||
if(!this->size_) return true;
|
||||
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i)
|
||||
{
|
||||
node_ptr it1 = i->next_;
|
||||
while(BOOST_UNORDERED_BORLAND_BOOL(it1))
|
||||
{
|
||||
node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1));
|
||||
if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
|
||||
|
||||
node_ptr end1 = node::next_group(it1);
|
||||
node_ptr end2 = node::next_group(it2);
|
||||
|
||||
do {
|
||||
if(!extractor::compare_mapped(
|
||||
node::get_value(it1), node::get_value(it2)))
|
||||
return false;
|
||||
it1 = it1->next_;
|
||||
it2 = it2->next_;
|
||||
} while(it1 != end1 && it2 != end2);
|
||||
if(it1 != end1 || it2 != end2) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// A convenience method for adding nodes.
|
||||
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::node_ptr
|
||||
hash_equivalent_table<T>
|
||||
::add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos)
|
||||
{
|
||||
node_ptr n = a.release();
|
||||
if(BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
node::add_after_node(n, pos);
|
||||
}
|
||||
else {
|
||||
node::add_to_bucket(n, *bucket);
|
||||
if(bucket < this->cached_begin_bucket_)
|
||||
this->cached_begin_bucket_ = bucket;
|
||||
}
|
||||
++this->size_;
|
||||
return n;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Insert methods
|
||||
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME
|
||||
hash_equivalent_table<T>::iterator_base
|
||||
hash_equivalent_table<T>::emplace_impl(node_constructor& a)
|
||||
{
|
||||
key_type const& k = this->get_key(a.value());
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
|
||||
if(!this->size_) {
|
||||
return this->emplace_empty_impl_with_node(a, 1);
|
||||
}
|
||||
else {
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr position = this->find_iterator(bucket, k);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->reserve_for_insert(this->size_ + 1))
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
return iterator_base(bucket, add_node(a, bucket, position));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_equivalent_table<T>
|
||||
::emplace_impl_no_rehash(node_constructor& a)
|
||||
{
|
||||
key_type const& k = this->get_key(a.value());
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
add_node(a, bucket, this->find_iterator(bucket, k));
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
// Emplace (equivalent key containers)
|
||||
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class... Args>
|
||||
BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base
|
||||
hash_equivalent_table<T>
|
||||
::emplace(Args&&... args)
|
||||
{
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(*this);
|
||||
a.construct(std::forward<Args>(args)...);
|
||||
|
||||
return emplace_impl(a);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base \
|
||||
hash_equivalent_table<T> \
|
||||
::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
node_constructor a(*this); \
|
||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
return emplace_impl(a); \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class I>
|
||||
inline void hash_equivalent_table<T>
|
||||
::insert_for_range(I i, I j, forward_traversal_tag)
|
||||
{
|
||||
if(i == j) return;
|
||||
std::size_t distance = unordered_detail::distance(i, j);
|
||||
if(distance == 1) {
|
||||
emplace(*i);
|
||||
}
|
||||
else {
|
||||
node_constructor a(*this);
|
||||
|
||||
// Only require basic exception safety here
|
||||
if(this->size_) {
|
||||
this->reserve_for_insert(this->size_ + distance);
|
||||
}
|
||||
else {
|
||||
a.construct(*i++);
|
||||
this->emplace_empty_impl_with_node(a, distance);
|
||||
}
|
||||
|
||||
for (; i != j; ++i) {
|
||||
a.construct(*i);
|
||||
emplace_impl_no_rehash(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class I>
|
||||
inline void hash_equivalent_table<T>
|
||||
::insert_for_range(I i, I j, boost::incrementable_traversal_tag)
|
||||
{
|
||||
node_constructor a(*this);
|
||||
for (; i != j; ++i) {
|
||||
a.construct(*i);
|
||||
emplace_impl(a);
|
||||
}
|
||||
}
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class I>
|
||||
void hash_equivalent_table<T>::insert_range(I i, I j)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
|
||||
iterator_traversal_tag;
|
||||
insert_for_range(i, j, iterator_traversal_tag);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
148
include/boost/unordered/detail/extract_key.hpp
Normal file
148
include/boost/unordered/detail/extract_key.hpp
Normal file
@ -0,0 +1,148 @@
|
||||
|
||||
// Copyright (C) 2005-2009 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_EXTRACT_KEY_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered_detail {
|
||||
|
||||
// key extractors
|
||||
//
|
||||
// no throw
|
||||
//
|
||||
// 'extract_key' is called with the emplace parameters to return a
|
||||
// key if available or 'no_key' is one isn't and will need to be
|
||||
// constructed. This could be done by overloading the emplace implementation
|
||||
// for the different cases, but that's a bit tricky on compilers without
|
||||
// variadic templates.
|
||||
|
||||
struct no_key {
|
||||
no_key() {}
|
||||
template <class T> no_key(T const&) {}
|
||||
};
|
||||
|
||||
template <class ValueType>
|
||||
struct set_extractor
|
||||
{
|
||||
typedef ValueType value_type;
|
||||
typedef ValueType key_type;
|
||||
|
||||
static key_type const& extract(key_type const& v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
static no_key extract()
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template <class... Args>
|
||||
static no_key extract(Args const&...)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
#else
|
||||
template <class Arg>
|
||||
static no_key extract(Arg const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
template <class Arg>
|
||||
static no_key extract(Arg const&, Arg const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool compare_mapped(value_type const&, value_type const&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Key, class ValueType>
|
||||
struct map_extractor
|
||||
{
|
||||
typedef ValueType value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::remove_const<Key>::type key_type;
|
||||
|
||||
static key_type const& extract(value_type const& v)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
|
||||
static key_type const& extract(key_type const& v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class Second>
|
||||
static key_type const& extract(std::pair<key_type, Second> const& v)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
|
||||
template <class Second>
|
||||
static key_type const& extract(
|
||||
std::pair<key_type const, Second> const& v)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template <class Arg1, class... Args>
|
||||
static key_type const& extract(key_type const& k,
|
||||
Arg1 const&, Args const&...)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
static no_key extract(Args const&...)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
#else
|
||||
template <class Arg1>
|
||||
static key_type const& extract(key_type const& k, Arg1 const&)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
static no_key extract()
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
template <class Arg>
|
||||
static no_key extract(Arg const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
template <class Arg, class Arg1>
|
||||
static no_key extract(Arg const&, Arg1 const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool compare_mapped(value_type const& x, value_type const& y)
|
||||
{
|
||||
return x.second == y.second;
|
||||
}
|
||||
};
|
||||
}}
|
||||
|
||||
#endif
|
856
include/boost/unordered/detail/fwd.hpp
Normal file
856
include/boost/unordered/detail/fwd.hpp
Normal file
@ -0,0 +1,856 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2009 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 contains the basic data structure, apart from the actual values. There's
|
||||
// no construction or deconstruction here. So this only depends on the pointer
|
||||
// type.
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/iterator.hpp>
|
||||
#include <boost/compressed_pair.hpp>
|
||||
#include <boost/type_traits/aligned_storage.hpp>
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
// This header defines most of the classes used to implement the unordered
|
||||
// containers. It doesn't include the insert methods as they require a lot
|
||||
// of preprocessor metaprogramming - they are in insert.hpp
|
||||
|
||||
// Template parameters:
|
||||
//
|
||||
// H = Hash Function
|
||||
// P = Predicate
|
||||
// A = Value Allocator
|
||||
// G = Grouped/Ungrouped
|
||||
// E = Key Extractor
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
|
||||
// STLport doesn't have std::forward.
|
||||
# else
|
||||
# define BOOST_UNORDERED_STD_FORWARD
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
|
||||
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
|
||||
#define BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||
BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg)
|
||||
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
||||
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, num_params, Arg, const& arg)
|
||||
#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
|
||||
BOOST_PP_ENUM_PARAMS_Z(z, num_params, arg)
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
static const float minimum_max_load_factor = 1e-3f;
|
||||
static const std::size_t default_bucket_count = 11;
|
||||
struct move_tag {};
|
||||
|
||||
template <class T> class hash_unique_table;
|
||||
template <class T> class hash_equivalent_table;
|
||||
template <class Alloc, class Grouped>
|
||||
class hash_node_constructor;
|
||||
template <class ValueType>
|
||||
struct set_extractor;
|
||||
template <class Key, class ValueType>
|
||||
struct map_extractor;
|
||||
struct no_key;
|
||||
|
||||
// Explicitly call a destructor
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline void destroy(T* x) {
|
||||
x->~T();
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// hash_bucket
|
||||
|
||||
template <class A>
|
||||
class hash_bucket
|
||||
{
|
||||
hash_bucket& operator=(hash_bucket const&);
|
||||
public:
|
||||
typedef hash_bucket<A> bucket;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::unordered_detail::rebind_wrap<A, bucket>::type
|
||||
bucket_allocator;
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket_allocator::pointer bucket_ptr;
|
||||
typedef bucket_ptr node_ptr;
|
||||
|
||||
node_ptr next_;
|
||||
|
||||
hash_bucket() : next_() {}
|
||||
};
|
||||
|
||||
template <class A>
|
||||
struct ungrouped_node_base : hash_bucket<A> {
|
||||
typedef hash_bucket<A> bucket;
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
||||
|
||||
ungrouped_node_base() : bucket() {}
|
||||
static inline node_ptr& next_group(node_ptr ptr);
|
||||
static inline std::size_t group_count(node_ptr ptr);
|
||||
static inline void add_to_bucket(node_ptr n, bucket& b);
|
||||
static inline void add_after_node(node_ptr n, node_ptr position);
|
||||
static void unlink_node(bucket& b, node_ptr n);
|
||||
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
|
||||
static void unlink_nodes(bucket& b, node_ptr end);
|
||||
};
|
||||
|
||||
template <class A>
|
||||
struct grouped_node_base : hash_bucket<A>
|
||||
{
|
||||
typedef hash_bucket<A> bucket;
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
||||
|
||||
node_ptr group_prev_;
|
||||
|
||||
grouped_node_base() : bucket(), group_prev_() {}
|
||||
static inline node_ptr& next_group(node_ptr ptr);
|
||||
static inline node_ptr first_in_group(node_ptr n);
|
||||
static inline std::size_t group_count(node_ptr ptr);
|
||||
static inline void add_to_bucket(node_ptr n, bucket& b);
|
||||
static inline void add_after_node(node_ptr n, node_ptr position);
|
||||
static void unlink_node(bucket& b, node_ptr n);
|
||||
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
|
||||
static void unlink_nodes(bucket& b, node_ptr end);
|
||||
|
||||
private:
|
||||
static inline node_ptr split_group(node_ptr split);
|
||||
static inline grouped_node_base& get(node_ptr ptr) {
|
||||
return static_cast<grouped_node_base&>(*ptr);
|
||||
}
|
||||
};
|
||||
|
||||
struct ungrouped
|
||||
{
|
||||
template <class A>
|
||||
struct base {
|
||||
typedef ungrouped_node_base<A> type;
|
||||
};
|
||||
};
|
||||
|
||||
struct grouped
|
||||
{
|
||||
template <class A>
|
||||
struct base {
|
||||
typedef grouped_node_base<A> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <class ValueType>
|
||||
struct value_base
|
||||
{
|
||||
typedef ValueType value_type;
|
||||
BOOST_DEDUCED_TYPENAME boost::aligned_storage<
|
||||
sizeof(value_type),
|
||||
::boost::alignment_of<value_type>::value>::type data_;
|
||||
|
||||
void* address() {
|
||||
return this;
|
||||
}
|
||||
value_type& value() {
|
||||
return *(ValueType*) this;
|
||||
}
|
||||
private:
|
||||
value_base& operator=(value_base const&);
|
||||
};
|
||||
|
||||
// Node
|
||||
|
||||
template <class A, class G>
|
||||
class hash_node :
|
||||
public G::BOOST_NESTED_TEMPLATE base<A>::type,
|
||||
public value_base<BOOST_DEDUCED_TYPENAME A::value_type>
|
||||
{
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME hash_bucket<A>::node_ptr node_ptr;
|
||||
|
||||
static value_type& get_value(node_ptr p) {
|
||||
return static_cast<hash_node&>(*p).value();
|
||||
}
|
||||
private:
|
||||
hash_node& operator=(hash_node const&);
|
||||
};
|
||||
|
||||
// Iterator Base
|
||||
|
||||
template <class A, class G>
|
||||
class hash_iterator_base
|
||||
{
|
||||
public:
|
||||
typedef A value_allocator;
|
||||
typedef hash_bucket<A> bucket;
|
||||
typedef hash_node<A, G> node;
|
||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
||||
|
||||
bucket_ptr bucket_;
|
||||
node_ptr node_;
|
||||
|
||||
hash_iterator_base() : bucket_(), node_() {}
|
||||
explicit hash_iterator_base(bucket_ptr b)
|
||||
: bucket_(b),
|
||||
node_(b ? b->next_ : node_ptr()) {}
|
||||
hash_iterator_base(bucket_ptr b, node_ptr n)
|
||||
: bucket_(b),
|
||||
node_(n) {}
|
||||
|
||||
bool operator==(hash_iterator_base const& x) const {
|
||||
return node_ == x.node_; }
|
||||
bool operator!=(hash_iterator_base const& x) const {
|
||||
return node_ != x.node_; }
|
||||
value_type& operator*() const {
|
||||
return node::get_value(node_);
|
||||
}
|
||||
|
||||
void increment_bucket(node_ptr n) {
|
||||
while(!n) {
|
||||
++bucket_;
|
||||
n = bucket_->next_;
|
||||
}
|
||||
node_ = bucket_ == n ? node_ptr() : n;
|
||||
}
|
||||
|
||||
void increment() {
|
||||
increment_bucket(node_->next_);
|
||||
}
|
||||
};
|
||||
|
||||
// hash_buckets
|
||||
//
|
||||
// This is responsible for allocating and deallocating buckets and nodes.
|
||||
//
|
||||
// Notes:
|
||||
// 1. For the sake exception safety the allocators themselves don't allocate
|
||||
// anything.
|
||||
// 2. It's the callers responsibility to allocate the buckets before calling
|
||||
// any of the methods (other than getters and setters).
|
||||
|
||||
template <class A, class G>
|
||||
class hash_buckets
|
||||
{
|
||||
hash_buckets(hash_buckets const&);
|
||||
hash_buckets& operator=(hash_buckets const&);
|
||||
public:
|
||||
// Types
|
||||
|
||||
typedef A value_allocator;
|
||||
typedef hash_bucket<A> bucket;
|
||||
typedef hash_iterator_base<A, G> iterator_base;
|
||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME iterator_base::node node;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator
|
||||
bucket_allocator;
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type
|
||||
node_allocator;
|
||||
typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr;
|
||||
|
||||
// Members
|
||||
|
||||
bucket_ptr buckets_;
|
||||
std::size_t bucket_count_;
|
||||
boost::compressed_pair<bucket_allocator, node_allocator> allocators_;
|
||||
|
||||
// Data access
|
||||
|
||||
bucket_allocator const& bucket_alloc() const {
|
||||
return allocators_.first(); }
|
||||
node_allocator const& node_alloc() const {
|
||||
return allocators_.second(); }
|
||||
bucket_allocator& bucket_alloc() {
|
||||
return allocators_.first(); }
|
||||
node_allocator& node_alloc() {
|
||||
return allocators_.second(); }
|
||||
std::size_t max_bucket_count() const;
|
||||
|
||||
// Constructors
|
||||
|
||||
hash_buckets(node_allocator const& a, std::size_t n);
|
||||
void create_buckets();
|
||||
~hash_buckets();
|
||||
|
||||
// no throw
|
||||
void swap(hash_buckets& other);
|
||||
void move(hash_buckets& other);
|
||||
|
||||
// For the remaining functions, buckets_ must not be null.
|
||||
|
||||
bucket_ptr get_bucket(std::size_t n) const;
|
||||
bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const;
|
||||
std::size_t bucket_size(std::size_t index) const;
|
||||
node_ptr bucket_begin(std::size_t n) const;
|
||||
|
||||
// Alloc/Dealloc
|
||||
|
||||
void delete_node(node_ptr);
|
||||
|
||||
//
|
||||
void delete_buckets();
|
||||
void clear_bucket(bucket_ptr);
|
||||
std::size_t delete_nodes(node_ptr begin, node_ptr end);
|
||||
std::size_t delete_to_bucket_end(node_ptr begin);
|
||||
};
|
||||
|
||||
template <class H, class P> class set_hash_functions;
|
||||
|
||||
template <class H, class P>
|
||||
class hash_buffered_functions
|
||||
{
|
||||
friend class set_hash_functions<H, P>;
|
||||
hash_buffered_functions& operator=(hash_buffered_functions const&);
|
||||
|
||||
typedef boost::compressed_pair<H, P> function_pair;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage<
|
||||
sizeof(function_pair),
|
||||
::boost::alignment_of<function_pair>::value>::type aligned_function;
|
||||
|
||||
bool current_; // The currently active functions.
|
||||
aligned_function funcs_[2];
|
||||
|
||||
function_pair const& current() const {
|
||||
return *static_cast<function_pair const*>(
|
||||
static_cast<void const*>(&funcs_[current_]));
|
||||
}
|
||||
|
||||
void construct(bool which, H const& hf, P const& eq)
|
||||
{
|
||||
new((void*) &funcs_[which]) function_pair(hf, eq);
|
||||
}
|
||||
|
||||
void construct(bool which, function_pair const& f)
|
||||
{
|
||||
new((void*) &funcs_[which]) function_pair(f);
|
||||
}
|
||||
|
||||
void destroy(bool which)
|
||||
{
|
||||
boost::unordered_detail::destroy((function_pair*)(&funcs_[which]));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
hash_buffered_functions(H const& hf, P const& eq)
|
||||
: current_(false)
|
||||
{
|
||||
construct(current_, hf, eq);
|
||||
}
|
||||
|
||||
hash_buffered_functions(hash_buffered_functions const& bf)
|
||||
: current_(false)
|
||||
{
|
||||
construct(current_, bf.current());
|
||||
}
|
||||
|
||||
~hash_buffered_functions() {
|
||||
destroy(current_);
|
||||
}
|
||||
|
||||
H const& hash_function() const {
|
||||
return current().first();
|
||||
}
|
||||
|
||||
P const& key_eq() const {
|
||||
return current().second();
|
||||
}
|
||||
};
|
||||
|
||||
template <class H, class P>
|
||||
class set_hash_functions
|
||||
{
|
||||
set_hash_functions(set_hash_functions const&);
|
||||
set_hash_functions& operator=(set_hash_functions const&);
|
||||
|
||||
typedef hash_buffered_functions<H, P> buffered_functions;
|
||||
buffered_functions& buffered_functions_;
|
||||
bool tmp_functions_;
|
||||
|
||||
public:
|
||||
|
||||
set_hash_functions(buffered_functions& f, H const& h, P const& p)
|
||||
: buffered_functions_(f),
|
||||
tmp_functions_(!f.current_)
|
||||
{
|
||||
f.construct(tmp_functions_, h, p);
|
||||
}
|
||||
|
||||
set_hash_functions(buffered_functions& f,
|
||||
buffered_functions const& other)
|
||||
: buffered_functions_(f),
|
||||
tmp_functions_(!f.current_)
|
||||
{
|
||||
f.construct(tmp_functions_, other.current());
|
||||
}
|
||||
|
||||
~set_hash_functions()
|
||||
{
|
||||
buffered_functions_.destroy(tmp_functions_);
|
||||
}
|
||||
|
||||
void commit()
|
||||
{
|
||||
buffered_functions_.current_ = tmp_functions_;
|
||||
tmp_functions_ = !tmp_functions_;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class hash_table : public T::buckets, public T::buffered_functions
|
||||
{
|
||||
hash_table(hash_table const&);
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::buffered_functions base;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::buckets buckets;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node node;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::bucket bucket;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::iterator_pair iterator_pair;
|
||||
|
||||
// Members
|
||||
|
||||
std::size_t size_;
|
||||
float mlf_;
|
||||
// Cached data - invalid if !this->buckets_
|
||||
bucket_ptr cached_begin_bucket_;
|
||||
std::size_t max_load_;
|
||||
|
||||
// Helper methods
|
||||
|
||||
key_type const& get_key(value_type const& v) const {
|
||||
return extractor::extract(v);
|
||||
}
|
||||
key_type const& get_key_from_ptr(node_ptr n) const {
|
||||
return extractor::extract(node::get_value(n));
|
||||
}
|
||||
bool equal(key_type const& k, value_type const& v) const;
|
||||
template <class Key, class Pred>
|
||||
node_ptr find_iterator(bucket_ptr bucket, Key const& k,
|
||||
Pred const&) const;
|
||||
node_ptr find_iterator(bucket_ptr bucket, key_type const& k) const;
|
||||
node_ptr find_iterator(key_type const& k) const;
|
||||
node_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const;
|
||||
|
||||
// Load methods
|
||||
|
||||
std::size_t max_size() const;
|
||||
std::size_t bucket_index(key_type const& k) const;
|
||||
void max_load_factor(float z);
|
||||
std::size_t min_buckets_for_size(std::size_t n) const;
|
||||
std::size_t calculate_max_load();
|
||||
|
||||
// Constructors
|
||||
|
||||
hash_table(std::size_t n, hasher const& hf, key_equal const& eq,
|
||||
node_allocator const& a);
|
||||
hash_table(hash_table const& x, node_allocator const& a);
|
||||
hash_table(hash_table& x, move_tag m);
|
||||
hash_table(hash_table& x, node_allocator const& a, move_tag m);
|
||||
~hash_table() {}
|
||||
hash_table& operator=(hash_table const&);
|
||||
|
||||
// Iterators
|
||||
|
||||
iterator_base begin() const {
|
||||
return this->size_ ?
|
||||
iterator_base(this->cached_begin_bucket_) :
|
||||
iterator_base();
|
||||
}
|
||||
iterator_base end() const {
|
||||
return iterator_base();
|
||||
}
|
||||
|
||||
// Swap & Move
|
||||
|
||||
void swap(hash_table& x);
|
||||
void fast_swap(hash_table& other);
|
||||
void slow_swap(hash_table& other);
|
||||
void partial_swap(hash_table& other);
|
||||
void move(hash_table& x);
|
||||
|
||||
// Reserve and rehash
|
||||
|
||||
void create_for_insert(std::size_t n);
|
||||
bool reserve_for_insert(std::size_t n);
|
||||
void rehash(std::size_t n);
|
||||
void rehash_impl(std::size_t n);
|
||||
|
||||
// Move/copy buckets
|
||||
|
||||
void move_buckets_to(buckets& dst);
|
||||
void copy_buckets_to(buckets& dst) const;
|
||||
|
||||
// Misc. key methods
|
||||
|
||||
std::size_t count(key_type const& k) const;
|
||||
iterator_base find(key_type const& k) const;
|
||||
template <class Key, class Hash, class Pred>
|
||||
iterator_base find(Key const& k, Hash const& h, Pred const& eq) const;
|
||||
value_type& at(key_type const& k) const;
|
||||
iterator_pair equal_range(key_type const& k) const;
|
||||
|
||||
// Erase
|
||||
//
|
||||
// no throw
|
||||
|
||||
void clear();
|
||||
std::size_t erase_key(key_type const& k);
|
||||
iterator_base erase_return_iterator(iterator_base r);
|
||||
void erase(iterator_base r);
|
||||
std::size_t erase_group(node_ptr* it, bucket_ptr bucket);
|
||||
iterator_base erase_range(iterator_base r1, iterator_base r2);
|
||||
|
||||
// recompute_begin_bucket
|
||||
|
||||
void init_buckets();
|
||||
|
||||
// After an erase cached_begin_bucket_ might be left pointing to
|
||||
// an empty bucket, so this is called to update it
|
||||
//
|
||||
// no throw
|
||||
|
||||
void recompute_begin_bucket(bucket_ptr b);
|
||||
|
||||
// This is called when a range has been erased
|
||||
//
|
||||
// no throw
|
||||
|
||||
void recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2);
|
||||
|
||||
// no throw
|
||||
float load_factor() const;
|
||||
|
||||
iterator_base emplace_empty_impl_with_node(
|
||||
node_constructor&, std::size_t);
|
||||
};
|
||||
|
||||
// Iterator Access
|
||||
|
||||
#if !defined(__clang__)
|
||||
class iterator_access
|
||||
{
|
||||
public:
|
||||
template <class Iterator>
|
||||
static BOOST_DEDUCED_TYPENAME Iterator::base const&
|
||||
get(Iterator const& it)
|
||||
{
|
||||
return it.base_;
|
||||
}
|
||||
};
|
||||
#else
|
||||
class iterator_access
|
||||
{
|
||||
public:
|
||||
// Note: we access Iterator::base here, rather than in the function
|
||||
// signature to work around a bug in the friend support of an
|
||||
// early version of clang.
|
||||
|
||||
template <class Iterator>
|
||||
struct base
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Iterator::base type;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
static BOOST_DEDUCED_TYPENAME base<Iterator>::type const&
|
||||
get(Iterator const& it)
|
||||
{
|
||||
return it.base_;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// Iterators
|
||||
|
||||
template <class A, class G> class hash_iterator;
|
||||
template <class A, class G> class hash_const_iterator;
|
||||
template <class A, class G> class hash_local_iterator;
|
||||
template <class A, class G> class hash_const_local_iterator;
|
||||
|
||||
// Local Iterators
|
||||
//
|
||||
// all no throw
|
||||
|
||||
template <class A, class G>
|
||||
class hash_local_iterator
|
||||
: public boost::iterator <
|
||||
std::forward_iterator_tag,
|
||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
std::ptrdiff_t,
|
||||
BOOST_DEDUCED_TYPENAME A::pointer,
|
||||
BOOST_DEDUCED_TYPENAME A::reference>
|
||||
{
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
||||
|
||||
private:
|
||||
typedef hash_buckets<A, G> buckets;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
||||
typedef hash_const_local_iterator<A, G> const_local_iterator;
|
||||
|
||||
friend class hash_const_local_iterator<A, G>;
|
||||
node_ptr ptr_;
|
||||
|
||||
public:
|
||||
hash_local_iterator() : ptr_() {}
|
||||
explicit hash_local_iterator(node_ptr x) : ptr_(x) {}
|
||||
BOOST_DEDUCED_TYPENAME A::reference operator*() const {
|
||||
return node::get_value(ptr_);
|
||||
}
|
||||
value_type* operator->() const {
|
||||
return &node::get_value(ptr_);
|
||||
}
|
||||
hash_local_iterator& operator++() {
|
||||
ptr_ = ptr_->next_; return *this;
|
||||
}
|
||||
hash_local_iterator operator++(int) {
|
||||
hash_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp; }
|
||||
bool operator==(hash_local_iterator x) const {
|
||||
return ptr_ == x.ptr_;
|
||||
}
|
||||
bool operator==(const_local_iterator x) const {
|
||||
return ptr_ == x.ptr_;
|
||||
}
|
||||
bool operator!=(hash_local_iterator x) const {
|
||||
return ptr_ != x.ptr_;
|
||||
}
|
||||
bool operator!=(const_local_iterator x) const {
|
||||
return ptr_ != x.ptr_;
|
||||
}
|
||||
};
|
||||
|
||||
template <class A, class G>
|
||||
class hash_const_local_iterator
|
||||
: public boost::iterator <
|
||||
std::forward_iterator_tag,
|
||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
std::ptrdiff_t,
|
||||
BOOST_DEDUCED_TYPENAME A::const_pointer,
|
||||
BOOST_DEDUCED_TYPENAME A::const_reference >
|
||||
{
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
||||
|
||||
private:
|
||||
typedef hash_buckets<A, G> buckets;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
||||
typedef hash_local_iterator<A, G> local_iterator;
|
||||
friend class hash_local_iterator<A, G>;
|
||||
ptr ptr_;
|
||||
|
||||
public:
|
||||
hash_const_local_iterator() : ptr_() {}
|
||||
explicit hash_const_local_iterator(ptr x) : ptr_(x) {}
|
||||
hash_const_local_iterator(local_iterator x) : ptr_(x.ptr_) {}
|
||||
BOOST_DEDUCED_TYPENAME A::const_reference
|
||||
operator*() const {
|
||||
return node::get_value(ptr_);
|
||||
}
|
||||
value_type const* operator->() const {
|
||||
return &node::get_value(ptr_);
|
||||
}
|
||||
hash_const_local_iterator& operator++() {
|
||||
ptr_ = ptr_->next_; return *this;
|
||||
}
|
||||
hash_const_local_iterator operator++(int) {
|
||||
hash_const_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp;
|
||||
}
|
||||
bool operator==(local_iterator x) const {
|
||||
return ptr_ == x.ptr_;
|
||||
}
|
||||
bool operator==(hash_const_local_iterator x) const {
|
||||
return ptr_ == x.ptr_;
|
||||
}
|
||||
bool operator!=(local_iterator x) const {
|
||||
return ptr_ != x.ptr_;
|
||||
}
|
||||
bool operator!=(hash_const_local_iterator x) const {
|
||||
return ptr_ != x.ptr_;
|
||||
}
|
||||
};
|
||||
|
||||
// iterators
|
||||
//
|
||||
// all no throw
|
||||
|
||||
|
||||
template <class A, class G>
|
||||
class hash_iterator
|
||||
: public boost::iterator <
|
||||
std::forward_iterator_tag,
|
||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
std::ptrdiff_t,
|
||||
BOOST_DEDUCED_TYPENAME A::pointer,
|
||||
BOOST_DEDUCED_TYPENAME A::reference >
|
||||
{
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
||||
|
||||
private:
|
||||
typedef hash_buckets<A, G> buckets;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base;
|
||||
typedef hash_const_iterator<A, G> const_iterator;
|
||||
friend class hash_const_iterator<A, G>;
|
||||
base base_;
|
||||
|
||||
public:
|
||||
|
||||
hash_iterator() : base_() {}
|
||||
explicit hash_iterator(base const& x) : base_(x) {}
|
||||
BOOST_DEDUCED_TYPENAME A::reference operator*() const {
|
||||
return *base_;
|
||||
}
|
||||
value_type* operator->() const {
|
||||
return &*base_;
|
||||
}
|
||||
hash_iterator& operator++() {
|
||||
base_.increment(); return *this;
|
||||
}
|
||||
hash_iterator operator++(int) {
|
||||
hash_iterator tmp(base_); base_.increment(); return tmp;
|
||||
}
|
||||
bool operator==(hash_iterator const& x) const {
|
||||
return base_ == x.base_;
|
||||
}
|
||||
bool operator==(const_iterator const& x) const {
|
||||
return base_ == x.base_;
|
||||
}
|
||||
bool operator!=(hash_iterator const& x) const {
|
||||
return base_ != x.base_;
|
||||
}
|
||||
bool operator!=(const_iterator const& x) const {
|
||||
return base_ != x.base_;
|
||||
}
|
||||
};
|
||||
|
||||
template <class A, class G>
|
||||
class hash_const_iterator
|
||||
: public boost::iterator <
|
||||
std::forward_iterator_tag,
|
||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
std::ptrdiff_t,
|
||||
BOOST_DEDUCED_TYPENAME A::const_pointer,
|
||||
BOOST_DEDUCED_TYPENAME A::const_reference >
|
||||
{
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
||||
|
||||
private:
|
||||
typedef hash_buckets<A, G> buckets;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base;
|
||||
typedef hash_iterator<A, G> iterator;
|
||||
friend class hash_iterator<A, G>;
|
||||
friend class iterator_access;
|
||||
base base_;
|
||||
|
||||
public:
|
||||
|
||||
hash_const_iterator() : base_() {}
|
||||
explicit hash_const_iterator(base const& x) : base_(x) {}
|
||||
hash_const_iterator(iterator const& x) : base_(x.base_) {}
|
||||
BOOST_DEDUCED_TYPENAME A::const_reference operator*() const {
|
||||
return *base_;
|
||||
}
|
||||
value_type const* operator->() const {
|
||||
return &*base_;
|
||||
}
|
||||
hash_const_iterator& operator++() {
|
||||
base_.increment(); return *this;
|
||||
}
|
||||
hash_const_iterator operator++(int) {
|
||||
hash_const_iterator tmp(base_); base_.increment(); return tmp;
|
||||
}
|
||||
bool operator==(iterator const& x) const {
|
||||
return base_ == x.base_;
|
||||
}
|
||||
bool operator==(hash_const_iterator const& x) const {
|
||||
return base_ == x.base_;
|
||||
}
|
||||
bool operator!=(iterator const& x) const {
|
||||
return base_ != x.base_;
|
||||
}
|
||||
bool operator!=(hash_const_iterator const& x) const {
|
||||
return base_ != x.base_;
|
||||
}
|
||||
};
|
||||
|
||||
// types
|
||||
|
||||
template <class K, class V, class H, class P, class A, class E, class G>
|
||||
struct types
|
||||
{
|
||||
public:
|
||||
typedef K key_type;
|
||||
typedef V value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef A value_allocator;
|
||||
typedef E extractor;
|
||||
typedef G group_type;
|
||||
|
||||
typedef hash_node_constructor<value_allocator, group_type>
|
||||
node_constructor;
|
||||
typedef hash_buckets<value_allocator, group_type> buckets;
|
||||
typedef hash_buffered_functions<hasher, key_equal> buffered_functions;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base iterator_base;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator;
|
||||
|
||||
typedef std::pair<iterator_base, iterator_base> iterator_pair;
|
||||
};
|
||||
}}
|
||||
|
||||
#endif
|
@ -1,307 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2008 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_helpers.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 defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/mpl/not.hpp>
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0582)
|
||||
#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 {};
|
||||
|
||||
static const std::size_t default_initial_bucket_count = 50;
|
||||
static const float minimum_max_load_factor = 1e-3f;
|
||||
|
||||
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 double_to_size_t(double f)
|
||||
{
|
||||
return f >= static_cast<double>((std::numeric_limits<std::size_t>::max)()) ?
|
||||
(std::numeric_limits<std::size_t>::max)() :
|
||||
static_cast<std::size_t>(f);
|
||||
}
|
||||
|
||||
// prime number list, accessor
|
||||
|
||||
template<typename T> struct prime_list_template
|
||||
{
|
||||
static std::size_t const value[];
|
||||
static std::ptrdiff_t const length;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::size_t const prime_list_template<T>::value[] = {
|
||||
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 };
|
||||
|
||||
template<typename T>
|
||||
std::ptrdiff_t const prime_list_template<T>::length = 28;
|
||||
|
||||
typedef prime_list_template<std::size_t> prime_list;
|
||||
|
||||
// no throw
|
||||
inline std::size_t next_prime(std::size_t n) {
|
||||
std::size_t const* const prime_list_begin = prime_list::value;
|
||||
std::size_t const* const prime_list_end = prime_list_begin +
|
||||
prime_list::length;
|
||||
std::size_t const* bound =
|
||||
std::lower_bound(prime_list_begin, 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_begin = prime_list::value;
|
||||
std::size_t const* const prime_list_end = prime_list_begin +
|
||||
prime_list::length;
|
||||
std::size_t const* bound =
|
||||
std::upper_bound(prime_list_begin,prime_list_end, n);
|
||||
if(bound != prime_list_begin)
|
||||
bound--;
|
||||
return *bound;
|
||||
}
|
||||
|
||||
// Controls how many buckets are allocated and which buckets hash
|
||||
// values map to. Does not contain the buckets themselves, or ever
|
||||
// deal with them directly.
|
||||
|
||||
struct bucket_manager {
|
||||
std::size_t bucket_count_;
|
||||
|
||||
bucket_manager()
|
||||
: bucket_count_(0) {}
|
||||
|
||||
explicit bucket_manager(std::size_t n)
|
||||
: bucket_count_(next_prime(n)) {}
|
||||
|
||||
std::size_t bucket_count() const {
|
||||
return bucket_count_;
|
||||
}
|
||||
|
||||
std::size_t bucket_from_hash(std::size_t hashed) const {
|
||||
return hashed % bucket_count_;
|
||||
}
|
||||
|
||||
std::size_t max_bucket_count(std::size_t max_size) const {
|
||||
return prev_prime(max_size);
|
||||
}
|
||||
};
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_STD_DISTANCE)
|
||||
using ::std::distance;
|
||||
#else
|
||||
template <class ForwardIterator>
|
||||
inline std::size_t distance(ForwardIterator i, ForwardIterator j) {
|
||||
std::size_t x;
|
||||
std::distance(i, j, x);
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct move_tag {};
|
||||
|
||||
// Both hasher and key_equal's copy/assign can throw so double
|
||||
// buffering is used to copy them.
|
||||
|
||||
template <typename Hash, typename Pred>
|
||||
struct buffered_functions
|
||||
{
|
||||
typedef Hash hasher;
|
||||
typedef Pred key_equal;
|
||||
|
||||
class functions
|
||||
{
|
||||
std::pair<hasher, key_equal> functions_;
|
||||
|
||||
public:
|
||||
|
||||
functions(hasher const& h, key_equal const& k)
|
||||
: functions_(h, k) {}
|
||||
|
||||
hasher const& hash_function() const
|
||||
{
|
||||
return functions_.first;
|
||||
}
|
||||
|
||||
key_equal const& key_eq() const
|
||||
{
|
||||
return functions_.second;
|
||||
}
|
||||
};
|
||||
|
||||
typedef functions buffered_functions::*functions_ptr;
|
||||
|
||||
buffered_functions(hasher const& h, key_equal const& k)
|
||||
: func1_(h, k), func2_(h, k), func_(&buffered_functions::func1_) {}
|
||||
|
||||
// This copies the given function objects into the currently unused
|
||||
// function objects and returns a pointer, that func_ can later be
|
||||
// set to, to commit the change.
|
||||
//
|
||||
// Strong exception safety (since only usued function objects are
|
||||
// changed).
|
||||
functions_ptr buffer(buffered_functions const& x) {
|
||||
functions_ptr ptr = func_ == &buffered_functions::func1_
|
||||
? &buffered_functions::func2_ : &buffered_functions::func1_;
|
||||
this->*ptr = x.current();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void set(functions_ptr ptr) {
|
||||
BOOST_ASSERT(ptr != func_);
|
||||
func_ = ptr;
|
||||
}
|
||||
|
||||
functions const& current() const {
|
||||
return this->*func_;
|
||||
}
|
||||
|
||||
private:
|
||||
functions func1_;
|
||||
functions func2_;
|
||||
functions_ptr func_; // The currently active functions.
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#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
@ -11,7 +11,7 @@
|
||||
#ifndef BOOST_UNORDERED_DETAIL_MOVE_HEADER
|
||||
#define BOOST_UNORDERED_DETAIL_MOVE_HEADER
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
#include <boost/mpl/or.hpp>
|
||||
@ -20,7 +20,20 @@
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_class.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/unordered/detail/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#if defined(BOOST_NO_SFINAE)
|
||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
#elif defined(__GNUC__) && \
|
||||
(__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
|
||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \
|
||||
BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \
|
||||
BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593))
|
||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
#endif
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
@ -96,6 +109,8 @@ struct move_from
|
||||
{
|
||||
explicit move_from(T& x) : source(x) { }
|
||||
T& source;
|
||||
private:
|
||||
move_from& operator=(move_from const&);
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
226
include/boost/unordered/detail/node.hpp
Normal file
226
include/boost/unordered/detail/node.hpp
Normal file
@ -0,0 +1,226 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2009 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 contains the basic data structure, apart from the actual values. There's
|
||||
// no construction or deconstruction here. So this only depends on the pointer
|
||||
// type.
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582)
|
||||
#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x)
|
||||
#else
|
||||
#define BOOST_UNORDERED_BORLAND_BOOL(x) x
|
||||
#endif
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// ungrouped node implementation
|
||||
|
||||
template <class A>
|
||||
inline BOOST_DEDUCED_TYPENAME ungrouped_node_base<A>::node_ptr&
|
||||
ungrouped_node_base<A>::next_group(node_ptr ptr)
|
||||
{
|
||||
return ptr->next_;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline std::size_t ungrouped_node_base<A>::group_count(node_ptr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
|
||||
{
|
||||
n->next_ = b.next_;
|
||||
b.next_ = n;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::add_after_node(node_ptr n,
|
||||
node_ptr position)
|
||||
{
|
||||
n->next_ = position->next_;
|
||||
position->next_ = position;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b,
|
||||
node_ptr begin, node_ptr end)
|
||||
{
|
||||
node_ptr* pos = &b.next_;
|
||||
while(*pos != begin) pos = &(*pos)->next_;
|
||||
*pos = end;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
|
||||
{
|
||||
b.next_ = end;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
|
||||
{
|
||||
unlink_nodes(b, n, n->next_);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// grouped node implementation
|
||||
|
||||
// If ptr is the first element in a group, return pointer to next group.
|
||||
// Otherwise returns a pointer to ptr.
|
||||
template <class A>
|
||||
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr&
|
||||
grouped_node_base<A>::next_group(node_ptr ptr)
|
||||
{
|
||||
return get(ptr).group_prev_->next_;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
|
||||
grouped_node_base<A>::first_in_group(node_ptr ptr)
|
||||
{
|
||||
while(next_group(ptr) == ptr)
|
||||
ptr = get(ptr).group_prev_;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline std::size_t grouped_node_base<A>::group_count(node_ptr ptr)
|
||||
{
|
||||
node_ptr start = ptr;
|
||||
std::size_t size = 0;
|
||||
do {
|
||||
++size;
|
||||
ptr = get(ptr).group_prev_;
|
||||
} while(ptr != start);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void grouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
|
||||
{
|
||||
n->next_ = b.next_;
|
||||
get(n).group_prev_ = n;
|
||||
b.next_ = n;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void grouped_node_base<A>::add_after_node(node_ptr n, node_ptr pos)
|
||||
{
|
||||
n->next_ = next_group(pos);
|
||||
get(n).group_prev_ = get(pos).group_prev_;
|
||||
next_group(pos) = n;
|
||||
get(pos).group_prev_ = n;
|
||||
}
|
||||
|
||||
// Break a ciruclar list into two, with split as the beginning
|
||||
// of the second group (if split is at the beginning then don't
|
||||
// split).
|
||||
template <class A>
|
||||
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
|
||||
grouped_node_base<A>::split_group(node_ptr split)
|
||||
{
|
||||
node_ptr first = first_in_group(split);
|
||||
if(first == split) return split;
|
||||
|
||||
node_ptr last = get(first).group_prev_;
|
||||
get(first).group_prev_ = get(split).group_prev_;
|
||||
get(split).group_prev_ = last;
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
void grouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
|
||||
{
|
||||
node_ptr next = n->next_;
|
||||
node_ptr* pos = &next_group(n);
|
||||
|
||||
if(*pos != n) {
|
||||
// The node is at the beginning of a group.
|
||||
|
||||
// Find the previous node pointer:
|
||||
pos = &b.next_;
|
||||
while(*pos != n) pos = &next_group(*pos);
|
||||
|
||||
// Remove from group
|
||||
if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
|
||||
get(next).group_prev_ == n)
|
||||
{
|
||||
get(next).group_prev_ = get(n).group_prev_;
|
||||
}
|
||||
}
|
||||
else if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
|
||||
get(next).group_prev_ == n)
|
||||
{
|
||||
// The deleted node is not at the end of the group, so
|
||||
// change the link from the next node.
|
||||
get(next).group_prev_ = get(n).group_prev_;
|
||||
}
|
||||
else {
|
||||
// The deleted node is at the end of the group, so the
|
||||
// first node in the group is pointing to it.
|
||||
// Find that to change its pointer.
|
||||
node_ptr x = get(n).group_prev_;
|
||||
while(get(x).group_prev_ != n) {
|
||||
x = get(x).group_prev_;
|
||||
}
|
||||
get(x).group_prev_ = get(n).group_prev_;
|
||||
}
|
||||
*pos = next;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
void grouped_node_base<A>::unlink_nodes(bucket& b,
|
||||
node_ptr begin, node_ptr end)
|
||||
{
|
||||
node_ptr* pos = &next_group(begin);
|
||||
|
||||
if(*pos != begin) {
|
||||
// The node is at the beginning of a group.
|
||||
|
||||
// Find the previous node pointer:
|
||||
pos = &b.next_;
|
||||
while(*pos != begin) pos = &next_group(*pos);
|
||||
|
||||
// Remove from group
|
||||
if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end);
|
||||
}
|
||||
else {
|
||||
node_ptr group1 = split_group(begin);
|
||||
if(BOOST_UNORDERED_BORLAND_BOOL(end)) {
|
||||
node_ptr group2 = split_group(end);
|
||||
|
||||
if(begin == group2) {
|
||||
node_ptr end1 = get(group1).group_prev_;
|
||||
node_ptr end2 = get(group2).group_prev_;
|
||||
get(group1).group_prev_ = end2;
|
||||
get(group2).group_prev_ = end1;
|
||||
}
|
||||
}
|
||||
}
|
||||
*pos = end;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
void grouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
|
||||
{
|
||||
split_group(end);
|
||||
b.next_ = end;
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
778
include/boost/unordered/detail/table.hpp
Normal file
778
include/boost/unordered/detail/table.hpp
Normal file
@ -0,0 +1,778 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2009 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_ALL_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
#include <boost/iterator/iterator_categories.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/unordered/detail/buckets.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Helper methods
|
||||
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
inline bool hash_table<T>::equal(
|
||||
key_type const& k, value_type const& v) const
|
||||
{
|
||||
return this->key_eq()(k, get_key(v));
|
||||
}
|
||||
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
template <class Key, class Pred>
|
||||
inline BOOST_DEDUCED_TYPENAME T::node_ptr
|
||||
hash_table<T>::find_iterator(bucket_ptr bucket, Key const& k,
|
||||
Pred const& eq) const
|
||||
{
|
||||
node_ptr it = bucket->next_;
|
||||
while (BOOST_UNORDERED_BORLAND_BOOL(it) &&
|
||||
!eq(k, get_key(node::get_value(it))))
|
||||
{
|
||||
it = node::next_group(it);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME T::node_ptr
|
||||
hash_table<T>::find_iterator(
|
||||
bucket_ptr bucket, key_type const& k) const
|
||||
{
|
||||
node_ptr it = bucket->next_;
|
||||
while (BOOST_UNORDERED_BORLAND_BOOL(it) &&
|
||||
!equal(k, node::get_value(it)))
|
||||
{
|
||||
it = node::next_group(it);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
// strong exception safety, no side effects
|
||||
// pre: this->buckets_
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME T::node_ptr
|
||||
hash_table<T>::find_iterator(key_type const& k) const
|
||||
{
|
||||
return find_iterator(this->get_bucket(this->bucket_index(k)), k);
|
||||
}
|
||||
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME T::node_ptr*
|
||||
hash_table<T>::find_for_erase(
|
||||
bucket_ptr bucket, key_type const& k) const
|
||||
{
|
||||
node_ptr* it = &bucket->next_;
|
||||
while(BOOST_UNORDERED_BORLAND_BOOL(*it) &&
|
||||
!equal(k, node::get_value(*it)))
|
||||
{
|
||||
it = &node::next_group(*it);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Load methods
|
||||
|
||||
// no throw
|
||||
template <class T>
|
||||
std::size_t hash_table<T>::max_size() const
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// size < mlf_ * count
|
||||
return double_to_size_t(ceil(
|
||||
(double) this->mlf_ * this->max_bucket_count())) - 1;
|
||||
}
|
||||
|
||||
// strong safety
|
||||
template <class T>
|
||||
inline std::size_t hash_table<T>::bucket_index(
|
||||
key_type const& k) const
|
||||
{
|
||||
// hash_function can throw:
|
||||
return this->hash_function()(k) % this->bucket_count_;
|
||||
}
|
||||
|
||||
|
||||
// no throw
|
||||
template <class T>
|
||||
inline std::size_t hash_table<T>::calculate_max_load()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// From 6.3.1/13:
|
||||
// Only resize when size >= mlf_ * count
|
||||
return double_to_size_t(ceil((double) mlf_ * this->bucket_count_));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::max_load_factor(float z)
|
||||
{
|
||||
BOOST_ASSERT(z > 0);
|
||||
mlf_ = (std::max)(z, minimum_max_load_factor);
|
||||
this->max_load_ = this->calculate_max_load();
|
||||
}
|
||||
|
||||
// no throw
|
||||
template <class T>
|
||||
inline std::size_t hash_table<T>::min_buckets_for_size(
|
||||
std::size_t size) const
|
||||
{
|
||||
BOOST_ASSERT(this->mlf_ != 0);
|
||||
|
||||
using namespace std;
|
||||
|
||||
// From 6.3.1/13:
|
||||
// size < mlf_ * count
|
||||
// => count > size / mlf_
|
||||
//
|
||||
// Or from rehash post-condition:
|
||||
// count > size / mlf_
|
||||
return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// recompute_begin_bucket
|
||||
|
||||
// init_buckets
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::init_buckets()
|
||||
{
|
||||
if (this->size_) {
|
||||
this->cached_begin_bucket_ = this->buckets_;
|
||||
while (!this->cached_begin_bucket_->next_)
|
||||
++this->cached_begin_bucket_;
|
||||
} else {
|
||||
this->cached_begin_bucket_ = this->get_bucket(this->bucket_count_);
|
||||
}
|
||||
this->max_load_ = calculate_max_load();
|
||||
}
|
||||
|
||||
// After an erase cached_begin_bucket_ might be left pointing to
|
||||
// an empty bucket, so this is called to update it
|
||||
//
|
||||
// no throw
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::recompute_begin_bucket(bucket_ptr b)
|
||||
{
|
||||
BOOST_ASSERT(!(b < this->cached_begin_bucket_));
|
||||
|
||||
if(b == this->cached_begin_bucket_)
|
||||
{
|
||||
if (this->size_ != 0) {
|
||||
while (!this->cached_begin_bucket_->next_)
|
||||
++this->cached_begin_bucket_;
|
||||
} else {
|
||||
this->cached_begin_bucket_ =
|
||||
this->get_bucket(this->bucket_count_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is called when a range has been erased
|
||||
//
|
||||
// no throw
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::recompute_begin_bucket(
|
||||
bucket_ptr b1, bucket_ptr b2)
|
||||
{
|
||||
BOOST_ASSERT(!(b1 < this->cached_begin_bucket_) && !(b2 < b1));
|
||||
BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_));
|
||||
|
||||
if(b1 == this->cached_begin_bucket_ && !b1->next_)
|
||||
this->cached_begin_bucket_ = b2;
|
||||
}
|
||||
|
||||
// no throw
|
||||
template <class T>
|
||||
inline float hash_table<T>::load_factor() const
|
||||
{
|
||||
BOOST_ASSERT(this->bucket_count_ != 0);
|
||||
return static_cast<float>(this->size_)
|
||||
/ static_cast<float>(this->bucket_count_);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors
|
||||
|
||||
template <class T>
|
||||
hash_table<T>::hash_table(std::size_t num_buckets,
|
||||
hasher const& hf, key_equal const& eq, node_allocator const& a)
|
||||
: buckets(a, next_prime(num_buckets)),
|
||||
base(hf, eq),
|
||||
size_(),
|
||||
mlf_(1.0f),
|
||||
cached_begin_bucket_(),
|
||||
max_load_(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Copy Construct with allocator
|
||||
|
||||
template <class T>
|
||||
hash_table<T>::hash_table(hash_table const& x,
|
||||
node_allocator const& a)
|
||||
: buckets(a, x.min_buckets_for_size(x.size_)),
|
||||
base(x),
|
||||
size_(x.size_),
|
||||
mlf_(x.mlf_),
|
||||
cached_begin_bucket_(),
|
||||
max_load_(0)
|
||||
{
|
||||
if(x.size_) {
|
||||
x.copy_buckets_to(*this);
|
||||
this->init_buckets();
|
||||
}
|
||||
}
|
||||
|
||||
// Move Construct
|
||||
|
||||
template <class T>
|
||||
hash_table<T>::hash_table(hash_table& x, move_tag)
|
||||
: buckets(x.node_alloc(), x.bucket_count_),
|
||||
base(x),
|
||||
size_(0),
|
||||
mlf_(1.0f),
|
||||
cached_begin_bucket_(),
|
||||
max_load_(0)
|
||||
{
|
||||
this->partial_swap(x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
hash_table<T>::hash_table(hash_table& x,
|
||||
node_allocator const& a, move_tag)
|
||||
: buckets(a, x.bucket_count_),
|
||||
base(x),
|
||||
size_(0),
|
||||
mlf_(x.mlf_),
|
||||
cached_begin_bucket_(),
|
||||
max_load_(0)
|
||||
{
|
||||
if(a == x.node_alloc()) {
|
||||
this->partial_swap(x);
|
||||
}
|
||||
else if(x.size_) {
|
||||
x.copy_buckets_to(*this);
|
||||
this->size_ = x.size_;
|
||||
this->init_buckets();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
hash_table<T>& hash_table<T>::operator=(
|
||||
hash_table const& x)
|
||||
{
|
||||
hash_table tmp(x, this->node_alloc());
|
||||
this->fast_swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Swap & Move
|
||||
|
||||
// Swap
|
||||
//
|
||||
// Strong exception safety
|
||||
//
|
||||
// Can throw if hash or predicate object's copy constructor throws
|
||||
// or if allocators are unequal.
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::partial_swap(hash_table& x)
|
||||
{
|
||||
this->buckets::swap(x); // No throw
|
||||
std::swap(this->size_, x.size_);
|
||||
std::swap(this->mlf_, x.mlf_);
|
||||
std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_);
|
||||
std::swap(this->max_load_, x.max_load_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::fast_swap(hash_table& x)
|
||||
{
|
||||
// These can throw, but they only affect the function objects
|
||||
// that aren't in use so it is strongly exception safe, via.
|
||||
// double buffering.
|
||||
{
|
||||
set_hash_functions<hasher, key_equal> op1(*this, x);
|
||||
set_hash_functions<hasher, key_equal> op2(x, *this);
|
||||
op1.commit();
|
||||
op2.commit();
|
||||
}
|
||||
this->buckets::swap(x); // No throw
|
||||
std::swap(this->size_, x.size_);
|
||||
std::swap(this->mlf_, x.mlf_);
|
||||
std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_);
|
||||
std::swap(this->max_load_, x.max_load_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::slow_swap(hash_table& x)
|
||||
{
|
||||
if(this == &x) return;
|
||||
|
||||
{
|
||||
// These can throw, but they only affect the function objects
|
||||
// that aren't in use so it is strongly exception safe, via.
|
||||
// double buffering.
|
||||
set_hash_functions<hasher, key_equal> op1(*this, x);
|
||||
set_hash_functions<hasher, key_equal> op2(x, *this);
|
||||
|
||||
// Create new buckets in separate hash_buckets objects
|
||||
// which will clean up if anything throws an exception.
|
||||
// (all can throw, but with no effect as these are new objects).
|
||||
|
||||
buckets b1(this->node_alloc(), x.min_buckets_for_size(x.size_));
|
||||
if(x.size_) x.copy_buckets_to(b1);
|
||||
|
||||
buckets b2(x.node_alloc(), this->min_buckets_for_size(this->size_));
|
||||
if(this->size_) copy_buckets_to(b2);
|
||||
|
||||
// Modifying the data, so no throw from now on.
|
||||
|
||||
b1.swap(*this);
|
||||
b2.swap(x);
|
||||
op1.commit();
|
||||
op2.commit();
|
||||
}
|
||||
|
||||
std::swap(this->size_, x.size_);
|
||||
|
||||
if(this->buckets_) this->init_buckets();
|
||||
if(x.buckets_) x.init_buckets();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::swap(hash_table& x)
|
||||
{
|
||||
if(this->node_alloc() == x.node_alloc()) {
|
||||
if(this != &x) this->fast_swap(x);
|
||||
}
|
||||
else {
|
||||
this->slow_swap(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Move
|
||||
//
|
||||
// Strong exception safety (might change unused function objects)
|
||||
//
|
||||
// Can throw if hash or predicate object's copy constructor throws
|
||||
// or if allocators are unequal.
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::move(hash_table& x)
|
||||
{
|
||||
// This can throw, but it only affects the function objects
|
||||
// that aren't in use so it is strongly exception safe, via.
|
||||
// double buffering.
|
||||
set_hash_functions<hasher, key_equal> new_func_this(*this, x);
|
||||
|
||||
if(this->node_alloc() == x.node_alloc()) {
|
||||
this->buckets::move(x); // no throw
|
||||
this->size_ = x.size_;
|
||||
this->cached_begin_bucket_ = x.cached_begin_bucket_;
|
||||
this->max_load_ = x.max_load_;
|
||||
x.size_ = 0;
|
||||
}
|
||||
else {
|
||||
// Create new buckets in separate HASH_TABLE_DATA objects
|
||||
// which will clean up if anything throws an exception.
|
||||
// (all can throw, but with no effect as these are new objects).
|
||||
|
||||
buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_));
|
||||
if(x.size_) x.copy_buckets_to(b);
|
||||
|
||||
// Start updating the data here, no throw from now on.
|
||||
this->size_ = x.size_;
|
||||
b.swap(*this);
|
||||
this->init_buckets();
|
||||
}
|
||||
|
||||
// We've made it, the rest is no throw.
|
||||
this->mlf_ = x.mlf_;
|
||||
new_func_this.commit();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Reserve & Rehash
|
||||
|
||||
// basic exception safety
|
||||
template <class T>
|
||||
inline void hash_table<T>::create_for_insert(std::size_t size)
|
||||
{
|
||||
this->bucket_count_ = (std::max)(this->bucket_count_,
|
||||
this->min_buckets_for_size(size));
|
||||
this->create_buckets();
|
||||
this->init_buckets();
|
||||
}
|
||||
|
||||
// basic exception safety
|
||||
template <class T>
|
||||
inline bool hash_table<T>::reserve_for_insert(std::size_t size)
|
||||
{
|
||||
if(size >= max_load_) {
|
||||
std::size_t num_buckets
|
||||
= this->min_buckets_for_size((std::max)(size,
|
||||
this->size_ + (this->size_ >> 1)));
|
||||
if(num_buckets != this->bucket_count_) {
|
||||
rehash_impl(num_buckets);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise.
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::rehash(std::size_t min_buckets)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
if(!this->size_) {
|
||||
if(this->buckets_) this->delete_buckets();
|
||||
this->bucket_count_ = next_prime(min_buckets);
|
||||
}
|
||||
else {
|
||||
// no throw:
|
||||
min_buckets = next_prime((std::max)(min_buckets,
|
||||
double_to_size_t(floor(this->size_ / (double) mlf_)) + 1));
|
||||
if(min_buckets != this->bucket_count_) rehash_impl(min_buckets);
|
||||
}
|
||||
}
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>
|
||||
::rehash_impl(std::size_t num_buckets)
|
||||
{
|
||||
hasher const& hf = this->hash_function();
|
||||
std::size_t size = this->size_;
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
|
||||
buckets dst(this->node_alloc(), num_buckets);
|
||||
dst.create_buckets();
|
||||
|
||||
buckets src(this->node_alloc(), this->bucket_count_);
|
||||
src.swap(*this);
|
||||
this->size_ = 0;
|
||||
|
||||
for(bucket_ptr bucket = this->cached_begin_bucket_;
|
||||
bucket != end; ++bucket)
|
||||
{
|
||||
node_ptr group = bucket->next_;
|
||||
while(group) {
|
||||
// Move the first group of equivalent nodes in bucket to dst.
|
||||
|
||||
// This next line throws iff the hash function throws.
|
||||
bucket_ptr dst_bucket = dst.bucket_ptr_from_hash(
|
||||
hf(get_key_from_ptr(group)));
|
||||
|
||||
node_ptr& next_group = node::next_group(group);
|
||||
bucket->next_ = next_group;
|
||||
next_group = dst_bucket->next_;
|
||||
dst_bucket->next_ = group;
|
||||
group = bucket->next_;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap the new nodes back into the container and setup the local
|
||||
// variables.
|
||||
this->size_ = size;
|
||||
dst.swap(*this); // no throw
|
||||
this->init_buckets();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// copy_buckets_to
|
||||
|
||||
// copy_buckets_to
|
||||
//
|
||||
// basic excpetion safety. If an exception is thrown this will
|
||||
// leave dst partially filled.
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>
|
||||
::copy_buckets_to(buckets& dst) const
|
||||
{
|
||||
BOOST_ASSERT(this->buckets_ && !dst.buckets_);
|
||||
|
||||
hasher const& hf = this->hash_function();
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
|
||||
node_constructor a(dst);
|
||||
dst.create_buckets();
|
||||
|
||||
// no throw:
|
||||
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) {
|
||||
// no throw:
|
||||
for(node_ptr it = i->next_; it;) {
|
||||
// hash function can throw.
|
||||
bucket_ptr dst_bucket = dst.bucket_ptr_from_hash(
|
||||
hf(get_key_from_ptr(it)));
|
||||
// throws, strong
|
||||
|
||||
node_ptr group_end = node::next_group(it);
|
||||
|
||||
a.construct(node::get_value(it));
|
||||
node_ptr n = a.release();
|
||||
node::add_to_bucket(n, *dst_bucket);
|
||||
|
||||
for(it = it->next_; it != group_end; it = it->next_) {
|
||||
a.construct(node::get_value(it));
|
||||
node::add_after_node(a.release(), n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Misc. key methods
|
||||
|
||||
// strong exception safety
|
||||
|
||||
// count
|
||||
//
|
||||
// strong exception safety, no side effects
|
||||
|
||||
template <class T>
|
||||
std::size_t hash_table<T>::count(key_type const& k) const
|
||||
{
|
||||
if(!this->size_) return 0;
|
||||
node_ptr it = find_iterator(k); // throws, strong
|
||||
return BOOST_UNORDERED_BORLAND_BOOL(it) ? node::group_count(it) : 0;
|
||||
}
|
||||
|
||||
// find
|
||||
//
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_base
|
||||
hash_table<T>::find(key_type const& k) const
|
||||
{
|
||||
if(!this->size_) return this->end();
|
||||
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
node_ptr it = find_iterator(bucket, k);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(it))
|
||||
return iterator_base(bucket, it);
|
||||
else
|
||||
return this->end();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class Key, class Hash, class Pred>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_base hash_table<T>::find(Key const& k,
|
||||
Hash const& h, Pred const& eq) const
|
||||
{
|
||||
if(!this->size_) return this->end();
|
||||
|
||||
bucket_ptr bucket = this->get_bucket(h(k) % this->bucket_count_);
|
||||
node_ptr it = find_iterator(bucket, k, eq);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(it))
|
||||
return iterator_base(bucket, it);
|
||||
else
|
||||
return this->end();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::value_type&
|
||||
hash_table<T>::at(key_type const& k) const
|
||||
{
|
||||
if(!this->size_)
|
||||
boost::throw_exception(std::out_of_range("Unable to find key in unordered_map."));
|
||||
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
node_ptr it = find_iterator(bucket, k);
|
||||
|
||||
if (!it)
|
||||
boost::throw_exception(std::out_of_range("Unable to find key in unordered_map."));
|
||||
|
||||
return node::get_value(it);
|
||||
}
|
||||
|
||||
// equal_range
|
||||
//
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_pair
|
||||
hash_table<T>::equal_range(key_type const& k) const
|
||||
{
|
||||
if(!this->size_)
|
||||
return iterator_pair(this->end(), this->end());
|
||||
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
node_ptr it = find_iterator(bucket, k);
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(it)) {
|
||||
iterator_base first(iterator_base(bucket, it));
|
||||
iterator_base second(first);
|
||||
second.increment_bucket(node::next_group(second.node_));
|
||||
return iterator_pair(first, second);
|
||||
}
|
||||
else {
|
||||
return iterator_pair(this->end(), this->end());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Erase methods
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::clear()
|
||||
{
|
||||
if(!this->size_) return;
|
||||
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
||||
this->clear_bucket(begin);
|
||||
}
|
||||
|
||||
this->size_ = 0;
|
||||
this->cached_begin_bucket_ = end;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline std::size_t hash_table<T>::erase_group(
|
||||
node_ptr* it, bucket_ptr bucket)
|
||||
{
|
||||
node_ptr pos = *it;
|
||||
node_ptr end = node::next_group(pos);
|
||||
*it = end;
|
||||
std::size_t count = this->delete_nodes(pos, end);
|
||||
this->size_ -= count;
|
||||
this->recompute_begin_bucket(bucket);
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::size_t hash_table<T>::erase_key(key_type const& k)
|
||||
{
|
||||
if(!this->size_) return 0;
|
||||
|
||||
// No side effects in initial section
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
node_ptr* it = this->find_for_erase(bucket, k);
|
||||
|
||||
// No throw.
|
||||
return *it ? this->erase_group(it, bucket) : 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::erase(iterator_base r)
|
||||
{
|
||||
BOOST_ASSERT(r.node_);
|
||||
--this->size_;
|
||||
node::unlink_node(*r.bucket_, r.node_);
|
||||
this->delete_node(r.node_);
|
||||
// r has been invalidated but its bucket is still valid
|
||||
this->recompute_begin_bucket(r.bucket_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_base
|
||||
hash_table<T>::erase_return_iterator(iterator_base r)
|
||||
{
|
||||
BOOST_ASSERT(r.node_);
|
||||
iterator_base next = r;
|
||||
next.increment();
|
||||
--this->size_;
|
||||
node::unlink_node(*r.bucket_, r.node_);
|
||||
this->delete_node(r.node_);
|
||||
// r has been invalidated but its bucket is still valid
|
||||
this->recompute_begin_bucket(r.bucket_, next.bucket_);
|
||||
return next;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_base
|
||||
hash_table<T>::erase_range(
|
||||
iterator_base r1, iterator_base r2)
|
||||
{
|
||||
if(r1 != r2)
|
||||
{
|
||||
BOOST_ASSERT(r1.node_);
|
||||
if (r1.bucket_ == r2.bucket_) {
|
||||
node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_);
|
||||
this->size_ -= this->delete_nodes(r1.node_, r2.node_);
|
||||
|
||||
// No need to call recompute_begin_bucket because
|
||||
// the nodes are only deleted from one bucket, which
|
||||
// still contains r2 after the erase.
|
||||
BOOST_ASSERT(r1.bucket_->next_);
|
||||
}
|
||||
else {
|
||||
bucket_ptr end_bucket = r2.node_ ?
|
||||
r2.bucket_ : this->get_bucket(this->bucket_count_);
|
||||
BOOST_ASSERT(r1.bucket_ < end_bucket);
|
||||
node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr());
|
||||
this->size_ -= this->delete_nodes(r1.node_, node_ptr());
|
||||
|
||||
bucket_ptr i = r1.bucket_;
|
||||
for(++i; i != end_bucket; ++i) {
|
||||
this->size_ -= this->delete_nodes(i->next_, node_ptr());
|
||||
i->next_ = node_ptr();
|
||||
}
|
||||
|
||||
if(r2.node_) {
|
||||
node_ptr first = r2.bucket_->next_;
|
||||
node::unlink_nodes(*r2.bucket_, r2.node_);
|
||||
this->size_ -= this->delete_nodes(first, r2.node_);
|
||||
}
|
||||
|
||||
// r1 has been invalidated but its bucket is still
|
||||
// valid.
|
||||
this->recompute_begin_bucket(r1.bucket_, end_bucket);
|
||||
}
|
||||
}
|
||||
|
||||
return r2;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME hash_table<T>::iterator_base
|
||||
hash_table<T>::emplace_empty_impl_with_node(
|
||||
node_constructor& a, std::size_t size)
|
||||
{
|
||||
key_type const& k = get_key(a.value());
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
if(this->buckets_) this->reserve_for_insert(size);
|
||||
else this->create_for_insert(size);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr n = a.release();
|
||||
node::add_to_bucket(n, *bucket);
|
||||
++this->size_;
|
||||
this->cached_begin_bucket_ = bucket;
|
||||
return iterator_base(bucket, n);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
500
include/boost/unordered/detail/unique.hpp
Normal file
500
include/boost/unordered/detail/unique.hpp
Normal file
@ -0,0 +1,500 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2009 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_UNIQUE_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
||||
|
||||
#include <boost/unordered/detail/table.hpp>
|
||||
#include <boost/unordered/detail/extract_key.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
template <class T>
|
||||
class hash_unique_table : public T::table
|
||||
{
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::table table;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node node;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
|
||||
|
||||
typedef std::pair<iterator_base, bool> emplace_return;
|
||||
|
||||
// Constructors
|
||||
|
||||
hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq,
|
||||
value_allocator const& a)
|
||||
: table(n, hf, eq, a) {}
|
||||
hash_unique_table(hash_unique_table const& x)
|
||||
: table(x, x.node_alloc()) {}
|
||||
hash_unique_table(hash_unique_table const& x, value_allocator const& a)
|
||||
: table(x, a) {}
|
||||
hash_unique_table(hash_unique_table& x, move_tag m)
|
||||
: table(x, m) {}
|
||||
hash_unique_table(hash_unique_table& x, value_allocator const& a,
|
||||
move_tag m)
|
||||
: table(x, a, m) {}
|
||||
~hash_unique_table() {}
|
||||
|
||||
// Insert methods
|
||||
|
||||
emplace_return emplace_impl_with_node(node_constructor& a);
|
||||
value_type& operator[](key_type const& k);
|
||||
|
||||
// equals
|
||||
|
||||
bool equals(hash_unique_table const&) const;
|
||||
|
||||
node_ptr add_node(node_constructor& a, bucket_ptr bucket);
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
template<class... Args>
|
||||
emplace_return emplace(Args&&... args);
|
||||
template<class... Args>
|
||||
emplace_return emplace_impl(key_type const& k, Args&&... args);
|
||||
template<class... Args>
|
||||
emplace_return emplace_impl(no_key, Args&&... args);
|
||||
template<class... Args>
|
||||
emplace_return emplace_empty_impl(Args&&... args);
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
||||
emplace_return emplace( \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
||||
emplace_return emplace_impl(key_type const& k, \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
||||
emplace_return emplace_impl(no_key, \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
||||
emplace_return emplace_empty_impl( \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, n));
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
||||
|
||||
#endif
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception
|
||||
// safety strong otherwise
|
||||
template <class InputIt>
|
||||
void insert_range(InputIt i, InputIt j);
|
||||
template <class InputIt>
|
||||
void insert_range_impl(key_type const&, InputIt i, InputIt j);
|
||||
template <class InputIt>
|
||||
void insert_range_impl(no_key, InputIt i, InputIt j);
|
||||
};
|
||||
|
||||
template <class H, class P, class A>
|
||||
struct set : public types<
|
||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
H, P, A,
|
||||
set_extractor<BOOST_DEDUCED_TYPENAME A::value_type>,
|
||||
ungrouped>
|
||||
{
|
||||
typedef hash_unique_table<set<H, P, A> > impl;
|
||||
typedef hash_table<set<H, P, A> > table;
|
||||
};
|
||||
|
||||
template <class K, class H, class P, class A>
|
||||
struct map : public types<
|
||||
K, BOOST_DEDUCED_TYPENAME A::value_type,
|
||||
H, P, A,
|
||||
map_extractor<K, BOOST_DEDUCED_TYPENAME A::value_type>,
|
||||
ungrouped>
|
||||
{
|
||||
typedef hash_unique_table<map<K, H, P, A> > impl;
|
||||
typedef hash_table<map<K, H, P, A> > table;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Equality
|
||||
|
||||
template <class T>
|
||||
bool hash_unique_table<T>
|
||||
::equals(hash_unique_table<T> const& other) const
|
||||
{
|
||||
if(this->size_ != other.size_) return false;
|
||||
if(!this->size_) return true;
|
||||
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i)
|
||||
{
|
||||
node_ptr it1 = i->next_;
|
||||
while(BOOST_UNORDERED_BORLAND_BOOL(it1))
|
||||
{
|
||||
node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1));
|
||||
if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
|
||||
if(!extractor::compare_mapped(
|
||||
node::get_value(it1), node::get_value(it2)))
|
||||
return false;
|
||||
it1 = it1->next_;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// A convenience method for adding nodes.
|
||||
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::node_ptr
|
||||
hash_unique_table<T>::add_node(node_constructor& a,
|
||||
bucket_ptr bucket)
|
||||
{
|
||||
node_ptr n = a.release();
|
||||
node::add_to_bucket(n, *bucket);
|
||||
++this->size_;
|
||||
if(bucket < this->cached_begin_bucket_)
|
||||
this->cached_begin_bucket_ = bucket;
|
||||
return n;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Insert methods
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::value_type&
|
||||
hash_unique_table<T>::operator[](key_type const& k)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
|
||||
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
if(!this->buckets_) {
|
||||
node_constructor a(*this);
|
||||
a.construct_pair(k, (mapped_type*) 0);
|
||||
return *this->emplace_empty_impl_with_node(a, 1);
|
||||
}
|
||||
|
||||
node_ptr pos = this->find_iterator(bucket, k);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
return node::get_value(pos);
|
||||
}
|
||||
else {
|
||||
// Side effects only in this block.
|
||||
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(*this);
|
||||
a.construct_pair(k, (mapped_type*) 0);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->reserve_for_insert(this->size_ + 1))
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
// Nothing after this point can throw.
|
||||
|
||||
return node::get_value(add_node(a, bucket));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace_impl_with_node(node_constructor& a)
|
||||
{
|
||||
// No side effects in this initial code
|
||||
key_type const& k = this->get_key(a.value());
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr pos = this->find_iterator(bucket, k);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
// Found an existing key, return it (no throw).
|
||||
return emplace_return(iterator_base(bucket, pos), false);
|
||||
} else {
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->reserve_for_insert(this->size_ + 1))
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
// Nothing after this point can throw.
|
||||
|
||||
return emplace_return(
|
||||
iterator_base(bucket, add_node(a, bucket)),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
template <class T>
|
||||
template<class... Args>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace_impl(key_type const& k,
|
||||
Args&&... args)
|
||||
{
|
||||
// No side effects in this initial code
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr pos = this->find_iterator(bucket, k);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
// Found an existing key, return it (no throw).
|
||||
return emplace_return(iterator_base(bucket, pos), false);
|
||||
|
||||
} else {
|
||||
// Doesn't already exist, add to bucket.
|
||||
// Side effects only in this block.
|
||||
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(*this);
|
||||
a.construct(std::forward<Args>(args)...);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->reserve_for_insert(this->size_ + 1))
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
// Nothing after this point can throw.
|
||||
|
||||
return emplace_return(
|
||||
iterator_base(bucket, add_node(a, bucket)),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template<class... Args>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace_impl(no_key, Args&&... args)
|
||||
{
|
||||
// Construct the node regardless - in order to get the key.
|
||||
// It will be discarded if it isn't used
|
||||
node_constructor a(*this);
|
||||
a.construct(std::forward<Args>(args)...);
|
||||
return emplace_impl_with_node(a);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template<class... Args>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace_empty_impl(Args&&... args)
|
||||
{
|
||||
node_constructor a(*this);
|
||||
a.construct(std::forward<Args>(args)...);
|
||||
return emplace_return(this->emplace_empty_impl_with_node(a, 1), true);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
inline BOOST_DEDUCED_TYPENAME \
|
||||
hash_unique_table<T>::emplace_return \
|
||||
hash_unique_table<T>::emplace_impl( \
|
||||
key_type const& k, \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
std::size_t hash_value = this->hash_function()(k); \
|
||||
bucket_ptr bucket \
|
||||
= this->bucket_ptr_from_hash(hash_value); \
|
||||
node_ptr pos = this->find_iterator(bucket, k); \
|
||||
\
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
|
||||
return emplace_return(iterator_base(bucket, pos), false); \
|
||||
} else { \
|
||||
node_constructor a(*this); \
|
||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
\
|
||||
if(this->reserve_for_insert(this->size_ + 1)) \
|
||||
bucket = this->bucket_ptr_from_hash(hash_value); \
|
||||
\
|
||||
return emplace_return(iterator_base(bucket, \
|
||||
add_node(a, bucket)), true); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
inline BOOST_DEDUCED_TYPENAME \
|
||||
hash_unique_table<T>::emplace_return \
|
||||
hash_unique_table<T>:: \
|
||||
emplace_impl(no_key, \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
node_constructor a(*this); \
|
||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
return emplace_impl_with_node(a); \
|
||||
} \
|
||||
\
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
inline BOOST_DEDUCED_TYPENAME \
|
||||
hash_unique_table<T>::emplace_return \
|
||||
hash_unique_table<T>:: \
|
||||
emplace_empty_impl( \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
node_constructor a(*this); \
|
||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
// Emplace (unique keys)
|
||||
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise
|
||||
|
||||
template <class T>
|
||||
template<class... Args>
|
||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace(Args&&... args)
|
||||
{
|
||||
return this->size_ ?
|
||||
emplace_impl(
|
||||
extractor::extract(std::forward<Args>(args)...),
|
||||
std::forward<Args>(args)...) :
|
||||
emplace_empty_impl(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
template <class Arg0>
|
||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace(Arg0 const& arg0)
|
||||
{
|
||||
return this->size_ ?
|
||||
emplace_impl(extractor::extract(arg0), arg0) :
|
||||
emplace_empty_impl(arg0);
|
||||
}
|
||||
|
||||
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return \
|
||||
hash_unique_table<T>::emplace( \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
return this->size_ ? \
|
||||
emplace_impl(extractor::extract(arg0, arg1), \
|
||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params)) : \
|
||||
emplace_empty_impl( \
|
||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
|
||||
template <class T>
|
||||
template <class InputIt>
|
||||
inline void hash_unique_table<T>::insert_range_impl(
|
||||
key_type const&, InputIt i, InputIt j)
|
||||
{
|
||||
node_constructor a(*this);
|
||||
|
||||
if(!this->size_) {
|
||||
a.construct(*i);
|
||||
this->emplace_empty_impl_with_node(a, 1);
|
||||
++i;
|
||||
if(i == j) return;
|
||||
}
|
||||
|
||||
do {
|
||||
// No side effects in this initial code
|
||||
// Note: can't use get_key as '*i' might not be value_type - it
|
||||
// could be a pair with first_types as key_type without const or a
|
||||
// different second_type.
|
||||
key_type const& k = extractor::extract(*i);
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr pos = this->find_iterator(bucket, k);
|
||||
|
||||
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
// Doesn't already exist, add to bucket.
|
||||
// Side effects only in this block.
|
||||
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
a.construct(*i);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->size_ + 1 >= this->max_load_) {
|
||||
this->reserve_for_insert(this->size_ + insert_size(i, j));
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
}
|
||||
|
||||
// Nothing after this point can throw.
|
||||
add_node(a, bucket);
|
||||
}
|
||||
} while(++i != j);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class InputIt>
|
||||
inline void hash_unique_table<T>::insert_range_impl(
|
||||
no_key, InputIt i, InputIt j)
|
||||
{
|
||||
node_constructor a(*this);
|
||||
|
||||
if(!this->size_) {
|
||||
a.construct(*i);
|
||||
this->emplace_empty_impl_with_node(a, 1);
|
||||
++i;
|
||||
if(i == j) return;
|
||||
}
|
||||
|
||||
do {
|
||||
// No side effects in this initial code
|
||||
a.construct(*i);
|
||||
emplace_impl_with_node(a);
|
||||
} while(++i != j);
|
||||
}
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class InputIt>
|
||||
void hash_unique_table<T>::insert_range(InputIt i, InputIt j)
|
||||
{
|
||||
if(i != j)
|
||||
return insert_range_impl(extractor::extract(*i), i, j);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
331
include/boost/unordered/detail/util.hpp
Normal file
331
include/boost/unordered/detail/util.hpp
Normal file
@ -0,0 +1,331 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2009 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_UTIL_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/iterator/iterator_categories.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
#include <boost/preprocessor/seq/enum.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// convert double to std::size_t
|
||||
|
||||
inline std::size_t double_to_size_t(double f)
|
||||
{
|
||||
return f >= static_cast<double>(
|
||||
(std::numeric_limits<std::size_t>::max)()) ?
|
||||
(std::numeric_limits<std::size_t>::max)() :
|
||||
static_cast<std::size_t>(f);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// primes
|
||||
|
||||
#define BOOST_UNORDERED_PRIMES \
|
||||
(5ul)(11ul)(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \
|
||||
(97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \
|
||||
(1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \
|
||||
(49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \
|
||||
(1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \
|
||||
(50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \
|
||||
(1610612741ul)(3221225473ul)(4294967291ul)
|
||||
|
||||
template<class T> struct prime_list_template
|
||||
{
|
||||
static std::size_t const value[];
|
||||
|
||||
#if !defined(SUNPRO_CC)
|
||||
static std::ptrdiff_t const length;
|
||||
#else
|
||||
static std::ptrdiff_t const length
|
||||
= BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES);
|
||||
#endif
|
||||
};
|
||||
|
||||
template<class T>
|
||||
std::size_t const prime_list_template<T>::value[] = {
|
||||
BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)
|
||||
};
|
||||
|
||||
#if !defined(SUNPRO_CC)
|
||||
template<class T>
|
||||
std::ptrdiff_t const prime_list_template<T>::length
|
||||
= BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES);
|
||||
#endif
|
||||
|
||||
#undef BOOST_UNORDERED_PRIMES
|
||||
|
||||
typedef prime_list_template<std::size_t> prime_list;
|
||||
|
||||
// no throw
|
||||
inline std::size_t next_prime(std::size_t num) {
|
||||
std::size_t const* const prime_list_begin = prime_list::value;
|
||||
std::size_t const* const prime_list_end = prime_list_begin +
|
||||
prime_list::length;
|
||||
std::size_t const* bound =
|
||||
std::lower_bound(prime_list_begin, prime_list_end, num);
|
||||
if(bound == prime_list_end)
|
||||
bound--;
|
||||
return *bound;
|
||||
}
|
||||
|
||||
// no throw
|
||||
inline std::size_t prev_prime(std::size_t num) {
|
||||
std::size_t const* const prime_list_begin = prime_list::value;
|
||||
std::size_t const* const prime_list_end = prime_list_begin +
|
||||
prime_list::length;
|
||||
std::size_t const* bound =
|
||||
std::upper_bound(prime_list_begin,prime_list_end, num);
|
||||
if(bound != prime_list_begin)
|
||||
bound--;
|
||||
return *bound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// pair_cast - because some libraries don't have the full pair constructors.
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// insert_size/initial_size
|
||||
|
||||
#if !defined(BOOST_NO_STD_DISTANCE)
|
||||
using ::std::distance;
|
||||
#else
|
||||
template <class ForwardIterator>
|
||||
inline std::size_t distance(ForwardIterator i, ForwardIterator j) {
|
||||
std::size_t x;
|
||||
std::distance(i, j, x);
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class I>
|
||||
inline std::size_t insert_size(I i, I j, boost::forward_traversal_tag)
|
||||
{
|
||||
return std::distance(i, j);
|
||||
}
|
||||
|
||||
template <class I>
|
||||
inline std::size_t insert_size(I, I, boost::incrementable_traversal_tag)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class I>
|
||||
inline std::size_t insert_size(I i, I j)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
|
||||
iterator_traversal_tag;
|
||||
return insert_size(i, j, iterator_traversal_tag);
|
||||
}
|
||||
|
||||
template <class I>
|
||||
inline std::size_t initial_size(I i, I j,
|
||||
std::size_t num_buckets = boost::unordered_detail::default_bucket_count)
|
||||
{
|
||||
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1,
|
||||
num_buckets);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Node Constructors
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
template <class T, class... Args>
|
||||
inline void construct_impl(T*, void* address, Args&&... args)
|
||||
{
|
||||
new(address) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_CPP0X_PAIR)
|
||||
template <class First, class Second, class Key, class Arg0, class... Args>
|
||||
inline void construct_impl(std::pair<First, Second>*, void* address,
|
||||
Key&& k, Arg0&& arg0, Args&&... args)
|
||||
)
|
||||
{
|
||||
new(address) std::pair<First, Second>(k,
|
||||
Second(arg0, std::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
|
||||
template < \
|
||||
class T, \
|
||||
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||
> \
|
||||
inline void construct_impl( \
|
||||
T*, void* address, \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
||||
) \
|
||||
{ \
|
||||
new(address) T( \
|
||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
} \
|
||||
\
|
||||
template <class First, class Second, class Key, \
|
||||
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||
> \
|
||||
inline void construct_impl( \
|
||||
std::pair<First, Second>*, void* address, \
|
||||
Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
new(address) std::pair<First, Second>(k, \
|
||||
Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_CONSTRUCT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
|
||||
#endif
|
||||
|
||||
// hash_node_constructor
|
||||
//
|
||||
// Used to construct nodes in an exception safe manner.
|
||||
|
||||
template <class Alloc, class Grouped>
|
||||
class hash_node_constructor
|
||||
{
|
||||
typedef hash_buckets<Alloc, Grouped> buckets;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type;
|
||||
|
||||
buckets& buckets_;
|
||||
real_node_ptr node_;
|
||||
bool node_constructed_;
|
||||
bool value_constructed_;
|
||||
|
||||
public:
|
||||
|
||||
hash_node_constructor(buckets& m) :
|
||||
buckets_(m),
|
||||
node_(),
|
||||
node_constructed_(false),
|
||||
value_constructed_(false)
|
||||
{
|
||||
}
|
||||
|
||||
~hash_node_constructor();
|
||||
void construct_preamble();
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template <class... Args>
|
||||
void construct(Args&&... args)
|
||||
{
|
||||
construct_preamble();
|
||||
construct_impl((value_type*) 0, node_->address(),
|
||||
std::forward<Args>(args)...);
|
||||
value_constructed_ = true;
|
||||
}
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \
|
||||
template < \
|
||||
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||
> \
|
||||
void construct( \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
||||
) \
|
||||
{ \
|
||||
construct_preamble(); \
|
||||
construct_impl( \
|
||||
(value_type*) 0, node_->address(), \
|
||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
|
||||
); \
|
||||
value_constructed_ = true; \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_CONSTRUCT, _)
|
||||
|
||||
#undef BOOST_UNORDERED_CONSTRUCT
|
||||
|
||||
#endif
|
||||
template <class K, class M>
|
||||
void construct_pair(K const& k, M*)
|
||||
{
|
||||
construct_preamble();
|
||||
new(node_->address()) value_type(k, M());
|
||||
value_constructed_ = true;
|
||||
}
|
||||
|
||||
value_type& value() const
|
||||
{
|
||||
BOOST_ASSERT(node_);
|
||||
return node_->value();
|
||||
}
|
||||
|
||||
// no throw
|
||||
BOOST_DEDUCED_TYPENAME buckets::node_ptr release()
|
||||
{
|
||||
real_node_ptr p = node_;
|
||||
node_ = real_node_ptr();
|
||||
// node_ptr cast
|
||||
return buckets_.bucket_alloc().address(*p);
|
||||
}
|
||||
|
||||
private:
|
||||
hash_node_constructor(hash_node_constructor const&);
|
||||
hash_node_constructor& operator=(hash_node_constructor const&);
|
||||
};
|
||||
|
||||
// hash_node_constructor
|
||||
|
||||
template <class Alloc, class Grouped>
|
||||
inline hash_node_constructor<Alloc, Grouped>::~hash_node_constructor()
|
||||
{
|
||||
if (node_) {
|
||||
if (value_constructed_) {
|
||||
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
|
||||
struct dummy { hash_node<Alloc, Grouped> x; };
|
||||
#endif
|
||||
boost::unordered_detail::destroy(&node_->value());
|
||||
}
|
||||
|
||||
if (node_constructed_)
|
||||
buckets_.node_alloc().destroy(node_);
|
||||
|
||||
buckets_.node_alloc().deallocate(node_, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Alloc, class Grouped>
|
||||
inline void hash_node_constructor<Alloc, Grouped>::construct_preamble()
|
||||
{
|
||||
if(!node_) {
|
||||
node_constructed_ = false;
|
||||
value_constructed_ = false;
|
||||
|
||||
node_ = buckets_.node_alloc().allocate(1);
|
||||
buckets_.node_alloc().construct(node_, node());
|
||||
node_constructed_ = true;
|
||||
}
|
||||
else {
|
||||
BOOST_ASSERT(node_constructed_ && value_constructed_);
|
||||
boost::unordered_detail::destroy(&node_->value());
|
||||
value_constructed_ = false;
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
1118
include/boost/unordered/unordered_map.hpp
Normal file
1118
include/boost/unordered/unordered_map.hpp
Normal file
File diff suppressed because it is too large
Load Diff
53
include/boost/unordered/unordered_map_fwd.hpp
Normal file
53
include/boost/unordered/unordered_map_fwd.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
// Copyright (C) 2008-2009 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_FWD_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_MAP_FWD_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class K,
|
||||
class T,
|
||||
class H = hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
class unordered_map;
|
||||
template <class K, class T, class H, class P, class A>
|
||||
bool operator==(unordered_map<K, T, H, P, A> const&,
|
||||
unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
bool operator!=(unordered_map<K, T, H, P, A> const&,
|
||||
unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void swap(unordered_map<K, T, H, P, A>&,
|
||||
unordered_map<K, T, H, P, A>&);
|
||||
|
||||
template <class K,
|
||||
class T,
|
||||
class H = hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
class unordered_multimap;
|
||||
template <class K, class T, class H, class P, class A>
|
||||
bool operator==(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
bool operator!=(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void swap(unordered_multimap<K, T, H, P, A>&,
|
||||
unordered_multimap<K, T, H, P, A>&);
|
||||
}
|
||||
|
||||
#endif
|
1037
include/boost/unordered/unordered_set.hpp
Normal file
1037
include/boost/unordered/unordered_set.hpp
Normal file
File diff suppressed because it is too large
Load Diff
51
include/boost/unordered/unordered_set_fwd.hpp
Normal file
51
include/boost/unordered/unordered_set_fwd.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
|
||||
// Copyright (C) 2008-2009 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_FWD_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_SET_FWD_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class T,
|
||||
class H = hash<T>,
|
||||
class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
class unordered_set;
|
||||
template <class T, class H, class P, class A>
|
||||
bool operator==(unordered_set<T, H, P, A> const&,
|
||||
unordered_set<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
bool operator!=(unordered_set<T, H, P, A> const&,
|
||||
unordered_set<T, H, P, A> const&);
|
||||
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);
|
||||
|
||||
template <class T,
|
||||
class H = hash<T>,
|
||||
class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
class unordered_multiset;
|
||||
template <class T, class H, class P, class A>
|
||||
bool operator==(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
bool operator!=(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
@ -13,775 +13,6 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/unordered/detail/hash_table.hpp>
|
||||
|
||||
#if !defined(BOOST_HAS_RVALUE_REFS)
|
||||
#include <boost/unordered/detail/move.hpp>
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: Should this be explicit?
|
||||
unordered_map(allocator_type const& a)
|
||||
: base(boost::unordered_detail::default_initial_bucket_count,
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_map(unordered_map const& other, allocator_type const& a)
|
||||
: base(other.base, 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)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
unordered_map(unordered_map&& other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_map(unordered_map&& other, allocator_type const& a)
|
||||
: base(other.base, a, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_map& operator=(unordered_map&& x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unordered_map(boost::unordered_detail::move_from<unordered_map<Key, T, Hash, Pred, Alloc> > other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
|
||||
unordered_map& operator=(unordered_map x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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.data_.begin());
|
||||
}
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(base.data_.begin());
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return iterator(base.data_.end());
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator(base.data_.end());
|
||||
}
|
||||
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return const_iterator(base.data_.begin());
|
||||
}
|
||||
|
||||
const_iterator cend() const
|
||||
{
|
||||
return const_iterator(base.data_.end());
|
||||
}
|
||||
|
||||
// modifiers
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
return boost::unordered_detail::pair_cast<iterator, bool>(
|
||||
base.insert(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace(const_iterator hint, Args&&... args)
|
||||
{
|
||||
return iterator(base.insert_hint(get(hint), std::forward<Args>(args)...));
|
||||
}
|
||||
#endif
|
||||
|
||||
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_hint(get(hint), obj));
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
base.insert_range(first, last);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator position)
|
||||
{
|
||||
return iterator(base.data_.erase(get(position)));
|
||||
}
|
||||
|
||||
size_type erase(const key_type& k)
|
||||
{
|
||||
return base.erase_key(k);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
return iterator(base.data_.erase_range(get(first), get(last)));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
base.data_.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.data_.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.data_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.begin(n));
|
||||
}
|
||||
|
||||
local_iterator end(size_type n)
|
||||
{
|
||||
return local_iterator(base.data_.end(n));
|
||||
}
|
||||
|
||||
const_local_iterator end(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.end(n));
|
||||
}
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.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);
|
||||
}
|
||||
|
||||
friend bool operator==(unordered_map const& m1, unordered_map const& m2)
|
||||
{
|
||||
return m1.base.equals(m2.base);
|
||||
}
|
||||
|
||||
friend bool operator!=(unordered_map const& m1, unordered_map const& m2)
|
||||
{
|
||||
return !m1.base.equals(m2.base);
|
||||
}
|
||||
|
||||
friend std::size_t hash_value(unordered_map const& m)
|
||||
{
|
||||
return m.base.hash_value();
|
||||
}
|
||||
}; // class template unordered_map
|
||||
|
||||
template <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)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multimap(allocator_type const& a)
|
||||
: base(boost::unordered_detail::default_initial_bucket_count,
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multimap(unordered_multimap const& other, allocator_type const& a)
|
||||
: base(other.base, 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)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
unordered_multimap(unordered_multimap&& other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multimap(unordered_multimap&& other, allocator_type const& a)
|
||||
: base(other.base, a, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multimap& operator=(unordered_multimap&& x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unordered_multimap(boost::unordered_detail::move_from<unordered_multimap<Key, T, Hash, Pred, Alloc> > other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
|
||||
unordered_multimap& operator=(unordered_multimap x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
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.data_.begin());
|
||||
}
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(base.data_.begin());
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return iterator(base.data_.end());
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator(base.data_.end());
|
||||
}
|
||||
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return const_iterator(base.data_.begin());
|
||||
}
|
||||
|
||||
const_iterator cend() const
|
||||
{
|
||||
return const_iterator(base.data_.end());
|
||||
}
|
||||
|
||||
// modifiers
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
template <class... Args>
|
||||
iterator emplace(Args&&... args)
|
||||
{
|
||||
return iterator(base.insert(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace(const_iterator hint, Args&&... args)
|
||||
{
|
||||
return iterator(base.insert_hint(get(hint), std::forward<Args>(args)...));
|
||||
}
|
||||
#endif
|
||||
|
||||
iterator insert(const value_type& obj)
|
||||
{
|
||||
return iterator(base.insert(obj));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& obj)
|
||||
{
|
||||
return iterator(base.insert_hint(get(hint), obj));
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
base.insert_range(first, last);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator position)
|
||||
{
|
||||
return iterator(base.data_.erase(get(position)));
|
||||
}
|
||||
|
||||
size_type erase(const key_type& k)
|
||||
{
|
||||
return base.erase_key(k);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
return iterator(base.data_.erase_range(get(first), get(last)));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
base.data_.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.data_.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.data_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.begin(n));
|
||||
}
|
||||
|
||||
local_iterator end(size_type n)
|
||||
{
|
||||
return local_iterator(base.data_.end(n));
|
||||
}
|
||||
|
||||
const_local_iterator end(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.end(n));
|
||||
}
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.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);
|
||||
}
|
||||
|
||||
friend bool operator==(unordered_multimap const& m1, unordered_multimap const& m2)
|
||||
{
|
||||
return m1.base.equals(m2.base);
|
||||
}
|
||||
|
||||
friend bool operator!=(unordered_multimap const& m1, unordered_multimap const& m2)
|
||||
{
|
||||
return !m1.base.equals(m2.base);
|
||||
}
|
||||
|
||||
friend std::size_t hash_value(unordered_multimap const& m)
|
||||
{
|
||||
return m.base.hash_value();
|
||||
}
|
||||
}; // class template unordered_multimap
|
||||
|
||||
template <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
|
||||
#include <boost/unordered/unordered_map.hpp>
|
||||
|
||||
#endif // BOOST_UNORDERED_MAP_HPP_INCLUDED
|
||||
|
@ -13,731 +13,6 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/unordered/detail/hash_table.hpp>
|
||||
|
||||
#if !defined(BOOST_HAS_RVALUE_REFS)
|
||||
#include <boost/unordered/detail/move.hpp>
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: Should this be explicit?
|
||||
unordered_set(allocator_type const& a)
|
||||
: base(boost::unordered_detail::default_initial_bucket_count,
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_set(unordered_set const& other, allocator_type const& a)
|
||||
: base(other.base, 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)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
unordered_set(unordered_set&& other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_set(unordered_set&& other, allocator_type const& a)
|
||||
: base(other.base, a, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_set& operator=(unordered_set&& x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unordered_set(boost::unordered_detail::move_from<unordered_set<Value, Hash, Pred, Alloc> > other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
|
||||
unordered_set& operator=(unordered_set x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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.data_.begin());
|
||||
}
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(base.data_.begin());
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return iterator(base.data_.end());
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator(base.data_.end());
|
||||
}
|
||||
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return const_iterator(base.data_.begin());
|
||||
}
|
||||
|
||||
const_iterator cend() const
|
||||
{
|
||||
return const_iterator(base.data_.end());
|
||||
}
|
||||
|
||||
// modifiers
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
return boost::unordered_detail::pair_cast<iterator, bool>(
|
||||
base.insert(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace(const_iterator hint, Args&&... args)
|
||||
{
|
||||
return iterator(
|
||||
base.insert_hint(get(hint), std::forward<Args>(args)...));
|
||||
}
|
||||
#endif
|
||||
|
||||
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_hint(get(hint), obj));
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
base.insert_range(first, last);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator position)
|
||||
{
|
||||
return iterator(base.data_.erase(get(position)));
|
||||
}
|
||||
|
||||
size_type erase(const key_type& k)
|
||||
{
|
||||
return base.erase_key(k);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
return iterator(base.data_.erase_range(get(first), get(last)));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
base.data_.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.data_.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.data_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.begin(n));
|
||||
}
|
||||
|
||||
local_iterator end(size_type n)
|
||||
{
|
||||
return local_iterator(base.data_.end(n));
|
||||
}
|
||||
|
||||
const_local_iterator end(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.end(n));
|
||||
}
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.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);
|
||||
}
|
||||
|
||||
friend bool operator==(unordered_set const& m1, unordered_set const& m2)
|
||||
{
|
||||
return m1.base.equals(m2.base);
|
||||
}
|
||||
|
||||
friend bool operator!=(unordered_set const& m1, unordered_set const& m2)
|
||||
{
|
||||
return !m1.base.equals(m2.base);
|
||||
}
|
||||
|
||||
friend std::size_t hash_value(unordered_set const& m)
|
||||
{
|
||||
return m.base.hash_value();
|
||||
}
|
||||
}; // class template unordered_set
|
||||
|
||||
template <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)
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: Should this be explicit?
|
||||
unordered_multiset(allocator_type const& a)
|
||||
: base(boost::unordered_detail::default_initial_bucket_count,
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multiset(unordered_multiset const& other, allocator_type const& a)
|
||||
: base(other.base, 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)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
unordered_multiset(unordered_multiset&& other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multiset(unordered_multiset&& other, allocator_type const& a)
|
||||
: base(other.base, a, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multiset& operator=(unordered_multiset&& x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unordered_multiset(boost::unordered_detail::move_from<unordered_multiset<Value, Hash, Pred, Alloc> > other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
|
||||
unordered_multiset& operator=(unordered_multiset x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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.data_.begin());
|
||||
}
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(base.data_.begin());
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return iterator(base.data_.end());
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator(base.data_.end());
|
||||
}
|
||||
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return const_iterator(base.data_.begin());
|
||||
}
|
||||
|
||||
const_iterator cend() const
|
||||
{
|
||||
return const_iterator(base.data_.end());
|
||||
}
|
||||
|
||||
// modifiers
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
template <class... Args>
|
||||
iterator emplace(Args&&... args)
|
||||
{
|
||||
return iterator(base.insert(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace(const_iterator hint, Args&&... args)
|
||||
{
|
||||
return iterator(base.insert_hint(get(hint), std::forward<Args>(args)...));
|
||||
}
|
||||
#endif
|
||||
|
||||
iterator insert(const value_type& obj)
|
||||
{
|
||||
return iterator(base.insert(obj));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& obj)
|
||||
{
|
||||
return iterator(base.insert_hint(get(hint), obj));
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
base.insert_range(first, last);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator position)
|
||||
{
|
||||
return iterator(base.data_.erase(get(position)));
|
||||
}
|
||||
|
||||
size_type erase(const key_type& k)
|
||||
{
|
||||
return base.erase_key(k);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
return iterator(base.data_.erase_range(get(first), get(last)));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
base.data_.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.data_.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.data_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.begin(n));
|
||||
}
|
||||
|
||||
local_iterator end(size_type n)
|
||||
{
|
||||
return local_iterator(base.data_.end(n));
|
||||
}
|
||||
|
||||
const_local_iterator end(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.end(n));
|
||||
}
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type n) const
|
||||
{
|
||||
return const_local_iterator(base.data_.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);
|
||||
}
|
||||
|
||||
friend bool operator==(unordered_multiset const& m1, unordered_multiset const& m2)
|
||||
{
|
||||
return m1.base.equals(m2.base);
|
||||
}
|
||||
|
||||
friend bool operator!=(unordered_multiset const& m1, unordered_multiset const& m2)
|
||||
{
|
||||
return !m1.base.equals(m2.base);
|
||||
}
|
||||
|
||||
friend std::size_t hash_value(unordered_multiset const& m)
|
||||
{
|
||||
return m.base.hash_value();
|
||||
}
|
||||
}; // class template unordered_multiset
|
||||
|
||||
template <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
|
||||
#include <boost/unordered/unordered_set.hpp>
|
||||
|
||||
#endif // BOOST_UNORDERED_SET_HPP_INCLUDED
|
||||
|
@ -3,5 +3,7 @@
|
||||
# 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 ;
|
||||
|
||||
build-project unordered ;
|
||||
build-project exception ;
|
||||
|
@ -10,8 +10,15 @@ alias framework : ;
|
||||
|
||||
project unordered-test/exception-tests
|
||||
: requirements
|
||||
<toolset>intel-linux:"<cxxflags>-strict_ansi -cxxlib-icc"
|
||||
<toolset>gcc:<cxxflags>"-Wsign-promo -Wunused-parameter"
|
||||
<warnings>all
|
||||
<toolset>intel:<warnings>on
|
||||
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
<toolset>gcc:<define>_GLIBCXX_DEBUG
|
||||
#<toolset>darwin:<define>_GLIBCXX_DEBUG
|
||||
<toolset>msvc:<warnings-as-errors>on
|
||||
#<toolset>gcc:<warnings-as-errors>on
|
||||
#<toolset>darwin:<warnings-as-errors>on
|
||||
;
|
||||
|
||||
test-suite unordered-exception
|
||||
|
@ -1,12 +1,18 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable:4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
test::seed_t seed(12847);
|
||||
|
||||
template <class T>
|
||||
@ -18,7 +24,8 @@ struct self_assign_base : public test::exception_base
|
||||
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); }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{ test::check_equivalent_keys(x); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@ -40,15 +47,20 @@ struct assign_base : public test::exception_base
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
|
||||
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, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
|
||||
y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2), allocator_type(tag2)) {}
|
||||
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, hasher(tag1), key_equal(tag1),
|
||||
allocator_type(tag1)),
|
||||
y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2),
|
||||
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); }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
|
||||
{ test::check_equivalent_keys(x1); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
@ -1,12 +1,16 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/input_iterator.hpp"
|
||||
|
||||
template <typename T> inline void avoid_unused_warning(T const&) {}
|
||||
|
||||
test::seed_t seed(91274);
|
||||
|
||||
struct objects
|
||||
@ -22,6 +26,7 @@ struct construct_test1 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x;
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -30,6 +35,7 @@ struct construct_test2 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(300);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -38,6 +44,7 @@ struct construct_test3 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(0, hash);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -46,6 +53,7 @@ struct construct_test4 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(0, hash, equal_to);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -54,6 +62,7 @@ struct construct_test5 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(50, hash, equal_to, allocator);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -62,6 +71,7 @@ struct construct_test6 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(allocator);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -79,6 +89,7 @@ struct range_construct_test1 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end());
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -87,6 +98,7 @@ struct range_construct_test2 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 0);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -95,6 +107,7 @@ struct range_construct_test3 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 0, hash);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -103,6 +116,7 @@ struct range_construct_test4 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 100, hash, equal_to);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -114,7 +128,9 @@ 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);
|
||||
T x(this->values.begin(), this->values.end(), 0,
|
||||
hash, equal_to, allocator);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
@ -124,14 +140,25 @@ 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()),
|
||||
BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
begin = this->values.begin(), end = this->values.end();
|
||||
T x(test::input_iterator(begin), test::input_iterator(end),
|
||||
0, hash, equal_to, allocator);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
};
|
||||
|
||||
RUN_EXCEPTION_TESTS(
|
||||
(construct_test1)(construct_test2)(construct_test3)(construct_test4)(construct_test5)(construct_test6)
|
||||
(range_construct_test1)(range_construct_test2)(range_construct_test3)(range_construct_test4)(range_construct_test5)
|
||||
(construct_test1)
|
||||
(construct_test2)
|
||||
(construct_test3)
|
||||
(construct_test4)
|
||||
(construct_test5)
|
||||
(construct_test6)
|
||||
(range_construct_test1)
|
||||
(range_construct_test2)
|
||||
(range_construct_test3)
|
||||
(range_construct_test4)
|
||||
(range_construct_test5)
|
||||
(input_range_construct_test),
|
||||
CONTAINER_SEQ)
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
template <typename T> inline void avoid_unused_warning(T const&) {}
|
||||
|
||||
test::seed_t seed(73041);
|
||||
|
||||
template <class T>
|
||||
@ -15,6 +19,7 @@ struct copy_test1 : public test::exception_base
|
||||
|
||||
void run() const {
|
||||
T y(x);
|
||||
avoid_unused_warning(y);
|
||||
}
|
||||
};
|
||||
|
||||
@ -28,6 +33,7 @@ struct copy_test2 : public test::exception_base
|
||||
|
||||
void run() const {
|
||||
T y(x);
|
||||
avoid_unused_warning(y);
|
||||
}
|
||||
};
|
||||
|
||||
@ -41,6 +47,7 @@ struct copy_test3 : public test::exception_base
|
||||
|
||||
void run() const {
|
||||
T y(x);
|
||||
avoid_unused_warning(y);
|
||||
}
|
||||
};
|
||||
|
||||
@ -55,6 +62,7 @@ struct copy_with_allocator_test : public test::exception_base
|
||||
|
||||
void run() const {
|
||||
T y(x, allocator);
|
||||
avoid_unused_warning(y);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
@ -22,10 +24,10 @@ struct erase_test_base : public test::exception_base
|
||||
return T(values.begin(), values.end());
|
||||
}
|
||||
|
||||
void check(T const& x) const {
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
std::string scope(test::scope);
|
||||
|
||||
BOOST_CHECK(scope.find("hash::") != std::string::npos ||
|
||||
BOOST_TEST(scope.find("hash::") != std::string::npos ||
|
||||
scope.find("equal_to::") != std::string::npos ||
|
||||
scope == "operator==(object, object)");
|
||||
|
||||
@ -38,7 +40,8 @@ struct erase_by_key_test1 : public erase_test_base<T>
|
||||
{
|
||||
void run(T& x) const
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator iterator;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
test::random_values<T>::const_iterator iterator;
|
||||
|
||||
for(iterator it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
|
@ -1,14 +1,15 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include <string>
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/strong.hpp"
|
||||
#include "../helpers/input_iterator.hpp"
|
||||
#include <boost/utility.hpp>
|
||||
#include <cmath>
|
||||
|
||||
@ -27,16 +28,18 @@ struct insert_test_base : public test::exception_base
|
||||
return T();
|
||||
}
|
||||
|
||||
void check(T const& x, strong_type const& strong) const {
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(
|
||||
T const& x, strong_type const& strong) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
if(scope.find("hash::operator()") == std::string::npos)
|
||||
strong.test(x);
|
||||
strong.test(x, test::exception::detail::tracker.count_allocations);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
|
||||
template <class T>
|
||||
struct emplace_test1 : public insert_test_base<T>
|
||||
@ -45,9 +48,10 @@ struct emplace_test1 : public insert_test_base<T>
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end(); it != end; ++it)
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.emplace(*it);
|
||||
}
|
||||
}
|
||||
@ -62,9 +66,10 @@ struct insert_test1 : public insert_test_base<T>
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end(); it != end; ++it)
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(*it);
|
||||
}
|
||||
}
|
||||
@ -77,9 +82,10 @@ struct insert_test2 : public insert_test_base<T>
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end(); it != end; ++it)
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(x.begin(), *it);
|
||||
}
|
||||
}
|
||||
@ -92,7 +98,7 @@ struct insert_test3 : public insert_test_base<T>
|
||||
x.insert(this->values.begin(), this->values.end());
|
||||
}
|
||||
|
||||
void check(T const& x) const {
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
@ -104,9 +110,10 @@ struct insert_test4 : public insert_test_base<T>
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end(); it != end; ++it)
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(it, boost::next(it));
|
||||
}
|
||||
}
|
||||
@ -128,10 +135,10 @@ struct insert_test_rehash1 : public insert_test_base<T>
|
||||
size_type bucket_count = x.bucket_count();
|
||||
size_type initial_elements = static_cast<size_type>(
|
||||
ceil(bucket_count * (double) x.max_load_factor()) - 1);
|
||||
BOOST_REQUIRE(initial_elements < this->values.size());
|
||||
BOOST_TEST(initial_elements < this->values.size());
|
||||
x.insert(this->values.begin(),
|
||||
boost::next(this->values.begin(), initial_elements));
|
||||
BOOST_REQUIRE(bucket_count == x.bucket_count());
|
||||
BOOST_TEST(bucket_count == x.bucket_count());
|
||||
return x;
|
||||
}
|
||||
|
||||
@ -141,16 +148,17 @@ struct insert_test_rehash1 : public insert_test_base<T>
|
||||
BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin();
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = boost::next(this->values.begin(), x.size()), end = this->values.end();
|
||||
it = boost::next(this->values.begin(), x.size()),
|
||||
end = this->values.end();
|
||||
it != end && count < 10; ++it, ++count)
|
||||
{
|
||||
strong.store(x);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
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);
|
||||
BOOST_TEST(x.bucket_count() != bucket_count);
|
||||
}
|
||||
};
|
||||
|
||||
@ -164,23 +172,25 @@ struct insert_test_rehash2 : public insert_test_rehash1<T>
|
||||
int count = 0;
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = boost::next(this->values.begin(), x.size()), end = this->values.end();
|
||||
it = boost::next(this->values.begin(), x.size()),
|
||||
end = this->values.end();
|
||||
it != end && count < 10; ++it, ++count)
|
||||
{
|
||||
strong.store(x);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
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);
|
||||
BOOST_TEST(x.bucket_count() != bucket_count);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test_rehash3 : public insert_test_base<T>
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::size_type mutable rehash_bucket_count, original_bucket_count;
|
||||
BOOST_DEDUCED_TYPENAME T::size_type mutable
|
||||
rehash_bucket_count, original_bucket_count;
|
||||
|
||||
insert_test_rehash3() : insert_test_base<T>(1000) {}
|
||||
|
||||
@ -195,12 +205,13 @@ struct insert_test_rehash3 : public insert_test_base<T>
|
||||
rehash_bucket_count = static_cast<size_type>(
|
||||
ceil(original_bucket_count * (double) x.max_load_factor())) - 1;
|
||||
|
||||
size_type initial_elements = rehash_bucket_count - 5;
|
||||
size_type initial_elements =
|
||||
rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1;
|
||||
|
||||
BOOST_REQUIRE(initial_elements < this->values.size());
|
||||
BOOST_TEST(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());
|
||||
BOOST_TEST(original_bucket_count == x.bucket_count());
|
||||
return x;
|
||||
}
|
||||
|
||||
@ -212,12 +223,12 @@ struct insert_test_rehash3 : public insert_test_base<T>
|
||||
|
||||
// This isn't actually a failure, but it means the test isn't doing its
|
||||
// job.
|
||||
BOOST_REQUIRE(x.bucket_count() != bucket_count);
|
||||
BOOST_TEST(x.bucket_count() != bucket_count);
|
||||
}
|
||||
|
||||
void check(T const& x) const {
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
if(x.size() < rehash_bucket_count) {
|
||||
//BOOST_CHECK(x.bucket_count() == original_bucket_count);
|
||||
//BOOST_TEST(x.bucket_count() == original_bucket_count);
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
@ -227,7 +238,7 @@ struct insert_test_rehash3 : public insert_test_base<T>
|
||||
(insert_test1)(insert_test2)(insert_test3)(insert_test4) \
|
||||
(insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3)
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#define ALL_TESTS (emplace_test1)BASIC_TESTS
|
||||
#else
|
||||
#define ALL_TESTS BASIC_TESTS
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include <string>
|
||||
#include "../helpers/random_values.hpp"
|
||||
@ -18,7 +20,9 @@ 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) {}
|
||||
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;
|
||||
@ -28,7 +32,9 @@ struct rehash_test_base : public test::exception_base
|
||||
return x;
|
||||
}
|
||||
|
||||
void check(T const& x, strong_type const& strong) const {
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x,
|
||||
strong_type const& strong) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
if(scope.find("hash::operator()") == std::string::npos &&
|
||||
|
@ -1,12 +1,18 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable:4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
test::seed_t seed(9387);
|
||||
|
||||
template <class T>
|
||||
@ -18,11 +24,11 @@ struct self_swap_base : public test::exception_base
|
||||
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 {
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
std::string scope(test::scope);
|
||||
|
||||
#if BOOST_UNORDERED_SWAP_METHOD != 2
|
||||
BOOST_CHECK(
|
||||
BOOST_TEST(
|
||||
scope == "hash::operator(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::operator(equal_to)" ||
|
||||
@ -73,11 +79,11 @@ struct swap_base : public test::exception_base
|
||||
d.x.swap(d.y);
|
||||
} catch (std::runtime_error) {}
|
||||
}
|
||||
void check(data_type const& d) const {
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const {
|
||||
std::string scope(test::scope);
|
||||
|
||||
#if BOOST_UNORDERED_SWAP_METHOD != 2
|
||||
BOOST_CHECK(
|
||||
BOOST_TEST(
|
||||
scope == "hash::operator(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::operator(equal_to)" ||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
@ -58,8 +58,8 @@ namespace test
|
||||
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; }
|
||||
bool operator==(malloc_allocator const&) const { return true; }
|
||||
bool operator!=(malloc_allocator const&) const { return false; }
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
template <class T> void deallocate(T* p, size_type) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Copyright 2005-2009 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)
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
|
||||
// Copyright 2008 Daniel James.
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace test {
|
||||
struct object_count {
|
||||
int instances;
|
||||
@ -36,6 +38,18 @@ namespace test {
|
||||
bool operator!=(object_count const& x) const {
|
||||
return !(*this == x);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out,
|
||||
object_count const& c)
|
||||
{
|
||||
out
|
||||
<< "[instances: "
|
||||
<< c.instances
|
||||
<< ", constructions: "
|
||||
<< c.constructions
|
||||
<< "]";
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@ -53,6 +67,11 @@ namespace test {
|
||||
struct globally_counted_object
|
||||
: counted_object<globally_counted_object> {};
|
||||
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
object_count& global_object_count = globally_counted_object::count_;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Copyright 2005-2009 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)
|
||||
|
||||
@ -21,12 +21,16 @@ namespace test
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(boost::hash<T> const&, boost::hash<T> const&, derived_type) {
|
||||
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) {
|
||||
bool equivalent_impl(std::equal_to<T> const&, std::equal_to<T> const&,
|
||||
derived_type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -44,6 +48,11 @@ namespace test
|
||||
}
|
||||
};
|
||||
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
equivalent_type equivalent;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
@ -8,64 +8,54 @@
|
||||
|
||||
#include "./test.hpp"
|
||||
|
||||
#if defined(BOOST_UNORDERED_FULL_TEST)
|
||||
# define BOOST_TEST_MAIN
|
||||
# include <boost/test/exception_safety.hpp>
|
||||
# include <boost/test/unit_test.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
#include <boost/preprocessor/seq/elem.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
|
||||
#if defined(BOOST_UNORDERED_FULL_TEST)
|
||||
# define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \
|
||||
UNORDERED_AUTO_TEST(name) \
|
||||
{ \
|
||||
test_func< type > fixture; \
|
||||
::test::exception_safety(fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
}
|
||||
# define UNORDERED_EPOINT_IMPL BOOST_ITEST_EPOINT
|
||||
#else
|
||||
# define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \
|
||||
UNORDERED_AUTO_TEST(name) \
|
||||
{ \
|
||||
test_func< type > fixture; \
|
||||
::test::lightweight::exception_safety(fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
}
|
||||
# define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \
|
||||
UNORDERED_AUTO_TEST(name) \
|
||||
{ \
|
||||
test_func< type > fixture; \
|
||||
::test::lightweight::exception_safety( \
|
||||
fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
} \
|
||||
|
||||
# define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
|
||||
#endif
|
||||
|
||||
#define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS()
|
||||
|
||||
#define RUN_EXCEPTION_TESTS(test_seq, param_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP, (test_seq)(param_seq)) \
|
||||
RUN_TESTS()
|
||||
#define RUN_EXCEPTION_TESTS(test_seq, param_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP, \
|
||||
(test_seq)(param_seq)) \
|
||||
RUN_TESTS() \
|
||||
|
||||
#define RUN_EXCEPTION_TESTS_OP(r, product) \
|
||||
UNORDERED_EXCEPTION_TEST_CASE( \
|
||||
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_OP(r, product) \
|
||||
UNORDERED_EXCEPTION_TEST_CASE( \
|
||||
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 UNORDERED_SCOPE(scope_name) \
|
||||
for(::test::scope_guard unordered_test_guard( \
|
||||
BOOST_STRINGIZE(scope_name)); \
|
||||
!unordered_test_guard.dismissed(); \
|
||||
unordered_test_guard.dismiss())
|
||||
#define UNORDERED_SCOPE(scope_name) \
|
||||
for(::test::scope_guard unordered_test_guard( \
|
||||
BOOST_STRINGIZE(scope_name)); \
|
||||
!unordered_test_guard.dismissed(); \
|
||||
unordered_test_guard.dismiss()) \
|
||||
|
||||
#define UNORDERED_EPOINT(name) \
|
||||
if(::test::exceptions_enabled) { \
|
||||
UNORDERED_EPOINT_IMPL(name); \
|
||||
}
|
||||
#define UNORDERED_EPOINT(name) \
|
||||
if(::test::exceptions_enabled) { \
|
||||
UNORDERED_EPOINT_IMPL(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 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) \
|
||||
|
||||
namespace test {
|
||||
static char const* scope = "";
|
||||
@ -126,25 +116,28 @@ namespace test {
|
||||
template <class T> void test(T const&) const {}
|
||||
};
|
||||
data_type init() const { return data_type(); }
|
||||
void check() const {}
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {}
|
||||
};
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(void (T::*fn)() const, T2 const& obj,
|
||||
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,
|
||||
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,
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)(P1&, P2&) const, T2 const& obj,
|
||||
P1& p1, P2& p2)
|
||||
{
|
||||
(obj.*fn)(p1, p2);
|
||||
@ -159,6 +152,9 @@ namespace test {
|
||||
class test_runner
|
||||
{
|
||||
Test const& test_;
|
||||
|
||||
test_runner(test_runner const&);
|
||||
test_runner& operator=(test_runner const&);
|
||||
public:
|
||||
test_runner(Test const& t) : test_(t) {}
|
||||
void operator()() const {
|
||||
@ -169,25 +165,23 @@ namespace test {
|
||||
strong.store(x);
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
call_ignore_extra_parameters<Test, BOOST_DEDUCED_TYPENAME Test::data_type, BOOST_DEDUCED_TYPENAME Test::strong_type>(&Test::run, test_, x, strong);
|
||||
call_ignore_extra_parameters<
|
||||
Test,
|
||||
BOOST_DEDUCED_TYPENAME Test::data_type,
|
||||
BOOST_DEDUCED_TYPENAME Test::strong_type
|
||||
>(&Test::run, test_, x, strong);
|
||||
}
|
||||
catch(...) {
|
||||
call_ignore_extra_parameters<Test, BOOST_DEDUCED_TYPENAME Test::data_type const, BOOST_DEDUCED_TYPENAME Test::strong_type const>(&Test::check, test_,
|
||||
constant(x), constant(strong));
|
||||
call_ignore_extra_parameters<
|
||||
Test,
|
||||
BOOST_DEDUCED_TYPENAME Test::data_type const,
|
||||
BOOST_DEDUCED_TYPENAME Test::strong_type const
|
||||
>(&Test::check, test_, constant(x), constant(strong));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if defined(BOOST_UNORDERED_FULL_TEST)
|
||||
template <class Test>
|
||||
void exception_safety(Test const& f, char const* name) {
|
||||
test_runner<Test> runner(f);
|
||||
::boost::itest::exception_safety(runner, name);
|
||||
}
|
||||
#else
|
||||
// Quick exception testing based on lightweight test
|
||||
|
||||
namespace lightweight {
|
||||
@ -237,7 +231,6 @@ namespace test {
|
||||
} while(!success);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Copyright 2005-2009 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)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
@ -19,13 +19,15 @@ namespace test
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static key_type const& get_key(std::pair<key_type, T> const& x, char = 0)
|
||||
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)
|
||||
static key_type const& get_key(std::pair<key_type const, T> const& x,
|
||||
unsigned char = 0)
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
|
@ -1,31 +1,71 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Copyright 2005-2009 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>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/iterator.hpp>
|
||||
#include <boost/iterator/iterator_traits.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>
|
||||
struct proxy
|
||||
{
|
||||
typedef boost::iterator_adaptor<
|
||||
input_iterator_adaptor<Iterator>, Iterator,
|
||||
boost::use_default, std::input_iterator_tag> base;
|
||||
typedef BOOST_DEDUCED_TYPENAME Iterator::value_type value_type;
|
||||
|
||||
explicit input_iterator_adaptor(Iterator it = Iterator())
|
||||
: base(it) {}
|
||||
explicit proxy(value_type const& v) : v_(v) {}
|
||||
proxy(proxy const& x) : v_(x.v_) {}
|
||||
operator value_type const&() const { return v_; }
|
||||
|
||||
value_type v_;
|
||||
private:
|
||||
proxy& operator=(proxy const&);
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
input_iterator_adaptor<Iterator> input_iterator(Iterator it)
|
||||
struct input_iterator_adaptor
|
||||
: public boost::iterator<
|
||||
std::input_iterator_tag,
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type,
|
||||
std::ptrdiff_t,
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_pointer<Iterator>::type,
|
||||
proxy<Iterator>
|
||||
>
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type
|
||||
value_type;
|
||||
|
||||
input_iterator_adaptor()
|
||||
: base_() {}
|
||||
explicit input_iterator_adaptor(Iterator& it)
|
||||
: base_(&it) {}
|
||||
proxy<Iterator> operator*() const {
|
||||
return proxy<Iterator>(**base_);
|
||||
}
|
||||
value_type* operator->() const {
|
||||
return &**base_;
|
||||
}
|
||||
input_iterator_adaptor& operator++() {
|
||||
++*base_; return *this;
|
||||
}
|
||||
//input_iterator_adaptor operator++(int) {
|
||||
//}
|
||||
bool operator==(input_iterator_adaptor const& x) const {
|
||||
return *base_ == *x.base_;
|
||||
}
|
||||
bool operator!=(input_iterator_adaptor const& x) const {
|
||||
return *base_ != *x.base_;
|
||||
}
|
||||
private:
|
||||
Iterator* base_;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
input_iterator_adaptor<Iterator> input_iterator(Iterator& it)
|
||||
{
|
||||
return input_iterator_adaptor<Iterator>(it);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
@ -17,7 +17,9 @@
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data
|
||||
#endif
|
||||
|
||||
namespace test
|
||||
@ -29,9 +31,11 @@ namespace test
|
||||
typedef BOOST_DEDUCED_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_;
|
||||
std::set<key_type, std::less<key_type>,
|
||||
test::malloc_allocator<key_type> > found_;
|
||||
|
||||
BOOST_DEDUCED_TYPENAME X::const_iterator it = x1.begin(), end = x1.end();
|
||||
BOOST_DEDUCED_TYPENAME X::const_iterator
|
||||
it = x1.begin(), end = x1.end();
|
||||
BOOST_DEDUCED_TYPENAME X::size_type size = 0;
|
||||
while(it != end) {
|
||||
// First test that the current key has not occured before, required
|
||||
@ -71,7 +75,8 @@ namespace test
|
||||
// // Check that the keys are in the correct bucket and are
|
||||
// // adjacent in the bucket.
|
||||
// BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key);
|
||||
// BOOST_DEDUCED_TYPENAME X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket);
|
||||
// BOOST_DEDUCED_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");
|
||||
@ -81,7 +86,8 @@ namespace test
|
||||
// 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.");
|
||||
// BOOST_ERROR("Non-adjacent element with equivalent key "
|
||||
// "in bucket.");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
@ -90,7 +96,8 @@ namespace test
|
||||
// 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());
|
||||
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.");
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2008 Daniel James.
|
||||
// Copyright 2008-2009 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)
|
||||
|
||||
@ -17,18 +17,38 @@
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <typename It1, typename It2>
|
||||
bool equal(It1 begin, It1 end, It2 compare)
|
||||
{
|
||||
for(;begin != end; ++begin, ++compare)
|
||||
if(*begin != *compare) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename It1, typename It2, typename Pred>
|
||||
bool equal(It1 begin, It1 end, It2 compare, Pred predicate)
|
||||
{
|
||||
for(;begin != end; ++begin, ++compare)
|
||||
if(!predicate(*begin, *compare)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename T> class list;
|
||||
|
||||
namespace test_detail
|
||||
{
|
||||
template <typename T> struct list_node;
|
||||
template <typename T> class list_node;
|
||||
template <typename T> class list_data;
|
||||
template <typename T> class list_iterator;
|
||||
template <typename T> class list_const_iterator;
|
||||
|
||||
template <typename T>
|
||||
struct list_node
|
||||
class list_node
|
||||
{
|
||||
list_node(list_node const&);
|
||||
list_node& operator=(list_node const&);
|
||||
public:
|
||||
T value_;
|
||||
list_node* next_;
|
||||
|
||||
@ -74,14 +94,14 @@ namespace test
|
||||
|
||||
node* ptr_;
|
||||
public:
|
||||
list_iterator() : ptr_(0) {};
|
||||
list_iterator() : ptr_(0) {}
|
||||
explicit list_iterator(node* x) : ptr_(x) {}
|
||||
|
||||
T& operator*() const { return ptr_->value_; }
|
||||
T* operator->() const { return &ptr_->value_; }
|
||||
list_iterator& operator++() {
|
||||
ptr_ = ptr_->next_; return *this; }
|
||||
list_iterator& operator++(int) {
|
||||
list_iterator operator++(int) {
|
||||
list_iterator tmp = *this; ptr_ = ptr_->next_; return tmp; }
|
||||
bool operator==(const_iterator y) const { return ptr_ == y.ptr_; }
|
||||
bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; }
|
||||
@ -106,12 +126,29 @@ namespace test
|
||||
|
||||
T const& operator*() const { return ptr_->value_; }
|
||||
T const* operator->() const { return &ptr_->value_; }
|
||||
list_const_iterator& operator++() {
|
||||
ptr_ = ptr_->next_; return *this; }
|
||||
list_const_iterator& operator++(int) {
|
||||
list_const_iterator tmp = *this; ptr_ = ptr_->next_; return tmp; }
|
||||
bool operator==(const_iterator y) const { return ptr_ == y.ptr_; }
|
||||
bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; }
|
||||
|
||||
list_const_iterator& operator++()
|
||||
{
|
||||
ptr_ = ptr_->next_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
list_const_iterator operator++(int)
|
||||
{
|
||||
list_const_iterator tmp = *this;
|
||||
ptr_ = ptr_->next_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const_iterator y) const
|
||||
{
|
||||
return ptr_ == y.ptr_;
|
||||
}
|
||||
|
||||
bool operator!=(const_iterator y) const
|
||||
{
|
||||
return ptr_ != y.ptr_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -144,6 +181,7 @@ namespace test
|
||||
list& operator=(list const& other) {
|
||||
clear();
|
||||
insert(other.begin(), other.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(data_.first_); }
|
||||
@ -218,7 +256,7 @@ namespace test
|
||||
|
||||
bool operator==(list const& y) const {
|
||||
return size() == y.size() &&
|
||||
std::equal(begin(), end(), y.begin());
|
||||
test::equal(begin(), end(), y.begin());
|
||||
}
|
||||
|
||||
bool operator!=(list const& y) const {
|
||||
@ -242,14 +280,28 @@ namespace test
|
||||
node** merge_adjacent_ranges(node** first, node** second,
|
||||
node** third, Less less)
|
||||
{
|
||||
while(first != second) {
|
||||
if(less((*second)->value_, (*first)->value_)) {
|
||||
swap_adjacent_ranges(first, second, third);
|
||||
std::swap(second, third);
|
||||
for(;;) {
|
||||
for(;;) {
|
||||
if(first == second) return third;
|
||||
if(less((*second)->value_, (*first)->value_)) break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, second, third);
|
||||
first = &(*first)->next_;
|
||||
|
||||
// Since the two ranges we just swapped, the order is now:
|
||||
// first...third...second
|
||||
|
||||
for(;;) {
|
||||
if(first == third) return second;
|
||||
if(!less((*first)->value_, (*third)->value_)) break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, third, second);
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
return third;
|
||||
}
|
||||
|
||||
void swap_adjacent_ranges(node** first, node** second, node** third)
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
@ -18,11 +18,6 @@ namespace test
|
||||
{
|
||||
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.
|
||||
|
||||
struct memory_area {
|
||||
void const* start;
|
||||
void const* end;
|
||||
@ -67,7 +62,8 @@ namespace test
|
||||
#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
|
||||
template <>
|
||||
struct allocator_memory_type_gen<int> {
|
||||
typedef std::map<memory_area, memory_track, memory_area_compare> type;
|
||||
typedef std::map<memory_area, memory_track, memory_area_compare>
|
||||
type;
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -78,7 +74,8 @@ namespace test
|
||||
std::pair<memory_area const, memory_track> >::type
|
||||
allocator_type;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME allocator_memory_type_gen<allocator_type>::type
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
allocator_memory_type_gen<allocator_type>::type
|
||||
allocated_memory_type;
|
||||
|
||||
allocated_memory_type allocated_memory;
|
||||
@ -103,7 +100,7 @@ namespace test
|
||||
|
||||
void allocator_unref()
|
||||
{
|
||||
BOOST_CHECK(count_allocators > 0);
|
||||
BOOST_TEST(count_allocators > 0);
|
||||
if(count_allocators > 0) {
|
||||
--count_allocators;
|
||||
if(count_allocators == 0) {
|
||||
@ -111,19 +108,21 @@ namespace test
|
||||
bool no_constructions_left = (count_constructions == 0);
|
||||
bool allocated_memory_empty = allocated_memory.empty();
|
||||
|
||||
// Clearing the data before the checks terminate the tests.
|
||||
// Clearing the data before the checks terminate the
|
||||
// tests.
|
||||
count_allocations = 0;
|
||||
count_constructions = 0;
|
||||
allocated_memory.clear();
|
||||
|
||||
BOOST_CHECK(no_allocations_left);
|
||||
BOOST_CHECK(no_constructions_left);
|
||||
BOOST_CHECK(allocated_memory_empty);
|
||||
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)
|
||||
void track_allocate(void *ptr, std::size_t n, std::size_t size,
|
||||
int tag)
|
||||
{
|
||||
if(n == 0) {
|
||||
BOOST_ERROR("Allocating 0 length array.");
|
||||
@ -137,30 +136,34 @@ namespace test
|
||||
}
|
||||
}
|
||||
|
||||
void track_deallocate(void* ptr, std::size_t n, std::size_t size, int tag)
|
||||
void track_deallocate(void* ptr, std::size_t n, std::size_t size,
|
||||
int tag)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos
|
||||
= allocated_memory.find(memory_area(ptr, (char*) ptr + n * size));
|
||||
BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos =
|
||||
allocated_memory.find(
|
||||
memory_area(ptr, (char*) ptr + n * size));
|
||||
if(pos == allocated_memory.end()) {
|
||||
BOOST_ERROR("Deallocating unknown pointer.");
|
||||
} else {
|
||||
BOOST_CHECK(pos->first.start == ptr);
|
||||
BOOST_CHECK(pos->first.end == (char*) ptr + n * size);
|
||||
BOOST_CHECK(pos->second.tag_ == tag);
|
||||
BOOST_TEST(pos->first.start == ptr);
|
||||
BOOST_TEST(pos->first.end == (char*) ptr + n * size);
|
||||
BOOST_TEST(pos->second.tag_ == tag);
|
||||
allocated_memory.erase(pos);
|
||||
}
|
||||
BOOST_CHECK(count_allocations > 0);
|
||||
BOOST_TEST(count_allocations > 0);
|
||||
if(count_allocations > 0) --count_allocations;
|
||||
}
|
||||
|
||||
void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
|
||||
void track_construct(void* /*ptr*/, std::size_t /*size*/,
|
||||
int /*tag*/)
|
||||
{
|
||||
++count_constructions;
|
||||
}
|
||||
|
||||
void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
|
||||
void track_destroy(void* /*ptr*/, std::size_t /*size*/,
|
||||
int /*tag*/)
|
||||
{
|
||||
BOOST_CHECK(count_constructions > 0);
|
||||
BOOST_TEST(count_constructions > 0);
|
||||
if(count_constructions > 0) --count_constructions;
|
||||
}
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Copyright 2005-2009 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)
|
||||
|
||||
|
11
test/helpers/prefix.hpp
Normal file
11
test/helpers/prefix.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
// Copyright 2009 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(_WIN32_WCE)
|
||||
// The standard windows mobile headers trigger this warning so I disable it
|
||||
// before doing anything else.
|
||||
#pragma warning(disable:4201) // nonstandard extension used :
|
||||
// nameless struct/union
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Copyright 2005-2009 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)
|
||||
|
||||
@ -71,7 +71,9 @@ namespace test
|
||||
type_ == generate_collisions ?
|
||||
generate(int_ptr) % 10 : 1;
|
||||
count; --count) {
|
||||
x.push_back(std::pair<key_type const, mapped_type>(key, generate(mapped_ptr)));
|
||||
x.push_back(
|
||||
std::pair<key_type const, mapped_type>(
|
||||
key, generate(mapped_ptr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Copyright 2005-2009 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)
|
||||
|
||||
@ -20,18 +20,22 @@ namespace test
|
||||
{
|
||||
typedef test::list<BOOST_DEDUCED_TYPENAME X::value_type> values_type;
|
||||
values_type values_;
|
||||
unsigned int allocations_;
|
||||
public:
|
||||
void store(X const& x) {
|
||||
void store(X const& x, unsigned int allocations = 0) {
|
||||
DISABLE_EXCEPTIONS;
|
||||
values_.clear();
|
||||
values_.insert(x.cbegin(), x.cend());
|
||||
allocations_ = allocations;
|
||||
}
|
||||
|
||||
void test(X const& x) const {
|
||||
void test(X const& x, unsigned int allocations = 0) const {
|
||||
if(!(x.size() == values_.size() &&
|
||||
std::equal(x.cbegin(), x.cend(), values_.begin(),
|
||||
test::equal(x.cbegin(), x.cend(), values_.begin(),
|
||||
test::equivalent)))
|
||||
BOOST_ERROR("Strong exception safety failure.");
|
||||
if(allocations != allocations_)
|
||||
BOOST_ERROR("Strong exception failure: extra allocations.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,36 +1,30 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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_TEST_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_TEST_HEADER
|
||||
|
||||
#if defined(BOOST_UNORDERED_FULL_TEST)
|
||||
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#define UNORDERED_AUTO_TEST(x) BOOST_AUTO_TEST_CASE(x)
|
||||
#define RUN_TESTS()
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#define UNORDERED_AUTO_TEST(x) \
|
||||
struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base { \
|
||||
BOOST_PP_CAT(x, _type)() \
|
||||
: ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \
|
||||
{ \
|
||||
::test::test_list::add_test(this); \
|
||||
} \
|
||||
void run(); \
|
||||
}; \
|
||||
BOOST_PP_CAT(x, _type) x; \
|
||||
void BOOST_PP_CAT(x, _type)::run()
|
||||
#define RUN_TESTS() int test_main(int, char**) { ::test::test_list::run_tests(); return 0; }
|
||||
#define UNORDERED_AUTO_TEST(x) \
|
||||
struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base { \
|
||||
BOOST_PP_CAT(x, _type)() \
|
||||
: ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \
|
||||
{ \
|
||||
::test::test_list::add_test(this); \
|
||||
} \
|
||||
void run(); \
|
||||
}; \
|
||||
BOOST_PP_CAT(x, _type) x; \
|
||||
void BOOST_PP_CAT(x, _type)::run() \
|
||||
|
||||
#define RUN_TESTS() int main(int, char**) \
|
||||
{ ::test::test_list::run_tests(); return boost::report_errors(); } \
|
||||
|
||||
namespace test {
|
||||
struct registered_test_base {
|
||||
@ -74,8 +68,6 @@ namespace test {
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
#include <boost/preprocessor/seq/fold_left.hpp>
|
||||
#include <boost/preprocessor/seq/to_tuple.hpp>
|
||||
@ -83,20 +75,22 @@ namespace test {
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
|
||||
// Run test with every combination of the parameters (a sequence of sequences)
|
||||
#define UNORDERED_TEST(name, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name)) parameters)
|
||||
#define UNORDERED_TEST(name, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name)) parameters) \
|
||||
|
||||
#define UNORDERED_TEST_OP(r, product) \
|
||||
UNORDERED_TEST_OP2( \
|
||||
BOOST_PP_SEQ_HEAD(product), \
|
||||
BOOST_PP_SEQ_TAIL(product))
|
||||
#define UNORDERED_TEST_OP(r, product) \
|
||||
UNORDERED_TEST_OP2( \
|
||||
BOOST_PP_SEQ_HEAD(product), \
|
||||
BOOST_PP_SEQ_TAIL(product)) \
|
||||
|
||||
#define UNORDERED_TEST_OP2(name, params) \
|
||||
UNORDERED_AUTO_TEST(BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) { \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
}
|
||||
#define UNORDERED_TEST_OP2(name, params) \
|
||||
UNORDERED_AUTO_TEST( \
|
||||
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) \
|
||||
{ \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
} \
|
||||
|
||||
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
|
||||
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem))
|
||||
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
|
||||
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem)) \
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
@ -27,7 +27,8 @@ namespace test
|
||||
{
|
||||
template <class X>
|
||||
struct equals_to_compare2
|
||||
: public boost::mpl::identity<std::less<BOOST_DEDUCED_TYPENAME X::first_argument_type> >
|
||||
: public boost::mpl::identity<
|
||||
std::less<BOOST_DEDUCED_TYPENAME X::first_argument_type> >
|
||||
{
|
||||
};
|
||||
|
||||
@ -49,8 +50,8 @@ namespace test
|
||||
value_list values2(x2.begin(), x2.end());
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_CHECK(values1.size() == values2.size() &&
|
||||
std::equal(values1.begin(), values1.end(), values2.begin(),
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(), values2.begin(),
|
||||
test::equivalent));
|
||||
}
|
||||
|
||||
@ -61,38 +62,56 @@ namespace test
|
||||
test::list<T> values2(x2.first, x2.second);
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_CHECK(values1.size() == values2.size() &&
|
||||
std::equal(values1.begin(), values1.end(), values2.begin(), test::equivalent));
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(),
|
||||
values2.begin(), test::equivalent));
|
||||
}
|
||||
|
||||
template <class X>
|
||||
struct ordered_set
|
||||
: public boost::mpl::if_<
|
||||
struct ordered_set : public
|
||||
boost::mpl::if_<
|
||||
test::has_unique_keys<X>,
|
||||
std::set<BOOST_DEDUCED_TYPENAME X::value_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>,
|
||||
std::multiset<BOOST_DEDUCED_TYPENAME X::value_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
|
||||
> {};
|
||||
std::set<
|
||||
BOOST_DEDUCED_TYPENAME X::value_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>,
|
||||
std::multiset<
|
||||
BOOST_DEDUCED_TYPENAME X::value_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>
|
||||
> {};
|
||||
|
||||
template <class X>
|
||||
struct ordered_map
|
||||
: public boost::mpl::if_<
|
||||
struct ordered_map : public
|
||||
boost::mpl::if_<
|
||||
test::has_unique_keys<X>,
|
||||
std::map<BOOST_DEDUCED_TYPENAME X::key_type, BOOST_DEDUCED_TYPENAME X::mapped_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>,
|
||||
std::multimap<BOOST_DEDUCED_TYPENAME X::key_type, BOOST_DEDUCED_TYPENAME X::mapped_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
|
||||
> {};
|
||||
std::map<
|
||||
BOOST_DEDUCED_TYPENAME X::key_type,
|
||||
BOOST_DEDUCED_TYPENAME X::mapped_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>,
|
||||
std::multimap<
|
||||
BOOST_DEDUCED_TYPENAME X::key_type,
|
||||
BOOST_DEDUCED_TYPENAME X::mapped_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>
|
||||
> {};
|
||||
|
||||
template <class X>
|
||||
struct ordered_base
|
||||
: public boost::mpl::eval_if<
|
||||
struct ordered_base : public
|
||||
boost::mpl::eval_if<
|
||||
test::is_set<X>,
|
||||
test::ordered_set<X>,
|
||||
test::ordered_map<X> >
|
||||
{
|
||||
};
|
||||
test::ordered_map<X>
|
||||
> {};
|
||||
|
||||
template <class X>
|
||||
class ordered : public ordered_base<X>::type
|
||||
@ -114,7 +133,8 @@ namespace test
|
||||
compare_range(x, *this);
|
||||
}
|
||||
|
||||
void compare_key(X const& x, BOOST_DEDUCED_TYPENAME X::value_type const& val)
|
||||
void compare_key(X const& x,
|
||||
BOOST_DEDUCED_TYPENAME X::value_type const& val)
|
||||
{
|
||||
compare_pairs(
|
||||
x.equal_range(get_key<X>(val)),
|
||||
@ -132,7 +152,8 @@ namespace test
|
||||
};
|
||||
|
||||
template <class Equals>
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<Equals>::type create_compare(Equals const&)
|
||||
BOOST_DEDUCED_TYPENAME
|
||||
equals_to_compare<Equals>::type create_compare(Equals const&)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<Equals>::type x;
|
||||
return x;
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
#include <new>
|
||||
#include "../helpers/fwd.hpp"
|
||||
#include "../helpers/allocator.hpp"
|
||||
#include "./memory.hpp"
|
||||
#include "../helpers/memory.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
@ -347,7 +347,7 @@ namespace exception
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template<class... Args> void construct(pointer p, Args&&... args) {
|
||||
UNORDERED_SCOPE(allocator::construct(pointer, Args&&...)) {
|
||||
UNORDERED_EPOINT("Mock allocator construct function.");
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
@ -46,31 +46,61 @@ namespace minimal
|
||||
class copy_constructible_equality_comparable
|
||||
{
|
||||
public:
|
||||
static copy_constructible_equality_comparable create() { return copy_constructible_equality_comparable(); }
|
||||
copy_constructible_equality_comparable(copy_constructible_equality_comparable const&) {}
|
||||
~copy_constructible_equality_comparable() {}
|
||||
static copy_constructible_equality_comparable create() {
|
||||
return copy_constructible_equality_comparable();
|
||||
}
|
||||
|
||||
copy_constructible_equality_comparable(
|
||||
copy_constructible_equality_comparable const&)
|
||||
{
|
||||
}
|
||||
|
||||
~copy_constructible_equality_comparable()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
copy_constructible_equality_comparable& operator=(copy_constructible_equality_comparable const&);
|
||||
copy_constructible_equality_comparable& operator=(
|
||||
copy_constructible_equality_comparable const&);
|
||||
copy_constructible_equality_comparable() {}
|
||||
};
|
||||
|
||||
bool operator==(copy_constructible_equality_comparable, copy_constructible_equality_comparable) {
|
||||
bool operator==(
|
||||
copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(copy_constructible_equality_comparable, copy_constructible_equality_comparable) {
|
||||
bool operator!=(
|
||||
copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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() {}
|
||||
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&);
|
||||
default_copy_constructible& operator=(
|
||||
default_copy_constructible const&);
|
||||
};
|
||||
|
||||
class assignable
|
||||
@ -130,7 +160,8 @@ namespace minimal
|
||||
ptr& operator++() { ++ptr_; return *this; }
|
||||
ptr operator++(int) { ptr tmp(*this); ++ptr_; return tmp; }
|
||||
ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
|
||||
friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr<T>(s + p.ptr_); }
|
||||
friend ptr operator+(std::ptrdiff_t s, ptr p)
|
||||
{ return ptr<T>(s + p.ptr_); }
|
||||
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
|
||||
@ -169,8 +200,10 @@ namespace minimal
|
||||
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+(std::ptrdiff_t s) const { return const_ptr(ptr_ + s); }
|
||||
friend const_ptr operator+(std::ptrdiff_t s, const_ptr p) { return ptr<T>(s + p.ptr_); }
|
||||
const_ptr operator+(std::ptrdiff_t s) const
|
||||
{ return const_ptr(ptr_ + s); }
|
||||
friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
|
||||
{ return ptr<T>(s + p.ptr_); }
|
||||
T const& operator[](int s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
operator bool() const { return !!ptr_; }
|
||||
@ -229,7 +262,7 @@ namespace minimal
|
||||
|
||||
void construct(pointer p, T const& t) { new((void*)p.ptr_) T(t); }
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template<class... Args> void construct(pointer p, Args&&... args) {
|
||||
new((void*)p.ptr_) T(std::forward<Args>(args)...);
|
||||
}
|
||||
@ -240,7 +273,7 @@ namespace minimal
|
||||
size_type max_size() const { return 1000; }
|
||||
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || \
|
||||
BOOST_WORKAROUND(MSVC, <= 1300)
|
||||
BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
|
||||
public: allocator& operator=(allocator const&) { return *this;}
|
||||
#else
|
||||
private: allocator& operator=(allocator const&);
|
||||
@ -272,7 +305,9 @@ namespace boost {
|
||||
namespace test {
|
||||
namespace minimal {
|
||||
#endif
|
||||
std::size_t hash_value(test::minimal::copy_constructible_equality_comparable) {
|
||||
std::size_t hash_value(
|
||||
test::minimal::copy_constructible_equality_comparable)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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)
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
#include <iostream>
|
||||
#include "../helpers/fwd.hpp"
|
||||
#include "../helpers/count.hpp"
|
||||
#include "./memory.hpp"
|
||||
#include "../helpers/memory.hpp"
|
||||
#include <map>
|
||||
|
||||
namespace test
|
||||
@ -93,6 +93,10 @@ namespace test
|
||||
return x1.type_ != x2.type_;
|
||||
}
|
||||
};
|
||||
|
||||
std::size_t hash_value(test::object const& x) {
|
||||
return hash()(x);
|
||||
}
|
||||
|
||||
class less
|
||||
{
|
||||
@ -156,6 +160,11 @@ namespace test
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
test::detail::memory_tracker<std::allocator<int> > tracker;
|
||||
}
|
||||
@ -181,13 +190,37 @@ namespace test
|
||||
|
||||
template <class U> struct rebind { typedef allocator<U> other; };
|
||||
|
||||
explicit allocator(int t = 0) : tag_(t) { detail::tracker.allocator_ref(); }
|
||||
template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_) { detail::tracker.allocator_ref(); }
|
||||
allocator(allocator const& x) : tag_(x.tag_) { detail::tracker.allocator_ref(); }
|
||||
~allocator() { detail::tracker.allocator_unref(); }
|
||||
explicit allocator(int t = 0) : tag_(t)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
template <class Y> allocator(allocator<Y> const& x)
|
||||
: tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
pointer address(reference r) { return pointer(&r); }
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
allocator(allocator const& x)
|
||||
: tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
~allocator()
|
||||
{
|
||||
detail::tracker.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))));
|
||||
@ -213,7 +246,7 @@ namespace test
|
||||
new(p) T(t);
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template<class... Args> void construct(pointer p, Args&&... args) {
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
new(p) T(std::forward<Args>(args)...);
|
||||
@ -241,7 +274,9 @@ namespace test
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(allocator<T> const& x, allocator<T> const& y, test::derived_type) {
|
||||
bool equivalent_impl(allocator<T> const& x, allocator<T> const& y,
|
||||
test::derived_type)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
|
@ -7,16 +7,25 @@ import testing ;
|
||||
|
||||
project unordered-test/unordered
|
||||
: requirements
|
||||
<toolset>intel-linux:"<cxxflags>-strict_ansi -cxxlib-icc"
|
||||
<toolset>gcc:<cxxflags>"-Wsign-promo -Wunused-parameter"
|
||||
#<toolset>msvc:<cxxflags>/W4
|
||||
<warnings>all
|
||||
<toolset>intel:<warnings>on
|
||||
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
<toolset>gcc:<define>_GLIBCXX_DEBUG
|
||||
#<toolset>darwin:<define>_GLIBCXX_DEBUG
|
||||
<toolset>msvc:<warnings-as-errors>on
|
||||
#<toolset>gcc:<warnings-as-errors>on
|
||||
#<toolset>darwin:<warnings-as-errors>on
|
||||
;
|
||||
|
||||
test-suite unordered
|
||||
:
|
||||
[ run fwd_set_test.cpp ]
|
||||
[ run fwd_map_test.cpp ]
|
||||
[ run compile_set.cpp ]
|
||||
[ run compile_map.cpp ]
|
||||
[ run link_test_1.cpp link_test_2.cpp ]
|
||||
[ run incomplete_test.cpp ]
|
||||
[ run simple_tests.cpp ]
|
||||
[ run equivalent_keys_tests.cpp ]
|
||||
[ run constructor_tests.cpp ]
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -18,7 +20,8 @@ namespace assign_tests {
|
||||
test::seed_t seed(96785);
|
||||
|
||||
template <class T>
|
||||
void assign_tests1(T*, test::random_generator generator = test::default_generator)
|
||||
void assign_tests1(T*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
@ -27,9 +30,9 @@ void assign_tests1(T*, test::random_generator generator = test::default_generato
|
||||
{
|
||||
T x;
|
||||
x = x;
|
||||
BOOST_CHECK(x.empty());
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
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";
|
||||
@ -47,12 +50,13 @@ void assign_tests1(T*, test::random_generator generator = test::default_generato
|
||||
y.max_load_factor(x.max_load_factor() / 20);
|
||||
y = x;
|
||||
tracker.compare(y);
|
||||
BOOST_CHECK(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void assign_tests2(T*, test::random_generator generator = test::default_generator)
|
||||
void assign_tests2(T*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf2(2);
|
||||
@ -67,8 +71,8 @@ void assign_tests2(T*, test::random_generator generator = test::default_generato
|
||||
T x1(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T x2(0, hf2, eq2);
|
||||
x2 = x1;
|
||||
BOOST_CHECK(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_CHECK(test::equivalent(x2.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
test::check_container(x2, v);
|
||||
}
|
||||
|
||||
@ -78,17 +82,25 @@ void assign_tests2(T*, test::random_generator generator = test::default_generato
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_CHECK(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_CHECK(test::equivalent(x2.key_eq(), eq1));
|
||||
BOOST_CHECK(test::equivalent(x2.get_allocator(), al2));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
@ -103,6 +115,38 @@ UNORDERED_TEST(assign_tests2,
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(assign_default_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
std::initializer_list<std::pair<int const, int> > init;
|
||||
boost::unordered_map<int, int> x1;
|
||||
x1[25] = 3;
|
||||
x1[16] = 10;
|
||||
BOOST_TEST(!x1.empty());
|
||||
x1 = init;
|
||||
BOOST_TEST(x1.empty());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
|
||||
!defined(BOOST_NO_INITIALIZER_LISTS)
|
||||
|
||||
UNORDERED_AUTO_TEST(assign_initializer_list)
|
||||
{
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
|
||||
boost::unordered_set<int> x;
|
||||
x.insert(10);
|
||||
x.insert(20);
|
||||
x = { 1, 2, -10 };
|
||||
BOOST_TEST(x.find(10) == x.end());
|
||||
BOOST_TEST(x.find(-10) != x.end());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2007-2008 Daniel James.
|
||||
// Copyright 2007-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
#include <string>
|
||||
@ -16,8 +18,8 @@ UNORDERED_AUTO_TEST(at_tests) {
|
||||
x["one"] = 1;
|
||||
x["two"] = 2;
|
||||
|
||||
BOOST_CHECK(x.at("one") == 1);
|
||||
BOOST_CHECK(x.at("two") == 2);
|
||||
BOOST_TEST(x.at("one") == 1);
|
||||
BOOST_TEST(x.at("two") == 2);
|
||||
|
||||
try {
|
||||
x.at("three");
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -11,6 +13,11 @@
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#endif
|
||||
|
||||
namespace bucket_tests {
|
||||
|
||||
test::seed_t seed(54635);
|
||||
@ -24,7 +31,7 @@ void tests(X* = 0, test::random_generator generator = test::default_generator)
|
||||
|
||||
X x(v.begin(), v.end());
|
||||
|
||||
BOOST_CHECK(x.bucket_count() < x.max_bucket_count());
|
||||
BOOST_TEST(x.bucket_count() < x.max_bucket_count());
|
||||
std::cerr<<x.bucket_count()<<"<"<<x.max_bucket_count()<<"\n";
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator
|
||||
@ -32,28 +39,44 @@ void tests(X* = 0, test::random_generator generator = test::default_generator)
|
||||
{
|
||||
size_type bucket = x.bucket(test::get_key<X>(*it));
|
||||
|
||||
BOOST_CHECK(bucket < x.bucket_count());
|
||||
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_CHECK(lit != lend);
|
||||
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_CHECK(x.bucket_size(i) == (size_type) std::distance(x.begin(i), x.end(i)));
|
||||
BOOST_CHECK(x.bucket_size(i) == (size_type) std::distance(x.cbegin(i), x.cend(i)));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x.begin(i), x.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x.cbegin(i), x.cend(i))));
|
||||
X const& x_ref = x;
|
||||
BOOST_CHECK(x.bucket_size(i) == (size_type) std::distance(x_ref.begin(i), x_ref.end(i)));
|
||||
BOOST_CHECK(x.bucket_size(i) == (size_type) std::distance(x_ref.cbegin(i), x_ref.cend(i)));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x_ref.begin(i), x_ref.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x_ref.cbegin(i), x_ref.cend(i))));
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
UNORDERED_TEST(tests, ((test_set)(test_multiset)(test_map)(test_multimap)))
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <iostream>
|
||||
@ -13,6 +15,21 @@
|
||||
#include "../objects/minimal.hpp"
|
||||
#include "./compile_tests.hpp"
|
||||
|
||||
// Explicit instantiation to catch compile-time errors
|
||||
|
||||
template class 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<test::minimal::assignable> >;
|
||||
template class 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<test::minimal::assignable> >;
|
||||
|
||||
UNORDERED_AUTO_TEST(test0)
|
||||
{
|
||||
typedef std::pair<test::minimal::assignable const,
|
||||
|
@ -1,11 +1,13 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include <iostream>
|
||||
@ -13,6 +15,19 @@
|
||||
#include "../objects/minimal.hpp"
|
||||
#include "./compile_tests.hpp"
|
||||
|
||||
// Explicit instantiation to catch compile-time errors
|
||||
|
||||
template class 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> >;
|
||||
template class 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> >;
|
||||
|
||||
UNORDERED_AUTO_TEST(test0)
|
||||
{
|
||||
test::minimal::assignable assignable = test::minimal::assignable::create();
|
||||
|
@ -1,11 +1,13 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Copyright 2005-2009 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
|
||||
#pragma warning(disable:4610) // class can never be instantiated
|
||||
#pragma warning(disable:4510) // default constructor could not be generated
|
||||
#endif
|
||||
|
||||
#include <boost/concept_check.hpp>
|
||||
@ -35,10 +37,15 @@ void container_test(X& r, T const&)
|
||||
typedef BOOST_DEDUCED_TYPENAME X::difference_type difference_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_value<iterator>::type iterator_value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_value<const_iterator>::type const_iterator_value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference<iterator>::type iterator_difference_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference<const_iterator>::type const_iterator_difference_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_value<iterator>::type iterator_value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_value<const_iterator>::type const_iterator_value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_difference<iterator>::type iterator_difference_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_difference<const_iterator>::type
|
||||
const_iterator_difference_type;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::reference reference;
|
||||
@ -87,10 +94,10 @@ void container_test(X& r, T const&)
|
||||
// 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_CHECK((std::numeric_limits<difference_type>::max)()
|
||||
BOOST_TEST((std::numeric_limits<difference_type>::max)()
|
||||
== converted_diff);
|
||||
|
||||
BOOST_CHECK(
|
||||
BOOST_TEST(
|
||||
static_cast<comparison_type>(
|
||||
(std::numeric_limits<size_type>::max)()) >
|
||||
static_cast<comparison_type>(
|
||||
@ -98,8 +105,8 @@ void container_test(X& r, T const&)
|
||||
|
||||
// I don't test the runtime post-conditions here.
|
||||
X u;
|
||||
BOOST_CHECK(u.size() == 0);
|
||||
BOOST_CHECK(X().size() == 0);
|
||||
BOOST_TEST(u.size() == 0);
|
||||
BOOST_TEST(X().size() == 0);
|
||||
|
||||
X a,b;
|
||||
|
||||
@ -131,6 +138,12 @@ void container_test(X& r, T const&)
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
|
||||
test::check_return_type<allocator_type>::equals(a_const.get_allocator());
|
||||
|
||||
// Avoid unused variable warnings:
|
||||
|
||||
sink(u);
|
||||
sink(u2);
|
||||
sink(u3);
|
||||
}
|
||||
|
||||
template <class X, class Key>
|
||||
@ -147,18 +160,17 @@ void unordered_map_test(X& r, Key const& k, T const& v)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||
BOOST_MPL_ASSERT((boost::is_same<value_type, std::pair<key_type const, T> >));
|
||||
BOOST_MPL_ASSERT((
|
||||
boost::is_same<value_type, std::pair<key_type const, T> >));
|
||||
|
||||
r.insert(std::pair<Key const, T>(k, v));
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
Key k_lvalue(k);
|
||||
T v_lvalue(v);
|
||||
|
||||
r.emplace(k, v);
|
||||
r.emplace(k_lvalue, v_lvalue);
|
||||
r.emplace(rvalue(k), rvalue(v));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class X>
|
||||
@ -168,11 +180,6 @@ void equality_test(X& r)
|
||||
|
||||
test::check_return_type<bool>::equals(a == b);
|
||||
test::check_return_type<bool>::equals(a != b);
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
|
||||
test::check_return_type<std::size_t>::equals(boost::hash_value(a));
|
||||
#else
|
||||
test::check_return_type<std::size_t>::equals(hash_value(a));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class X, class T>
|
||||
@ -180,9 +187,7 @@ void unordered_unique_test(X& r, T const& t)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
test::check_return_type<std::pair<iterator, bool> >::equals(r.insert(t));
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
test::check_return_type<std::pair<iterator, bool> >::equals(r.emplace(t));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class X, class T>
|
||||
@ -190,9 +195,7 @@ void unordered_equivalent_test(X& r, T const& t)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
test::check_return_type<iterator>::equals(r.insert(t));
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
test::check_return_type<iterator>::equals(r.emplace(t));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class X, class Key, class T>
|
||||
@ -221,25 +224,57 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
|
||||
typedef BOOST_DEDUCED_TYPENAME X::local_iterator local_iterator;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::BOOST_ITERATOR_CATEGORY<iterator>::type iterator_category;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference<iterator>::type iterator_difference;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_pointer<iterator>::type iterator_pointer;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference<iterator>::type iterator_reference;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::BOOST_ITERATOR_CATEGORY<iterator>::type
|
||||
iterator_category;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_difference<iterator>::type
|
||||
iterator_difference;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_pointer<iterator>::type
|
||||
iterator_pointer;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_reference<iterator>::type
|
||||
iterator_reference;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::BOOST_ITERATOR_CATEGORY<local_iterator>::type local_iterator_category;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference<local_iterator>::type local_iterator_difference;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_pointer<local_iterator>::type local_iterator_pointer;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference<local_iterator>::type local_iterator_reference;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::BOOST_ITERATOR_CATEGORY<local_iterator>::type
|
||||
local_iterator_category;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_difference<local_iterator>::type
|
||||
local_iterator_difference;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_pointer<local_iterator>::type
|
||||
local_iterator_pointer;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_reference<local_iterator>::type
|
||||
local_iterator_reference;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::BOOST_ITERATOR_CATEGORY<const_iterator>::type const_iterator_category;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference<const_iterator>::type const_iterator_difference;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_pointer<const_iterator>::type const_iterator_pointer;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference<const_iterator>::type const_iterator_reference;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::BOOST_ITERATOR_CATEGORY<const_iterator>::type
|
||||
const_iterator_category;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_difference<const_iterator>::type
|
||||
const_iterator_difference;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_pointer<const_iterator>::type
|
||||
const_iterator_pointer;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_reference<const_iterator>::type
|
||||
const_iterator_reference;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::BOOST_ITERATOR_CATEGORY<const_local_iterator>::type const_local_iterator_category;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference<const_local_iterator>::type const_local_iterator_difference;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_pointer<const_local_iterator>::type const_local_iterator_pointer;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference<const_local_iterator>::type const_local_iterator_reference;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::BOOST_ITERATOR_CATEGORY<const_local_iterator>::type
|
||||
const_local_iterator_category;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_difference<const_local_iterator>::type
|
||||
const_local_iterator_difference;
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::iterator_pointer<const_local_iterator>::type
|
||||
const_local_iterator_pointer;
|
||||
typedef BOOST_DEDUCED_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> >();
|
||||
@ -252,16 +287,25 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
|
||||
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_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>));
|
||||
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);
|
||||
@ -294,14 +338,12 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
|
||||
|
||||
const_iterator q = a.cbegin();
|
||||
test::check_return_type<iterator>::equals(a.insert(q, t));
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
test::check_return_type<iterator>::equals(a.emplace(q, t));
|
||||
#endif
|
||||
test::check_return_type<iterator>::equals(a.emplace_hint(q, t));
|
||||
|
||||
a.insert(i, j);
|
||||
test::check_return_type<size_type>::equals(a.erase(k));
|
||||
|
||||
BOOST_CHECK(a.empty());
|
||||
BOOST_TEST(a.empty());
|
||||
if(a.empty()) {
|
||||
a.insert(t);
|
||||
q = a.cbegin();
|
||||
@ -339,4 +381,16 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
|
||||
test::check_return_type<float>::equals(b.max_load_factor());
|
||||
a.max_load_factor((float) 2.0);
|
||||
a.rehash(100);
|
||||
|
||||
// Avoid unused variable warnings:
|
||||
|
||||
sink(a);
|
||||
sink(a2);
|
||||
sink(a3);
|
||||
sink(a4);
|
||||
sink(a5);
|
||||
sink(a6);
|
||||
sink(a7);
|
||||
sink(a8);
|
||||
sink(a9);
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -20,7 +22,8 @@ namespace constructor_tests {
|
||||
test::seed_t seed(356730);
|
||||
|
||||
template <class T>
|
||||
void constructor_tests1(T*, test::random_generator generator = test::default_generator)
|
||||
void constructor_tests1(T*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
@ -29,42 +32,42 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen
|
||||
std::cerr<<"Construct 1\n";
|
||||
{
|
||||
T x(0, hf, eq);
|
||||
BOOST_CHECK(x.empty());
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), 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 2\n";
|
||||
{
|
||||
T x(100, hf);
|
||||
BOOST_CHECK(x.empty());
|
||||
BOOST_CHECK(x.bucket_count() >= 100);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), al));
|
||||
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_CHECK(x.empty());
|
||||
BOOST_CHECK(x.bucket_count() >= 2000);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), al));
|
||||
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_CHECK(x.empty());
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), 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);
|
||||
}
|
||||
|
||||
@ -72,10 +75,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq);
|
||||
BOOST_CHECK(x.bucket_count() >= 10000);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), 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);
|
||||
}
|
||||
@ -84,10 +87,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen
|
||||
{
|
||||
test::random_values<T> v(10, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf);
|
||||
BOOST_CHECK(x.bucket_count() >= 10000);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), 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);
|
||||
}
|
||||
@ -96,10 +99,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 100);
|
||||
BOOST_CHECK(x.bucket_count() >= 100);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), al));
|
||||
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);
|
||||
}
|
||||
@ -108,9 +111,9 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen
|
||||
{
|
||||
test::random_values<T> v(1, generator);
|
||||
T x(v.begin(), v.end());
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), al));
|
||||
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);
|
||||
}
|
||||
@ -118,10 +121,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen
|
||||
std::cerr<<"Construct 9\n";
|
||||
{
|
||||
T x(0, hf, eq, al);
|
||||
BOOST_CHECK(x.empty());
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), 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);
|
||||
}
|
||||
|
||||
@ -129,28 +132,28 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq, al);
|
||||
BOOST_CHECK(x.bucket_count() >= 10000);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), 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);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 11\n";
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(al);
|
||||
BOOST_CHECK(x.empty());
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), 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);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void constructor_tests2(T*, test::random_generator const& generator = test::default_generator)
|
||||
void constructor_tests2(T*,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
|
||||
@ -165,21 +168,21 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa
|
||||
std::cerr<<"Construct 1\n";
|
||||
{
|
||||
T x(10000, hf1, eq1);
|
||||
BOOST_CHECK(x.bucket_count() >= 10000);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), al));
|
||||
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_CHECK(x.empty());
|
||||
BOOST_CHECK(x.bucket_count() >= 100);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), al));
|
||||
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);
|
||||
}
|
||||
|
||||
@ -187,9 +190,9 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), al));
|
||||
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);
|
||||
}
|
||||
@ -198,10 +201,10 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa
|
||||
{
|
||||
test::random_values<T> v(5, generator);
|
||||
T x(v.begin(), v.end(), 1000, hf1);
|
||||
BOOST_CHECK(x.bucket_count() >= 1000);
|
||||
BOOST_CHECK(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_CHECK(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(x.get_allocator(), al));
|
||||
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);
|
||||
}
|
||||
@ -243,21 +246,99 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa
|
||||
std::cerr<<"Construct 8 - from input iterator\n";
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
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);
|
||||
BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
v_begin = v.begin(), v_end = v.end();
|
||||
T x(test::input_iterator(v_begin),
|
||||
test::input_iterator(v_end), 0, hf1, eq1);
|
||||
BOOST_DEDUCED_TYPENAME T::const_iterator
|
||||
x_begin = x.begin(), x_end = x.end();
|
||||
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);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 9\n";
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(50);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.max_load_factor(10);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.insert(v.begin(), v.end());
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
std::initializer_list<BOOST_DEDUCED_TYPENAME T::value_type> list;
|
||||
|
||||
std::cerr<<"Initializer list construct 1\n";
|
||||
{
|
||||
T x(list);
|
||||
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));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 2\n";
|
||||
{
|
||||
T x(list, 1000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 3\n";
|
||||
{
|
||||
T x(list, 10, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 4\n";
|
||||
{
|
||||
T x(list, 10, hf1, eq1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 5\n";
|
||||
{
|
||||
T x(list, 10, hf1, eq1, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void map_constructor_test(T* = 0, test::random_generator const& generator = test::default_generator)
|
||||
void map_constructor_test(T* = 0,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"map_constructor_test\n";
|
||||
|
||||
typedef test::list<std::pair<BOOST_DEDUCED_TYPENAME T::key_type, BOOST_DEDUCED_TYPENAME T::mapped_type> > list;
|
||||
typedef test::list<
|
||||
std::pair<
|
||||
BOOST_DEDUCED_TYPENAME T::key_type,
|
||||
BOOST_DEDUCED_TYPENAME T::mapped_type
|
||||
>
|
||||
> list;
|
||||
test::random_values<T> v(1000, generator);
|
||||
list l(v.begin(), v.end());
|
||||
T x(l.begin(), l.end());
|
||||
@ -266,10 +347,18 @@ void map_constructor_test(T* = 0, test::random_generator const& generator = test
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
@ -288,6 +377,29 @@ UNORDERED_TEST(map_constructor_test,
|
||||
((test_map)(test_multimap))
|
||||
)
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(test_default_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
std::initializer_list<int> init;
|
||||
boost::unordered_set<int> x1 = init;
|
||||
BOOST_TEST(x1.empty());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
|
||||
!defined(BOOST_NO_INITIALIZER_LISTS)
|
||||
|
||||
UNORDERED_AUTO_TEST(test_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
boost::unordered_set<int> x1 = { 2, 10, 45, -5 };
|
||||
BOOST_TEST(x1.find(10) != x1.end());
|
||||
BOOST_TEST(x1.find(46) == x1.end());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -18,7 +20,8 @@ namespace copy_tests
|
||||
{
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests1(T*, test::random_generator const& generator = test::default_generator)
|
||||
void copy_construct_tests1(T*,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
@ -27,11 +30,11 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d
|
||||
{
|
||||
T x;
|
||||
T y(x);
|
||||
BOOST_CHECK(y.empty());
|
||||
BOOST_CHECK(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_CHECK(x.max_load_factor() == y.max_load_factor());
|
||||
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);
|
||||
}
|
||||
|
||||
@ -41,7 +44,7 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d
|
||||
T x(v.begin(), v.end());
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
equivalent(y);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
@ -55,15 +58,16 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d
|
||||
x.max_load_factor(x.load_factor() / 4);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
equivalent(y);
|
||||
BOOST_TEST(equivalent(y));
|
||||
// This isn't guaranteed:
|
||||
BOOST_CHECK(y.load_factor() < y.max_load_factor());
|
||||
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests2(T* ptr, test::random_generator const& generator = test::default_generator)
|
||||
void copy_construct_tests2(T* ptr,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
copy_construct_tests1(ptr);
|
||||
|
||||
@ -75,22 +79,22 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes
|
||||
{
|
||||
T x(10000, hf, eq, al);
|
||||
T y(x);
|
||||
BOOST_CHECK(y.empty());
|
||||
BOOST_CHECK(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_CHECK(x.max_load_factor() == y.max_load_factor());
|
||||
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);
|
||||
}
|
||||
|
||||
{
|
||||
T x(1000, hf, eq, al);
|
||||
T y(x, al2);
|
||||
BOOST_CHECK(y.empty());
|
||||
BOOST_CHECK(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_CHECK(x.max_load_factor() == y.max_load_factor());
|
||||
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(), al2));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
@ -100,9 +104,9 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
equivalent(y);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_CHECK(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
}
|
||||
|
||||
{
|
||||
@ -111,16 +115,24 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x, al2);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
equivalent(y);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_CHECK(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2008 Daniel James.
|
||||
// Copyright 2008-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/preprocessor/seq.hpp>
|
||||
@ -13,6 +15,10 @@ namespace equality_tests
|
||||
{
|
||||
struct mod_compare
|
||||
{
|
||||
bool alt_hash_;
|
||||
|
||||
explicit mod_compare(bool alt_hash = false) : alt_hash_(alt_hash) {}
|
||||
|
||||
bool operator()(int x, int y) const
|
||||
{
|
||||
return x % 1000 == y % 1000;
|
||||
@ -20,123 +26,145 @@ namespace equality_tests
|
||||
|
||||
int operator()(int x) const
|
||||
{
|
||||
return x % 250;
|
||||
return alt_hash_ ? x % 250 : (x + 5) % 250;
|
||||
}
|
||||
};
|
||||
|
||||
#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \
|
||||
do { \
|
||||
boost::unordered_set<int, mod_compare, mod_compare> set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_CHECK(set1 op set2); \
|
||||
} while(false)
|
||||
#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_set<int, mod_compare, mod_compare> set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \
|
||||
do { \
|
||||
boost::unordered_multiset<int, mod_compare, mod_compare> set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_CHECK(set1 op set2); \
|
||||
} while(false)
|
||||
#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multiset<int, mod_compare, mod_compare> \
|
||||
set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \
|
||||
do { \
|
||||
boost::unordered_map<int, int, mod_compare, mod_compare> map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_CHECK(map1 op map2); \
|
||||
} while(false)
|
||||
#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_map<int, int, mod_compare, mod_compare> \
|
||||
map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \
|
||||
do { \
|
||||
boost::unordered_multimap<int, int, mod_compare, mod_compare> map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_CHECK(map1 op map2); \
|
||||
} while(false)
|
||||
#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multimap<int, int, mod_compare, mod_compare> \
|
||||
map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_SET_INSERT(r, set, item) set.insert(item);
|
||||
#define UNORDERED_MAP_INSERT(r, map, item) \
|
||||
map.insert(std::pair<int const, int> BOOST_PP_SEQ_TO_TUPLE(item));
|
||||
map.insert(std::pair<int const, int> BOOST_PP_SEQ_TO_TUPLE(item));
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_size_tests)
|
||||
{
|
||||
boost::unordered_set<int> x1, x2;
|
||||
BOOST_CHECK(x1 == x2);
|
||||
BOOST_CHECK(!(x1 != x2));
|
||||
UNORDERED_AUTO_TEST(equality_size_tests)
|
||||
{
|
||||
boost::unordered_set<int> x1, x2;
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x1.insert(1);
|
||||
BOOST_CHECK(x1 != x2);
|
||||
BOOST_CHECK(!(x1 == x2));
|
||||
BOOST_CHECK(x2 != x1);
|
||||
BOOST_CHECK(!(x2 == x1));
|
||||
|
||||
x2.insert(1);
|
||||
BOOST_CHECK(x1 == x2);
|
||||
BOOST_CHECK(!(x1 != x2));
|
||||
|
||||
x2.insert(2);
|
||||
BOOST_CHECK(x1 != x2);
|
||||
BOOST_CHECK(!(x1 == x2));
|
||||
BOOST_CHECK(x2 != x1);
|
||||
BOOST_CHECK(!(x2 == x1));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_key_value_tests)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2));
|
||||
UNORDERED_EQUALITY_SET_TEST((2), ==, (2));
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1)));
|
||||
}
|
||||
|
||||
x1.insert(1);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
|
||||
x2.insert(1);
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x2.insert(2);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_key_value_tests)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2))
|
||||
UNORDERED_EQUALITY_SET_TEST((2), ==, (2))
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_collision_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1), !=, (501));
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(251), !=, (1)(501));
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((251)(1))((1)(1)), !=, ((501)(1))((1)(1)));
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(501), ==, (1)(501));
|
||||
UNORDERED_EQUALITY_SET_TEST(
|
||||
(1)(501), ==, (501)(1));
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1), !=, (501))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(251), !=, (1)(501))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((251)(1))((1)(1)), !=, ((501)(1))((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(501), ==, (1)(501))
|
||||
UNORDERED_EQUALITY_SET_TEST(
|
||||
(1)(501), ==, (501)(1))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_group_size_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(10)(20)(20), !=, (10)(10)(20));
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((10)(1))((20)(1))((20)(1)), !=,
|
||||
((10)(1))((20)(1))((10)(1)));
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((20)(1))((10)(1))((10)(1)), ==,
|
||||
((10)(1))((20)(1))((10)(1)));
|
||||
UNORDERED_AUTO_TEST(equality_group_size_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(10)(20)(20), !=, (10)(10)(20))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((10)(1))((20)(1))((20)(1)), !=,
|
||||
((10)(1))((20)(1))((10)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((20)(1))((10)(1))((10)(1)), ==,
|
||||
((10)(1))((20)(1))((10)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_map_value_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(1)), !=, ((1)(2)));
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(1)), ==, ((1)(1)));
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(1)), !=, ((1)(2)));
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(1))((1)(1)), !=, ((1)(1))((1)(2)));
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(2))((1)(1)), !=, ((1)(1))((1)(2)));
|
||||
}
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(1)), ==, ((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(2))((1)(1)), !=, ((1)(1))((1)(2)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_predicate_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_SET_TEST(
|
||||
(1), ==, (1001));
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1)));
|
||||
}
|
||||
UNORDERED_EQUALITY_SET_TEST(
|
||||
(1), ==, (1001))
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1)))
|
||||
}
|
||||
|
||||
// Test that equality still works when the two containers have
|
||||
// different hash functions but the same equality predicate.
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_different_hash_test)
|
||||
{
|
||||
typedef boost::unordered_set<int, mod_compare, mod_compare> set;
|
||||
set set1(0, mod_compare(false), mod_compare(false));
|
||||
set set2(0, mod_compare(true), mod_compare(true));
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(1); set2.insert(2);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(2); set2.insert(1);
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(10); set2.insert(20);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(20); set2.insert(10);
|
||||
BOOST_TEST(set1 == set2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -42,17 +44,20 @@ UNORDERED_AUTO_TEST(set_tests)
|
||||
{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);
|
||||
typedef boost::unordered_set<int> set;
|
||||
typedef boost::unordered_multiset<int> multiset;
|
||||
|
||||
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);
|
||||
test_equal_insertion<set>(values[0], values[0] + 1);
|
||||
test_equal_insertion<set>(values[1], values[1] + 2);
|
||||
test_equal_insertion<set>(values[2], values[2] + 2);
|
||||
test_equal_insertion<set>(values[3], values[3] + 2);
|
||||
test_equal_insertion<set>(values[4], values[4] + 3);
|
||||
|
||||
test_equal_insertion<multiset>(values[0], values[0] + 1);
|
||||
test_equal_insertion<multiset>(values[1], values[1] + 2);
|
||||
test_equal_insertion<multiset>(values[2], values[2] + 2);
|
||||
test_equal_insertion<multiset>(values[3], values[3] + 2);
|
||||
test_equal_insertion<multiset>(values[4], values[4] + 3);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(map_tests)
|
||||
|
@ -1,11 +1,13 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/list.hpp"
|
||||
@ -15,6 +17,11 @@
|
||||
#include <boost/next_prior.hpp>
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#endif
|
||||
|
||||
struct write_pair_type
|
||||
{
|
||||
template <class X1, class X2>
|
||||
@ -67,11 +74,11 @@ UNORDERED_AUTO_TEST(single_item_tests)
|
||||
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
BOOST_CHECK(x.count(1) == 1 && x.size() == 1);
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
x.erase(x.end(), x.end());
|
||||
BOOST_CHECK(x.count(1) == 1 && x.size() == 1);
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_CHECK(x.count(1) == 0 && x.size() == 0);
|
||||
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(two_equivalent_item_tests)
|
||||
@ -83,14 +90,14 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_CHECK(x.count(1) == 0 && x.size() == 0);
|
||||
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_CHECK(x.count(1) == 1 && x.size() == 1 &&
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
|
||||
x.begin()->first == 1 && x.begin()->second == value);
|
||||
}
|
||||
|
||||
@ -98,7 +105,7 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
|
||||
collide_map x(init.begin(), init.end());
|
||||
int value = x.begin()->second;
|
||||
x.erase(boost::next(x.begin()), x.end());
|
||||
BOOST_CHECK(x.count(1) == 1 && x.size() == 1 &&
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
|
||||
x.begin()->first == 1 && x.begin()->second == value);
|
||||
}
|
||||
}
|
||||
@ -116,7 +123,7 @@ bool compare(Range1 const& x, Range2 const& y)
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
bool general_erase_range_test(Container& x, int start, int end)
|
||||
bool general_erase_range_test(Container& x, std::size_t start, std::size_t end)
|
||||
{
|
||||
collide_list l(x.begin(), x.end());
|
||||
l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end));
|
||||
@ -128,7 +135,8 @@ 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) {
|
||||
for(std::size_t position = 0; position < x.size() - length; ++position)
|
||||
{
|
||||
Container y(x);
|
||||
collide_list init(y.begin(), y.end());
|
||||
if(!general_erase_range_test(y, position, position + length)) {
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -21,21 +23,22 @@ namespace erase_tests
|
||||
test::seed_t seed(85638);
|
||||
|
||||
template <class Container>
|
||||
void erase_tests1(Container*, test::random_generator generator = test::default_generator)
|
||||
void erase_tests1(Container*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"Erase by key.\n";
|
||||
{
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<Container>::iterator it = v.begin();
|
||||
it != v.end(); ++it)
|
||||
for(BOOST_DEDUCED_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_CHECK(count == x.erase(test::get_key<Container>(*it)));
|
||||
BOOST_CHECK(x.size() == old_size - count);
|
||||
BOOST_CHECK(x.count(test::get_key<Container>(*it)) == 0);
|
||||
BOOST_CHECK(x.find(test::get_key<Container>(*it)) == x.end());
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,15 +49,17 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g
|
||||
std::size_t size = x.size();
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key<Container>(*x.begin());
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_DEDUCED_TYPENAME Container::iterator pos = x.erase(x.begin());
|
||||
BOOST_DEDUCED_TYPENAME Container::iterator
|
||||
pos = x.erase(x.begin());
|
||||
--size;
|
||||
BOOST_CHECK(pos == x.begin());
|
||||
BOOST_CHECK(x.count(key) == count - 1);
|
||||
BOOST_CHECK(x.size() == size);
|
||||
BOOST_TEST(pos == x.begin());
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
}
|
||||
BOOST_CHECK(x.empty());
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
std::cerr<<"erase(random position).\n";
|
||||
@ -65,7 +70,7 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
using namespace std;
|
||||
int index = rand() % x.size();
|
||||
int index = rand() % (int) x.size();
|
||||
BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next;
|
||||
if(index == 0) {
|
||||
prev = pos = x.begin();
|
||||
@ -75,17 +80,18 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g
|
||||
pos = boost::next(prev);
|
||||
}
|
||||
next = boost::next(pos);
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key<Container>(*pos);
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_CHECK(next == x.erase(pos));
|
||||
BOOST_TEST(next == x.erase(pos));
|
||||
--size;
|
||||
if(size > 0)
|
||||
BOOST_CHECK(index == 0 ? next == x.begin() :
|
||||
BOOST_TEST(index == 0 ? next == x.begin() :
|
||||
next == boost::next(prev));
|
||||
BOOST_CHECK(x.count(key) == count - 1);
|
||||
BOOST_CHECK(x.size() == size);
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
}
|
||||
BOOST_CHECK(x.empty());
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
std::cerr<<"erase(ranges).\n";
|
||||
@ -99,33 +105,92 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g
|
||||
// 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_CHECK(x.erase(x.end(), x.end()) == x.end());
|
||||
BOOST_CHECK(x.erase(x.begin(), x.begin()) == x.begin());
|
||||
BOOST_CHECK(x.size() == size);
|
||||
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_CHECK(x.erase(x.begin(), x.end()) == x.end());
|
||||
BOOST_CHECK(x.empty());
|
||||
BOOST_CHECK(x.begin() == x.end());
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.end());
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
|
||||
BOOST_CHECK(x.erase(x.begin(), x.end()) == x.begin());
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin());
|
||||
}
|
||||
|
||||
std::cerr<<"quick_erase(begin()).\n";
|
||||
{
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
x.quick_erase(x.begin());
|
||||
--size;
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
std::cerr<<"quick_erase(random position).\n";
|
||||
{
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
using namespace std;
|
||||
int index = rand() % (int) x.size();
|
||||
BOOST_DEDUCED_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);
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
x.quick_erase(pos);
|
||||
--size;
|
||||
if(size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() :
|
||||
next == boost::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
|
||||
std::cerr<<"clear().\n";
|
||||
{
|
||||
test::random_values<Container> v(500, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
x.clear();
|
||||
BOOST_CHECK(x.empty());
|
||||
BOOST_CHECK(x.begin() == x.end());
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
}
|
||||
|
||||
std::cerr<<"\n";
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -33,13 +35,14 @@ void find_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it1);
|
||||
iterator pos = x.find(key);
|
||||
BOOST_DEDUCED_TYPENAME X::const_iterator const_pos = x_const.find(key);
|
||||
BOOST_CHECK(pos != x.end() &&
|
||||
BOOST_DEDUCED_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_CHECK(const_pos != x_const.end() &&
|
||||
BOOST_TEST(const_pos != x_const.end() &&
|
||||
x_const.key_eq()(key, test::get_key<X>(*const_pos)));
|
||||
|
||||
BOOST_CHECK(x.count(key) == tracker.count(key));
|
||||
BOOST_TEST(x.count(key) == tracker.count(key));
|
||||
|
||||
test::compare_pairs(x.equal_range(key),
|
||||
tracker.equal_range(key),
|
||||
@ -56,11 +59,11 @@ void find_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it2);
|
||||
if(tracker.find(test::get_key<X>(key)) == tracker.end())
|
||||
{
|
||||
BOOST_CHECK(x.find(key) == x.end());
|
||||
BOOST_CHECK(x_const.find(key) == x_const.end());
|
||||
BOOST_CHECK(x.count(key) == 0);
|
||||
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_CHECK(range.first == range.second);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,18 +76,77 @@ void find_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
v2.begin(); it3 != v2.end(); ++it3)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it3);
|
||||
BOOST_CHECK(x.find(key) == x.end());
|
||||
BOOST_CHECK(x.count(key) == 0);
|
||||
BOOST_TEST(x.find(key) == x.end());
|
||||
BOOST_TEST(x.count(key) == 0);
|
||||
std::pair<iterator, iterator> range = x.equal_range(key);
|
||||
BOOST_CHECK(range.first == range.second);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
struct compatible_key
|
||||
{
|
||||
test::object o_;
|
||||
|
||||
compatible_key(test::object const& o) : o_(o) {}
|
||||
};
|
||||
|
||||
struct compatible_hash
|
||||
{
|
||||
test::hash hash_;
|
||||
|
||||
std::size_t operator()(compatible_key const& k) const {
|
||||
return hash_(k.o_);
|
||||
}
|
||||
};
|
||||
|
||||
struct compatible_predicate
|
||||
{
|
||||
test::equal_to equal_;
|
||||
|
||||
bool operator()(compatible_key const& k1, compatible_key const& k2) const {
|
||||
return equal_(k1.o_, k2.o_);
|
||||
}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
void find_compatible_keys_test(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
typedef BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
|
||||
value_iterator;
|
||||
test::random_values<X> v(500, generator);
|
||||
X x(v.begin(), v.end());
|
||||
|
||||
compatible_hash h;
|
||||
compatible_predicate eq;
|
||||
|
||||
for(value_iterator it = v.begin(), end = v.end(); it != end; ++it) {
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
}
|
||||
|
||||
test::random_values<X> v2(20, generator);
|
||||
|
||||
for(value_iterator it = v2.begin(), end = v2.end(); it != end; ++it) {
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
@ -93,6 +155,10 @@ UNORDERED_TEST(find_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(find_compatible_keys_test,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
64
test/unordered/fwd_map_test.cpp
Normal file
64
test/unordered/fwd_map_test.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
// Copyright 2008-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered/unordered_map_fwd.hpp>
|
||||
|
||||
typedef boost::unordered_map<int, int> int_map;
|
||||
|
||||
void call_swap(int_map& x, int_map& y) {
|
||||
swap(x,y);
|
||||
}
|
||||
|
||||
bool call_equals(int_map& x, int_map& y) {
|
||||
return x == y;
|
||||
}
|
||||
|
||||
bool call_not_equals(int_map& x, int_map& y) {
|
||||
return x != y;
|
||||
}
|
||||
|
||||
typedef boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
void call_swap(int_multimap& x, int_multimap& y) {
|
||||
swap(x,y);
|
||||
}
|
||||
|
||||
bool call_equals(int_multimap& x, int_multimap& y) {
|
||||
return x == y;
|
||||
}
|
||||
|
||||
bool call_not_equals(int_multimap& x, int_multimap& y) {
|
||||
return x != y;
|
||||
}
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
UNORDERED_AUTO_TEST(use_map_fwd_declared_function) {
|
||||
int_map x, y;
|
||||
x[1] = 2;
|
||||
y[2] = 1;
|
||||
call_swap(x, y);
|
||||
|
||||
BOOST_TEST(y.find(1) != y.end() && y.find(1)->second == 2);
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end() && x.find(2)->second == 1);
|
||||
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(use_multimap_fwd_declared_function) {
|
||||
int_multimap x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
86
test/unordered/fwd_set_test.cpp
Normal file
86
test/unordered/fwd_set_test.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
// Copyright 2008-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered/unordered_set_fwd.hpp>
|
||||
|
||||
struct true_type { char x[100]; };
|
||||
struct false_type { char x; };
|
||||
|
||||
false_type is_unordered_set_impl(void*);
|
||||
|
||||
template <class Value, class Hash, class Pred, class Alloc>
|
||||
true_type is_unordered_set_impl(
|
||||
boost::unordered_set<Value, Hash, Pred, Alloc>*);
|
||||
|
||||
typedef boost::unordered_set<int> int_set;
|
||||
|
||||
void call_swap(int_set& x, int_set& y) {
|
||||
swap(x,y);
|
||||
}
|
||||
|
||||
bool call_equals(int_set& x, int_set& y) {
|
||||
return x == y;
|
||||
}
|
||||
|
||||
bool call_not_equals(int_set& x, int_set& y) {
|
||||
return x != y;
|
||||
}
|
||||
|
||||
typedef boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
void call_swap(int_multiset& x, int_multiset& y) {
|
||||
swap(x,y);
|
||||
}
|
||||
|
||||
bool call_equals(int_multiset& x, int_multiset& y) {
|
||||
return x == y;
|
||||
}
|
||||
|
||||
bool call_not_equals(int_multiset& x, int_multiset& y) {
|
||||
return x != y;
|
||||
}
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
UNORDERED_AUTO_TEST(use_fwd_declared_trait_without_definition) {
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int_set*) 0))
|
||||
== sizeof(true_type));
|
||||
}
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
UNORDERED_AUTO_TEST(use_fwd_declared_trait) {
|
||||
boost::unordered_set<int> x;
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type));
|
||||
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int*) 0)) == sizeof(false_type));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(use_set_fwd_declared_function) {
|
||||
int_set x, y;
|
||||
x.insert(1);
|
||||
y.insert(2);
|
||||
call_swap(x, y);
|
||||
|
||||
BOOST_TEST(y.find(1) != y.end());
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end());
|
||||
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(use_multiset_fwd_declared_function) {
|
||||
int_multiset x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
147
test/unordered/incomplete_test.cpp
Normal file
147
test/unordered/incomplete_test.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
|
||||
// Copyright 2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
namespace x
|
||||
{
|
||||
struct D { boost::unordered_map<D, D> x; };
|
||||
}
|
||||
|
||||
namespace test
|
||||
{
|
||||
// Declare, but don't define some types.
|
||||
|
||||
struct value;
|
||||
struct hash;
|
||||
struct equals;
|
||||
template <class T>
|
||||
struct malloc_allocator;
|
||||
|
||||
// Declare some instances
|
||||
|
||||
typedef boost::unordered_map<value, value, hash, equals,
|
||||
malloc_allocator<std::pair<value const, value> > > map;
|
||||
typedef boost::unordered_multimap<value, value, hash, equals,
|
||||
malloc_allocator<std::pair<value const, value> > > multimap;
|
||||
typedef boost::unordered_set<value, hash, equals,
|
||||
malloc_allocator<value> > set;
|
||||
typedef boost::unordered_multiset<value, hash, equals,
|
||||
malloc_allocator<value> > multiset;
|
||||
|
||||
// Now define the types which are stored as members, as they are needed for
|
||||
// declaring struct members.
|
||||
|
||||
struct hash {
|
||||
template <typename T>
|
||||
std::size_t operator()(T const&) const { return 0; }
|
||||
};
|
||||
|
||||
struct equals {
|
||||
template <typename T>
|
||||
bool operator()(T const&, T const&) const { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "../helpers/allocator.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
// Declare some members of a structs.
|
||||
//
|
||||
// Incomplete hash, equals and allocator aren't here supported at the
|
||||
// moment.
|
||||
|
||||
struct struct1 {
|
||||
boost::unordered_map<struct1, struct1, hash, equals,
|
||||
malloc_allocator<std::pair<struct1 const, struct1> > > x;
|
||||
};
|
||||
struct struct2 {
|
||||
boost::unordered_multimap<struct2, struct2, hash, equals,
|
||||
malloc_allocator<std::pair<struct2 const, struct2> > > x;
|
||||
};
|
||||
struct struct3 {
|
||||
boost::unordered_set<struct3, hash, equals,
|
||||
malloc_allocator<struct3> > x;
|
||||
};
|
||||
struct struct4 {
|
||||
boost::unordered_multiset<struct4, hash, equals,
|
||||
malloc_allocator<struct4> > x;
|
||||
};
|
||||
|
||||
// Now define the value type.
|
||||
|
||||
struct value {};
|
||||
|
||||
// Create some instances.
|
||||
|
||||
test::map m1;
|
||||
test::multimap m2;
|
||||
test::set s1;
|
||||
test::multiset s2;
|
||||
|
||||
test::struct1 c1;
|
||||
test::struct2 c2;
|
||||
test::struct3 c3;
|
||||
test::struct4 c4;
|
||||
|
||||
// Now declare, but don't define, the operators required for comparing
|
||||
// elements.
|
||||
|
||||
std::size_t hash_value(value const&);
|
||||
bool operator==(value const&, value const&);
|
||||
|
||||
std::size_t hash_value(struct1 const&);
|
||||
std::size_t hash_value(struct2 const&);
|
||||
std::size_t hash_value(struct3 const&);
|
||||
std::size_t hash_value(struct4 const&);
|
||||
|
||||
bool operator==(struct1 const&, struct1 const&);
|
||||
bool operator==(struct2 const&, struct2 const&);
|
||||
bool operator==(struct3 const&, struct3 const&);
|
||||
bool operator==(struct4 const&, struct4 const&);
|
||||
|
||||
// And finally use these
|
||||
|
||||
void use_types()
|
||||
{
|
||||
test::value x;
|
||||
m1[x] = x;
|
||||
m2.insert(std::make_pair(x, x));
|
||||
s1.insert(x);
|
||||
s2.insert(x);
|
||||
|
||||
c1.x.insert(std::make_pair(c1, c1));
|
||||
c2.x.insert(std::make_pair(c2, c2));
|
||||
c3.x.insert(c3);
|
||||
c4.x.insert(c4);
|
||||
}
|
||||
|
||||
// And finally define the operators required for comparing elements.
|
||||
|
||||
std::size_t hash_value(value const&) { return 0; }
|
||||
bool operator==(value const&, value const&) { return true; }
|
||||
|
||||
std::size_t hash_value(struct1 const&) { return 0; }
|
||||
std::size_t hash_value(struct2 const&) { return 0; }
|
||||
std::size_t hash_value(struct3 const&) { return 0; }
|
||||
std::size_t hash_value(struct4 const&) { return 0; }
|
||||
|
||||
bool operator==(struct1 const&, struct1 const&) { return true; }
|
||||
bool operator==(struct2 const&, struct2 const&) { return true; }
|
||||
bool operator==(struct3 const&, struct3 const&) { return true; }
|
||||
bool operator==(struct4 const&, struct4 const&) { return true; }
|
||||
}
|
||||
|
||||
int main() {
|
||||
// This could just be a compile test, but I like to be able to run these
|
||||
// things. It's probably irrational, but I find it reassuring.
|
||||
|
||||
test::use_types();
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2007-2008 Daniel James.
|
||||
// Copyright 2007-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -46,33 +48,37 @@ UNORDERED_AUTO_TEST(stable_insert_test1) {
|
||||
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_CHECK(it != end);
|
||||
if(it != end) { BOOST_CHECK(it->tag2_ == 1); ++it; }
|
||||
BOOST_CHECK(it != end);
|
||||
if(it != end) { BOOST_CHECK(it->tag2_ == 2); ++it; }
|
||||
BOOST_CHECK(it != end);
|
||||
if(it != end) { BOOST_CHECK(it->tag2_ == 3); ++it; }
|
||||
BOOST_CHECK(it == end);
|
||||
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);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(stable_insert_test2) {
|
||||
boost::unordered_multimap<insert_stable::member, int> x;
|
||||
typedef boost::unordered_multimap<insert_stable::member, int>::const_iterator iterator;
|
||||
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));
|
||||
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_CHECK(it != end);
|
||||
if(it != end) { BOOST_CHECK(it->first.tag2_ == 1 && it->second == 1); ++it; }
|
||||
BOOST_CHECK(it != end);
|
||||
if(it != end) { BOOST_CHECK(it->first.tag2_ == 2 && it->second == 2); ++it; }
|
||||
BOOST_CHECK(it != end);
|
||||
if(it != end) { BOOST_CHECK(it->first.tag2_ == 3 && it->second == 3); ++it; }
|
||||
BOOST_CHECK(it == 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);
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -21,7 +23,8 @@ namespace insert_tests {
|
||||
test::seed_t seed(243432);
|
||||
|
||||
template <class X>
|
||||
void unique_insert_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
void unique_insert_tests1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
typedef test::ordered<X> ordered;
|
||||
@ -41,22 +44,24 @@ void unique_insert_tests1(X*, test::random_generator generator = test::default_g
|
||||
float b = x.max_load_factor();
|
||||
|
||||
std::pair<iterator, bool> r1 = x.insert(*it);
|
||||
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool> r2 = tracker.insert(*it);
|
||||
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool>
|
||||
r2 = tracker.insert(*it);
|
||||
|
||||
BOOST_CHECK(r1.second == r2.second);
|
||||
BOOST_CHECK(*r1.first == *r2.first);
|
||||
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_CHECK(x.bucket_count() == old_bucket_count);
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void equivalent_insert_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
void equivalent_insert_tests1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
|
||||
|
||||
@ -71,21 +76,23 @@ void equivalent_insert_tests1(X*, test::random_generator generator = test::defau
|
||||
float b = x.max_load_factor();
|
||||
|
||||
BOOST_DEDUCED_TYPENAME X::iterator r1 = x.insert(*it);
|
||||
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2 = tracker.insert(*it);
|
||||
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2
|
||||
= tracker.insert(*it);
|
||||
|
||||
BOOST_CHECK(*r1 == *r2);
|
||||
BOOST_TEST(*r1 == *r2);
|
||||
|
||||
tracker.compare_key(x, *it);
|
||||
|
||||
if(x.size() < b * old_bucket_count)
|
||||
BOOST_CHECK(x.bucket_count() == old_bucket_count);
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void insert_tests2(X*, test::random_generator generator = test::default_generator)
|
||||
void insert_tests2(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME test::ordered<X> tracker_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
@ -99,19 +106,20 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<X> v(1000, generator);
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
|
||||
it != v.end(); ++it)
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
|
||||
it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
|
||||
BOOST_DEDUCED_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_CHECK(*r1 == *r2);
|
||||
BOOST_TEST(*r1 == *r2);
|
||||
tracker.compare_key(x, *it);
|
||||
|
||||
if(x.size() < b * old_bucket_count)
|
||||
BOOST_CHECK(x.bucket_count() == old_bucket_count);
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
@ -125,19 +133,20 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<X> v(100, generator);
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
|
||||
it != v.end(); ++it)
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
|
||||
it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
|
||||
BOOST_DEDUCED_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_CHECK(*r1 == *r2);
|
||||
BOOST_TEST(*r1 == *r2);
|
||||
tracker.compare_key(x, *it);
|
||||
|
||||
if(x.size() < b * old_bucket_count)
|
||||
BOOST_CHECK(x.bucket_count() == old_bucket_count);
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
@ -151,19 +160,20 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<X> v(1000, generator);
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
|
||||
it != v.end(); ++it)
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
|
||||
it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
|
||||
BOOST_DEDUCED_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_CHECK(*pos == *r2);
|
||||
BOOST_TEST(*pos == *r2);
|
||||
tracker.compare_key(x, *it);
|
||||
|
||||
if(x.size() < b * old_bucket_count)
|
||||
BOOST_CHECK(x.bucket_count() == old_bucket_count);
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
@ -176,10 +186,11 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<X> v(1000, generator);
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
|
||||
it != v.end(); ++it)
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
|
||||
it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
|
||||
BOOST_DEDUCED_TYPENAME X::size_type
|
||||
old_bucket_count = x.bucket_count();
|
||||
float b = x.max_load_factor();
|
||||
|
||||
x.insert(it, boost::next(it));
|
||||
@ -187,7 +198,7 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato
|
||||
tracker.compare_key(x, *it);
|
||||
|
||||
if(x.size() < b * old_bucket_count)
|
||||
BOOST_CHECK(x.bucket_count() == old_bucket_count);
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
@ -211,17 +222,20 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato
|
||||
X x;
|
||||
|
||||
test::random_values<X> v(1000, generator);
|
||||
x.insert(test::input_iterator(v.begin()), test::input_iterator(v.end()));
|
||||
BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator
|
||||
begin = v.begin(), end = v.end();
|
||||
x.insert(test::input_iterator(begin), test::input_iterator(end));
|
||||
test::check_container(x, v);
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
|
||||
template <class X>
|
||||
void unique_emplace_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
void unique_emplace_tests1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
typedef test::ordered<X> ordered;
|
||||
@ -241,22 +255,24 @@ void unique_emplace_tests1(X*, test::random_generator generator = test::default_
|
||||
float b = x.max_load_factor();
|
||||
|
||||
std::pair<iterator, bool> r1 = x.emplace(*it);
|
||||
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool> r2 = tracker.insert(*it);
|
||||
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool>
|
||||
r2 = tracker.insert(*it);
|
||||
|
||||
BOOST_CHECK(r1.second == r2.second);
|
||||
BOOST_CHECK(*r1.first == *r2.first);
|
||||
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_CHECK(x.bucket_count() == old_bucket_count);
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void equivalent_emplace_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
void equivalent_emplace_tests1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"emplace(value) tests for containers with equivalent keys.\n";
|
||||
|
||||
@ -271,14 +287,15 @@ void equivalent_emplace_tests1(X*, test::random_generator generator = test::defa
|
||||
float b = x.max_load_factor();
|
||||
|
||||
BOOST_DEDUCED_TYPENAME X::iterator r1 = x.emplace(*it);
|
||||
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2 = tracker.insert(*it);
|
||||
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator
|
||||
r2 = tracker.insert(*it);
|
||||
|
||||
BOOST_CHECK(*r1 == *r2);
|
||||
BOOST_TEST(*r1 == *r2);
|
||||
|
||||
tracker.compare_key(x, *it);
|
||||
|
||||
if(x.size() < b * old_bucket_count)
|
||||
BOOST_CHECK(x.bucket_count() == old_bucket_count);
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
@ -307,18 +324,27 @@ void map_tests(X*, test::random_generator generator = test::default_generator)
|
||||
tracker.compare_key(x, *it);
|
||||
|
||||
if(x.size() < b * old_bucket_count)
|
||||
BOOST_CHECK(x.bucket_count() == 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*, test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"associative_insert_range_test\n";
|
||||
// Some tests for when the range's value type doesn't match the container's
|
||||
// value type.
|
||||
|
||||
typedef test::list<std::pair<BOOST_DEDUCED_TYPENAME X::key_type, BOOST_DEDUCED_TYPENAME X::mapped_type> > list;
|
||||
template <class X>
|
||||
void map_insert_range_test1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"map_insert_range_test1\n";
|
||||
|
||||
typedef test::list<
|
||||
std::pair<
|
||||
BOOST_DEDUCED_TYPENAME X::key_type,
|
||||
BOOST_DEDUCED_TYPENAME X::mapped_type
|
||||
>
|
||||
> list;
|
||||
test::random_values<X> v(1000, generator);
|
||||
list l(v.begin(), v.end());
|
||||
|
||||
@ -327,10 +353,37 @@ void associative_insert_range_test(X*, test::random_generator generator = test::
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
template <class X>
|
||||
void map_insert_range_test2(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"map_insert_range_test2\n";
|
||||
|
||||
typedef test::list<
|
||||
std::pair<BOOST_DEDUCED_TYPENAME X::key_type const, int>
|
||||
> list;
|
||||
test::random_values<
|
||||
boost::unordered_map<BOOST_DEDUCED_TYPENAME X::key_type, int>
|
||||
> v(1000, generator);
|
||||
list l(v.begin(), v.end());
|
||||
|
||||
X x; x.insert(l.begin(), l.end());
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
@ -350,7 +403,7 @@ UNORDERED_TEST(insert_tests2,
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
UNORDERED_TEST(unique_emplace_tests1,
|
||||
((test_set)(test_map))
|
||||
((default_generator)(generate_collisions))
|
||||
@ -367,11 +420,65 @@ UNORDERED_TEST(map_tests,
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(associative_insert_range_test,
|
||||
UNORDERED_TEST(map_insert_range_test1,
|
||||
((test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(map_insert_range_test2,
|
||||
((test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
|
||||
!defined(BOOST_NO_INITIALIZER_LISTS)
|
||||
|
||||
UNORDERED_AUTO_TEST(insert_initializer_list_set)
|
||||
{
|
||||
boost::unordered_set<int> set;
|
||||
set.insert({1,2,3,1});
|
||||
BOOST_TEST_EQ(set.size(), 3u);
|
||||
BOOST_TEST(set.find(1) != set.end());
|
||||
BOOST_TEST(set.find(4) == set.end());
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(insert_initializer_list_multiset)
|
||||
{
|
||||
boost::unordered_multiset<std::string> multiset;
|
||||
//multiset.insert({});
|
||||
BOOST_TEST(multiset.empty());
|
||||
multiset.insert({"a"});
|
||||
BOOST_TEST_EQ(multiset.size(), 1u);
|
||||
BOOST_TEST(multiset.find("a") != multiset.end());
|
||||
BOOST_TEST(multiset.find("b") == multiset.end());
|
||||
multiset.insert({"a","b"});
|
||||
BOOST_TEST(multiset.size() == 3);
|
||||
BOOST_TEST_EQ(multiset.count("a"), 2u);
|
||||
BOOST_TEST_EQ(multiset.count("b"), 1u);
|
||||
BOOST_TEST_EQ(multiset.count("c"), 0u);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(insert_initializer_list_map)
|
||||
{
|
||||
boost::unordered_map<std::string, std::string> map;
|
||||
//map.insert({});
|
||||
BOOST_TEST(map.empty());
|
||||
map.insert({{"a", "b"},{"a", "b"},{"d", ""}});
|
||||
BOOST_TEST_EQ(map.size(), 2u);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(insert_initializer_list_multimap)
|
||||
{
|
||||
boost::unordered_multimap<std::string, std::string> multimap;
|
||||
//multimap.insert({});
|
||||
BOOST_TEST(multimap.empty());
|
||||
multimap.insert({{"a", "b"},{"a", "b"},{"d", ""}});
|
||||
BOOST_TEST_EQ(multimap.size(), 3u);
|
||||
BOOST_TEST_EQ(multimap.count("a"), 2u);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
@ -11,6 +13,15 @@ void foo(boost::unordered_set<int>& x1,
|
||||
boost::unordered_multiset<int>& x3,
|
||||
boost::unordered_multimap<int, int>& x4)
|
||||
{
|
||||
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
|
||||
struct dummy {
|
||||
boost::unordered_set<int> x1;
|
||||
boost::unordered_map<int, int> x2;
|
||||
boost::unordered_multiset<int> x3;
|
||||
boost::unordered_multimap<int, int> x4;
|
||||
};
|
||||
#endif
|
||||
|
||||
x1.insert(1);
|
||||
x2[2] = 2;
|
||||
x3.insert(3);
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -24,17 +26,18 @@ void set_load_factor_tests(X* = 0)
|
||||
{
|
||||
X x;
|
||||
|
||||
BOOST_CHECK(x.max_load_factor() == 1.0);
|
||||
BOOST_CHECK(x.load_factor() == 0);
|
||||
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_CHECK(x.max_load_factor() == 2.0);
|
||||
x.max_load_factor(0.5); BOOST_CHECK(x.max_load_factor() == 0.5);
|
||||
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, test::random_generator generator = test::default_generator)
|
||||
void insert_test(X*, float mlf,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
X x;
|
||||
x.max_load_factor(mlf);
|
||||
@ -49,7 +52,7 @@ void insert_test(X*, float mlf, test::random_generator generator = test::default
|
||||
old_bucket_count = x.bucket_count();
|
||||
x.insert(*it);
|
||||
if(old_size + 1 < b * old_bucket_count)
|
||||
BOOST_CHECK(x.bucket_count() == old_bucket_count);
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2008 Daniel James.
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -44,7 +46,8 @@ namespace move_tests
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_construct_tests1(T* ptr, test::random_generator const& generator = test::default_generator)
|
||||
void move_construct_tests1(T* ptr,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
@ -52,11 +55,11 @@ namespace move_tests
|
||||
|
||||
{
|
||||
T y(empty(ptr));
|
||||
BOOST_CHECK(y.empty());
|
||||
BOOST_CHECK(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_CHECK(y.max_load_factor() == 1.0);
|
||||
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(y.max_load_factor() == 1.0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
@ -64,21 +67,26 @@ namespace move_tests
|
||||
test::random_values<T> v(1000, generator);
|
||||
test::object_count count;
|
||||
T y(create(v, count));
|
||||
BOOST_CHECK(count == test::global_object_count);
|
||||
#if defined(BOOST_HAS_NRVO)
|
||||
BOOST_TEST(count == test::global_object_count);
|
||||
#endif
|
||||
test::check_container(y, v);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_assign_tests1(T*, test::random_generator const& generator = test::default_generator)
|
||||
void move_assign_tests1(T*,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
{
|
||||
test::random_values<T> v(500, generator);
|
||||
test::object_count count;
|
||||
T y;
|
||||
y = create(v, count);
|
||||
BOOST_CHECK(count == test::global_object_count);
|
||||
#if defined(BOOST_HAS_NRVO)
|
||||
BOOST_TEST(count == test::global_object_count);
|
||||
#endif
|
||||
test::check_container(y, v);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
@ -98,51 +106,63 @@ namespace move_tests
|
||||
{
|
||||
test::random_values<T> v(500, generator);
|
||||
T y(create(v, count, hf, eq, al, 0.5));
|
||||
BOOST_CHECK(count == test::global_object_count);
|
||||
#if defined(BOOST_HAS_NRVO)
|
||||
BOOST_TEST(count == test::global_object_count);
|
||||
#endif
|
||||
test::check_container(y, v);
|
||||
BOOST_CHECK(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_CHECK(y.max_load_factor() == 0.5); // Not necessarily required.
|
||||
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(y.max_load_factor() == 0.5); // Not necessarily required.
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
// TODO: To do this correctly requires the fancy new allocator stuff.
|
||||
// TODO: To do this correctly requires the fancy new allocator
|
||||
// stuff.
|
||||
test::random_values<T> v(500, generator);
|
||||
T y(create(v, count, hf, eq, al, 2.0), al2);
|
||||
BOOST_CHECK(count != test::global_object_count);
|
||||
BOOST_TEST(count != test::global_object_count);
|
||||
test::check_container(y, v);
|
||||
BOOST_CHECK(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_CHECK(y.max_load_factor() == 2.0); // Not necessarily required.
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required.
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
test::random_values<T> v(25, generator);
|
||||
T y(create(v, count, hf, eq, al, 1.0), al);
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
BOOST_CHECK(count == test::global_object_count);
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
BOOST_TEST(count == test::global_object_count);
|
||||
#else
|
||||
BOOST_CHECK(test::global_object_count.constructions - count.constructions <=
|
||||
BOOST_TEST(
|
||||
test::global_object_count.constructions - count.constructions <=
|
||||
(test::is_map<T>::value ? 50 : 25));
|
||||
BOOST_CHECK(count.instances == test::global_object_count.instances);
|
||||
BOOST_TEST(count.instances == test::global_object_count.instances);
|
||||
#endif
|
||||
test::check_container(y, v);
|
||||
BOOST_CHECK(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_CHECK(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_CHECK(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_CHECK(y.max_load_factor() == 1.0); // Not necessarily required.
|
||||
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(y.max_load_factor() == 1.0); // Not necessarily required.
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
*/ }
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -17,7 +19,8 @@ test::seed_t seed(2974);
|
||||
template <class X>
|
||||
bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n)
|
||||
{
|
||||
return x.bucket_count() > x.size() / x.max_load_factor() && x.bucket_count() >= n;
|
||||
return x.bucket_count() > x.size() / x.max_load_factor() &&
|
||||
x.bucket_count() >= n;
|
||||
}
|
||||
|
||||
template <class X>
|
||||
@ -26,32 +29,72 @@ void rehash_empty_test1(X* = 0)
|
||||
X x;
|
||||
|
||||
x.rehash(10000);
|
||||
BOOST_CHECK(postcondition(x, 10000));
|
||||
BOOST_TEST(postcondition(x, 10000));
|
||||
|
||||
x.rehash(0);
|
||||
BOOST_CHECK(postcondition(x, 0));
|
||||
BOOST_TEST(postcondition(x, 0));
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void rehash_test1(X* = 0, test::random_generator generator = test::default_generator)
|
||||
void rehash_empty_test2(X* = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
test::random_values<X> v(1000, generator);
|
||||
test::ordered<X> tracker;
|
||||
|
||||
X x;
|
||||
|
||||
x.rehash(10000);
|
||||
BOOST_TEST(postcondition(x, 10000));
|
||||
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
x.insert(v.begin(), v.end());
|
||||
tracker.compare(x);
|
||||
|
||||
BOOST_TEST(postcondition(x, 10000));
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void rehash_empty_test3(X* = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
test::random_values<X> v(1000, generator);
|
||||
test::ordered<X> tracker;
|
||||
|
||||
X x;
|
||||
|
||||
x.rehash(0);
|
||||
BOOST_TEST(postcondition(x, 0));
|
||||
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
x.insert(v.begin(), v.end());
|
||||
tracker.compare(x);
|
||||
|
||||
BOOST_TEST(postcondition(x, 0));
|
||||
}
|
||||
|
||||
|
||||
template <class X>
|
||||
void rehash_test1(X* = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
test::random_values<X> v(1000, generator);
|
||||
test::ordered<X> tracker;
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
X x(v.begin(), v.end());
|
||||
|
||||
x.rehash(0); BOOST_CHECK(postcondition(x, 0));
|
||||
x.rehash(0); BOOST_TEST(postcondition(x, 0));
|
||||
tracker.compare(x);
|
||||
|
||||
x.max_load_factor(0.25);
|
||||
x.rehash(0); BOOST_CHECK(postcondition(x, 0));
|
||||
x.rehash(0); BOOST_TEST(postcondition(x, 0));
|
||||
tracker.compare(x);
|
||||
|
||||
x.max_load_factor(50.0);
|
||||
x.rehash(0); BOOST_CHECK(postcondition(x, 0));
|
||||
x.rehash(0); BOOST_TEST(postcondition(x, 0));
|
||||
tracker.compare(x);
|
||||
|
||||
x.rehash(1000); BOOST_CHECK(postcondition(x, 1000));
|
||||
x.rehash(1000); BOOST_TEST(postcondition(x, 1000));
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
@ -63,6 +106,12 @@ boost::unordered_multimap<int, int>* int_multimap_ptr;
|
||||
UNORDERED_TEST(rehash_empty_test1,
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
UNORDERED_TEST(rehash_empty_test2,
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
UNORDERED_TEST(rehash_empty_test3,
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
UNORDERED_TEST(rehash_test1,
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
|
@ -1,10 +1,12 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -19,67 +21,69 @@ void simple_test(X const& a)
|
||||
|
||||
{
|
||||
X u;
|
||||
BOOST_CHECK(u.size() == 0);
|
||||
BOOST_CHECK(X().size() == 0);
|
||||
BOOST_TEST(u.size() == 0);
|
||||
BOOST_TEST(X().size() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_CHECK(equivalent(X(a)));
|
||||
BOOST_TEST(equivalent(X(a)));
|
||||
}
|
||||
|
||||
{
|
||||
X u(a);
|
||||
BOOST_CHECK(equivalent(u));
|
||||
BOOST_TEST(equivalent(u));
|
||||
}
|
||||
|
||||
{
|
||||
X u = a;
|
||||
BOOST_CHECK(equivalent(u));
|
||||
BOOST_TEST(equivalent(u));
|
||||
}
|
||||
|
||||
{
|
||||
X b(a);
|
||||
BOOST_CHECK(b.begin() == const_cast<X const&>(b).cbegin());
|
||||
BOOST_CHECK(b.end() == const_cast<X const&>(b).cend());
|
||||
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_CHECK(equivalent(b));
|
||||
BOOST_CHECK(c.empty());
|
||||
BOOST_TEST(equivalent(b));
|
||||
BOOST_TEST(c.empty());
|
||||
b.swap(c);
|
||||
BOOST_CHECK(b.empty());
|
||||
BOOST_CHECK(equivalent(c));
|
||||
BOOST_TEST(b.empty());
|
||||
BOOST_TEST(equivalent(c));
|
||||
b.swap(c);
|
||||
BOOST_CHECK(c.empty());
|
||||
BOOST_CHECK(equivalent(b));
|
||||
BOOST_TEST(c.empty());
|
||||
BOOST_TEST(equivalent(b));
|
||||
}
|
||||
|
||||
{
|
||||
X u;
|
||||
X& r = u;
|
||||
BOOST_CHECK(&(r = r) == &r);
|
||||
BOOST_CHECK(r.empty());
|
||||
BOOST_CHECK(&(r = a) == &r);
|
||||
BOOST_CHECK(equivalent(r));
|
||||
BOOST_CHECK(&(r = r) == &r);
|
||||
BOOST_CHECK(equivalent(r));
|
||||
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_CHECK(a.size() ==
|
||||
(BOOST_DEDUCED_TYPENAME X::size_type) std::distance(a.begin(), a.end()));
|
||||
BOOST_TEST(a.size() ==
|
||||
static_cast<BOOST_DEDUCED_TYPENAME X::size_type>(
|
||||
std::distance(a.begin(), a.end())));
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_CHECK(a.empty() == (a.size() == 0));
|
||||
BOOST_TEST(a.empty() == (a.size() == 0));
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_CHECK(a.empty() == (a.begin() == a.end()));
|
||||
BOOST_TEST(a.empty() == (a.begin() == a.end()));
|
||||
X u;
|
||||
BOOST_CHECK(u.begin() == u.end());
|
||||
BOOST_TEST(u.begin() == u.end());
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +95,7 @@ UNORDERED_AUTO_TEST(simple_tests)
|
||||
std::cout<<"Test unordered_set.\n";
|
||||
boost::unordered_set<int> set;
|
||||
simple_test(set);
|
||||
|
||||
|
||||
set.insert(1); set.insert(2); set.insert(1456);
|
||||
simple_test(set);
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
@ -60,7 +62,8 @@ void swap_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void swap_tests2(X* ptr = 0, test::random_generator generator = test::default_generator)
|
||||
void swap_tests2(X* ptr = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
swap_tests1(ptr);
|
||||
|
||||
@ -96,7 +99,8 @@ void swap_tests2(X* ptr = 0, test::random_generator generator = test::default_ge
|
||||
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.");
|
||||
BOOST_ERROR("Using swap method 1, "
|
||||
"swapping with unequal allocators didn't throw.");
|
||||
} catch (std::runtime_error) {}
|
||||
}
|
||||
#else
|
||||
@ -109,18 +113,28 @@ void swap_tests2(X* ptr = 0, test::random_generator generator = test::default_ge
|
||||
|
||||
{
|
||||
test::random_values<X> vx(100, generator), vy(100, generator);
|
||||
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));
|
||||
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
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
UNORDERED_TEST(swap_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
// Copyright 2006-2008 Daniel James.
|
||||
// Copyright 2006-2009 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
@ -29,7 +31,7 @@ namespace unnecessary_copy_tests
|
||||
: tag_(x.tag_) { ++copies; }
|
||||
|
||||
count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; }
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
count_copies(count_copies&& x) : tag_(x.tag_) {
|
||||
x.tag_ = -1; ++moves;
|
||||
}
|
||||
@ -65,15 +67,33 @@ namespace unnecessary_copy_tests
|
||||
}
|
||||
}
|
||||
|
||||
#define COPY_COUNT(n) \
|
||||
if(count_copies::copies != n) { \
|
||||
BOOST_ERROR("Wrong number of copies."); \
|
||||
std::cerr<<"Number of copies: "<<count_copies::copies<<std::endl; \
|
||||
#define COPY_COUNT(n) \
|
||||
if(count_copies::copies != n) { \
|
||||
BOOST_ERROR("Wrong number of copies."); \
|
||||
std::cerr \
|
||||
<< "Number of copies: " << count_copies::copies \
|
||||
<< " expecting: " << n << std::endl; \
|
||||
}
|
||||
#define MOVE_COUNT(n) \
|
||||
if(count_copies::moves != n) { \
|
||||
BOOST_ERROR("Wrong number of moves."); \
|
||||
std::cerr<<"Number of moves: "<<count_copies::moves<<std::endl; \
|
||||
#define MOVE_COUNT(n) \
|
||||
if(count_copies::moves != n) { \
|
||||
BOOST_ERROR("Wrong number of moves."); \
|
||||
std::cerr \
|
||||
<< "Number of moves: " << count_copies::moves \
|
||||
<< " expecting: " <<n << std::endl; \
|
||||
}
|
||||
#define COPY_COUNT_RANGE(a, b) \
|
||||
if(count_copies::copies < a || count_copies::copies > b) { \
|
||||
BOOST_ERROR("Wrong number of copies."); \
|
||||
std::cerr \
|
||||
<< "Number of copies: " << count_copies::copies \
|
||||
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
|
||||
}
|
||||
#define MOVE_COUNT_RANGE(a, b) \
|
||||
if(count_copies::moves < a || count_copies::moves > b) { \
|
||||
BOOST_ERROR("Wrong number of moves."); \
|
||||
std::cerr \
|
||||
<< "Number of moves: " << count_copies::copies \
|
||||
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
|
||||
}
|
||||
|
||||
namespace unnecessary_copy_tests
|
||||
@ -84,12 +104,11 @@ namespace unnecessary_copy_tests
|
||||
template <class T>
|
||||
void unnecessary_copy_insert_test(T*)
|
||||
{
|
||||
reset();
|
||||
T x;
|
||||
BOOST_DEDUCED_TYPENAME T::value_type a;
|
||||
COPY_COUNT(1);
|
||||
reset();
|
||||
x.insert(a);
|
||||
COPY_COUNT(2);
|
||||
COPY_COUNT(1);
|
||||
}
|
||||
|
||||
boost::unordered_set<count_copies>* set;
|
||||
@ -100,7 +119,6 @@ namespace unnecessary_copy_tests
|
||||
UNORDERED_TEST(unnecessary_copy_insert_test,
|
||||
((set)(multiset)(map)(multimap)))
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
template <class T>
|
||||
void unnecessary_copy_emplace_test(T*)
|
||||
{
|
||||
@ -118,9 +136,19 @@ namespace unnecessary_copy_tests
|
||||
reset();
|
||||
T x;
|
||||
x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>());
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
COPY_COUNT(1);
|
||||
#else
|
||||
COPY_COUNT(2);
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_TEST(unnecessary_copy_emplace_test,
|
||||
((set)(multiset)(map)(multimap)))
|
||||
UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test,
|
||||
((set)(multiset)(map)(multimap)))
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
template <class T>
|
||||
void unnecessary_copy_emplace_move_test(T*)
|
||||
{
|
||||
@ -132,13 +160,11 @@ namespace unnecessary_copy_tests
|
||||
COPY_COUNT(1); MOVE_COUNT(1);
|
||||
}
|
||||
|
||||
UNORDERED_TEST(unnecessary_copy_emplace_test,
|
||||
((set)(multiset)(map)(multimap)))
|
||||
UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test,
|
||||
((set)(multiset)(map)(multimap)))
|
||||
UNORDERED_TEST(unnecessary_copy_emplace_move_test,
|
||||
((set)(multiset)(map)(multimap)))
|
||||
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
|
||||
{
|
||||
reset();
|
||||
@ -173,10 +199,12 @@ namespace unnecessary_copy_tests
|
||||
x.emplace(source<count_copies>());
|
||||
COPY_COUNT(1); MOVE_COUNT(0);
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
// No move should take place.
|
||||
reset();
|
||||
x.emplace(std::move(a));
|
||||
COPY_COUNT(0); MOVE_COUNT(0);
|
||||
#endif
|
||||
|
||||
// Just in case a did get moved...
|
||||
count_copies b;
|
||||
@ -193,8 +221,12 @@ namespace unnecessary_copy_tests
|
||||
|
||||
// The container will have to create b copy in order to compare with
|
||||
// the existing element.
|
||||
//
|
||||
// Note to self: If copy_count == 0 it's an error not an optimization.
|
||||
// TODO: Devise a better test.
|
||||
|
||||
reset();
|
||||
|
||||
x.emplace(b, b);
|
||||
COPY_COUNT(1); MOVE_COUNT(0);
|
||||
}
|
||||
@ -231,24 +263,22 @@ namespace unnecessary_copy_tests
|
||||
x.emplace(source<std::pair<count_copies, count_copies> >());
|
||||
COPY_COUNT(2); MOVE_COUNT(0);
|
||||
|
||||
count_copies part;
|
||||
reset();
|
||||
std::pair<count_copies const&, count_copies const&> a_ref(part, part);
|
||||
x.emplace(a_ref);
|
||||
COPY_COUNT(0); MOVE_COUNT(0);
|
||||
// TODO: This doesn't work on older versions of gcc.
|
||||
//count_copies part;
|
||||
std::pair<count_copies const, count_copies> b;
|
||||
//reset();
|
||||
//std::pair<count_copies const&, count_copies const&> a_ref(part, part);
|
||||
//x.emplace(a_ref);
|
||||
//COPY_COUNT(0); MOVE_COUNT(0);
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
// No move should take place.
|
||||
// (since a is already in the container)
|
||||
reset();
|
||||
x.emplace(std::move(a));
|
||||
COPY_COUNT(0); MOVE_COUNT(0);
|
||||
#endif
|
||||
|
||||
// Just in case a did get moved
|
||||
std::pair<count_copies const, count_copies> b;
|
||||
|
||||
// This test requires a C++0x std::pair. Which gcc hasn't got yet.
|
||||
//reset();
|
||||
//x.emplace(b.first.tag_);
|
||||
//COPY_COUNT(2); MOVE_COUNT(0);
|
||||
|
||||
//
|
||||
// 2 arguments
|
||||
@ -268,10 +298,9 @@ namespace unnecessary_copy_tests
|
||||
COPY_COUNT(1); MOVE_COUNT(0);
|
||||
|
||||
reset();
|
||||
x.emplace(b.first.tag_, b.second.tag_);
|
||||
COPY_COUNT(2); MOVE_COUNT(0);
|
||||
x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_));
|
||||
COPY_COUNT(2); MOVE_COUNT(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
Reference in New Issue
Block a user