Compare commits

...

44 Commits

Author SHA1 Message Date
bea92e8842 Merge unordered and hash from trunk.
- Only use Visual C++ pragma with appropriate compilers.
- Working link for Thomas Wang's hash function.
- Updated unordered rationale.
- Fix `unnecessary_copy_tests` for Visual C++ 12.
- Some extra insert tests.


[SVN r86728]
2013-11-16 20:36:27 +00:00
6ca8d5e0d9 Merge Visual C++ 12 fix for Unordered.
[SVN r86551]
2013-11-03 19:20:09 +00:00
9b9a1d21a6 Merge release notes + float hash fix. Ref #8822.
[SVN r86210]
2013-10-08 21:26:30 +00:00
a7c0ddb5b3 Merge unordered to release. Fixes #8851, #8874
Avoid some warnings, and move detail functions into a sub-namespace to avoid
exposing them via. ADL.


[SVN r85388]
2013-08-18 09:44:14 +00:00
c88126e1d2 Merge unordered from trunk.
Add `BOOST_NOEXPECT` to:

- Move constructors (when appropriate)
- Destructors
- Iterators

Also, fix some misleading documentation about the containers' move support.


[SVN r85048]
2013-07-15 21:32:45 +00:00
0c7c7cc6ad Merge some change log entries to release.
[SVN r84497]
2013-05-25 15:53:49 +00:00
bd10a8b5aa Merge initial unordered use of noexcept + friends.
Still more to come, hopefully in time for the release.


[SVN r84304]
2013-05-16 22:15:42 +00:00
0221f1a9bd Unordered: Merge assign fix.
[SVN r82651]
2013-01-27 23:10:29 +00:00
34b69e67ee Unordered: Merge test tweaks + inspect fixes from trunk.
[SVN r81922]
2012-12-13 22:39:44 +00:00
654fed166a Unordered: Remove and update various deprecated things.
[SVN r81727]
2012-12-05 22:06:57 +00:00
981f1e2acb Unordered: Merge code clean up.
[SVN r81358]
2012-11-15 13:43:37 +00:00
81897a6469 Unordered: Fix erasing ranges, and some tests. Fixes #7471
[SVN r80958]
2012-10-11 17:29:19 +00:00
ced2139eea Unordered/Hash: Merge change log.
[SVN r80778]
2012-09-30 11:58:06 +00:00
0a8037243b Unordered: Merge slightly simpler implementation.
[SVN r80632]
2012-09-22 17:28:55 +00:00
a0ceefc91a Unordered: Merge from trunk.
Faster assign, plus simplified some of the implementation.


[SVN r80558]
2012-09-17 18:53:30 +00:00
05f7c37f54 Unordered: Merge tests to release
[SVN r80435]
2012-09-07 19:51:10 +00:00
d5971171da Unordered: Merge from trunk.
- Some changes to the internals, including reverting some of the
  recent changes to constructing values which turned out to be
  more bother than it was worth.
- On C++11 compilers, better use of `construct` and `destroy`.
- Better testing.


[SVN r80350]
2012-09-01 15:50:36 +00:00
035396e89f Unordered: Merge reference documentation update.
[SVN r80294]
2012-08-28 21:56:18 +00:00
8683332b2c Unordered: Merge from trunk
- Avoid an incorrect MSVC unused variable warning in the tests.
- Remove a `try..catch`.
- Adjust SFINAE use to try to supprt g++ 3.4. Fixes #7175.
- Fix some use of rvalues.
- Extra info in `at_tests`.



[SVN r79868]
2012-08-05 08:34:44 +00:00
d77453b7ad Unordered: Merge allocator fix + improved tests. Fixes #7100.
[SVN r79547]
2012-07-15 23:58:02 +00:00
cf9930fe20 Unordered: Merge updated c++11 config macros.
[SVN r79546]
2012-07-15 23:47:12 +00:00
e30a99d2fc Unordered: Merge some of the older changes from trunk.
Code reorganization, simpler tests, better use of Boost.Move.


[SVN r79545]
2012-07-15 23:44:41 +00:00
c788780792 Unordered: Merge msvc 11 fix from trunk.
[SVN r78853]
2012-06-07 19:47:01 +00:00
e1416d0a3e Unordered: Fix bcp namespace fix. Fixes #6905.
[SVN r78534]
2012-05-21 22:08:19 +00:00
808f1f939f Unordered: Merge unordered from trunk.
- Activate `std::allocator_traits` for gcc 4.7 and Visual C++ 11.
- Implement variadic construct in `boost::unordered::detail::allocator_traits`
  when variadics, rvalue references and SFINAE expression are available.
- Use variadic construct from `allocator_traits`, or when not available move
  the logic for constructing `value_type` to a lower level, so the container
  code is a bit simpler.
- Avoid `-Wshadow` warnings. Fixes #6190.
- Implement `reserve`. Fixes #6857.


[SVN r78432]
2012-05-12 08:14:05 +00:00
880d778ab6 Unordered: Missing revision from last merge.
[SVN r78320]
2012-05-03 22:29:25 +00:00
a8cd8cdd0b Unordered/Hash: Merge from trunk.
[SVN r78319]
2012-05-03 22:05:21 +00:00
fa3d93ddbc Unordered: Merge to release. Fixes #6522.
Fixes undefined macros, removes some unused code and fix some potential issues
for when `std::allocator_traits` is used.


[SVN r76943]
2012-02-07 20:48:50 +00:00
5622afdafa Iostreams: Merge spelling fix.
[SVN r76787]
2012-01-29 22:54:03 +00:00
63d56953af Unordered: Merge move changes. Fixes #6311.
[SVN r76531]
2012-01-15 20:22:15 +00:00
280b1971b6 Unordered: merge from trunk.
[SVN r75908]
2011-12-11 21:39:18 +00:00
abc556950b Unordered: Remove support for TR1 tuples. Fixes #6111.
[SVN r75450]
2011-11-12 12:01:34 +00:00
a8f75b7cea Merge to release several changes for 1.48.
[SVN r75293]
2011-11-04 02:31:36 +00:00
1f111edec8 Merge unordered+hash documentation updates.
[SVN r75015]
2011-10-17 20:23:27 +00:00
8591c1f180 Unordered: merge from trunk.
[SVN r74932]
2011-10-12 22:30:02 +00:00
50e8df5e12 Unordered: Merge from trunk.
Anotehr overhaul. Can now use `void_pointer` for links between nodes, although
it doesn't as I don't think `void_pointer` support is strong enough in existing
allocators.

Also no longer relies on using base pointers for custome pointer types.  And
scaled back member function detection to just detect if an allocator has a
member, not what its signature is. I found that the trait could be confused by
ambiguous overloads. This might be fixable.

Better documentation of C++11 compliance to come.


[SVN r74859]
2011-10-09 18:30:10 +00:00
17ba6c9916 Unordered: Merge from trunk.
Remove some workarounds for old compilers, some documentation updates and tweak
some tests for problem compilers.


[SVN r74469]
2011-09-19 18:22:18 +00:00
0618d01f86 Unordered: Move from trunk.
[SVN r74308]
2011-09-08 07:33:34 +00:00
5867994b8c Unordered: Merge from trunk
- Remove use of BOOST_DEDUCED_TYPENAME and BOOST_UNORDERED_PAIR_CAST, it's
  unlikely that the compilers which require them will be able to cope with the
  new version of unordered.
- Use the old equality algorithm if BOOST_UNORDERED_DEPRECATED_EQUALITY is
  defined.
- Use SFINAE to control which overloads of `construct_impl` are available.
  Fixes problems with differing overload resolution on different compilers.
- Support for piecewise pair construction.
- Only support the old variadic pair construction when
  BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT is defined (also fixed some bugs).
- Avoid instantiating BOOST_RV_REF for non-classes.
- Support optional allocator member functions for compilers with SFINAE
  expressions and Visual C++ 9.0/10.0
- Follow boost macro naming conventions.
- Improved portability for `allocator_traits` emulation.

Current compiler support:

- Full support for GCC 4.4+, Visual C++ 9.0+, Clang.
- All other compilers odn't support optional allocator members.
- No other errors for GCC 3.4.6+, Visual C++ 8.0, Intel, Pathscale.
- Visual Age has a compile error if `select_on_container_copy_construction`
  isn't `const` (it should ignore it).
- `select_on_container_copy_construction` detection doesn't work on Sun.
- `unnecessary_copy_tests` is failling for vacpp on AIX, but not on linux.
- Warnings causing failures for Visual C++ with STLport and WM5.


[SVN r74234]
2011-09-04 19:37:45 +00:00
f6f19aaaaa Unordered: Merge from trunk.
Portability fixes, and fix some issues with constructing std::pair.


[SVN r74101]
2011-08-28 11:26:38 +00:00
a4372314c2 Unordered: Merge to release.
Using Boost.Move and better C++11 support.


[SVN r73987]
2011-08-21 19:19:12 +00:00
3fd5635d7d Unordered: Fix some overly strict tests.
[SVN r70443]
2011-03-23 00:07:17 +00:00
147181530d Add copy constructors and assignment operators when using rvalue references. Fixes #5119.
[SVN r69469]
2011-03-02 08:47:34 +00:00
54f9626c12 Merge unordered from trunk.
- Avoid using operator& with the value type.
- More comments in headers.
- Remove old clang workaround.
- Adjust use of inline to make Borland a little happier.
- Avoid `-Wconversion` warnings.


[SVN r67663]
2011-01-04 23:05:55 +00:00
82 changed files with 12912 additions and 5868 deletions

View File

@ -3,6 +3,9 @@
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
using boostbook ;
using quickbook ;
path-constant images_location : ../ ;
path-constant admonishment_location : ../../../../doc/src/images ;

View File

@ -112,7 +112,7 @@ load factor is /required/ to be less than the maximum is following a call to
below the max load factor, and set the maximum load factor to be the same as
or close to the hint - unless your hint is unreasonably small or large.
[table Methods for Controlling Bucket Size
[table:bucket_size Methods for Controlling Bucket Size
[[Method] [Description]]
[

View File

@ -3,6 +3,9 @@
/ 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) ]
[template ticket[number]'''<ulink
url="https://svn.boost.org/trac/boost/ticket/'''[number]'''">'''#[number]'''</ulink>''']
[section:changes Change Log]
[h2 Review Version]
@ -134,4 +137,107 @@ First official release.
* Fix a bug when inserting into an `unordered_map` or `unordered_set` using
iterators which returns `value_type` by copy.
[h2 Boost 1.48.0 - Major update]
This is major change which has been converted to use Boost.Move's move
emulation, and be more compliant with the C++11 standard. See the
[link unordered.compliance compliance section] for details.
The container now meets C++11's complexity requirements, but to do so
uses a little more memory. This means that `quick_erase` and
`erase_return_void` are no longer required, they'll be removed in a
future version.
C++11 support has resulted in some breaking changes:
* Equality comparison has been changed to the C++11 specification.
In a container with equivalent keys, elements in a group with equal
keys used to have to be in the same order to be considered equal,
now they can be a permutation of each other. To use the old
behavior define the macro `BOOST_UNORDERED_DEPRECATED_EQUALITY`.
* The behaviour of swap is different when the two containers to be
swapped has unequal allocators. It used to allocate new nodes using
the appropriate allocators, it now swaps the allocators if
the allocator has a member structure `propagate_on_container_swap`,
such that `propagate_on_container_swap::value` is true.
* Allocator's `construct` and `destroy` functions are called with raw
pointers, rather than the allocator's `pointer` type.
* `emplace` used to emulate the variadic pair constructors that
appeared in early C++0x drafts. Since they were removed it no
longer does so. It does emulate the new `piecewise_construct`
pair constructors - only you need to use
`boost::piecewise_construct`. To use the old emulation of
the variadic consturctors define
`BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT`.
[h2 Boost 1.49.0]
* Fix warning due to accidental odd assignment.
* Slightly better error messages.
[h2 Boost 1.50.0]
* Fix equality for `unordered_multiset` and `unordered_multimap`.
* [@https://svn.boost.org/trac/boost/ticket/6857 Ticket 6857]:
Implement `reserve`.
* [@https://svn.boost.org/trac/boost/ticket/6771 Ticket 6771]:
Avoid gcc's `-Wfloat-equal` warning.
* [@https://svn.boost.org/trac/boost/ticket/6784 Ticket 6784]:
Fix some Sun specific code.
* [@https://svn.boost.org/trac/boost/ticket/6190 Ticket 6190]:
Avoid gcc's `-Wshadow` warning.
* [@https://svn.boost.org/trac/boost/ticket/6905 Ticket 6905]:
Make namespaces in macros compatible with `bcp` custom namespaces.
Fixed by Luke Elliott.
* Remove some of the smaller prime number of buckets, as they may make
collisions quite probable (e.g. multiples of 5 are very common because
we used base 10).
* On old versions of Visual C++, use the container library's implementation
of `allocator_traits`, as it's more likely to work.
* On machines with 64 bit std::size_t, use power of 2 buckets, with Thomas
Wang's hash function to pick which one to use. As modulus is very slow
for 64 bit values.
* Some internal changes.
[h2 Boost 1.51.0]
* Fix construction/destruction issue when using a C++11 compiler with a
C++03 allocator ([ticket 7100]).
* Remove a `try..catch` to support compiling without exceptions.
* Adjust SFINAE use to try to supprt g++ 3.4 ([ticket 7175]).
* Updated to use the new config macros.
[h2 Boost 1.52.0]
* Faster assign, which assigns to existing nodes where possible, rather than
creating entirely new nodes and copy constructing.
* Fixed bug in `erase_range` ([ticket 7471]).
* Reverted some of the internal changes to how nodes are created, especially
for C++11 compilers. 'construct' and 'destroy' should work a little better
for C++11 allocators.
* Simplified the implementation a bit. Hopefully more robust.
[h2 Boost 1.53.0]
* Remove support for the old pre-standard variadic pair constructors, and
equality implementation. Both have been deprecated since Boost 1.48.
* Remove use of deprecated config macros.
* More internal implementation changes, including a much simpler
implementation of `erase`.
[h2 Boost 1.54.0]
* Mark methods specified in standard as `noexpect`. More to come in the next
release.
* If the hash function and equality predicate are known to both have nothrow
move assignment or construction then use them.
[h2 Boost 1.55.0]
* Avoid some warnings ([ticket 8851], [ticket 8874]).
* Avoid exposing some detail functions via. ADL on the iterators.
[endsect]

View File

@ -1,10 +1,10 @@
[/ Copyright 2006-2008 Daniel James.
[/ Copyright 2006-2011 Daniel James.
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[section:comparison Comparison with Associative Containers]
[table Interface differences.
[table:interface_differences Interface differences.
[[Associative Containers] [Unordered Associative Containers]]
[
@ -66,15 +66,12 @@
[
[No equivalent]
[Local iterators can be used to iterate through individual buckets.
(I don't think that the order of local iterators and iterators are
(The order of local iterators and iterators aren't
required to have any correspondence.)]
]
[
[Can be compared using the `==`, `!=`, `<`, `<=`, `>`, `>=` operators.]
[No comparison operators are defined in the standard, although
[link unordered.rationale.equality_operators
implementations might extend the containers to support `==` and
`!=`].]
[Can be compared using the `==` and `!=` operators.]
]
[
[]
@ -88,7 +85,7 @@
]
]
[table Complexity Guarantees
[table:complexity_guarantees Complexity Guarantees
[[Operation] [Associative Containers] [Unordered Associative Containers]]
[
[Construction of empty container]

112
doc/compliance.qbk Normal file
View File

@ -0,0 +1,112 @@
[/ Copyright 2011 Daniel James.
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[section:compliance C++11 Compliance]
[section:move Move emulation]
Support for move semantics is implemented using Boost.Move. If rvalue
references are available it will use them, but if not it uses a close,
but imperfect emulation. On such compilers:
* Non-copyable objects can be stored in the containers.
They can be constructed in place using `emplace`, or if they support
Boost.Move, moved into place.
* The containers themselves are not movable.
* Argument forwarding is not perfect.
[endsect]
[section:allocator_compliance Use of allocators]
C++11 introduced a new allocator system. It's backwards compatible due to
the lax requirements for allocators in the old standard, but might need
some changes for allocators which worked with the old versions of the
unordered containers.
It uses a traits class, `allocator_traits` to handle the allocator
adding extra functionality, and making some methods and types optional.
During development a stable release of
`allocator_traits` wasn't available so an internal partial implementation
is always used in this version. Hopefully a future version will use the
standard implementation where available.
The member functions `construct`, `destroy` and `max_size` are now
optional, if they're not available a fallback is used.
A full implementation of `allocator_traits` requires sophisticated
member function detection so that the fallback is used whenever the
member function call is not well formed.
This requires support for SFINAE expressions, which are available on
GCC from version 4.4 and Clang.
On other compilers, there's just a test to see if the allocator has
a member, but no check that it can be called. So rather than using a
fallback there will just be a compile error.
`propagate_on_container_copy_assignment`,
`propagate_on_container_move_assignment`,
`propagate_on_container_swap` and
`select_on_container_copy_construction` are also supported.
Due to imperfect move emulation, some assignments might check
`propagate_on_container_copy_assignment` on some compilers and
`propagate_on_container_move_assignment` on others.
The use of the allocator's construct and destruct methods might be a bit
surprising.
Nodes are constructed and destructed using the allocator, but the elements
are stored in aligned space within the node and constructed and destructed
by calling the constructor and destructor directly.
In C++11 the allocator's construct function has the signature:
template <class U, class... Args>
void construct(U* p, Args&&... args);
which supports calling `construct` for the contained object, but
most existing allocators don't support this. If member function detection
was good enough then with old allocators it would fall back to calling
the element's constructor directly but in general, detection isn't good
enough to do this which is why Boost.Unordered just calls the constructor
directly every time. In most cases this will work okay.
`pointer_traits` aren't used. Instead, pointer types are obtained from
rebound allocators, this can cause problems if the allocator can't be
used with incomplete types. If `const_pointer` is not defined in the
allocator, `boost::pointer_to_other<pointer, const value_type>::type`
is used to obtain a const pointer.
[endsect]
[section:pairs Pairs]
Since the containers use `std::pair` they're limited to the version
from the current standard library. But since C++11 `std::pair`'s
`piecewise_construct` based constructor is very useful, `emplace`
emulates it with a `piecewise_construct` in the `boost::unordered`
namespace. So for example, the following will work:
boost::unordered_multimap<std::string, std::complex> x;
x.emplace(
boost::unordered::piecewise_construct,
boost::make_tuple("key"), boost::make_tuple(1, 2));
Older drafts of the standard also supported variadic constructors
for `std::pair`, where the first argument would be used for the
first part of the pair, and the remaining for the second part.
[endsect]
[section:misc Miscellaneous]
When swapping, `Pred` and `Hash` are not currently swapped by calling
`swap`, their copy constructors are used. As a consequence when swapping
an exception may be throw from their copy constructor.
Variadic constructor arguments for `emplace` are only used when both
rvalue references and variadic template parameters are available.
Otherwise `emplace` can only take up to 10 constructors arguments.
[endsect]
[endsect]

View File

@ -67,9 +67,10 @@ so that the hash function doesn't need to be explicitly given:
See the [link hash.custom Boost.Hash documentation] for more detail on how to
do this. Remember that it relies on extensions to the draft standard - so it
won't work on other implementations of the unordered associative containers.
won't work for other implementations of the unordered associative containers,
you'll need to explicitly use Boost.Hash.
[table Methods for accessing the hash and equality functions.
[table:access_methods Methods for accessing the hash and equality functions.
[[Method] [Description]]
[

View File

@ -2,15 +2,6 @@
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[def __tr1__
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
C++ Standard Library Technical Report]]
[def __boost-tr1__
[@http://www.boost.org/doc/html/boost_tr1.html
Boost.TR1]]
[def __draft__
[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2960.pdf
Working Draft of the C++ Standard]]
[def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table
hash table]]
[def __hash-function__ [@http://en.wikipedia.org/wiki/Hash_function
@ -31,12 +22,10 @@ to order their elements. For some data types this is impossible to implement
or isn't practical. In contrast, a hash table only needs an equality function
and a hash function for the key.
With this in mind, the __tr1__ introduced the unordered associative containers,
which are implemented using hash tables, and they have now been added to the
__draft__.
This library supplies an almost complete implementation of the specification in
the __draft__.
With this in mind, unordered associative containers were added to the C++
standard. This is an implementation of the containers described in C++11,
with some [link unordered.compliance deviations from the standard] in
order to work with non-C++11 compilers and libraries.
`unordered_set` and `unordered_multiset` are defined in the header
<[headerref boost/unordered_set.hpp]>

View File

@ -3,7 +3,7 @@
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[def __wang__
[@http://www.concentric.net/~Ttwang/tech/inthash.htm
[@http://web.archive.org/web/20121102023700/http://www.concentric.net/~Ttwang/tech/inthash.htm
Thomas Wang's article on integer hash functions]]
[section:rationale Implementation Rationale]
@ -44,6 +44,8 @@ bucket but there are a some serious problems with this:
So chained addressing is used.
[/ (Removing for now as this is out of date)
For containers with unique keys I store the buckets in a single-linked list.
There are other possible data structures (such as a double-linked list)
that allow for some operations to be faster (such as erasing and iteration)
@ -63,6 +65,17 @@ nodes in reverse order. This allows quick navigation to the end of a group (sinc
the first element points to the last) and can be quickly updated when elements
are inserted or erased. The main disadvantage of this approach is some hairy code
for erasing elements.
]
[/ (Starting to write up new structure, might not be ready in time)
The node used to be stored in a linked list for each bucket but that
didn't meet the complexity requirements for C++11, so now the nodes
are stored in one long single linked list. But there needs a way to get
the bucket from the node, to do that a copy of the key's hash value is
stored in the node. Another possibility would be to store a pointer to
the bucket, or the bucket's index, but storing the hash value allows
some operations to be faster.
]
[h2 Number of Buckets]
@ -72,7 +85,8 @@ of 2.
Using a prime number of buckets, and choosing a bucket by using the modulus
of the hash function's result will usually give a good result. The downside
is that the required modulus operation is fairly expensive.
is that the required modulus operation is fairly expensive. This is what the
containers do in most cases.
Using a power of 2 allows for much quicker selection of the bucket
to use, but at the expense of loosing the upper bits of the hash value.
@ -82,60 +96,16 @@ functions this can't be relied on.
To avoid this a transformation could be applied to the hash function, for an
example see __wang__. Unfortunately, a transformation like Wang's requires
knowledge of the number of bits in the hash value, so it isn't portable enough.
This leaves more expensive methods, such as Knuth's Multiplicative Method
(mentioned in Wang's article). These don't tend to work as well as taking the
modulus of a prime, and the extra computation required might negate
efficiency advantage of power of 2 hash tables.
knowledge of the number of bits in the hash value, so it isn't portable enough
to use as a default. It can applicable in certain cases so the containers
have a policy based implementation that can use this alternative technique.
So, this implementation uses a prime number for the hash table size.
Currently this is only done on 64 bit architecures, where prime number
modulus can be expensive. Although this varies depending on the architecture,
so I probably should revisit it.
[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 C++0x allocators]
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]. 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 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`).
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.
I'm also thinking of introducing a mechanism whereby a hash function can
indicate that it's safe to be used directly with power of 2 buckets, in
which case a faster plain power of 2 implementation can be used.
[endsect]

1219
doc/ref.php Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[library Boost.Unordered
[quickbook 1.4]
[quickbook 1.5]
[authors [James, Daniel]]
[copyright 2003 2004 Jeremy B. Maitin-Shepard]
[copyright 2005 2006 2007 2008 Daniel James]
@ -31,6 +31,7 @@
[include:unordered buckets.qbk]
[include:unordered hash_equality.qbk]
[include:unordered comparison.qbk]
[include:unordered compliance.qbk]
[include:unordered rationale.qbk]
[include:unordered changes.qbk]
[xinclude ref.xml]

File diff suppressed because it is too large Load Diff

View File

@ -1,111 +0,0 @@
// 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
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/config.hpp>
#if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
&& !defined(__BORLANDC__)
# define BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES
#endif
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
# include <boost/detail/allocator_utilities.hpp>
#endif
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> {};
#else
template <class Alloc, class T>
struct rebind_wrap
{
typedef BOOST_DEDUCED_TYPENAME
Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other
type;
};
#endif
// 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 Allocator>
struct allocator_array_constructor
{
typedef BOOST_DEDUCED_TYPENAME Allocator::pointer pointer;
Allocator& alloc_;
pointer ptr_;
pointer constructed_;
std::size_t length_;
allocator_array_constructor(Allocator& a)
: alloc_(a), ptr_(), constructed_(), length_(0)
{
constructed_ = pointer();
ptr_ = pointer();
}
~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_);
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
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,304 +1,680 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2005-2011 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
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/extract_key.hpp>
namespace boost { namespace unordered_detail {
namespace boost { namespace unordered { namespace detail {
template <class T>
class hash_equivalent_table : public T::table
template <typename A, typename T> struct grouped_node;
template <typename T> struct grouped_ptr_node;
template <typename Types> struct grouped_table_impl;
template <typename A, typename T>
struct grouped_node :
boost::unordered::detail::value_base<T>
{
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 typename ::boost::unordered::detail::rebind_wrap<
A, grouped_node<A, T> >::type allocator;
typedef typename ::boost::unordered::detail::
allocator_traits<allocator>::pointer node_pointer;
typedef node_pointer link_pointer;
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;
link_pointer next_;
node_pointer group_prev_;
std::size_t hash_;
grouped_node() :
next_(),
group_prev_(),
hash_(0)
{}
void init(node_pointer self)
{
group_prev_ = self;
}
private:
grouped_node& operator=(grouped_node const&);
};
template <typename T>
struct grouped_ptr_node :
boost::unordered::detail::value_base<T>,
boost::unordered::detail::ptr_bucket
{
typedef boost::unordered::detail::ptr_bucket bucket_base;
typedef grouped_ptr_node<T>* node_pointer;
typedef ptr_bucket* link_pointer;
node_pointer group_prev_;
std::size_t hash_;
grouped_ptr_node() :
bucket_base(),
group_prev_(0),
hash_(0)
{}
void init(node_pointer self)
{
group_prev_ = self;
}
private:
grouped_ptr_node& operator=(grouped_ptr_node const&);
};
// If the allocator uses raw pointers use grouped_ptr_node
// Otherwise use grouped_node.
template <typename A, typename T, typename NodePtr, typename BucketPtr>
struct pick_grouped_node2
{
typedef boost::unordered::detail::grouped_node<A, T> node;
typedef typename boost::unordered::detail::allocator_traits<
typename boost::unordered::detail::rebind_wrap<A, node>::type
>::pointer node_pointer;
typedef boost::unordered::detail::bucket<node_pointer> bucket;
typedef node_pointer link_pointer;
};
template <typename A, typename T>
struct pick_grouped_node2<A, T,
boost::unordered::detail::grouped_ptr_node<T>*,
boost::unordered::detail::ptr_bucket*>
{
typedef boost::unordered::detail::grouped_ptr_node<T> node;
typedef boost::unordered::detail::ptr_bucket bucket;
typedef bucket* link_pointer;
};
template <typename A, typename T>
struct pick_grouped_node
{
typedef boost::unordered::detail::allocator_traits<
typename boost::unordered::detail::rebind_wrap<A,
boost::unordered::detail::grouped_ptr_node<T> >::type
> tentative_node_traits;
typedef boost::unordered::detail::allocator_traits<
typename boost::unordered::detail::rebind_wrap<A,
boost::unordered::detail::ptr_bucket >::type
> tentative_bucket_traits;
typedef pick_grouped_node2<A, T,
typename tentative_node_traits::pointer,
typename tentative_bucket_traits::pointer> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
};
template <typename A, typename T, typename H, typename P>
struct multiset
{
typedef boost::unordered::detail::multiset<A, T, H, P> types;
typedef A allocator;
typedef T value_type;
typedef H hasher;
typedef P key_equal;
typedef T key_type;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
typedef boost::unordered::detail::pick_grouped_node<allocator,
value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef boost::unordered::detail::pick_policy::type policy;
};
template <typename A, typename K, typename M, typename H, typename P>
struct multimap
{
typedef boost::unordered::detail::multimap<A, K, M, H, P> types;
typedef A allocator;
typedef std::pair<K const, M> value_type;
typedef H hasher;
typedef P key_equal;
typedef K key_type;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
typedef boost::unordered::detail::pick_grouped_node<allocator,
value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::map_extractor<key_type, value_type>
extractor;
typedef boost::unordered::detail::pick_policy::type policy;
};
template <typename Types>
struct grouped_table_impl : boost::unordered::detail::table<Types>
{
typedef boost::unordered::detail::table<Types> table;
typedef typename table::value_type value_type;
typedef typename table::bucket bucket;
typedef typename table::policy policy;
typedef typename table::node_pointer node_pointer;
typedef typename table::node_allocator node_allocator;
typedef typename table::node_allocator_traits node_allocator_traits;
typedef typename table::bucket_pointer bucket_pointer;
typedef typename table::link_pointer link_pointer;
typedef typename table::hasher hasher;
typedef typename table::key_equal key_equal;
typedef typename table::key_type key_type;
typedef typename table::node_constructor node_constructor;
typedef typename table::extractor extractor;
typedef typename table::iterator iterator;
typedef typename table::c_iterator c_iterator;
// 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() {}
grouped_table_impl(std::size_t n,
hasher const& hf,
key_equal const& eq,
node_allocator const& a)
: table(n, hf, eq, a)
{}
// 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)
grouped_table_impl(grouped_table_impl const& x)
: table(x, node_allocator_traits::
select_on_container_copy_construction(x.node_alloc()))
{
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);
this->init(x);
}
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;
grouped_table_impl(grouped_table_impl const& x,
node_allocator const& a)
: table(x, a)
{
this->init(x);
}
grouped_table_impl(grouped_table_impl& x,
boost::unordered::detail::move_tag m)
: table(x, m)
{}
grouped_table_impl(grouped_table_impl& x,
node_allocator const& a,
boost::unordered::detail::move_tag m)
: table(x, a, m)
{
this->move_init(x);
}
// Accessors
template <class Key, class Pred>
iterator find_node_impl(
std::size_t key_hash,
Key const& k,
Pred const& eq) const
{
std::size_t bucket_index = this->hash_to_bucket(key_hash);
iterator n = this->begin(bucket_index);
for (;;)
{
if (!n.node_) return n;
std::size_t node_hash = n.node_->hash_;
if (key_hash == node_hash)
{
if (eq(k, this->get_key(*n)))
return n;
}
else
{
if (this->hash_to_bucket(node_hash) != bucket_index)
return iterator();
}
n = iterator(n.node_->group_prev_->next_);
}
}
return true;
}
std::size_t count(key_type const& k) const
{
iterator n = this->find_node(k);
if (!n.node_) return 0;
////////////////////////////////////////////////////////////////////////////
// A convenience method for adding nodes.
std::size_t x = 0;
node_pointer it = n.node_;
do {
it = it->group_prev_;
++x;
} while(it != n.node_);
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);
return x;
}
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);
std::pair<iterator, iterator>
equal_range(key_type const& k) const
{
iterator n = this->find_node(k);
return std::make_pair(
n, n.node_ ? iterator(n.node_->group_prev_->next_) : n);
}
else {
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr position = this->find_iterator(bucket, k);
// Equality
bool equals(grouped_table_impl const& other) const
{
if(this->size_ != other.size_) return false;
for(iterator n1 = this->begin(); n1.node_;)
{
iterator n2 = other.find_matching_node(n1);
if (!n2.node_) return false;
iterator end1(n1.node_->group_prev_->next_);
iterator end2(n2.node_->group_prev_->next_);
if (!group_equals(n1, end1, n2, end2)) return false;
n1 = end1;
}
return true;
}
static bool group_equals(iterator n1, iterator end1,
iterator n2, iterator end2)
{
for(;;)
{
if (*n1 != *n2) break;
++n1;
++n2;
if (n1 == end1) return n2 == end2;
if (n2 == end2) return false;
}
for(iterator n1a = n1, n2a = n2;;)
{
++n1a;
++n2a;
if (n1a == end1)
{
if (n2a == end2) break;
else return false;
}
if (n2a == end2) return false;
}
iterator start = n1;
for(;n1 != end1; ++n1)
{
value_type const& v = *n1;
if (find(start, n1, v)) continue;
std::size_t matches = count_equal(n2, end2, v);
if (!matches) return false;
iterator next = n1;
++next;
if (matches != 1 + count_equal(next, end1, v)) return false;
}
return true;
}
static bool find(iterator n, iterator end, value_type const& v)
{
for(;n != end; ++n)
if (*n == v)
return true;
return false;
}
static std::size_t count_equal(iterator n, iterator end,
value_type const& v)
{
std::size_t count = 0;
for(;n != end; ++n)
if (*n == v) ++count;
return count;
}
// Emplace/Insert
static inline void add_after_node(
node_pointer n,
node_pointer pos)
{
n->next_ = pos->group_prev_->next_;
n->group_prev_ = pos->group_prev_;
pos->group_prev_->next_ = n;
pos->group_prev_ = n;
}
inline iterator add_node(
node_constructor& a,
std::size_t key_hash,
iterator pos)
{
node_pointer n = a.release();
n->hash_ = key_hash;
if (pos.node_) {
this->add_after_node(n, pos.node_);
if (n->next_) {
std::size_t next_bucket = this->hash_to_bucket(
static_cast<node_pointer>(n->next_)->hash_);
if (next_bucket != this->hash_to_bucket(key_hash)) {
this->get_bucket(next_bucket)->next_ = n;
}
}
}
else {
bucket_pointer b = this->get_bucket(
this->hash_to_bucket(key_hash));
if (!b->next_)
{
link_pointer start_node = this->get_previous_start();
if (start_node->next_) {
this->get_bucket(this->hash_to_bucket(
static_cast<node_pointer>(start_node->next_)->hash_
))->next_ = n;
}
b->next_ = start_node;
n->next_ = start_node->next_;
start_node->next_ = n;
}
else
{
n->next_ = b->next_->next_;
b->next_->next_ = n;
}
}
++this->size_;
return iterator(n);
}
iterator emplace_impl(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t key_hash = this->hash(k);
iterator position = this->find_node(key_hash, 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));
this->reserve_for_insert(this->size_ + 1);
return this->add_node(a, key_hash, 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)
void emplace_impl_no_rehash(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t key_hash = this->hash(k);
this->add_node(a, key_hash, this->find_node(key_hash, k));
}
// 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
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
# if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
iterator emplace(boost::unordered::detail::emplace_args1<
boost::unordered::detail::please_ignore_this_overload> const&)
{
BOOST_ASSERT(false);
return iterator();
}
# else
iterator emplace(
boost::unordered::detail::please_ignore_this_overload const&)
{
BOOST_ASSERT(false);
return iterator();
}
# endif
#endif
////////////////////////////////////////////////////////////////////////////
// Insert range methods
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS)
{
node_constructor a(this->node_alloc());
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
// 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);
return iterator(emplace_impl(a));
}
else {
node_constructor a(*this);
// Only require basic exception safety here
if(this->size_) {
this->reserve_for_insert(this->size_ + distance);
////////////////////////////////////////////////////////////////////////
// Insert range methods
// if hash function throws, or inserting > 1 element, basic exception
// safety. Strong otherwise
template <class I>
typename boost::unordered::detail::enable_if_forward<I, void>::type
insert_range(I i, I j)
{
if(i == j) return;
std::size_t distance = boost::unordered::detail::distance(i, j);
if(distance == 1) {
node_constructor a(this->node_alloc());
a.construct_with_value2(*i);
emplace_impl(a);
}
else {
a.construct(*i++);
this->emplace_empty_impl_with_node(a, distance);
}
// Only require basic exception safety here
this->reserve_for_insert(this->size_ + distance);
node_constructor a(this->node_alloc());
for (; i != j; ++i) {
a.construct_with_value2(*i);
emplace_impl_no_rehash(a);
}
}
}
template <class I>
typename boost::unordered::detail::disable_if_forward<I, void>::type
insert_range(I i, I j)
{
node_constructor a(this->node_alloc());
for (; i != j; ++i) {
a.construct(*i);
emplace_impl_no_rehash(a);
a.construct_with_value2(*i);
emplace_impl(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);
////////////////////////////////////////////////////////////////////////
// Erase
//
// no throw
std::size_t erase_key(key_type const& k)
{
if(!this->size_) return 0;
std::size_t key_hash = this->hash(k);
std::size_t bucket_index = this->hash_to_bucket(key_hash);
link_pointer prev = this->get_previous_start(bucket_index);
if (!prev) return 0;
for (;;)
{
if (!prev->next_) return 0;
std::size_t node_hash =
static_cast<node_pointer>(prev->next_)->hash_;
if (this->hash_to_bucket(node_hash) != bucket_index)
return 0;
if (node_hash == key_hash &&
this->key_eq()(k, this->get_key(
static_cast<node_pointer>(prev->next_)->value())))
break;
prev = static_cast<node_pointer>(prev->next_)->group_prev_;
}
node_pointer first_node = static_cast<node_pointer>(prev->next_);
link_pointer end = first_node->group_prev_->next_;
std::size_t count = this->delete_nodes(prev, end);
this->fix_bucket(bucket_index, prev);
return count;
}
}
// 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);
}
}}
iterator erase(c_iterator r)
{
BOOST_ASSERT(r.node_);
iterator next(r.node_);
++next;
erase_nodes(r.node_, next.node_);
return next;
}
iterator erase_range(c_iterator r1, c_iterator r2)
{
if (r1 == r2) return iterator(r2.node_);
erase_nodes(r1.node_, r2.node_);
return iterator(r2.node_);
}
link_pointer erase_nodes(node_pointer begin, node_pointer end)
{
std::size_t bucket_index = this->hash_to_bucket(begin->hash_);
// Split the groups containing 'begin' and 'end'.
// And get the pointer to the node before begin while
// we're at it.
link_pointer prev = split_groups(begin, end);
// If we don't have a 'prev' it means that begin is at the
// beginning of a block, so search through the blocks in the
// same bucket.
if (!prev) {
prev = this->get_previous_start(bucket_index);
while (prev->next_ != begin)
prev = static_cast<node_pointer>(prev->next_)->group_prev_;
}
// Delete the nodes.
do {
link_pointer group_end =
static_cast<node_pointer>(prev->next_)->group_prev_->next_;
this->delete_nodes(prev, group_end);
bucket_index = this->fix_bucket(bucket_index, prev);
} while(prev->next_ != end);
return prev;
}
static link_pointer split_groups(node_pointer begin, node_pointer end)
{
node_pointer prev = begin->group_prev_;
if (prev->next_ != begin) prev = node_pointer();
if (end) {
node_pointer first = end;
while (first != begin && first->group_prev_->next_ == first) {
first = first->group_prev_;
}
boost::swap(first->group_prev_, end->group_prev_);
if (first == begin) return prev;
}
if (prev) {
node_pointer first = prev;
while (first->group_prev_->next_ == first) {
first = first->group_prev_;
}
boost::swap(first->group_prev_, begin->group_prev_);
}
return prev;
}
////////////////////////////////////////////////////////////////////////
// fill_buckets
template <class NodeCreator>
static void fill_buckets(iterator n, table& dst,
NodeCreator& creator)
{
link_pointer prev = dst.get_previous_start();
while (n.node_) {
std::size_t key_hash = n.node_->hash_;
iterator group_end(n.node_->group_prev_->next_);
node_pointer first_node = creator.create(*n);
node_pointer end = first_node;
first_node->hash_ = key_hash;
prev->next_ = first_node;
++dst.size_;
for (++n; n != group_end; ++n)
{
end = creator.create(*n);
end->hash_ = key_hash;
add_after_node(end, first_node);
++dst.size_;
}
prev = place_in_bucket(dst, prev, end);
}
}
// strong otherwise exception safety
void rehash_impl(std::size_t num_buckets)
{
BOOST_ASSERT(this->buckets_);
this->create_buckets(num_buckets);
link_pointer prev = this->get_previous_start();
while (prev->next_)
prev = place_in_bucket(*this, prev,
static_cast<node_pointer>(prev->next_)->group_prev_);
}
// Iterate through the nodes placing them in the correct buckets.
// pre: prev->next_ is not null.
static link_pointer place_in_bucket(table& dst,
link_pointer prev, node_pointer end)
{
bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(end->hash_));
if (!b->next_) {
b->next_ = prev;
return end;
}
else {
link_pointer next = end->next_;
end->next_ = b->next_->next_;
b->next_->next_ = prev->next_;
prev->next_ = next;
return prev;
}
}
};
}}}
#endif

View File

@ -1,17 +1,16 @@
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2005-2011 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>
#include <boost/unordered/detail/table.hpp>
namespace boost {
namespace unordered_detail {
namespace unordered {
namespace detail {
// key extractors
//
@ -28,6 +27,19 @@ namespace unordered_detail {
template <class T> no_key(T const&) {}
};
template <typename Key, typename T>
struct is_key {
template <typename T2>
static choice1::type test(T2 const&);
static choice2::type test(Key const&);
enum { value = sizeof(test(boost::unordered::detail::make<T>())) ==
sizeof(choice2::type) };
typedef typename boost::detail::if_true<value>::
BOOST_NESTED_TEMPLATE then<Key const&, no_key>::type type;
};
template <class ValueType>
struct set_extractor
{
@ -44,49 +56,38 @@ namespace unordered_detail {
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&)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class Arg1, class Arg2, class... Args>
static no_key extract(Arg1 const&, Arg2 const&, Args const&...)
{
return no_key();
}
#else
template <class Arg1, class Arg2>
static no_key extract(Arg1 const&, Arg2 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;
typedef 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)
{
@ -100,20 +101,6 @@ namespace unordered_detail {
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&)
{
@ -131,18 +118,66 @@ namespace unordered_detail {
return no_key();
}
template <class Arg, class Arg1>
static no_key extract(Arg const&, Arg1 const&)
template <class Arg1, class Arg2>
static no_key extract(Arg1 const&, Arg2 const&)
{
return no_key();
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class Arg1, class Arg2, class Arg3, class... Args>
static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&,
Args const&...)
{
return no_key();
}
#endif
static bool compare_mapped(value_type const& x, value_type const& y)
{
return x.second == y.second;
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
template <typename T2> \
static no_key extract(boost::unordered::piecewise_construct_t, \
namespace_ tuple<> const&, T2 const&) \
{ \
return no_key(); \
} \
\
template <typename T, typename T2> \
static typename is_key<key_type, T>::type \
extract(boost::unordered::piecewise_construct_t, \
namespace_ tuple<T> const& k, T2 const&) \
{ \
return typename is_key<key_type, T>::type( \
namespace_ get<0>(k)); \
}
#else
#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
static no_key extract(boost::unordered::piecewise_construct_t, \
namespace_ tuple<> const&) \
{ \
return no_key(); \
} \
\
template <typename T> \
static typename is_key<key_type, T>::type \
extract(boost::unordered::piecewise_construct_t, \
namespace_ tuple<T> const& k) \
{ \
return typename is_key<key_type, T>::type( \
namespace_ get<0>(k)); \
}
};
}}
#endif
BOOST_UNORDERED_KEY_FROM_TUPLE(boost::)
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
BOOST_UNORDERED_KEY_FROM_TUPLE(std::)
#endif
};
}}}
#endif

View File

@ -1,856 +1,23 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2008-2011 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_FWD_HPP_INCLUDED
#define BOOST_UNORDERED_FWD_HPP_INCLUDED
#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
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#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;
};
}}
namespace boost
{
namespace unordered
{
struct piecewise_construct_t {};
const piecewise_construct_t piecewise_construct = piecewise_construct_t();
}
}
#endif

View File

@ -1,243 +0,0 @@
/*
Copyright 2005-2007 Adobe Systems Incorporated
Use, modification and distribution are subject to 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_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>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/utility/enable_if.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
/*************************************************************************************************/
namespace boost {
namespace unordered_detail {
/*************************************************************************************************/
namespace move_detail {
/*************************************************************************************************/
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
/*************************************************************************************************/
template <typename T>
struct class_has_move_assign {
class type {
typedef T& (T::*E)(T t);
typedef char (&no_type)[1];
typedef char (&yes_type)[2];
template <E e> struct sfinae { typedef yes_type type; };
template <class U>
static typename sfinae<&U::operator=>::type test(int);
template <class U>
static no_type test(...);
public:
enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
};
};
/*************************************************************************************************/
template<typename T>
struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
/*************************************************************************************************/
class test_can_convert_anything { };
/*************************************************************************************************/
#endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
/*************************************************************************************************/
/*
REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where
boost::is_convertible<T, T> fails to compile.
*/
template <typename T, typename U>
struct is_convertible : boost::mpl::or_<
boost::is_same<T, U>,
boost::is_convertible<T, U>
> { };
/*************************************************************************************************/
} //namespace move_detail
/*************************************************************************************************/
/*!
\ingroup move_related
\brief move_from is used for move_ctors.
*/
template <typename T>
struct move_from
{
explicit move_from(T& x) : source(x) { }
T& source;
private:
move_from& operator=(move_from const&);
};
/*************************************************************************************************/
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
/*************************************************************************************************/
/*!
\ingroup move_related
\brief The is_movable trait can be used to identify movable types.
*/
template <typename T>
struct is_movable : boost::mpl::and_<
boost::is_convertible<move_from<T>, T>,
move_detail::has_move_assign<T>,
boost::mpl::not_<boost::is_convertible<move_detail::test_can_convert_anything, T> >
> { };
/*************************************************************************************************/
#else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
// On compilers which don't have adequate SFINAE support, treat most types as unmovable,
// unless the trait is specialized.
template <typename T>
struct is_movable : boost::mpl::false_ { };
#endif
/*************************************************************************************************/
#if !defined(BOOST_NO_SFINAE)
/*************************************************************************************************/
/*!
\ingroup move_related
\brief copy_sink and move_sink are used to select between overloaded operations according to
whether type T is movable and convertible to type U.
\sa move
*/
template <typename T,
typename U = T,
typename R = void*>
struct copy_sink : boost::enable_if<
boost::mpl::and_<
boost::unordered_detail::move_detail::is_convertible<T, U>,
boost::mpl::not_<is_movable<T> >
>,
R
>
{ };
/*************************************************************************************************/
/*!
\ingroup move_related
\brief move_sink and copy_sink are used to select between overloaded operations according to
whether type T is movable and convertible to type U.
\sa move
*/
template <typename T,
typename U = T,
typename R = void*>
struct move_sink : boost::enable_if<
boost::mpl::and_<
boost::unordered_detail::move_detail::is_convertible<T, U>,
is_movable<T>
>,
R
>
{ };
/*************************************************************************************************/
/*!
\ingroup move_related
\brief This version of move is selected when T is_movable . It in turn calls the move
constructor. This call, with the help of the return value optimization, will cause x to be moved
instead of copied to its destination. See adobe/test/move/main.cpp for examples.
*/
template <typename T>
T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
/*************************************************************************************************/
/*!
\ingroup move_related
\brief This version of move is selected when T is not movable . The net result will be that
x gets copied.
*/
template <typename T>
T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
/*************************************************************************************************/
#else // BOOST_NO_SFINAE
// On compilers without SFINAE, define copy_sink to always use the copy function.
template <typename T,
typename U = T,
typename R = void*>
struct copy_sink
{
typedef R type;
};
// Always copy the element unless this is overloaded.
template <typename T>
T& move(T& x) {
return x;
}
#endif // BOOST_NO_SFINAE
} // namespace unordered_detail
} // namespace boost
/*************************************************************************************************/
#endif
/*************************************************************************************************/

View File

@ -1,226 +0,0 @@
// 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +1,67 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2005-2011 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>
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_empty.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/detail/select_type.hpp>
#include <boost/move/move.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/unordered/detail/fwd.hpp>
#include <boost/swap.hpp>
namespace boost { namespace unordered_detail {
namespace boost { namespace unordered { namespace detail {
static const float minimum_max_load_factor = 1e-3f;
static const std::size_t default_bucket_count = 11;
struct move_tag {};
struct empty_emplace {};
namespace func {
template <class T>
inline void ignore_unused_variable_warning(T const&) {}
}
////////////////////////////////////////////////////////////////////////////
// convert double to std::size_t
// iterator SFINAE
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);
}
template <typename I>
struct is_forward :
boost::is_convertible<
typename boost::iterator_traversal<I>::type,
boost::forward_traversal_tag>
{};
template <typename I, typename ReturnType>
struct enable_if_forward :
boost::enable_if_c<
boost::unordered::detail::is_forward<I>::value,
ReturnType>
{};
template <typename I, typename ReturnType>
struct disable_if_forward :
boost::disable_if_c<
boost::unordered::detail::is_forward<I>::value,
ReturnType>
{};
////////////////////////////////////////////////////////////////////////////
// primes
#define BOOST_UNORDERED_PRIMES \
(5ul)(11ul)(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \
(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) \
@ -92,240 +120,146 @@ namespace boost { namespace unordered_detail {
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)
inline typename
boost::unordered::detail::enable_if_forward<I, std::size_t>::type
insert_size(I i, I j)
{
return std::distance(i, j);
}
template <class I>
inline std::size_t insert_size(I, I, boost::incrementable_traversal_tag)
inline typename
boost::unordered::detail::disable_if_forward<I, std::size_t>::type
insert_size(I, I)
{
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)
std::size_t num_buckets =
boost::unordered::detail::default_bucket_count)
{
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1,
// TODO: Why +1?
return (std::max)(
boost::unordered::detail::insert_size(i, j) + 1,
num_buckets);
}
////////////////////////////////////////////////////////////////////////////
// Node Constructors
// compressed
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <class T, class... Args>
inline void construct_impl(T*, void* address, Args&&... args)
template <typename T, int Index>
struct compressed_base : private T
{
new(address) T(std::forward<Args>(args)...);
}
compressed_base(T const& x) : T(x) {}
compressed_base(T& x, move_tag) : T(boost::move(x)) {}
#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)
)
T& get() { return *this; }
T const& get() const { return *this; }
};
template <typename T, int Index>
struct uncompressed_base
{
new(address) std::pair<First, Second>(k,
Second(arg0, std::forward<Args>(args)...);
}
#endif
uncompressed_base(T const& x) : value_(x) {}
uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {}
#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
T& get() { return value_; }
T const& get() const { return value_; }
private:
T value_;
};
template <typename T, int Index>
struct generate_base
: boost::detail::if_true<
boost::is_empty<T>::value
>:: BOOST_NESTED_TEMPLATE then<
boost::unordered::detail::compressed_base<T, Index>,
boost::unordered::detail::uncompressed_base<T, Index>
>
{};
template <typename T1, typename T2>
struct compressed
: private boost::unordered::detail::generate_base<T1, 1>::type,
private boost::unordered::detail::generate_base<T2, 2>::type
{
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;
typedef typename generate_base<T1, 1>::type base1;
typedef typename generate_base<T2, 2>::type base2;
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)
{
typedef T1 first_type;
typedef T2 second_type;
first_type& first() {
return static_cast<base1*>(this)->get();
}
~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; \
first_type const& first() const {
return static_cast<base1 const*>(this)->get();
}
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;
second_type& second() {
return static_cast<base2*>(this)->get();
}
value_type& value() const
{
BOOST_ASSERT(node_);
return node_->value();
second_type const& second() const {
return static_cast<base2 const*>(this)->get();
}
// no throw
BOOST_DEDUCED_TYPENAME buckets::node_ptr release()
template <typename First, typename Second>
compressed(First const& x1, Second const& x2)
: base1(x1), base2(x2) {}
compressed(compressed const& x)
: base1(x.first()), base2(x.second()) {}
compressed(compressed& x, move_tag m)
: base1(x.first(), m), base2(x.second(), m) {}
void assign(compressed const& x)
{
real_node_ptr p = node_;
node_ = real_node_ptr();
// node_ptr cast
return buckets_.bucket_alloc().address(*p);
first() = x.first();
second() = x.second();
}
void move_assign(compressed& x)
{
first() = boost::move(x.first());
second() = boost::move(x.second());
}
void swap(compressed& x)
{
boost::swap(first(), x.first());
boost::swap(second(), x.second());
}
private:
hash_node_constructor(hash_node_constructor const&);
hash_node_constructor& operator=(hash_node_constructor const&);
// Prevent assignment just to make use of assign or
// move_assign explicit.
compressed& operator=(compressed 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

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// Copyright (C) 2008-2009 Daniel James.
// Copyright (C) 2008-2011 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,40 +14,52 @@
#include <memory>
#include <functional>
#include <boost/functional/hash_fwd.hpp>
#include <boost/unordered/detail/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>&);
namespace unordered
{
template <class K,
class T,
class H = boost::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 = 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>&);
template <class K, class T, class H, class P, class A>
inline 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>
inline 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>
inline void swap(unordered_map<K, T, H, P, A>&,
unordered_map<K, T, H, P, A>&);
template <class K,
class T,
class H = boost::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>
inline 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>
inline 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>
inline void swap(unordered_multimap<K, T, H, P, A>&,
unordered_multimap<K, T, H, P, A>&);
}
using boost::unordered::unordered_map;
using boost::unordered::unordered_multimap;
using boost::unordered::swap;
using boost::unordered::operator==;
using boost::unordered::operator!=;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// Copyright (C) 2008-2009 Daniel James.
// Copyright (C) 2008-2011 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,38 +14,50 @@
#include <memory>
#include <functional>
#include <boost/functional/hash_fwd.hpp>
#include <boost/unordered/detail/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);
namespace unordered
{
template <class T,
class H = boost::hash<T>,
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_set;
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);
template <class T, class H, class P, class A>
inline 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>
inline 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>
inline void swap(unordered_set<T, H, P, A> &m1,
unordered_set<T, H, P, A> &m2);
template <class T,
class H = boost::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>
inline 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>
inline 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>
inline void swap(unordered_multiset<T, H, P, A> &m1,
unordered_multiset<T, H, P, A> &m2);
}
using boost::unordered::unordered_set;
using boost::unordered::unordered_multiset;
using boost::unordered::swap;
using boost::unordered::operator==;
using boost::unordered::operator!=;
}
#endif

View File

@ -14,9 +14,9 @@ project unordered-test/exception-tests
<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>gcc:<define>_GLIBCXX_DEBUG
#<toolset>darwin:<define>_GLIBCXX_DEBUG
<toolset>msvc:<warnings-as-errors>on
#<toolset>msvc:<warnings-as-errors>on
#<toolset>gcc:<warnings-as-errors>on
#<toolset>darwin:<warnings-as-errors>on
;

View File

@ -3,8 +3,6 @@
// 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"
@ -13,7 +11,7 @@
#pragma warning(disable:4512) // assignment operator could not be generated
#endif
test::seed_t seed(12847);
test::seed_t initialize_seed(12847);
template <class T>
struct self_assign_base : public test::exception_base
@ -41,26 +39,40 @@ template <class T>
struct assign_base : public test::exception_base
{
const test::random_values<T> x_values, y_values;
const T x,y;
T x,y;
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
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) :
assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2,
float mlf1 = 1.0, float mlf2 = 1.0) :
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))
{}
{
x.max_load_factor(mlf1);
y.max_load_factor(mlf2);
}
typedef T data_type;
T init() const { return T(x); }
void run(T& x1) const { x1 = y; }
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
{ test::check_equivalent_keys(x1); }
{
test::check_equivalent_keys(x1);
// If the container is empty at the point of the exception, the
// internal structure is hidden, this exposes it.
T& y = const_cast<T&>(x1);
if (x_values.size()) {
y.emplace(*x_values.begin());
test::check_equivalent_keys(y);
}
}
};
template <class T>
@ -87,7 +99,14 @@ struct assign_test4 : assign_base<T>
assign_test4() : assign_base<T>(10, 10, 1, 2) {}
};
RUN_EXCEPTION_TESTS(
template <class T>
struct assign_test5 : assign_base<T>
{
assign_test5() : assign_base<T>(5, 60, 0, 0, 1.0, 0.1) {}
};
EXCEPTION_TESTS(
(self_assign_test1)(self_assign_test2)
(assign_test1)(assign_test2)(assign_test3)(assign_test4),
(assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test5),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -3,15 +3,13 @@
// 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);
test::seed_t initialize_seed(91274);
struct objects
{
@ -161,7 +159,7 @@ struct copy_range_construct_test : public range<T>, objects
}
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(construct_test1)
(construct_test2)
(construct_test3)
@ -176,3 +174,4 @@ RUN_EXCEPTION_TESTS(
(input_range_construct_test)
(copy_range_construct_test),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -3,8 +3,10 @@
// 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>
#include "../helpers/postfix.hpp"
#include "../objects/exception.hpp"
typedef boost::unordered_set<
@ -16,13 +18,13 @@ typedef boost::unordered_multiset<
test::exception::object,
test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> > test_multiset;
test::exception::allocator2<test::exception::object> > test_multiset;
typedef boost::unordered_map<
test::exception::object,
test::exception::object,
test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> > test_map;
test::exception::allocator2<test::exception::object> > test_map;
typedef boost::unordered_multimap<
test::exception::object,
test::exception::object,

View File

@ -3,14 +3,12 @@
// 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);
test::seed_t initialize_seed(73041);
template <class T>
struct copy_test1 : public test::exception_base
@ -66,6 +64,7 @@ struct copy_with_allocator_test : public test::exception_base
}
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(copy_test1)(copy_test2)(copy_test3)(copy_with_allocator_test),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -3,14 +3,12 @@
// 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"
#include "../helpers/helpers.hpp"
test::seed_t seed(835193);
test::seed_t initialize_seed(835193);
template <class T>
struct erase_test_base : public test::exception_base
@ -51,6 +49,7 @@ struct erase_by_key_test1 : public erase_test_base<T>
}
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(erase_by_key_test1),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -3,8 +3,6 @@
// 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"
@ -13,7 +11,7 @@
#include <boost/utility.hpp>
#include <cmath>
test::seed_t seed(747373);
test::seed_t initialize_seed(747373);
template <class T>
struct insert_test_base : public test::exception_base
@ -34,12 +32,12 @@ struct insert_test_base : public test::exception_base
std::string scope(test::scope);
if(scope.find("hash::operator()") == std::string::npos)
strong.test(x, test::exception::detail::tracker.count_allocations);
strong.test(x, test::detail::tracker.count_allocations);
test::check_equivalent_keys(x);
}
};
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class T>
struct emplace_test1 : public insert_test_base<T>
@ -51,7 +49,7 @@ struct emplace_test1 : public insert_test_base<T>
it = this->values.begin(), end = this->values.end();
it != end; ++it)
{
strong.store(x, test::exception::detail::tracker.count_allocations);
strong.store(x, test::detail::tracker.count_allocations);
x.emplace(*it);
}
}
@ -69,7 +67,7 @@ struct insert_test1 : public insert_test_base<T>
it = this->values.begin(), end = this->values.end();
it != end; ++it)
{
strong.store(x, test::exception::detail::tracker.count_allocations);
strong.store(x, test::detail::tracker.count_allocations);
x.insert(*it);
}
}
@ -85,7 +83,7 @@ struct insert_test2 : public insert_test_base<T>
it = this->values.begin(), end = this->values.end();
it != end; ++it)
{
strong.store(x, test::exception::detail::tracker.count_allocations);
strong.store(x, test::detail::tracker.count_allocations);
x.insert(x.begin(), *it);
}
}
@ -113,7 +111,7 @@ struct insert_test4 : public insert_test_base<T>
it = this->values.begin(), end = this->values.end();
it != end; ++it)
{
strong.store(x, test::exception::detail::tracker.count_allocations);
strong.store(x, test::detail::tracker.count_allocations);
x.insert(it, boost::next(it));
}
}
@ -152,7 +150,7 @@ struct insert_test_rehash1 : public insert_test_base<T>
end = this->values.end();
it != end && count < 10; ++it, ++count)
{
strong.store(x, test::exception::detail::tracker.count_allocations);
strong.store(x, test::detail::tracker.count_allocations);
pos = x.insert(pos, *it);
}
@ -176,7 +174,7 @@ struct insert_test_rehash2 : public insert_test_rehash1<T>
end = this->values.end();
it != end && count < 10; ++it, ++count)
{
strong.store(x, test::exception::detail::tracker.count_allocations);
strong.store(x, test::detail::tracker.count_allocations);
x.insert(*it);
}
@ -238,11 +236,12 @@ 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_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#define ALL_TESTS (emplace_test1)BASIC_TESTS
#else
#define ALL_TESTS BASIC_TESTS
#endif
RUN_EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ)
EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ)
RUN_TESTS()

View File

@ -3,8 +3,6 @@
// 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"
@ -13,7 +11,7 @@
#include <iostream>
test::seed_t seed(3298597);
test::seed_t initialize_seed(3298597);
template <class T>
struct rehash_test_base : public test::exception_base
@ -81,7 +79,7 @@ struct rehash_test4 : rehash_test_base<T>
void run(T& x) const { x.rehash(0); }
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -3,8 +3,6 @@
// 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"
@ -13,7 +11,7 @@
#pragma warning(disable:4512) // assignment operator could not be generated
#endif
test::seed_t seed(9387);
test::seed_t initialize_seed(9387);
template <class T>
struct self_swap_base : public test::exception_base
@ -27,13 +25,12 @@ struct self_swap_base : public test::exception_base
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
std::string scope(test::scope);
#if BOOST_UNORDERED_SWAP_METHOD != 2
// TODO: In C++11 exceptions are only allowed in the swap function.
BOOST_TEST(
scope == "hash::operator(hash)" ||
scope == "hash::hash(hash)" ||
scope == "hash::operator=(hash)" ||
scope == "equal_to::operator(equal_to)" ||
scope == "equal_to::equal_to(equal_to)" ||
scope == "equal_to::operator=(equal_to)");
#endif
test::check_equivalent_keys(x);
}
@ -63,7 +60,9 @@ struct swap_base : public test::exception_base
initial_x(x_values.begin(), x_values.end(), 0, hasher(tag1),
key_equal(tag1), allocator_type(tag1)),
initial_y(y_values.begin(), y_values.end(), 0, hasher(tag2),
key_equal(tag2), allocator_type(tag2))
key_equal(tag2), allocator_type(
T::allocator_type::propagate_on_container_swap::value ?
tag2 : tag1))
{}
struct data_type {
@ -74,6 +73,7 @@ struct swap_base : public test::exception_base
};
data_type init() const { return data_type(initial_x, initial_y); }
void run(data_type& d) const {
try {
d.x.swap(d.y);
@ -82,13 +82,12 @@ struct swap_base : public test::exception_base
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const {
std::string scope(test::scope);
#if BOOST_UNORDERED_SWAP_METHOD != 2
// TODO: In C++11 exceptions are only allowed in the swap function.
BOOST_TEST(
scope == "hash::operator(hash)" ||
scope == "hash::hash(hash)" ||
scope == "hash::operator=(hash)" ||
scope == "equal_to::operator(equal_to)" ||
scope == "equal_to::equal_to(equal_to)" ||
scope == "equal_to::operator=(equal_to)");
#endif
test::check_equivalent_keys(d.x);
test::check_equivalent_keys(d.y);
@ -119,7 +118,8 @@ struct swap_test4 : swap_base<T>
swap_test4() : swap_base<T>(10, 10, 1, 2) {}
};
RUN_EXCEPTION_TESTS(
EXCEPTION_TESTS(
(self_swap_test1)(self_swap_test2)
(swap_test1)(swap_test2)(swap_test3)(swap_test4),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -1,84 +0,0 @@
// 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_MALLOC_ALLOCATOR_HEADER)
#define BOOST_UNORDERED_TEST_MALLOC_ALLOCATOR_HEADER
#include <cstddef>
#include <cstdlib>
#include <boost/limits.hpp>
#include <new>
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
namespace test
{
template <class T>
struct malloc_allocator
{
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef malloc_allocator<U> other; };
malloc_allocator() {}
template <class Y> malloc_allocator(malloc_allocator<Y> const&) {}
malloc_allocator(malloc_allocator const&) {}
pointer address(reference r) { return &r; }
const_pointer address(const_reference r) { return &r; }
pointer allocate(size_type n) {
using namespace std;
T* ptr = static_cast<T*>(malloc(n * sizeof(T)));
if(!ptr) throw std::bad_alloc();
return ptr;
}
pointer allocate(size_type n, void const* u) { return allocate(n); }
void deallocate(pointer p, size_type) {
using namespace std;
free(p);
}
void construct(pointer p, T const& t) { new(p) T(t); }
void destroy(pointer p) { p->~T(); }
size_type max_size() const {
return (std::numeric_limits<size_type>::max)();
}
bool operator==(malloc_allocator const&) 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) {
using namespace std;
free(p);
}
char* _Charalloc(size_type n) {
using namespace std;
T* ptr = static_cast<T*>(malloc(n * sizeof(char)));
if(!ptr) throw std::bad_alloc();
return (char*) ptr;
}
#endif
};
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
#endif

View File

@ -6,7 +6,7 @@
#if !defined(BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER
#include <boost/mpl/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_convertible.hpp>
@ -18,19 +18,19 @@ namespace test
template <class T2>
static void equals(T2)
{
BOOST_MPL_ASSERT((boost::is_same<T1, T2>));
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
}
template <class T2>
static void equals_ref(T2&)
{
BOOST_MPL_ASSERT((boost::is_same<T1, T2>));
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
}
template <class T2>
static void convertible(T2)
{
BOOST_MPL_ASSERT((boost::is_convertible<T2, T1>));
BOOST_STATIC_ASSERT((boost::is_convertible<T2, T1>::value));
}
};
}

View File

@ -52,29 +52,28 @@ namespace test {
}
};
template <class T>
struct counted_object
{
static object_count count_;
counted_object() { count_.construct(); }
counted_object(counted_object const&) { count_.construct(); }
~counted_object() { count_.destruct(); }
};
template <class T> object_count counted_object<T>::count_;
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_;
object_count global_object_count;
}
struct counted_object
{
counted_object() { global_object_count.construct(); }
counted_object(counted_object const&) { global_object_count.construct(); }
~counted_object() { global_object_count.destruct(); }
};
struct check_instances {
int instances;
check_instances() : instances(global_object_count.instances) {}
~check_instances() { BOOST_TEST(global_object_count.instances == instances); }
};
}
#endif

View File

@ -20,22 +20,37 @@
fixture, BOOST_STRINGIZE(test_func<type>)); \
} \
# define UNORDERED_EXCEPTION_TEST_CASE_REPEAT(name, test_func, n, type) \
UNORDERED_AUTO_TEST(name) \
{ \
for (unsigned i = 0; i < n; ++i) { \
test_func< type > fixture; \
::test::lightweight::exception_safety( \
fixture, BOOST_STRINGIZE(test_func<type>)); \
} \
} \
# define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
#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 EXCEPTION_TESTS(test_seq, param_seq) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, \
(test_seq)((1))(param_seq))
#define RUN_EXCEPTION_TESTS_OP(r, product) \
UNORDERED_EXCEPTION_TEST_CASE( \
#define EXCEPTION_TESTS_REPEAT(n, test_seq, param_seq) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, \
(test_seq)((n))(param_seq))
#define EXCEPTION_TESTS_OP(r, product) \
UNORDERED_EXCEPTION_TEST_CASE_REPEAT( \
BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(1, product)) \
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(2, product)) \
), \
BOOST_PP_SEQ_ELEM(0, product), \
BOOST_PP_SEQ_ELEM(1, product) \
BOOST_PP_SEQ_ELEM(1, product), \
BOOST_PP_SEQ_ELEM(2, product) \
) \
#define UNORDERED_SCOPE(scope_name) \

View File

@ -13,7 +13,6 @@
#include <cmath>
#include "./metafunctions.hpp"
#include "./helpers.hpp"
#include "./allocator.hpp"
#if defined(BOOST_MSVC)
#pragma warning(push)
@ -29,16 +28,13 @@ namespace test
{
BOOST_DEDUCED_TYPENAME X::key_equal eq = x1.key_eq();
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> > found_;
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
// First test that the current key has not occurred before, required
// to test either that keys are unique or that equivalent keys are
// adjacent. (6.3.1/6)
key_type key = get_key<X>(*it);
@ -65,42 +61,60 @@ namespace test
std::cerr<<x1.count(key)<<","<<count<<"\n";
}
// I'm not bothering with the following test for now, as the
// previous test is probably more enough to catch the kind of
// errors that this would catch (if an element was in the wrong
// bucket it not be found by the call to count, if elements are not
// adjacent then they would be caught when checking against
// found_.
// // Check that the keys are in the correct bucket and are
// // adjacent in the bucket.
// 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);
// for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
// if(lit == lend)
// BOOST_ERROR("Unable to find element with a local_iterator");
// unsigned int count2 = 0;
// for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
// if(count != count2)
// BOOST_ERROR("Element count doesn't match local_iterator.");
// for(; lit != lend; ++lit) {
// if(eq(get_key<X>(*lit), key)) {
// BOOST_ERROR("Non-adjacent element with equivalent key "
// "in bucket.");
// break;
// }
// }
// 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);
for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
if(lit == lend)
BOOST_ERROR("Unable to find element with a local_iterator");
unsigned int count2 = 0;
for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
if(count != count2)
BOOST_ERROR("Element count doesn't match local_iterator.");
for(; lit != lend; ++lit) {
if(eq(get_key<X>(*lit), key)) {
BOOST_ERROR("Non-adjacent element with equivalent key "
"in bucket.");
break;
}
}
};
// Finally, check that size matches up.
if(x1.size() != size)
// Check that size matches up.
if(x1.size() != size) {
BOOST_ERROR("x1.size() doesn't match actual size.");
std::cout<<x1.size()<<"/"<<size<<std::endl;
}
// Check the load factor.
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.");
// Check that size in the buckets matches up.
BOOST_DEDUCED_TYPENAME X::size_type bucket_size = 0;
for (BOOST_DEDUCED_TYPENAME X::size_type
i = 0; i < x1.bucket_count(); ++i)
{
for (BOOST_DEDUCED_TYPENAME X::const_local_iterator
begin = x1.begin(i), end = x1.end(i); begin != end; ++begin)
{
++bucket_size;
}
}
if(x1.size() != bucket_size) {
BOOST_ERROR("x1.size() doesn't match bucket size.");
std::cout<<x1.size()<<"/"<<bucket_size<<std::endl;
}
}
}

View File

@ -219,14 +219,14 @@ namespace test
data_.last_ptr_ = &data_.first_;
}
void erase(const_iterator start, const_iterator end) {
void erase(const_iterator i, const_iterator j) {
node** ptr = &data_.first_;
while(*ptr != start.ptr_) {
while(*ptr != i.ptr_) {
ptr = &(*ptr)->next_;
}
while(*ptr != end.ptr_) {
while(*ptr != j.ptr_) {
node* to_delete = *ptr;
*ptr = (*ptr)->next_;
--data_.size_;

View File

@ -8,10 +8,8 @@
#include <memory>
#include <map>
#include <boost/mpl/apply.hpp>
#include <boost/assert.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/mpl/aux_/config/eti.hpp>
#include <boost/unordered/detail/allocate.hpp>
#include "../helpers/test.hpp"
namespace test
@ -53,30 +51,10 @@ namespace test
}
};
template <class Alloc>
struct allocator_memory_type_gen {
typedef std::map<memory_area, memory_track, memory_area_compare,
Alloc> type;
};
#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;
};
#endif
template <class Alloc = std::allocator<int> >
struct memory_tracker {
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<Alloc,
std::pair<memory_area const, memory_track> >::type
allocator_type;
typedef BOOST_DEDUCED_TYPENAME
allocator_memory_type_gen<allocator_type>::type
allocated_memory_type;
typedef std::map<memory_area, memory_track, memory_area_compare,
std::allocator<std::pair<memory_area const, memory_track> >
> allocated_memory_type;
allocated_memory_type allocated_memory;
unsigned int count_allocators;
@ -137,9 +115,9 @@ namespace test
}
void track_deallocate(void* ptr, std::size_t n, std::size_t size,
int tag)
int tag, bool check_tag_ = true)
{
BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos =
allocated_memory_type::iterator pos =
allocated_memory.find(
memory_area(ptr, (char*) ptr + n * size));
if(pos == allocated_memory.end()) {
@ -147,7 +125,7 @@ namespace test
} else {
BOOST_TEST(pos->first.start == ptr);
BOOST_TEST(pos->first.end == (char*) ptr + n * size);
BOOST_TEST(pos->second.tag_ == tag);
if (check_tag_) BOOST_TEST(pos->second.tag_ == tag);
allocated_memory.erase(pos);
}
BOOST_TEST(count_allocations > 0);
@ -168,6 +146,18 @@ 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 required by the minimal test
// framework).
//
// boostinspect:nounnamed
namespace {
test::detail::memory_tracker tracker;
}
}
}
#endif

View File

@ -8,72 +8,33 @@
#include <boost/config.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/not.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
namespace test
{
/*
struct unordered_set_type { char x[100]; };
struct unordered_multiset_type { char x[200]; };
struct unordered_map_type { char x[300]; };
struct unordered_multimap_type { char x[400]; };
template <class V, class H, class P, class A>
unordered_set_type container_type(
boost::unordered_set<V, H, P, A> const*);
template <class V, class H, class P, class A>
unordered_multiset_type container_type(
boost::unordered_multiset<V, H, P, A> const*);
template <class K, class M, class H, class P, class A>
unordered_map_type container_type(
boost::unordered_map<K, M, H, P, A> const*);
template <class K, class M, class H, class P, class A>
unordered_multimap_type container_type(
boost::unordered_multimap<K, M, H, P, A> const*);
*/
template <class Container>
struct is_set
: public boost::is_same<
BOOST_DEDUCED_TYPENAME Container::key_type,
BOOST_DEDUCED_TYPENAME Container::value_type> {};
template <class Container>
struct is_map
: public boost::mpl::not_<is_set<Container> > {};
struct yes_type { char x[100]; };
struct no_type { char x[200]; };
template <class V, class H, class P, class A>
yes_type has_unique_key_impl(
boost::unordered_set<V, H, P, A> const*);
template <class V, class H, class P, class A>
no_type has_unique_key_impl(
boost::unordered_multiset<V, H, P, A> const*);
template <class K, class M, class H, class P, class A>
yes_type has_unique_key_impl(
boost::unordered_map<K, M, H, P, A> const*);
template <class K, class M, class H, class P, class A>
no_type has_unique_key_impl(
boost::unordered_multimap<K, M, H, P, A> const*);
template <class Container>
struct has_unique_keys
{
BOOST_STATIC_CONSTANT(bool, value =
sizeof(has_unique_key_impl((Container const*)0))
== sizeof(yes_type));
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <class Container>
struct has_equivalent_keys
template <class V, class H, class P, class A>
struct has_unique_keys<boost::unordered_set<V, H, P, A> >
{
BOOST_STATIC_CONSTANT(bool, value =
sizeof(has_unique_key_impl((Container const*)0))
== sizeof(no_type));
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <class K, class M, class H, class P, class A>
struct has_unique_keys<boost::unordered_map<K, M, H, P, A> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
}

10
test/helpers/postfix.hpp Normal file
View File

@ -0,0 +1,10 @@
// Copyright 2012 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 this after the boost headers, but before other test headers.
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif

View File

@ -8,7 +8,7 @@
#include "./list.hpp"
#include <algorithm>
#include <boost/mpl/if.hpp>
#include <boost/detail/select_type.hpp>
#include "./generators.hpp"
#include "./metafunctions.hpp"
@ -33,14 +33,15 @@ namespace test
void fill(T& x, std::size_t len) {
value_type* value_ptr = 0;
int* int_ptr = 0;
len += x.size();
for(std::size_t i = 0; i < len; ++i) {
for (std::size_t i = 0; i < len; ++i) {
value_type value = generate(value_ptr);
for(int count =
type_ == generate_collisions ?
generate(int_ptr) % 10 : 1;
count; --count) {
int count = type_ == generate_collisions ?
1 + (generate(int_ptr) % 5) : 1;
for(int i = 0; i < count; ++i) {
x.push_back(value);
}
}
@ -64,16 +65,15 @@ namespace test
mapped_type* mapped_ptr = 0;
int* int_ptr = 0;
for(std::size_t i = 0; i < len; ++i) {
for (std::size_t i = 0; i < len; ++i) {
key_type key = generate(key_ptr);
for(int count =
type_ == generate_collisions ?
generate(int_ptr) % 10 : 1;
count; --count) {
x.push_back(
std::pair<key_type const, mapped_type>(
key, generate(mapped_ptr)));
int count = type_ == generate_collisions ?
1 + (generate(int_ptr) % 5) : 1;
for(int i = 0; i < count; ++i) {
x.push_back(std::pair<key_type const, mapped_type>(
key, generate(mapped_ptr)));
}
}
}
@ -81,10 +81,12 @@ namespace test
template <class X>
struct unordered_generator_base
: public boost::mpl::if_<
test::is_set<X>,
: public boost::detail::if_true<
test::is_set<X>::value
>::BOOST_NESTED_TEMPLATE then<
test::unordered_generator_set<X>,
test::unordered_generator_map<X> >
test::unordered_generator_map<X>
>
{
};
@ -104,7 +106,7 @@ namespace test
random_values(int count, test::random_generator const& generator =
test::default_generator)
{
static test::unordered_generator<X> gen(generator);
test::unordered_generator<X> gen(generator);
gen.fill(*this, count);
}
};

View File

@ -8,7 +8,6 @@
#include <boost/config.hpp>
#include <iterator>
#include "./metafunctions.hpp"
#include "./equivalent.hpp"
#include "./list.hpp"
#include "./exception_test.hpp"

View File

@ -76,21 +76,29 @@ namespace test {
// 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) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, \
((name))((1)) parameters) \
#define UNORDERED_TEST_REPEAT(name, n, parameters) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, \
((name))((n)) parameters) \
#define UNORDERED_TEST_OP(r, product) \
UNORDERED_TEST_OP2( \
BOOST_PP_SEQ_HEAD(product), \
BOOST_PP_SEQ_TAIL(product)) \
BOOST_PP_SEQ_ELEM(0, product), \
BOOST_PP_SEQ_ELEM(1, product), \
BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product))) \
#define UNORDERED_TEST_OP2(name, params) \
#define UNORDERED_TEST_OP2(name, n, params) \
UNORDERED_AUTO_TEST( \
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) \
{ \
name BOOST_PP_SEQ_TO_TUPLE(params); \
for (int i = 0; i < n; ++i) \
name BOOST_PP_SEQ_TO_TUPLE(params); \
} \
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem)) \
#endif

View File

@ -13,9 +13,6 @@
#include <map>
#include <iterator>
#include <algorithm>
#include <boost/mpl/if.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/is_same.hpp>
#include "../objects/fwd.hpp"
#include "./metafunctions.hpp"
@ -25,21 +22,17 @@
namespace test
{
template <class X>
struct equals_to_compare2
: public boost::mpl::identity<
std::less<BOOST_DEDUCED_TYPENAME X::first_argument_type> >
template <typename X>
struct equals_to_compare
{
typedef std::less<BOOST_DEDUCED_TYPENAME X::first_argument_type>
type;
};
template <class X>
struct equals_to_compare
: public boost::mpl::eval_if<
boost::is_same<X, test::equal_to>,
boost::mpl::identity<test::less>,
equals_to_compare2<X>
>
template <>
struct equals_to_compare<test::equal_to>
{
typedef test::less type;
};
template <class X1, class X2>
@ -67,51 +60,40 @@ namespace test
values2.begin(), test::equivalent));
}
template <class X>
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
>
> {};
template <typename X>
struct ordered_base;
template <class X>
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
>
> {};
template <class V, class H, class P, class A>
struct ordered_base<boost::unordered_set<V, H, P, A> >
{
typedef std::set<V,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
type;
};
template <class X>
struct ordered_base : public
boost::mpl::eval_if<
test::is_set<X>,
test::ordered_set<X>,
test::ordered_map<X>
> {};
template <class V, class H, class P, class A>
struct ordered_base<boost::unordered_multiset<V, H, P, A> >
{
typedef std::multiset<V,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
type;
};
template <class K, class M, class H, class P, class A>
struct ordered_base<boost::unordered_map<K, M, H, P, A> >
{
typedef std::map<K, M,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
type;
};
template <class K, class M, class H, class P, class A>
struct ordered_base<boost::unordered_multimap<K, M, H, P, A> >
{
typedef std::multimap<K, M,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
type;
};
template <class X>
class ordered : public ordered_base<X>::type
@ -124,8 +106,8 @@ namespace test
: base()
{}
explicit ordered(key_compare const& compare)
: base(compare)
explicit ordered(key_compare const& kc)
: base(kc)
{}
void compare(X const& x)
@ -143,10 +125,10 @@ namespace test
}
template <class It>
void insert_range(It begin, It end) {
while(begin != end) {
this->insert(*begin);
++begin;
void insert_range(It b, It e) {
while(b != e) {
this->insert(*b);
++b;
}
}
};

View File

@ -0,0 +1,317 @@
// Copyright 2006-2011 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_CXX11_ALLOCATOR_HEADER)
#define BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER
#include <boost/config.hpp>
#include <boost/limits.hpp>
#include <cstddef>
#include "../helpers/fwd.hpp"
#include "../helpers/memory.hpp"
namespace test
{
struct allocator_false
{
enum {
is_select_on_copy = 0,
is_propagate_on_swap = 0,
is_propagate_on_assign = 0,
is_propagate_on_move = 0,
cxx11_construct = 0
};
};
struct allocator_flags_all
{
enum {
is_select_on_copy = 1,
is_propagate_on_swap = 1,
is_propagate_on_assign = 1,
is_propagate_on_move = 1,
cxx11_construct = 1
};
};
struct select_copy : allocator_false
{ enum { is_select_on_copy = 1 }; };
struct propagate_swap : allocator_false
{ enum { is_propagate_on_swap = 1 }; };
struct propagate_assign : allocator_false
{ enum { is_propagate_on_assign = 1 }; };
struct propagate_move : allocator_false
{ enum { is_propagate_on_move = 1 }; };
struct no_select_copy : allocator_flags_all
{ enum { is_select_on_copy = 0 }; };
struct no_propagate_swap : allocator_flags_all
{ enum { is_propagate_on_swap = 0 }; };
struct no_propagate_assign : allocator_flags_all
{ enum { is_propagate_on_assign = 0 }; };
struct no_propagate_move : allocator_flags_all
{ enum { is_propagate_on_move = 0 }; };
template <typename Flag>
struct swap_allocator_base
{
struct propagate_on_container_swap {
enum { value = Flag::is_propagate_on_swap }; };
};
template <typename Flag>
struct assign_allocator_base
{
struct propagate_on_container_copy_assignment {
enum { value = Flag::is_propagate_on_assign }; };
};
template <typename Flag>
struct move_allocator_base
{
struct propagate_on_container_move_assignment {
enum { value = Flag::is_propagate_on_move }; };
};
namespace
{
// boostinspect:nounnamed
bool force_equal_allocator_value = false;
}
struct force_equal_allocator
{
bool old_value_;
explicit force_equal_allocator(bool value)
: old_value_(force_equal_allocator_value)
{ force_equal_allocator_value = value; }
~force_equal_allocator()
{ force_equal_allocator_value = old_value_; }
};
template <typename T>
struct cxx11_allocator_base
{
int tag_;
int selected_;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef T value_type;
explicit cxx11_allocator_base(int t)
: tag_(t), selected_(0)
{
detail::tracker.allocator_ref();
}
template <typename Y> cxx11_allocator_base(
cxx11_allocator_base<Y> const& x)
: tag_(x.tag_), selected_(x.selected_)
{
detail::tracker.allocator_ref();
}
cxx11_allocator_base(cxx11_allocator_base const& x)
: tag_(x.tag_), selected_(x.selected_)
{
detail::tracker.allocator_ref();
}
~cxx11_allocator_base()
{
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))));
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
return ptr;
}
pointer allocate(size_type n, void const* u)
{
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
return ptr;
}
void deallocate(pointer p, size_type n)
{
// Only checking tags when propagating swap.
// Note that tags will be tested
// properly in the normal allocator.
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_,
!force_equal_allocator_value);
::operator delete((void*) p);
}
void construct(T* p, T const& t) {
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new(p) T(t);
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<typename... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new(p) T(boost::forward<Args>(args)...);
}
#endif
void destroy(T* p) {
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
p->~T();
}
size_type max_size() const {
return (std::numeric_limits<size_type>::max)();
}
};
template <typename T, typename Flags = propagate_swap,
typename Enable = void>
struct cxx11_allocator;
template <typename T, typename Flags>
struct cxx11_allocator<
T, Flags,
typename boost::disable_if_c<Flags::is_select_on_copy>::type
> : public cxx11_allocator_base<T>,
public swap_allocator_base<Flags>,
public assign_allocator_base<Flags>,
public move_allocator_base<Flags>,
Flags
{
template <typename U> struct rebind {
typedef cxx11_allocator<U, Flags> other;
};
explicit cxx11_allocator(int t = 0)
: cxx11_allocator_base<T>(t)
{
}
template <typename Y> cxx11_allocator(
cxx11_allocator<Y, Flags> const& x)
: cxx11_allocator_base<T>(x)
{
}
cxx11_allocator(cxx11_allocator const& x)
: cxx11_allocator_base<T>(x)
{
}
// When not propagating swap, allocators are always equal
// to avoid undefined behaviour.
bool operator==(cxx11_allocator const& x) const
{
return force_equal_allocator_value || (this->tag_ == x.tag_);
}
bool operator!=(cxx11_allocator const& x) const
{
return !(*this == x);
}
};
template <typename T, typename Flags>
struct cxx11_allocator<
T, Flags,
typename boost::enable_if_c<Flags::is_select_on_copy>::type
> : public cxx11_allocator_base<T>,
public swap_allocator_base<Flags>,
public assign_allocator_base<Flags>,
public move_allocator_base<Flags>,
Flags
{
cxx11_allocator select_on_container_copy_construction() const
{
cxx11_allocator tmp(*this);
++tmp.selected_;
return tmp;
}
template <typename U> struct rebind {
typedef cxx11_allocator<U, Flags> other;
};
explicit cxx11_allocator(int t = 0)
: cxx11_allocator_base<T>(t)
{
}
template <typename Y> cxx11_allocator(
cxx11_allocator<Y, Flags> const& x)
: cxx11_allocator_base<T>(x)
{
}
cxx11_allocator(cxx11_allocator const& x)
: cxx11_allocator_base<T>(x)
{
}
// When not propagating swap, allocators are always equal
// to avoid undefined behaviour.
bool operator==(cxx11_allocator const& x) const
{
return force_equal_allocator_value || (this->tag_ == x.tag_);
}
bool operator!=(cxx11_allocator const& x) const
{
return !(*this == x);
}
};
template <typename T, typename Flags>
bool equivalent_impl(
cxx11_allocator<T, Flags> const& x,
cxx11_allocator<T, Flags> const& y,
test::derived_type)
{
return x.tag_ == y.tag_;
}
// Function to check how many times an allocator has been selected,
// return 0 for other allocators.
struct convert_from_anything
{
template <typename T>
convert_from_anything(T const&) {}
};
inline int selected_count(convert_from_anything)
{
return 0;
}
template <typename T, typename Flags>
int selected_count(cxx11_allocator<T, Flags> const& x)
{
return x.selected_;
}
}
#endif

View File

@ -13,27 +13,28 @@
#include <boost/limits.hpp>
#include <new>
#include "../helpers/fwd.hpp"
#include "../helpers/allocator.hpp"
#include "../helpers/memory.hpp"
namespace test
{
namespace exception
{
namespace detail
{
namespace
{
test::detail::memory_tracker<test::malloc_allocator<int> > tracker;
}
}
class object;
class hash;
class equal_to;
template <class T> class allocator;
object generate(object const*);
struct true_type
{
enum { value = true };
};
struct false_type
{
enum { value = false };
};
class object
{
public:
@ -249,7 +250,7 @@ namespace exception
UNORDERED_SCOPE(allocator::allocator()) {
UNORDERED_EPOINT("Mock allocator default constructor.");
}
detail::tracker.allocator_ref();
test::detail::tracker.allocator_ref();
}
template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_)
@ -257,7 +258,7 @@ namespace exception
UNORDERED_SCOPE(allocator::allocator()) {
UNORDERED_EPOINT("Mock allocator template copy constructor.");
}
detail::tracker.allocator_ref();
test::detail::tracker.allocator_ref();
}
allocator(allocator const& x) : tag_(x.tag_)
@ -265,11 +266,11 @@ namespace exception
UNORDERED_SCOPE(allocator::allocator()) {
UNORDERED_EPOINT("Mock allocator copy constructor.");
}
detail::tracker.allocator_ref();
test::detail::tracker.allocator_ref();
}
~allocator() {
detail::tracker.allocator_unref();
test::detail::tracker.allocator_unref();
}
allocator& operator=(allocator const& x) {
@ -307,7 +308,7 @@ namespace exception
ptr = (T*) malloc(n * sizeof(T));
if(!ptr) throw std::bad_alloc();
}
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
return pointer(ptr);
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
@ -323,7 +324,7 @@ namespace exception
ptr = (T*) malloc(n * sizeof(T));
if(!ptr) throw std::bad_alloc();
}
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
return pointer(ptr);
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
@ -333,32 +334,32 @@ namespace exception
{
//::operator delete((void*) p);
if(p) {
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
test::detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
using namespace std;
free(p);
}
}
void construct(pointer p, T const& t) {
UNORDERED_SCOPE(allocator::construct(pointer, T)) {
UNORDERED_SCOPE(allocator::construct(T*, T)) {
UNORDERED_EPOINT("Mock allocator construct function.");
new(p) T(t);
}
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
template<class... Args> void construct(pointer p, Args&&... args) {
UNORDERED_SCOPE(allocator::construct(pointer, Args&&...)) {
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
UNORDERED_SCOPE(allocator::construct(pointer, BOOST_FWD_REF(Args)...)) {
UNORDERED_EPOINT("Mock allocator construct function.");
new(p) T(std::forward<Args>(args)...);
new(p) T(boost::forward<Args>(args)...);
}
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
}
#endif
void destroy(pointer p) {
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
void destroy(T* p) {
test::detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
p->~T();
}
@ -368,6 +369,10 @@ namespace exception
}
return (std::numeric_limits<std::size_t>::max)();
}
typedef true_type propagate_on_container_copy_assignment;
typedef true_type propagate_on_container_move_assignment;
typedef true_type propagate_on_container_swap;
};
template <class T>
@ -396,6 +401,186 @@ namespace exception
//}
return x.tag_ != y.tag_;
}
template <class T>
class allocator2
{
public:
int tag_;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef allocator2<U> other; };
explicit allocator2(int t = 0) : tag_(t)
{
UNORDERED_SCOPE(allocator2::allocator2()) {
UNORDERED_EPOINT("Mock allocator2 default constructor.");
}
test::detail::tracker.allocator_ref();
}
allocator2(allocator<T> const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator2::allocator2()) {
UNORDERED_EPOINT("Mock allocator2 constructor from allocator.");
}
test::detail::tracker.allocator_ref();
}
template <class Y> allocator2(allocator2<Y> const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator2::allocator2()) {
UNORDERED_EPOINT("Mock allocator2 template copy constructor.");
}
test::detail::tracker.allocator_ref();
}
allocator2(allocator2 const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator2::allocator2()) {
UNORDERED_EPOINT("Mock allocator2 copy constructor.");
}
test::detail::tracker.allocator_ref();
}
~allocator2() {
test::detail::tracker.allocator_unref();
}
allocator2& operator=(allocator2 const& x) {
UNORDERED_SCOPE(allocator2::allocator2()) {
UNORDERED_EPOINT("Mock allocator2 assignment operator.");
tag_ = x.tag_;
}
return *this;
}
// If address throws, then it can't be used in erase or the
// destructor, which is very limiting. I need to check up on
// this.
pointer address(reference r) {
//UNORDERED_SCOPE(allocator2::address(reference)) {
// UNORDERED_EPOINT("Mock allocator2 address function.");
//}
return pointer(&r);
}
const_pointer address(const_reference r) {
//UNORDERED_SCOPE(allocator2::address(const_reference)) {
// UNORDERED_EPOINT("Mock allocator2 const address function.");
//}
return const_pointer(&r);
}
pointer allocate(size_type n) {
T* ptr = 0;
UNORDERED_SCOPE(allocator2::allocate(size_type)) {
UNORDERED_EPOINT("Mock allocator2 allocate function.");
using namespace std;
ptr = (T*) malloc(n * sizeof(T));
if(!ptr) throw std::bad_alloc();
}
test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
return pointer(ptr);
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
}
pointer allocate(size_type n, void const* u)
{
T* ptr = 0;
UNORDERED_SCOPE(allocator2::allocate(size_type, const_pointer)) {
UNORDERED_EPOINT("Mock allocator2 allocate function.");
using namespace std;
ptr = (T*) malloc(n * sizeof(T));
if(!ptr) throw std::bad_alloc();
}
test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
return pointer(ptr);
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
}
void deallocate(pointer p, size_type n)
{
//::operator delete((void*) p);
if(p) {
test::detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
using namespace std;
free(p);
}
}
void construct(pointer p, T const& t) {
UNORDERED_SCOPE(allocator2::construct(T*, T)) {
UNORDERED_EPOINT("Mock allocator2 construct function.");
new(p) T(t);
}
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
UNORDERED_SCOPE(allocator2::construct(pointer, BOOST_FWD_REF(Args)...)) {
UNORDERED_EPOINT("Mock allocator2 construct function.");
new(p) T(boost::forward<Args>(args)...);
}
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
}
#endif
void destroy(T* p) {
test::detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
p->~T();
}
size_type max_size() const {
UNORDERED_SCOPE(allocator2::construct(pointer, T)) {
UNORDERED_EPOINT("Mock allocator2 max_size function.");
}
return (std::numeric_limits<std::size_t>::max)();
}
typedef false_type propagate_on_container_copy_assignment;
typedef false_type propagate_on_container_move_assignment;
typedef false_type propagate_on_container_swap;
};
template <class T>
void swap(allocator2<T>& x, allocator2<T>& y)
{
std::swap(x.tag_, y.tag_);
}
// It's pretty much impossible to write a compliant swap when these
// two can throw. So they don't.
template <class T>
inline bool operator==(allocator2<T> const& x, allocator2<T> const& y)
{
//UNORDERED_SCOPE(operator==(allocator2, allocator2)) {
// UNORDERED_EPOINT("Mock allocator2 equality operator.");
//}
return x.tag_ == y.tag_;
}
template <class T>
inline bool operator!=(allocator2<T> const& x, allocator2<T> const& y)
{
//UNORDERED_SCOPE(operator!=(allocator2, allocator2)) {
// UNORDERED_EPOINT("Mock allocator2 inequality operator.");
//}
return x.tag_ != y.tag_;
}
}
}

View File

@ -11,6 +11,8 @@
#define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER
#include <cstddef>
#include <boost/move/move.hpp>
#include <utility>
#if defined(BOOST_MSVC)
#pragma warning(push)
@ -21,21 +23,40 @@ namespace test
{
namespace minimal
{
class destructible;
class copy_constructible;
class copy_constructible_equality_comparable;
class default_copy_constructible;
class default_assignable;
class assignable;
struct ampersand_operator_used {};
template <class T> class hash;
template <class T> class equal_to;
template <class T> class ptr;
template <class T> class const_ptr;
template <class T> class allocator;
template <class T> class cxx11_allocator;
struct constructor_param
{
operator int() const { return 0; }
};
class destructible
{
public:
destructible(constructor_param const&) {}
~destructible() {}
private:
destructible(destructible const&);
destructible& operator=(destructible const&);
};
class copy_constructible
{
public:
static copy_constructible create() { return copy_constructible(); }
copy_constructible(constructor_param const&) {}
copy_constructible(copy_constructible const&) {}
~copy_constructible() {}
private:
@ -46,9 +67,7 @@ namespace minimal
class copy_constructible_equality_comparable
{
public:
static copy_constructible_equality_comparable create() {
return copy_constructible_equality_comparable();
}
copy_constructible_equality_comparable(constructor_param const&) {}
copy_constructible_equality_comparable(
copy_constructible_equality_comparable const&)
@ -63,6 +82,7 @@ namespace minimal
copy_constructible_equality_comparable& operator=(
copy_constructible_equality_comparable const&);
copy_constructible_equality_comparable() {}
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
bool operator==(
@ -79,81 +99,174 @@ namespace minimal
return false;
}
class default_copy_constructible
class default_assignable
{
public:
static default_copy_constructible create()
{
return default_copy_constructible();
}
default_assignable(constructor_param const&) {}
default_copy_constructible()
default_assignable()
{
}
default_copy_constructible(default_copy_constructible const&)
default_assignable(default_assignable const&)
{
}
~default_copy_constructible()
default_assignable& operator=(default_assignable const&)
{
return *this;
}
~default_assignable()
{
}
private:
default_copy_constructible& operator=(
default_copy_constructible const&);
ampersand_operator_used operator&() const {
return ampersand_operator_used(); }
};
class assignable
{
public:
static assignable create() { return assignable(); }
assignable(constructor_param const&) {}
assignable(assignable const&) {}
assignable& operator=(assignable const&) { return *this; }
~assignable() {}
private:
assignable() {}
// TODO: This messes up a concept check in the tests.
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
struct movable_init {};
class movable1
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(movable1)
public:
movable1(constructor_param const&) {}
movable1() {}
explicit movable1(movable_init) {}
movable1(BOOST_RV_REF(movable1)) {}
movable1& operator=(BOOST_RV_REF(movable1)) { return *this; }
~movable1() {}
};
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
class movable2
{
public:
movable2(constructor_param const&) {}
explicit movable2(movable_init) {}
movable2(movable2&&) {}
~movable2() {}
movable2& operator=(movable2&&) { return *this; }
private:
movable2() {}
movable2(movable2 const&);
movable2& operator=(movable2 const&);
};
#else
typedef movable1 movable2;
#endif
template <class T>
class hash
{
public:
static hash create() { return hash<T>(); }
hash(constructor_param const&) {}
hash() {}
hash(hash const&) {}
hash& operator=(hash const&) { return *this; }
~hash() {}
std::size_t operator()(T const&) const { return 0; }
private:
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T>
class equal_to
{
public:
static equal_to create() { return equal_to<T>(); }
equal_to(constructor_param const&) {}
equal_to() {}
equal_to(equal_to const&) {}
equal_to& operator=(equal_to const&) { return *this; }
~equal_to() {}
bool operator()(T const&, T const&) const { return true; }
private:
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T> class ptr;
template <class T> class const_ptr;
struct void_ptr
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename T>
friend class ptr;
private:
#endif
void* ptr_;
public:
void_ptr() : ptr_(0) {}
template <typename T>
explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
// I'm not using the safe bool idiom because the containers should be
// able to cope with bool conversions.
operator bool() const { return !!ptr_; }
bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
};
class void_const_ptr
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename T>
friend class const_ptr;
private:
#endif
void* ptr_;
public:
void_const_ptr() : ptr_(0) {}
template <typename T>
explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_) {}
// I'm not using the safe bool idiom because the containers should be
// able to cope with bool conversions.
operator bool() const { return !!ptr_; }
bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
};
template <class T>
class ptr
{
friend class allocator<T>;
friend class const_ptr<T>;
friend struct void_ptr;
T* ptr_;
ptr(T* x) : ptr_(x) {}
public:
ptr() : ptr_(0) {}
explicit ptr(void_ptr const& x) : ptr_((T*) x.ptr_) {}
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
@ -175,19 +288,16 @@ namespace minimal
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
bool operator==(const_ptr<T> const& x) const { return ptr_ == x.ptr_; }
bool operator!=(const_ptr<T> const& x) const { return ptr_ != x.ptr_; }
bool operator<(const_ptr<T> const& x) const { return ptr_ < x.ptr_; }
bool operator>(const_ptr<T> const& x) const { return ptr_ > x.ptr_; }
bool operator<=(const_ptr<T> const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(const_ptr<T> const& x) const { return ptr_ >= x.ptr_; }
private:
// TODO:
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T>
class const_ptr
{
friend class allocator<T>;
friend struct const_void_ptr;
T const* ptr_;
@ -195,6 +305,7 @@ namespace minimal
public:
const_ptr() : ptr_(0) {}
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
explicit const_ptr(void_const_ptr const& x) : ptr_((T const*) x.ptr_) {}
T const& operator*() const { return *ptr_; }
T const* operator->() const { return ptr_; }
@ -208,19 +319,15 @@ namespace minimal
bool operator!() const { return !ptr_; }
operator bool() const { return !!ptr_; }
bool operator==(ptr<T> const& x) const { return ptr_ == x.ptr_; }
bool operator!=(ptr<T> const& x) const { return ptr_ != x.ptr_; }
bool operator<(ptr<T> const& x) const { return ptr_ < x.ptr_; }
bool operator>(ptr<T> const& x) const { return ptr_ > x.ptr_; }
bool operator<=(ptr<T> const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(ptr<T> const& x) const { return ptr_ >= x.ptr_; }
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
private:
// TODO:
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T>
@ -229,6 +336,8 @@ namespace minimal
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef void_ptr void_pointer;
typedef void_const_ptr const_void_pointer;
typedef ptr<T> pointer;
typedef const_ptr<T> const_pointer;
typedef T& reference;
@ -260,15 +369,15 @@ namespace minimal
::operator delete((void*) p.ptr_);
}
void construct(pointer p, T const& t) { new((void*)p.ptr_) T(t); }
void construct(T* p, T const& t) { new((void*)p) T(t); }
#if defined(BOOST_UNORDERED_STD_FORWARD)
template<class... Args> void construct(pointer p, Args&&... args) {
new((void*)p.ptr_) T(std::forward<Args>(args)...);
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
new((void*)p) T(boost::forward<Args>(args)...);
}
#endif
void destroy(pointer p) { ((T*)p.ptr_)->~T(); }
void destroy(T* p) { p->~T(); }
size_type max_size() const { return 1000; }
@ -278,6 +387,8 @@ namespace minimal
#else
private: allocator& operator=(allocator const&);
#endif
private:
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T>
@ -296,6 +407,69 @@ namespace minimal
void swap(allocator<T>&, allocator<T>&)
{
}
// C++11 allocator
//
// Not a fully minimal C++11 allocator, just what I support. Hopefully will
// cut down further in the future.
template <class T>
class cxx11_allocator
{
public:
typedef T value_type;
template <class U> struct rebind { typedef cxx11_allocator<U> other; };
cxx11_allocator() {}
template <class Y> cxx11_allocator(cxx11_allocator<Y> const&) {}
cxx11_allocator(cxx11_allocator const&) {}
~cxx11_allocator() {}
T* address(T& r) { return &r; }
T const* address(T const& r) { return &r; }
T* allocate(std::size_t n) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
template <class Y>
T* allocate(std::size_t n, const_ptr<Y> u) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, std::size_t) {
::operator delete((void*) p);
}
void construct(T* p, T const& t) { new((void*)p) T(t); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
new((void*)p) T(boost::forward<Args>(args)...);
}
#endif
void destroy(T* p) { p->~T(); }
std::size_t max_size() const { return 1000u; }
};
template <class T>
inline bool operator==(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
{
return true;
}
template <class T>
inline bool operator!=(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
{
return false;
}
template <class T>
void swap(cxx11_allocator<T>&, cxx11_allocator<T>&)
{
}
}
}

View File

@ -9,24 +9,29 @@
#include <boost/config.hpp>
#include <boost/limits.hpp>
#include <cstddef>
#include <iostream>
#include "../helpers/fwd.hpp"
#include "../helpers/count.hpp"
#include "../helpers/memory.hpp"
#include <map>
namespace test
{
// Note that the default hash function will work for any equal_to (but not
// very well).
class object;
class movable;
class implicitly_convertible;
class hash;
class less;
class equal_to;
template <class T> class allocator;
template <class T> class allocator1;
template <class T> class allocator2;
object generate(object const*);
movable generate(movable const*);
implicitly_convertible generate(implicitly_convertible const*);
class object : globally_counted_object
inline void ignore_variable(void const*) {}
class object : private counted_object
{
friend class hash;
friend class equal_to;
@ -64,6 +69,112 @@ namespace test
}
};
class movable : private counted_object
{
friend class hash;
friend class equal_to;
friend class less;
int tag1_, tag2_;
BOOST_COPYABLE_AND_MOVABLE(movable)
public:
explicit movable(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
movable(movable const& x) :
counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
{
BOOST_TEST(x.tag1_ != -1);
}
movable(BOOST_RV_REF(movable) x) :
counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
{
BOOST_TEST(x.tag1_ != -1);
x.tag1_ = -1;
x.tag2_ = -1;
}
movable& operator=(BOOST_COPY_ASSIGN_REF(movable) x) // Copy assignment
{
BOOST_TEST(x.tag1_ != -1);
tag1_ = x.tag1_;
tag2_ = x.tag2_;
return *this;
}
movable& operator=(BOOST_RV_REF(movable) x) //Move assignment
{
BOOST_TEST(x.tag1_ != -1);
tag1_ = x.tag1_;
tag2_ = x.tag2_;
x.tag1_ = -1;
x.tag2_ = -1;
return *this;
}
~movable() {
tag1_ = -1;
tag2_ = -1;
}
friend bool operator==(movable const& x1, movable const& x2) {
BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
}
friend bool operator!=(movable const& x1, movable const& x2) {
BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
}
friend bool operator<(movable const& x1, movable const& x2) {
BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
return x1.tag1_ < x2.tag1_ ||
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
}
friend movable generate(movable const*) {
int* x = 0;
return movable(generate(x), generate(x));
}
friend std::ostream& operator<<(std::ostream& out, movable const& o)
{
return out<<"("<<o.tag1_<<","<<o.tag2_<<")";
}
};
class implicitly_convertible : private counted_object
{
int tag1_, tag2_;
public:
explicit implicitly_convertible(int t1 = 0, int t2 = 0)
: tag1_(t1), tag2_(t2)
{}
operator object() const
{
return object(tag1_, tag2_);
}
operator movable() const
{
return movable(tag1_, tag2_);
}
friend implicitly_convertible generate(implicitly_convertible const*) {
int* x = 0;
return implicitly_convertible(generate(x), generate(x));
}
friend std::ostream& operator<<(std::ostream& out, implicitly_convertible const& o)
{
return out<<"("<<o.tag1_<<","<<o.tag2_<<")";
}
};
// Note: This is a deliberately bad hash function.
class hash
{
int type_;
@ -81,6 +192,17 @@ namespace test
}
}
std::size_t operator()(movable const& x) const {
switch(type_) {
case 1:
return x.tag1_;
case 2:
return x.tag2_;
default:
return x.tag1_ + x.tag2_;
}
}
std::size_t operator()(int x) const {
return x;
}
@ -98,6 +220,10 @@ namespace test
return hash()(x);
}
std::size_t hash_value(test::movable const& x) {
return hash()(x);
}
class less
{
int type_;
@ -115,6 +241,17 @@ namespace test
}
}
bool operator()(movable const& x1, movable const& x2) const {
switch(type_) {
case 1:
return x1.tag1_ < x2.tag1_;
case 2:
return x1.tag2_ < x2.tag2_;
default:
return x1 < x2;
}
}
std::size_t operator()(int x1, int x2) const {
return x1 < x2;
}
@ -141,6 +278,17 @@ namespace test
}
}
bool operator()(movable const& x1, movable const& x2) const {
switch(type_) {
case 1:
return x1.tag1_ == x2.tag1_;
case 2:
return x1.tag2_ == x2.tag2_;
default:
return x1 == x2;
}
}
std::size_t operator()(int x1, int x2) const {
return x1 == x2;
}
@ -158,56 +306,253 @@ 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;
}
}
// allocator1 only has the old fashioned 'construct' method and has
// a few less typedefs. allocator2 uses a custom pointer class.
template <class T>
class allocator
class allocator1
{
public:
int tag_;
typedef T value_type;
template <class U> struct rebind { typedef allocator1<U> other; };
explicit allocator1(int t = 0) : tag_(t)
{
detail::tracker.allocator_ref();
}
template <class Y> allocator1(allocator1<Y> const& x)
: tag_(x.tag_)
{
detail::tracker.allocator_ref();
}
allocator1(allocator1 const& x)
: tag_(x.tag_)
{
detail::tracker.allocator_ref();
}
~allocator1()
{
detail::tracker.allocator_unref();
}
T* allocate(std::size_t n) {
T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
return ptr;
}
T* allocate(std::size_t n, void const* u)
{
T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
return ptr;
}
void deallocate(T* p, std::size_t n)
{
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
::operator delete((void*) p);
}
void construct(T* p, T const& t) {
// Don't count constructions here as it isn't always called.
//detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new(p) T(t);
}
void destroy(T* p) {
//detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
p->~T();
// Work around MSVC buggy unused parameter warning.
ignore_variable(&p);
}
bool operator==(allocator1 const& x) const
{
return tag_ == x.tag_;
}
bool operator!=(allocator1 const& x) const
{
return tag_ != x.tag_;
}
enum {
is_select_on_copy = false,
is_propagate_on_swap = false,
is_propagate_on_assign = false,
is_propagate_on_move = false
};
};
template <class T> class ptr;
template <class T> class const_ptr;
struct void_ptr
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename T>
friend class ptr;
private:
#endif
void* ptr_;
public:
void_ptr() : ptr_(0) {}
template <typename T>
explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
// I'm not using the safe bool idiom because the containers should be
// able to cope with bool conversions.
operator bool() const { return !!ptr_; }
bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
};
class void_const_ptr
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename T>
friend class const_ptr;
private:
#endif
void* ptr_;
public:
void_const_ptr() : ptr_(0) {}
template <typename T>
explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_) {}
// I'm not using the safe bool idiom because the containers should be
// able to cope with bool conversions.
operator bool() const { return !!ptr_; }
bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
};
template <class T>
class ptr
{
friend class allocator2<T>;
friend class const_ptr<T>;
friend struct void_ptr;
T* ptr_;
ptr(T* x) : ptr_(x) {}
public:
ptr() : ptr_(0) {}
explicit ptr(void_ptr const& x) : ptr_((T*) x.ptr_) {}
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
ptr& operator++() { ++ptr_; return *this; }
ptr operator++(int) { ptr tmp(*this); ++ptr_; return tmp; }
ptr operator+(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_); }
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
bool operator!() const { return !ptr_; }
// I'm not using the safe bool idiom because the containers should be
// able to cope with bool conversions.
operator bool() const { return !!ptr_; }
bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
};
template <class T>
class const_ptr
{
friend class allocator2<T>;
friend struct const_void_ptr;
T const* ptr_;
const_ptr(T const* ptr) : ptr_(ptr) {}
public:
const_ptr() : ptr_(0) {}
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
explicit const_ptr(void_const_ptr const& x) : ptr_((T const*) x.ptr_) {}
T const& operator*() const { return *ptr_; }
T const* operator->() const { return ptr_; }
const_ptr& operator++() { ++ptr_; return *this; }
const_ptr operator++(int) { const_ptr tmp(*this); ++ptr_; return tmp; }
const_ptr operator+(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_; }
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
};
template <class T>
class allocator2
{
# ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
public:
# else
template <class> friend class allocator;
template <class> friend class allocator2;
# endif
int tag_;
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef void_ptr void_pointer;
typedef void_const_ptr const_void_pointer;
typedef ptr<T> pointer;
typedef const_ptr<T> const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef allocator<U> other; };
template <class U> struct rebind { typedef allocator2<U> other; };
explicit allocator(int t = 0) : tag_(t)
explicit allocator2(int t = 0) : tag_(t)
{
detail::tracker.allocator_ref();
}
template <class Y> allocator(allocator<Y> const& x)
template <class Y> allocator2(allocator2<Y> const& x)
: tag_(x.tag_)
{
detail::tracker.allocator_ref();
}
allocator(allocator const& x)
allocator2(allocator2 const& x)
: tag_(x.tag_)
{
detail::tracker.allocator_ref();
}
~allocator()
~allocator2()
{
detail::tracker.allocator_unref();
}
@ -223,9 +568,9 @@ namespace test
}
pointer allocate(size_type n) {
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
return ptr;
pointer p(static_cast<T*>(::operator new(n * sizeof(T))));
detail::tracker.track_allocate((void*) p.ptr_, n, sizeof(T), tag_);
return p;
}
pointer allocate(size_type n, void const* u)
@ -237,23 +582,23 @@ namespace test
void deallocate(pointer p, size_type n)
{
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
::operator delete((void*) p);
detail::tracker.track_deallocate((void*) p.ptr_, n, sizeof(T), tag_);
::operator delete((void*) p.ptr_);
}
void construct(pointer p, T const& t) {
void construct(T* p, T const& t) {
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new(p) T(t);
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
template<class... Args> void construct(pointer p, Args&&... args) {
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new(p) T(std::forward<Args>(args)...);
new(p) T(boost::forward<Args>(args)...);
}
#endif
void destroy(pointer p) {
void destroy(T* p) {
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
p->~T();
}
@ -262,61 +607,37 @@ namespace test
return (std::numeric_limits<size_type>::max)();
}
bool operator==(allocator const& x) const
bool operator==(allocator2 const& x) const
{
return tag_ == x.tag_;
}
bool operator!=(allocator const& x) const
bool operator!=(allocator2 const& x) const
{
return tag_ != x.tag_;
}
enum {
is_select_on_copy = false,
is_propagate_on_swap = false,
is_propagate_on_assign = false,
is_propagate_on_move = false
};
};
template <class T>
bool equivalent_impl(allocator<T> const& x, allocator<T> const& y,
bool equivalent_impl(allocator1<T> const& x, allocator1<T> const& y,
test::derived_type)
{
return x == y;
}
#if BOOST_WORKAROUND(__GNUC__, < 3)
void swap(test::object& x, test::object& y) {
test::object tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::hash& x, test::hash& y) {
test::hash tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::less& x, test::less& y) {
test::less tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::equal_to& x, test::equal_to& y) {
test::equal_to tmp;
tmp = x;
x = y;
y = tmp;
}
template <class T>
void swap(test::allocator<T>& x, test::allocator<T>& y) {
test::allocator<T> tmp;
tmp = x;
x = y;
y = tmp;
bool equivalent_impl(allocator2<T> const& x, allocator2<T> const& y,
test::derived_type)
{
return x == y;
}
#endif
}
#endif

View File

@ -9,28 +9,30 @@ project unordered-test/unordered
: requirements
<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
# Would be nice to define -Wundef, but I'm getting warnings from
# Boost.Preprocessor on trunk.
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wno-long-long -Wfloat-equal"
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal"
#<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 allocator_traits.cpp ]
[ run minimal_allocator.cpp ]
[ run compile_set.cpp ]
[ run compile_map.cpp ]
[ run noexcept_tests.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 ]
[ run copy_tests.cpp ]
[ run move_tests.cpp : : : <test-info>always_show_run_output ]
[ run move_tests.cpp ]
[ run assign_tests.cpp ]
[ run insert_tests.cpp ]
[ run insert_stable_tests.cpp ]
@ -43,5 +45,21 @@ test-suite unordered
[ run load_factor_tests.cpp ]
[ run rehash_tests.cpp ]
[ run equality_tests.cpp ]
[ run swap_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=2 ]
[ run swap_tests.cpp ]
[ run compile_set.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_compile_set ]
[ run compile_map.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_compile_map ]
[ run copy_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_copy ]
[ run move_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_move ]
[ run assign_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_assign ]
;

View File

@ -0,0 +1,254 @@
// Copyright 2011 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered/detail/allocate.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>
#include <boost/limits.hpp>
// Boilerplate
#define ALLOCATOR_METHODS(name) \
template <typename U> struct rebind { \
typedef name<U> other; \
}; \
\
name() {} \
template <typename Y> name(name<Y> const&) {} \
T* address(T& r) { return &r;} \
T const* address(T const& r) { return &r; } \
T* allocate(std::size_t n) \
{ return static_cast<T*>(::operator new(n * sizeof(T))); } \
T* allocate(std::size_t n, void const* u) \
{ return static_cast<T*>(::operator new(n * sizeof(T))); } \
void deallocate(T* p, std::size_t n) { ::operator delete((void*) p); } \
void construct(T* p, T const& t) { new(p) T(t); } \
void destroy(T* p) { p->~T(); } \
std::size_t max_size() const \
{ return (std::numeric_limits<std::size_t>::max)(); } \
bool operator==(name<T> const&) { return true; } \
bool operator!=(name<T> const&) { return false; } \
/**/
#define ALLOCATOR_METHODS_TYPEDEFS(name) \
template <typename U> struct rebind { \
typedef name<U> other; \
}; \
\
name() {} \
template <typename Y> name(name<Y> const&) {} \
pointer address(T& r) { return &r;} \
const_pointer address(T const& r) { return &r; } \
pointer allocate(std::size_t n) \
{ return pointer(::operator new(n * sizeof(T))); } \
pointer allocate(std::size_t n, void const* u) \
{ return pointer(::operator new(n * sizeof(T))); } \
void deallocate(pointer p, std::size_t n) \
{ ::operator delete((void*) p); } \
void construct(T* p, T const& t) { new(p) T(t); } \
void destroy(T* p) { p->~T(); } \
size_type max_size() const \
{ return (std::numeric_limits<size_type>::max)(); } \
bool operator==(name<T> const&) { return true; } \
bool operator!=(name<T> const&) { return false; } \
/**/
struct yes_type { enum { value = true }; };
struct no_type { enum { value = false }; };
// For tracking calls...
static int selected;
void reset() {
selected = 0;
}
template <typename Allocator>
int call_select()
{
typedef boost::unordered::detail::allocator_traits<Allocator> traits;
Allocator a;
reset();
BOOST_TEST(traits::select_on_container_copy_construction(a) == a);
return selected;
}
// Empty allocator test
template <typename T>
struct empty_allocator
{
typedef T value_type;
ALLOCATOR_METHODS(empty_allocator)
};
void test_empty_allocator()
{
typedef empty_allocator<int> allocator;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
std::make_unsigned<std::ptrdiff_t>::type>::value));
#else
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
#endif
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, int const*>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
BOOST_TEST(!traits::propagate_on_container_swap::value);
BOOST_TEST(call_select<allocator>() == 0);
}
// allocator 1
template <typename T>
struct allocator1
{
typedef T value_type;
ALLOCATOR_METHODS(allocator1)
typedef yes_type propagate_on_container_copy_assignment;
typedef yes_type propagate_on_container_move_assignment;
typedef yes_type propagate_on_container_swap;
allocator1<T> select_on_container_copy_construction() const {
++selected;
return allocator1<T>();
}
};
void test_allocator1()
{
typedef allocator1<int> allocator;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
std::make_unsigned<std::ptrdiff_t>::type>::value));
#else
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
#endif
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, int const*>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
BOOST_TEST(traits::propagate_on_container_move_assignment::value);
BOOST_TEST(traits::propagate_on_container_swap::value);
BOOST_TEST(call_select<allocator>() == 1);
}
// allocator 2
template <typename Alloc>
struct allocator2_base
{
Alloc select_on_container_copy_construction() const {
++selected;
return Alloc();
}
};
template <typename T>
struct allocator2 : allocator2_base<allocator2<T> >
{
typedef T value_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef std::size_t size_type;
ALLOCATOR_METHODS(allocator2)
typedef no_type propagate_on_container_copy_assignment;
typedef no_type propagate_on_container_move_assignment;
typedef no_type propagate_on_container_swap;
};
void test_allocator2()
{
typedef allocator2<int> allocator;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, int const*>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
BOOST_TEST(!traits::propagate_on_container_swap::value);
BOOST_TEST(call_select<allocator>() == 1);
}
// allocator 3
template <typename T>
struct ptr
{
T* value_;
ptr(void* v) : value_((T*) v) {}
T& operator*() const { return *value_; }
};
template <>
struct ptr<void>
{
void* value_;
ptr(void* v) : value_(v) {}
};
template <>
struct ptr<const void>
{
void const* value_;
ptr(void const* v) : value_(v) {}
};
template <typename T>
struct allocator3
{
typedef T value_type;
typedef ptr<T> pointer;
typedef ptr<T const> const_pointer;
typedef unsigned short size_type;
ALLOCATOR_METHODS_TYPEDEFS(allocator3)
typedef yes_type propagate_on_container_copy_assignment;
typedef no_type propagate_on_container_move_assignment;
allocator3<T> select_on_container_copy_construction() const {
++selected;
return allocator3<T>();
}
};
void test_allocator3()
{
typedef allocator3<int> allocator;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, unsigned short>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, ptr<int> >::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, ptr<int const> >::value));
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
BOOST_TEST(!traits::propagate_on_container_swap::value);
BOOST_TEST(call_select<allocator>() == 1);
}
int main()
{
test_empty_allocator();
test_allocator1();
test_allocator2();
test_allocator3();
return boost::report_errors();
}

View File

@ -4,30 +4,36 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../objects/cxx11_allocator.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include <iostream>
#if defined(BOOST_MSVC)
#pragma warning(disable:4127) // conditional expression is constant
#endif
namespace assign_tests {
test::seed_t seed(96785);
test::seed_t initialize_seed(96785);
template <class T>
void assign_tests1(T*,
test::random_generator generator = test::default_generator)
void assign_tests1(T*, test::random_generator generator)
{
BOOST_DEDUCED_TYPENAME T::hasher hf;
BOOST_DEDUCED_TYPENAME T::key_equal eq;
std::cerr<<"assign_tests1.1\n";
{
test::check_instances check_;
T x;
x = x;
BOOST_TEST(x.empty());
@ -37,6 +43,8 @@ void assign_tests1(T*,
std::cerr<<"assign_tests1.2\n";
{
test::check_instances check_;
test::random_values<T> v(1000, generator);
T x(v.begin(), v.end());
@ -48,15 +56,18 @@ void assign_tests1(T*,
T y;
y.max_load_factor(x.max_load_factor() / 20);
float mlf = x.max_load_factor();
y = x;
tracker.compare(x);
tracker.compare(y);
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
BOOST_TEST(x.max_load_factor() == mlf);
BOOST_TEST(y.max_load_factor() == mlf);
BOOST_TEST(y.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)
{
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
BOOST_DEDUCED_TYPENAME T::hasher hf2(2);
@ -64,58 +75,199 @@ void assign_tests2(T*,
BOOST_DEDUCED_TYPENAME T::key_equal eq2(2);
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
std::cerr<<"assign_tests2.1\n";
{
test::check_instances check_;
test::random_values<T> v(1000, generator);
T x1(v.begin(), v.end(), 0, hf1, eq1);
T x2(0, hf2, eq2);
x2 = x1;
BOOST_TEST(test::equivalent(x1.hash_function(), hf1));
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
test::check_container(x1, v);
test::check_container(x2, v);
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr<<"assign_tests2.1a\n";
{
test::check_instances check_;
test::random_values<T> v1(0, generator);
test::random_values<T> v2(1000, generator);
T x1(0, hf2, eq2);
T x2(v2.begin(), v2.end(), 0, hf1, eq1);
x2 = x1;
BOOST_TEST(test::equivalent(x1.hash_function(), hf2));
BOOST_TEST(test::equivalent(x1.key_eq(), eq2));
BOOST_TEST(test::equivalent(x2.hash_function(), hf2));
BOOST_TEST(test::equivalent(x2.key_eq(), eq2));
test::check_container(x1, v1);
test::check_container(x2, v1);
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr<<"assign_tests2.2\n";
{
test::check_instances check_;
test::random_values<T> v1(100, generator), v2(100, generator);
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
x2 = x1;
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
if (allocator_type::is_propagate_on_assign) {
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
}
else {
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
}
test::check_container(x1, v1);
test::check_container(x2, v1);
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr<<"assign_tests2.3\n";
{
test::check_instances check_;
test::random_values<T> v1(100, generator), v2(1000, generator);
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
x2 = x1;
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
if (allocator_type::is_propagate_on_assign) {
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
}
else {
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
}
test::check_container(x1, v1);
test::check_container(x2, v1);
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr<<"assign_tests2.4\n";
{
test::check_instances check_;
test::random_values<T> v1(1000, generator), v2(100, generator);
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
x2 = x1;
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
if (allocator_type::is_propagate_on_assign) {
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
}
else {
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
}
test::check_container(x1, v1);
test::check_container(x2, v1);
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
}
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;
std::allocator<test::object> >* test_map_std_alloc;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::allocator1<test::object> >* test_set;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::allocator2<test::object> >* test_multiset;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::allocator2<test::object> >* test_map;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multimap;
test::allocator1<test::object> >* test_multimap;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_assign> >*
test_set_prop_assign;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_assign> >*
test_multiset_prop_assign;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_assign> >*
test_map_prop_assign;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_assign> >*
test_multimap_prop_assign;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
test_set_no_prop_assign;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
test_multiset_no_prop_assign;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
test_map_no_prop_assign;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
test_multimap_no_prop_assign;
using test::default_generator;
using test::generate_collisions;
UNORDERED_TEST(assign_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
template <typename T>
bool is_propagate(T*)
{
return T::allocator_type::is_propagate_on_assign;
}
UNORDERED_AUTO_TEST(check_traits)
{
BOOST_TEST(!is_propagate(test_set));
BOOST_TEST(is_propagate(test_set_prop_assign));
BOOST_TEST(!is_propagate(test_set_no_prop_assign));
}
UNORDERED_TEST(assign_tests1, (
(test_map_std_alloc)
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
(test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
)
((default_generator)(generate_collisions))
)
UNORDERED_TEST(assign_tests2,
((test_set)(test_multiset)(test_map)(test_multimap))
UNORDERED_TEST(assign_tests2, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
(test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
)
((default_generator)(generate_collisions))
)
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST(assign_default_initializer_list) {
std::cerr<<"Initializer List Tests\n";
@ -130,9 +282,7 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list) {
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
!defined(BOOST_NO_INITIALIZER_LISTS)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST(assign_initializer_list)
{
std::cerr<<"Initializer List Tests\n";

View File

@ -4,29 +4,40 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include <string>
namespace at_tests {
UNORDERED_AUTO_TEST(at_tests) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl;
boost::unordered_map<std::string, int> x;
typedef boost::unordered_map<std::string, int>::iterator iterator;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Add elements" << std::endl;
x["one"] = 1;
x["two"] = 2;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check existing elements" << std::endl;
BOOST_TEST(x.at("one") == 1);
BOOST_TEST(x.at("two") == 2);
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check missing element" << std::endl;
try {
x.at("three");
BOOST_ERROR("Should have thrown.");
}
catch(std::out_of_range) {
}
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Finished" << std::endl;
}
}

View File

@ -4,9 +4,10 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include <algorithm>
#include "../objects/test.hpp"
@ -20,11 +21,13 @@
namespace bucket_tests {
test::seed_t seed(54635);
test::seed_t initialize_seed(54635);
template <class X>
void tests(X* = 0, test::random_generator generator = test::default_generator)
void tests(X*, test::random_generator generator)
{
test::check_instances check_;
typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator;
test::random_values<X> v(1000, generator);
@ -65,20 +68,30 @@ void tests(X* = 0, test::random_generator generator = test::default_generator)
}
}
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;
std::allocator<test::object> >* test_multimap_std_alloc;
UNORDERED_TEST(tests, ((test_set)(test_multiset)(test_map)(test_multimap)))
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::allocator2<test::object> >* test_set;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::allocator1<test::object> >* test_multiset;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::allocator1<test::object> >* test_map;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator2<test::object> >* test_multimap;
using test::default_generator;
using test::generate_collisions;
UNORDERED_TEST(tests,
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
)
}

View File

@ -7,8 +7,8 @@
// requirements. Makes sure everything compiles and is defined correctly.
#include "../helpers/prefix.hpp"
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include <iostream>
#include "../helpers/test.hpp"
@ -17,82 +17,120 @@
// Explicit instantiation to catch compile-time errors
template class boost::unordered_map<
int,
int,
boost::hash<int>,
std::equal_to<int>,
test::minimal::allocator<std::pair<int const, int> > >;
template class boost::unordered_multimap<
int,
int,
boost::hash<int>,
std::equal_to<int>,
test::minimal::allocator<std::pair<int const, int> > >;
template class boost::unordered_map<
test::minimal::assignable,
test::minimal::default_copy_constructible,
test::minimal::default_assignable,
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::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::constructor_param x;
typedef std::pair<test::minimal::assignable const,
test::minimal::copy_constructible> value_type;
value_type value(
test::minimal::assignable::create(),
test::minimal::copy_constructible::create());
test::minimal::assignable> value_type;
value_type value(x, x);
std::cout<<"Test unordered_map.\n";
boost::unordered_map<int, int> int_map;
boost::unordered_map<int, int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<std::pair<int const, int> >
> int_map2;
boost::unordered_map<
test::minimal::assignable,
test::minimal::copy_constructible,
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<value_type> > map;
container_test(int_map, std::pair<int const, int>(0, 0));
container_test(int_map2, std::pair<int const, int>(0, 0));
container_test(map, value);
std::cout<<"Test unordered_multimap.\n";
boost::unordered_multimap<int, int> int_multimap;
boost::unordered_multimap<int, int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<std::pair<int const, int> >
> int_multimap2;
boost::unordered_multimap<
test::minimal::assignable,
test::minimal::copy_constructible,
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<value_type> > multimap;
container_test(int_multimap, std::pair<int const, int>(0, 0));
container_test(int_multimap2, std::pair<int const, int>(0, 0));
container_test(multimap, value);
}
UNORDERED_AUTO_TEST(equality_tests) {
typedef std::pair<test::minimal::assignable const,
test::minimal::copy_constructible> value_type;
typedef std::pair<
test::minimal::copy_constructible_equality_comparable const,
test::minimal::copy_constructible_equality_comparable> value_type;
boost::unordered_map<int, int> int_map;
boost::unordered_map<int, int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<std::pair<int const, int> >
> int_map2;
boost::unordered_map<
test::minimal::assignable,
test::minimal::copy_constructible_equality_comparable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::copy_constructible_equality_comparable,
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
test::minimal::allocator<value_type> > map;
equality_test(int_map);
equality_test(int_map2);
equality_test(map);
boost::unordered_multimap<int, int> int_multimap;
boost::unordered_multimap<int, int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<std::pair<int const, int> >
> int_multimap2;
boost::unordered_multimap<
test::minimal::assignable,
test::minimal::copy_constructible_equality_comparable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::copy_constructible_equality_comparable,
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
test::minimal::allocator<value_type> > multimap;
equality_test(int_multimap);
equality_test(int_multimap2);
equality_test(multimap);
}
@ -106,72 +144,88 @@ UNORDERED_AUTO_TEST(test1) {
boost::unordered_map<int, int> map;
boost::unordered_map<int, int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<std::pair<int const, int> >
> map2;
unordered_unique_test(map, map_value);
unordered_map_test(map, value, value);
unordered_test(map, value, map_value, hash, equal_to);
unordered_copyable_test(map, value, map_value, hash, equal_to);
unordered_map_functions(map, value, value);
unordered_unique_test(map2, map_value);
unordered_map_test(map2, value, value);
unordered_copyable_test(map2, value, map_value, hash, equal_to);
unordered_map_functions(map2, value, value);
std::cout<<"Test unordered_multimap.\n";
boost::unordered_multimap<int, int> multimap;
boost::unordered_multimap<int, int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<std::pair<int const, int> >
> multimap2;
unordered_equivalent_test(multimap, map_value);
unordered_map_test(multimap, value, value);
unordered_test(multimap, value, map_value, hash, equal_to);
unordered_copyable_test(multimap, value, map_value, hash, equal_to);
unordered_equivalent_test(multimap2, map_value);
unordered_map_test(multimap2, value, value);
unordered_copyable_test(multimap2, value, map_value, hash, equal_to);
}
UNORDERED_AUTO_TEST(test2)
{
test::minimal::assignable assignable
= test::minimal::assignable::create();
test::minimal::copy_constructible copy_constructible
= test::minimal::copy_constructible::create();
test::minimal::hash<test::minimal::assignable> hash
= test::minimal::hash<test::minimal::assignable>::create();
test::minimal::equal_to<test::minimal::assignable> equal_to
= test::minimal::equal_to<test::minimal::assignable>::create();
test::minimal::constructor_param x;
test::minimal::assignable assignable(x);
test::minimal::copy_constructible copy_constructible(x);
test::minimal::hash<test::minimal::assignable> hash(x);
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
typedef std::pair<test::minimal::assignable const,
test::minimal::copy_constructible> map_value_type;
map_value_type map_value(assignable, copy_constructible);
test::minimal::assignable> map_value_type;
map_value_type map_value(assignable, assignable);
std::cout<<"Test unordered_map.\n";
boost::unordered_map<
test::minimal::assignable,
test::minimal::copy_constructible,
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<map_value_type> > map;
unordered_unique_test(map, map_value);
unordered_map_test(map, assignable, copy_constructible);
unordered_test(map, assignable, map_value, hash, equal_to);
unordered_map_test(map, assignable, assignable);
unordered_copyable_test(map, assignable, map_value, hash, equal_to);
boost::unordered_map<
test::minimal::assignable,
test::minimal::default_copy_constructible,
test::minimal::default_assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<map_value_type> > map2;
test::minimal::default_copy_constructible default_copy_constructible;
test::minimal::default_assignable default_assignable;
unordered_map_functions(map2, assignable, default_copy_constructible);
unordered_map_functions(map2, assignable, default_assignable);
std::cout<<"Test unordered_multimap.\n";
boost::unordered_multimap<
test::minimal::assignable,
test::minimal::copy_constructible,
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<map_value_type> > multimap;
unordered_equivalent_test(multimap, map_value);
unordered_map_test(multimap, assignable, copy_constructible);
unordered_test(multimap, assignable, map_value, hash, equal_to);
unordered_map_test(multimap, assignable, assignable);
unordered_copyable_test(multimap, assignable, map_value, hash, equal_to);
}
RUN_TESTS()

View File

@ -7,8 +7,8 @@
// requirements. Makes sure everything compiles and is defined correctly.
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include "../helpers/postfix.hpp"
#include <iostream>
#include "../helpers/test.hpp"
@ -17,6 +17,17 @@
// Explicit instantiation to catch compile-time errors
template class boost::unordered_set<
int,
boost::hash<int>,
std::equal_to<int>,
test::minimal::allocator<int> >;
template class boost::unordered_multiset<
int,
boost::hash<int>,
std::equal_to<int>,
test::minimal::allocator<int> >;
template class boost::unordered_set<
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
@ -30,10 +41,19 @@ template class boost::unordered_multiset<
UNORDERED_AUTO_TEST(test0)
{
test::minimal::assignable assignable = test::minimal::assignable::create();
test::minimal::constructor_param x;
test::minimal::assignable assignable(x);
std::cout<<"Test unordered_set.\n";
boost::unordered_set<int> int_set;
boost::unordered_set<int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<int>
> int_set2;
boost::unordered_set<
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
@ -41,10 +61,18 @@ UNORDERED_AUTO_TEST(test0)
test::minimal::allocator<test::minimal::assignable> > set;
container_test(int_set, 0);
container_test(int_set2, 0);
container_test(set, assignable);
std::cout<<"Test unordered_multiset.\n";
boost::unordered_multiset<int> int_multiset;
boost::unordered_multiset<int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<int>
> int_multiset2;
boost::unordered_multiset<
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
@ -52,32 +80,45 @@ UNORDERED_AUTO_TEST(test0)
test::minimal::allocator<test::minimal::assignable> > multiset;
container_test(int_multiset, 0);
container_test(int_multiset2, 0);
container_test(multiset, assignable);
}
UNORDERED_AUTO_TEST(equality_tests) {
typedef test::minimal::assignable value_type;
typedef test::minimal::copy_constructible_equality_comparable value_type;
boost::unordered_set<int> int_set;
boost::unordered_set<int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<int>
> int_set2;
boost::unordered_set<
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::copy_constructible_equality_comparable,
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
test::minimal::allocator<value_type> > set;
equality_test(int_set);
equality_test(int_set2);
equality_test(set);
boost::unordered_multiset<int> int_multiset;
boost::unordered_multiset<int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<int>
> int_multiset2;
boost::unordered_multiset<
test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::copy_constructible_equality_comparable,
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
test::minimal::allocator<value_type> > multiset;
equality_test(int_multiset);
equality_test(int_multiset2);
equality_test(multiset);
}
@ -87,33 +128,49 @@ UNORDERED_AUTO_TEST(test1)
std::equal_to<int> equal_to;
int value = 0;
std::cout<<"Test unordered_set.\n";
std::cout<<"Test unordered_set." << std::endl;
boost::unordered_set<int> set;
boost::unordered_set<int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<int>
> set2;
unordered_unique_test(set, value);
unordered_set_test(set, value);
unordered_test(set, value, value, hash, equal_to);
unordered_copyable_test(set, value, value, hash, equal_to);
std::cout<<"Test unordered_multiset.\n";
unordered_unique_test(set2, value);
unordered_set_test(set2, value);
unordered_copyable_test(set2, value, value, hash, equal_to);
std::cout<<"Test unordered_multiset." << std::endl;
boost::unordered_multiset<int> multiset;
boost::unordered_multiset<int,
boost::hash<int>, std::equal_to<int>,
test::minimal::cxx11_allocator<int>
> multiset2;
unordered_equivalent_test(multiset, value);
unordered_set_test(multiset, value);
unordered_test(multiset, value, value, hash, equal_to);
unordered_copyable_test(multiset, value, value, hash, equal_to);
unordered_equivalent_test(multiset2, value);
unordered_set_test(multiset2, value);
unordered_copyable_test(multiset2, value, value, hash, equal_to);
}
UNORDERED_AUTO_TEST(test2)
{
test::minimal::assignable assignable
= test::minimal::assignable::create();
test::minimal::copy_constructible copy_constructible
= test::minimal::copy_constructible::create();
test::minimal::hash<test::minimal::assignable> hash
= test::minimal::hash<test::minimal::assignable>::create();
test::minimal::equal_to<test::minimal::assignable> equal_to
= test::minimal::equal_to<test::minimal::assignable>::create();
test::minimal::constructor_param x;
test::minimal::assignable assignable(x);
test::minimal::copy_constructible copy_constructible(x);
test::minimal::hash<test::minimal::assignable> hash(x);
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
std::cout<<"Test unordered_set.\n";
@ -125,7 +182,7 @@ UNORDERED_AUTO_TEST(test2)
unordered_unique_test(set, assignable);
unordered_set_test(set, assignable);
unordered_test(set, assignable, assignable, hash, equal_to);
unordered_copyable_test(set, assignable, assignable, hash, equal_to);
std::cout<<"Test unordered_multiset.\n";
@ -137,7 +194,100 @@ UNORDERED_AUTO_TEST(test2)
unordered_equivalent_test(multiset, assignable);
unordered_set_test(multiset, assignable);
unordered_test(multiset, assignable, assignable, hash, equal_to);
unordered_copyable_test(multiset, assignable, assignable, hash, equal_to);
}
UNORDERED_AUTO_TEST(movable1_tests)
{
test::minimal::constructor_param x;
test::minimal::movable1 movable1(x);
test::minimal::hash<test::minimal::movable1> hash(x);
test::minimal::equal_to<test::minimal::movable1> equal_to(x);
std::cout<<"Test unordered_set.\n";
boost::unordered_set<
test::minimal::movable1,
test::minimal::hash<test::minimal::movable1>,
test::minimal::equal_to<test::minimal::movable1>,
test::minimal::allocator<test::minimal::movable1> > set;
//unordered_unique_test(set, movable1);
unordered_set_test(set, movable1);
unordered_movable_test(set, movable1, movable1, hash, equal_to);
std::cout<<"Test unordered_multiset.\n";
boost::unordered_multiset<
test::minimal::movable1,
test::minimal::hash<test::minimal::movable1>,
test::minimal::equal_to<test::minimal::movable1>,
test::minimal::allocator<test::minimal::movable1> > multiset;
//unordered_equivalent_test(multiset, movable1);
unordered_set_test(multiset, movable1);
unordered_movable_test(multiset, movable1, movable1, hash, equal_to);
}
UNORDERED_AUTO_TEST(movable2_tests)
{
test::minimal::constructor_param x;
test::minimal::movable2 movable2(x);
test::minimal::hash<test::minimal::movable2> hash(x);
test::minimal::equal_to<test::minimal::movable2> equal_to(x);
std::cout<<"Test unordered_set.\n";
boost::unordered_set<
test::minimal::movable2,
test::minimal::hash<test::minimal::movable2>,
test::minimal::equal_to<test::minimal::movable2>,
test::minimal::allocator<test::minimal::movable2> > set;
//unordered_unique_test(set, movable2);
unordered_set_test(set, movable2);
unordered_movable_test(set, movable2, movable2, hash, equal_to);
std::cout<<"Test unordered_multiset.\n";
boost::unordered_multiset<
test::minimal::movable2,
test::minimal::hash<test::minimal::movable2>,
test::minimal::equal_to<test::minimal::movable2>,
test::minimal::allocator<test::minimal::movable2> > multiset;
//unordered_equivalent_test(multiset, movable2);
unordered_set_test(multiset, movable2);
unordered_movable_test(multiset, movable2, movable2, hash, equal_to);
}
UNORDERED_AUTO_TEST(destructible_tests)
{
test::minimal::constructor_param x;
test::minimal::destructible destructible(x);
test::minimal::hash<test::minimal::destructible> hash(x);
test::minimal::equal_to<test::minimal::destructible> equal_to(x);
std::cout<<"Test unordered_set.\n";
boost::unordered_set<
test::minimal::destructible,
test::minimal::hash<test::minimal::destructible>,
test::minimal::equal_to<test::minimal::destructible> > set;
unordered_destructible_test(set);
std::cout<<"Test unordered_multiset.\n";
boost::unordered_multiset<
test::minimal::destructible,
test::minimal::hash<test::minimal::destructible>,
test::minimal::equal_to<test::minimal::destructible> > multiset;
unordered_destructible_test(multiset);
}
RUN_TESTS()

View File

@ -16,18 +16,19 @@
#pragma warning(pop)
#endif
#include <boost/mpl/assert.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <boost/limits.hpp>
#include <boost/utility/swap.hpp>
#include "../helpers/check_return_type.hpp"
typedef long double comparison_type;
template <class T> void sink(T const&) {}
template <class T> T rvalue(T const& v) { return v; }
template <class T> T rvalue_default() { return T(); }
template <class X, class T>
void container_test(X& r, T const&)
@ -53,42 +54,38 @@ void container_test(X& r, T const&)
// value_type
BOOST_MPL_ASSERT((boost::is_same<T, value_type>));
BOOST_STATIC_ASSERT((boost::is_same<T, value_type>::value));
boost::function_requires<boost::CopyConstructibleConcept<X> >();
// reference_type / const_reference_type
BOOST_MPL_ASSERT((boost::is_same<T&, reference>));
BOOST_MPL_ASSERT((boost::is_same<T const&, const_reference>));
BOOST_STATIC_ASSERT((boost::is_same<T&, reference>::value));
BOOST_STATIC_ASSERT((boost::is_same<T const&, const_reference>::value));
// iterator
boost::function_requires<boost::InputIteratorConcept<iterator> >();
BOOST_MPL_ASSERT((boost::is_same<T, iterator_value_type>));
BOOST_MPL_ASSERT((boost::is_convertible<iterator, const_iterator>));
BOOST_STATIC_ASSERT((boost::is_same<T, iterator_value_type>::value));
BOOST_STATIC_ASSERT((boost::is_convertible<iterator, const_iterator>::value));
// const_iterator
boost::function_requires<boost::InputIteratorConcept<const_iterator> >();
BOOST_MPL_ASSERT((boost::is_same<T, const_iterator_value_type>));
BOOST_STATIC_ASSERT((boost::is_same<T, const_iterator_value_type>::value));
// difference_type
BOOST_MPL_ASSERT((boost::mpl::bool_<
std::numeric_limits<difference_type>::is_signed>));
BOOST_MPL_ASSERT((boost::mpl::bool_<
std::numeric_limits<difference_type>::is_integer>));
BOOST_MPL_ASSERT((boost::is_same<difference_type,
iterator_difference_type>));
BOOST_MPL_ASSERT((boost::is_same<difference_type,
const_iterator_difference_type>));
BOOST_STATIC_ASSERT(std::numeric_limits<difference_type>::is_signed);
BOOST_STATIC_ASSERT(std::numeric_limits<difference_type>::is_integer);
BOOST_STATIC_ASSERT((boost::is_same<difference_type,
iterator_difference_type>::value));
BOOST_STATIC_ASSERT((boost::is_same<difference_type,
const_iterator_difference_type>::value));
// size_type
BOOST_MPL_ASSERT_NOT((boost::mpl::bool_<
std::numeric_limits<size_type>::is_signed>));
BOOST_MPL_ASSERT((boost::mpl::bool_<
std::numeric_limits<size_type>::is_integer>));
BOOST_STATIC_ASSERT(!std::numeric_limits<size_type>::is_signed);
BOOST_STATIC_ASSERT(std::numeric_limits<size_type>::is_integer);
// size_type can represent any non-negative value type of difference_type
// I'm not sure about either of these tests...
@ -109,30 +106,15 @@ void container_test(X& r, T const&)
BOOST_TEST(X().size() == 0);
X a,b;
X a_const;
sink(X(a));
X u2(a);
X u3 = a;
X* ptr = new X();
X& a1 = *ptr;
(&a1)->~X();
X const a_const;
test::check_return_type<iterator>::equals(a.begin());
test::check_return_type<const_iterator>::equals(a_const.begin());
test::check_return_type<const_iterator>::equals(a.cbegin());
test::check_return_type<const_iterator>::equals(a_const.cbegin());
test::check_return_type<iterator>::equals(a.end());
test::check_return_type<const_iterator>::equals(a_const.end());
test::check_return_type<const_iterator>::equals(a.cend());
test::check_return_type<const_iterator>::equals(a_const.cend());
a.swap(b);
boost::swap(a, b);
test::check_return_type<X>::equals_ref(r = a);
test::check_return_type<size_type>::equals(a.size());
test::check_return_type<size_type>::equals(a.max_size());
test::check_return_type<bool>::convertible(a.empty());
// Allocator
@ -146,13 +128,58 @@ void container_test(X& r, T const&)
sink(u3);
}
template <class X>
void unordered_destructible_test(X&)
{
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
X x1;
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
X x2(rvalue_default<X>());
X x3 = rvalue_default<X>();
// This can only be done if propagate_on_container_move_assignment::value
// is true.
// x2 = rvalue_default<X>();
#endif
X* ptr = new X();
X& a1 = *ptr;
(&a1)->~X();
X a,b;
X const a_const;
test::check_return_type<iterator>::equals(a.begin());
test::check_return_type<const_iterator>::equals(a_const.begin());
test::check_return_type<const_iterator>::equals(a.cbegin());
test::check_return_type<const_iterator>::equals(a_const.cbegin());
test::check_return_type<iterator>::equals(a.end());
test::check_return_type<const_iterator>::equals(a_const.end());
test::check_return_type<const_iterator>::equals(a.cend());
test::check_return_type<const_iterator>::equals(a_const.cend());
a.swap(b);
boost::swap(a, b);
test::check_return_type<size_type>::equals(a.size());
test::check_return_type<size_type>::equals(a.max_size());
test::check_return_type<bool>::convertible(a.empty());
// Allocator
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
test::check_return_type<allocator_type>::equals(a_const.get_allocator());
}
template <class X, class Key>
void unordered_set_test(X&, Key const&)
{
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, key_type>));
BOOST_STATIC_ASSERT((boost::is_same<value_type, key_type>::value));
}
template <class X, class Key, class T>
@ -160,8 +187,9 @@ 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_STATIC_ASSERT((
boost::is_same<value_type, std::pair<key_type const, T> >::value));
r.insert(std::pair<Key const, T>(k, v));
@ -180,6 +208,8 @@ void equality_test(X& r)
test::check_return_type<bool>::equals(a == b);
test::check_return_type<bool>::equals(a != b);
test::check_return_type<bool>::equals(boost::operator==(a, b));
test::check_return_type<bool>::equals(boost::operator!=(a, b));
}
template <class X, class T>
@ -211,9 +241,11 @@ void unordered_map_functions(X&, Key const& k, T const&)
test::check_return_type<mapped_type const>::equals_ref(b.at(k));
}
template <class X, class Key, class T, class Hash, class Pred>
void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
template <class X, class Key, class Hash, class Pred>
void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
{
unordered_destructible_test(x);
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME X::hasher hasher;
typedef BOOST_DEDUCED_TYPENAME X::key_equal key_equal;
@ -276,36 +308,36 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
boost::iterator_reference<const_local_iterator>::type
const_local_iterator_reference;
BOOST_MPL_ASSERT((boost::is_same<Key, key_type>));
boost::function_requires<boost::CopyConstructibleConcept<key_type> >();
boost::function_requires<boost::AssignableConcept<key_type> >();
BOOST_STATIC_ASSERT((boost::is_same<Key, key_type>::value));
//boost::function_requires<boost::CopyConstructibleConcept<key_type> >();
//boost::function_requires<boost::AssignableConcept<key_type> >();
BOOST_MPL_ASSERT((boost::is_same<Hash, hasher>));
BOOST_STATIC_ASSERT((boost::is_same<Hash, hasher>::value));
test::check_return_type<std::size_t>::equals(hf(k));
BOOST_MPL_ASSERT((boost::is_same<Pred, key_equal>));
BOOST_STATIC_ASSERT((boost::is_same<Pred, key_equal>::value));
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_STATIC_ASSERT((boost::is_same<local_iterator_category,
iterator_category>::value));
BOOST_STATIC_ASSERT((boost::is_same<local_iterator_difference,
iterator_difference>::value));
BOOST_STATIC_ASSERT((boost::is_same<local_iterator_pointer,
iterator_pointer>::value));
BOOST_STATIC_ASSERT((boost::is_same<local_iterator_reference,
iterator_reference>::value));
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_STATIC_ASSERT((boost::is_same<const_local_iterator_category,
const_iterator_category>::value));
BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_difference,
const_iterator_difference>::value));
BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_pointer,
const_iterator_pointer>::value));
BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_reference,
const_iterator_reference>::value));
X(10, hf, eq);
X a(10, hf, eq);
@ -316,45 +348,18 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
X();
X a4;
BOOST_DEDUCED_TYPENAME X::value_type* i = 0;
BOOST_DEDUCED_TYPENAME X::value_type* j = 0;
X(i, j, 10, hf, eq);
X a5(i, j, 10, hf, eq);
X(i, j, 10, hf);
X a6(i, j, 10, hf);
X(i, j, 10);
X a7(i, j, 10);
X(i, j);
X a8(i, j);
X const b;
sink(X(b));
X a9(b);
a = b;
test::check_return_type<hasher>::equals(b.hash_function());
test::check_return_type<key_equal>::equals(b.key_eq());
const_iterator q = a.cbegin();
test::check_return_type<iterator>::equals(a.insert(q, t));
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_TEST(a.empty());
if(a.empty()) {
a.insert(t);
q = a.cbegin();
test::check_return_type<iterator>::equals(a.erase(q));
}
const_iterator q1 = a.cbegin(), q2 = a.cend();
test::check_return_type<iterator>::equals(a.erase(q1, q2));
a.clear();
X const b;
test::check_return_type<hasher>::equals(b.hash_function());
test::check_return_type<key_equal>::equals(b.key_eq());
test::check_return_type<iterator>::equals(a.find(k));
test::check_return_type<const_iterator>::equals(b.find(k));
test::check_return_type<size_type>::equals(b.count(k));
@ -388,9 +393,118 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
sink(a2);
sink(a3);
sink(a4);
}
template <class X, class Key, class T, class Hash, class Pred>
void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
{
unordered_test(x, k, hf, eq);
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
X a;
BOOST_DEDUCED_TYPENAME X::value_type* i = 0;
BOOST_DEDUCED_TYPENAME X::value_type* j = 0;
X(i, j, 10, hf, eq);
X a5(i, j, 10, hf, eq);
X(i, j, 10, hf);
X a6(i, j, 10, hf);
X(i, j, 10);
X a7(i, j, 10);
X(i, j);
X a8(i, j);
X const b;
sink(X(b));
X a9(b);
a = b;
const_iterator q = a.cbegin();
test::check_return_type<iterator>::equals(a.insert(q, t));
test::check_return_type<iterator>::equals(a.emplace_hint(q, t));
a.insert(i, j);
X a10;
a10.insert(t);
q = a10.cbegin();
test::check_return_type<iterator>::equals(a10.erase(q));
// Avoid unused variable warnings:
sink(a);
sink(a5);
sink(a6);
sink(a7);
sink(a8);
sink(a9);
}
template <class X, class Key, class T, class Hash, class Pred>
void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq)
{
unordered_test(x, k, hf, eq);
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
X x1(rvalue_default<X>());
X x2(boost::move(x1));
x1 = rvalue_default<X>();
x2 = boost::move(x1);
#endif
test::minimal::constructor_param* i = 0;
test::minimal::constructor_param* j = 0;
X(i, j, 10, hf, eq);
X a5(i, j, 10, hf, eq);
X(i, j, 10, hf);
X a6(i, j, 10, hf);
X(i, j, 10);
X a7(i, j, 10);
X(i, j);
X a8(i, j);
X a;
const_iterator q = a.cbegin();
test::minimal::constructor_param v;
a.emplace(v);
test::check_return_type<iterator>::equals(a.emplace_hint(q, v));
T v1(v);
a.emplace(boost::move(v1));
T v2(v);
a.insert(boost::move(v2));
T v3(v);
test::check_return_type<iterator>::equals(
a.emplace_hint(q, boost::move(v3)));
T v4(v);
test::check_return_type<iterator>::equals(
a.insert(q, boost::move(v4)));
a.insert(i, j);
X a10;
T v5(v);
a10.insert(boost::move(v5));
q = a10.cbegin();
test::check_return_type<iterator>::equals(a10.erase(q));
// Avoid unused variable warnings:
sink(a);
sink(a5);
sink(a6);
sink(a7);
sink(a8);
sink(a10);
}

View File

@ -4,9 +4,10 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
@ -15,15 +16,12 @@
#include "../helpers/input_iterator.hpp"
#include "../helpers/invariants.hpp"
#include <iostream>
namespace constructor_tests {
test::seed_t seed(356730);
test::seed_t initialize_seed(356730);
template <class T>
void constructor_tests1(T*,
test::random_generator generator = test::default_generator)
void constructor_tests1(T*, test::random_generator generator)
{
BOOST_DEDUCED_TYPENAME T::hasher hf;
BOOST_DEDUCED_TYPENAME T::key_equal eq;
@ -31,6 +29,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 1\n";
{
test::check_instances check_;
T x(0, hf, eq);
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
@ -41,6 +41,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 2\n";
{
test::check_instances check_;
T x(100, hf);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 100);
@ -52,6 +54,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 3\n";
{
test::check_instances check_;
T x(2000);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 2000);
@ -63,6 +67,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 4\n";
{
test::check_instances check_;
T x;
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
@ -73,6 +79,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 5\n";
{
test::check_instances check_;
test::random_values<T> v(1000, generator);
T x(v.begin(), v.end(), 10000, hf, eq);
BOOST_TEST(x.bucket_count() >= 10000);
@ -85,6 +93,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 6\n";
{
test::check_instances check_;
test::random_values<T> v(10, generator);
T x(v.begin(), v.end(), 10000, hf);
BOOST_TEST(x.bucket_count() >= 10000);
@ -97,6 +107,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 7\n";
{
test::check_instances check_;
test::random_values<T> v(100, generator);
T x(v.begin(), v.end(), 100);
BOOST_TEST(x.bucket_count() >= 100);
@ -109,6 +121,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 8\n";
{
test::check_instances check_;
test::random_values<T> v(1, generator);
T x(v.begin(), v.end());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
@ -120,6 +134,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 9\n";
{
test::check_instances check_;
T x(0, hf, eq, al);
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
@ -130,6 +146,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 10\n";
{
test::check_instances check_;
test::random_values<T> v(1000, generator);
T x(v.begin(), v.end(), 10000, hf, eq, al);
BOOST_TEST(x.bucket_count() >= 10000);
@ -142,6 +160,8 @@ void constructor_tests1(T*,
std::cerr<<"Construct 11\n";
{
test::check_instances check_;
T x(al);
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
@ -152,8 +172,7 @@ void constructor_tests1(T*,
}
template <class T>
void constructor_tests2(T*,
test::random_generator const& generator = test::default_generator)
void constructor_tests2(T*, test::random_generator const& generator)
{
BOOST_DEDUCED_TYPENAME T::hasher hf;
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
@ -167,6 +186,7 @@ void constructor_tests2(T*,
std::cerr<<"Construct 1\n";
{
test::check_instances check_;
T x(10000, hf1, eq1);
BOOST_TEST(x.bucket_count() >= 10000);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
@ -177,6 +197,7 @@ void constructor_tests2(T*,
std::cerr<<"Construct 2\n";
{
test::check_instances check_;
T x(100, hf1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 100);
@ -188,6 +209,7 @@ void constructor_tests2(T*,
std::cerr<<"Construct 3\n";
{
test::check_instances check_;
test::random_values<T> v(100, generator);
T x(v.begin(), v.end(), 0, hf1, eq1);
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
@ -199,6 +221,7 @@ void constructor_tests2(T*,
std::cerr<<"Construct 4\n";
{
test::check_instances check_;
test::random_values<T> v(5, generator);
T x(v.begin(), v.end(), 1000, hf1);
BOOST_TEST(x.bucket_count() >= 1000);
@ -212,6 +235,7 @@ void constructor_tests2(T*,
std::cerr<<"Construct 5\n";
{
test::check_instances check_;
test::random_values<T> v(100, generator);
T x(v.begin(), v.end(), 0, hf, eq, al1);
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
@ -223,6 +247,7 @@ void constructor_tests2(T*,
std::cerr<<"Construct 6\n";
{
test::check_instances check_;
test::random_values<T> v(100, generator);
T x(v.begin(), v.end(), 0, hf1, eq1);
T y(x.begin(), x.end(), 0, hf, eq);
@ -234,6 +259,7 @@ void constructor_tests2(T*,
std::cerr<<"Construct 7\n";
{
test::check_instances check_;
test::random_values<T> v(100, generator);
T x(v.begin(), v.end(), 0, hf1, eq1);
T y(x.begin(), x.end(), 0, hf2, eq2);
@ -245,6 +271,7 @@ void constructor_tests2(T*,
std::cerr<<"Construct 8 - from input iterator\n";
{
test::check_instances check_;
test::random_values<T> v(100, generator);
BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
v_begin = v.begin(), v_end = v.end();
@ -262,6 +289,7 @@ void constructor_tests2(T*,
std::cerr<<"Construct 8.5 - from copy iterator\n";
{
test::check_instances check_;
test::random_values<T> v(100, generator);
T x(test::copy_iterator(v.begin()),
test::copy_iterator(v.end()), 0, hf1, eq1);
@ -275,6 +303,8 @@ void constructor_tests2(T*,
std::cerr<<"Construct 9\n";
{
test::check_instances check_;
test::random_values<T> v(100, generator);
T x(50);
BOOST_TEST(x.bucket_count() >= 50);
@ -286,11 +316,13 @@ void constructor_tests2(T*,
test::check_equivalent_keys(x);
}
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
std::initializer_list<BOOST_DEDUCED_TYPENAME T::value_type> list;
std::cerr<<"Initializer list construct 1\n";
{
test::check_instances check_;
T x(list);
BOOST_TEST(x.empty());
BOOST_TEST(test::equivalent(x.hash_function(), hf));
@ -300,6 +332,8 @@ void constructor_tests2(T*,
std::cerr<<"Initializer list construct 2\n";
{
test::check_instances check_;
T x(list, 1000);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 1000);
@ -310,6 +344,8 @@ void constructor_tests2(T*,
std::cerr<<"Initializer list construct 3\n";
{
test::check_instances check_;
T x(list, 10, hf1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
@ -320,6 +356,8 @@ void constructor_tests2(T*,
std::cerr<<"Initializer list construct 4\n";
{
test::check_instances check_;
T x(list, 10, hf1, eq1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
@ -330,6 +368,8 @@ void constructor_tests2(T*,
std::cerr<<"Initializer list construct 5\n";
{
test::check_instances check_;
T x(list, 10, hf1, eq1, al1);
BOOST_TEST(x.empty());
BOOST_TEST(x.bucket_count() >= 10);
@ -341,8 +381,7 @@ void constructor_tests2(T*,
}
template <class T>
void map_constructor_test(T* = 0,
test::random_generator const& generator = test::default_generator)
void map_constructor_test(T*, test::random_generator const& generator)
{
std::cerr<<"map_constructor_test\n";
@ -360,24 +399,28 @@ void map_constructor_test(T* = 0,
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;
std::allocator<test::object> >* test_map_std_alloc;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::allocator1<test::object> >* test_set;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::allocator2<test::object> >* test_multiset;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::allocator2<test::object> >* test_map;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multimap;
test::allocator1<test::object> >* test_multimap;
using test::default_generator;
using test::generate_collisions;
UNORDERED_TEST(constructor_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
)
@ -387,10 +430,11 @@ UNORDERED_TEST(constructor_tests2,
)
UNORDERED_TEST(map_constructor_test,
((test_map)(test_multimap))
((test_map_std_alloc)(test_map)(test_multimap))
((default_generator)(generate_collisions))
)
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST(test_default_initializer_list) {
std::cerr<<"Initializer List Tests\n";
@ -401,8 +445,7 @@ UNORDERED_AUTO_TEST(test_default_initializer_list) {
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
!defined(BOOST_NO_INITIALIZER_LISTS)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST(test_initializer_list) {
std::cerr<<"Initializer List Tests\n";

View File

@ -4,30 +4,35 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../objects/cxx11_allocator.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/invariants.hpp"
test::seed_t seed(9063);
test::seed_t initialize_seed(9063);
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)
{
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
BOOST_DEDUCED_TYPENAME T::hasher hf;
BOOST_DEDUCED_TYPENAME T::key_equal eq;
BOOST_DEDUCED_TYPENAME T::allocator_type al;
BOOST_DEDUCED_TYPENAME T::allocator_type al;
{
test::check_instances check_;
T x;
T y(x);
BOOST_TEST(y.empty());
@ -35,20 +40,28 @@ void copy_construct_tests1(T*,
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());
BOOST_TEST(test::selected_count(y.get_allocator()) ==
(allocator_type::is_select_on_copy));
test::check_equivalent_keys(y);
}
{
test::check_instances check_;
test::random_values<T> v(1000, generator);
T x(v.begin(), v.end());
T y(x);
test::unordered_equivalence_tester<T> equivalent(x);
BOOST_TEST(equivalent(y));
BOOST_TEST(test::selected_count(y.get_allocator()) ==
(allocator_type::is_select_on_copy));
test::check_equivalent_keys(y);
}
{
test::check_instances check_;
// In this test I drop the original containers max load factor, so it
// is much lower than the load factor. The hash table is not allowed
// to rehash, but the destination container should probably allocate
@ -61,22 +74,25 @@ void copy_construct_tests1(T*,
BOOST_TEST(equivalent(y));
// This isn't guaranteed:
BOOST_TEST(y.load_factor() < y.max_load_factor());
BOOST_TEST(test::selected_count(y.get_allocator()) ==
(allocator_type::is_select_on_copy));
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*, test::random_generator const& generator)
{
copy_construct_tests1(ptr);
BOOST_DEDUCED_TYPENAME T::hasher hf(1);
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
BOOST_DEDUCED_TYPENAME T::allocator_type al(1);
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
{
test::check_instances check_;
T x(10000, hf, eq, al);
T y(x);
BOOST_TEST(y.empty());
@ -84,10 +100,14 @@ void copy_construct_tests2(T* ptr,
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());
BOOST_TEST(test::selected_count(y.get_allocator()) ==
(allocator_type::is_select_on_copy));
test::check_equivalent_keys(y);
}
{
test::check_instances check_;
T x(1000, hf, eq, al);
T y(x, al2);
BOOST_TEST(y.empty());
@ -95,10 +115,13 @@ void copy_construct_tests2(T* ptr,
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());
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
test::check_equivalent_keys(y);
}
{
test::check_instances check_;
test::random_values<T> v(1000, generator);
T x(v.begin(), v.end(), 0, hf, eq, al);
@ -106,10 +129,14 @@ void copy_construct_tests2(T* ptr,
test::unordered_equivalence_tester<T> equivalent(x);
BOOST_TEST(equivalent(y));
test::check_equivalent_keys(y);
BOOST_TEST(test::selected_count(y.get_allocator()) ==
(allocator_type::is_select_on_copy));
BOOST_TEST(test::equivalent(y.get_allocator(), al));
}
{
test::check_instances check_;
test::random_values<T> v(500, generator);
T x(v.begin(), v.end(), 0, hf, eq, al);
@ -117,32 +144,74 @@ void copy_construct_tests2(T* ptr,
test::unordered_equivalence_tester<T> equivalent(x);
BOOST_TEST(equivalent(y));
test::check_equivalent_keys(y);
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
}
}
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_set;
test::allocator1<test::object> >* test_set;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multiset;
test::allocator2<test::object> >* test_multiset;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_map;
test::allocator1<test::object> >* test_map;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multimap;
test::allocator2<test::object> >* test_multimap;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::select_copy> >*
test_set_select_copy;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::select_copy> >*
test_multiset_select_copy;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::select_copy> >*
test_map_select_copy;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::select_copy> >*
test_multimap_select_copy;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_select_copy> >*
test_set_no_select_copy;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_select_copy> >*
test_multiset_no_select_copy;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_select_copy> >*
test_map_no_select_copy;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_select_copy> >*
test_multimap_no_select_copy;
using test::default_generator;
using test::generate_collisions;
UNORDERED_TEST(copy_construct_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
UNORDERED_TEST(copy_construct_tests1, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
)
((default_generator)(generate_collisions))
)
UNORDERED_TEST(copy_construct_tests2,
((test_set)(test_multiset)(test_map)(test_multimap))
UNORDERED_TEST(copy_construct_tests2, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
)
((default_generator)(generate_collisions))
)

View File

@ -4,9 +4,10 @@
// 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/postfix.hpp"
#include <boost/preprocessor/seq.hpp>
#include <list>
#include "../helpers/test.hpp"
@ -136,15 +137,25 @@ namespace equality_tests
UNORDERED_EQUALITY_MULTIMAP_TEST(
((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
UNORDERED_EQUALITY_MULTIMAP_TEST(
((1)(2))((1)(1)), !=, ((1)(1))((1)(2)))
((1)(2))((1)(1)), ==, ((1)(1))((1)(2)))
UNORDERED_EQUALITY_MULTIMAP_TEST(
((1)(2))((1)(1)), !=, ((1)(1))((1)(3)))
}
UNORDERED_AUTO_TEST(equality_predicate_test)
{
UNORDERED_EQUALITY_SET_TEST(
(1), ==, (1001))
(1), !=, (1001))
UNORDERED_EQUALITY_MAP_TEST(
((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1)))
((1)(2))((1001)(1)), !=, ((1001)(2))((1)(1)))
}
UNORDERED_AUTO_TEST(equality_multiple_group_test)
{
UNORDERED_EQUALITY_MULTISET_TEST(
(1)(1)(1)(1001)(2001)(2001)(2)(1002)(3)(1003)(2003), ==,
(3)(1003)(2003)(1002)(2)(2001)(2001)(1)(1001)(1)(1)
);
}
// Test that equality still works when the two containers have
@ -165,7 +176,6 @@ namespace equality_tests
set1.insert(20); set2.insert(10);
BOOST_TEST(set1 == set2);
}
}
RUN_TESTS()

View File

@ -4,9 +4,10 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include <algorithm>
#include <map>

View File

@ -7,10 +7,12 @@
// hairy with several tricky edge cases - so explicitly test each one.
#include "../helpers/prefix.hpp"
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../helpers/list.hpp"
#include "../helpers/invariants.hpp"
#include <set>
#include <iostream>
#include <iterator>
@ -50,12 +52,21 @@ struct collision2_hash
int operator()(int x) const { return x & 1; }
};
// For testing erase in lots of buckets.
struct collision3_hash
{
int operator()(int x) const { return x; }
};
typedef boost::unordered_multimap<int, int,
collision_hash, std::equal_to<int>,
test::allocator<std::pair<int const, int> > > collide_map;
test::allocator1<std::pair<int const, int> > > collide_map;
typedef boost::unordered_multimap<int, int,
collision2_hash, std::equal_to<int>,
test::allocator<std::pair<int const, int> > > collide_map2;
test::allocator2<std::pair<int const, int> > > collide_map2;
typedef boost::unordered_multimap<int, int,
collision3_hash, std::equal_to<int>,
test::allocator2<std::pair<int const, int> > > collide_map3;
typedef collide_map::value_type collide_value;
typedef test::list<collide_value> collide_list;
@ -65,6 +76,7 @@ UNORDERED_AUTO_TEST(empty_range_tests)
x.erase(x.begin(), x.end());
x.erase(x.begin(), x.begin());
x.erase(x.end(), x.end());
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(single_item_tests)
@ -75,10 +87,13 @@ UNORDERED_AUTO_TEST(single_item_tests)
collide_map x(init.begin(), init.end());
x.erase(x.begin(), x.begin());
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
test::check_equivalent_keys(x);
x.erase(x.end(), x.end());
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
test::check_equivalent_keys(x);
x.erase(x.begin(), x.end());
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(two_equivalent_item_tests)
@ -91,6 +106,7 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
collide_map x(init.begin(), init.end());
x.erase(x.begin(), x.end());
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
test::check_equivalent_keys(x);
}
{
@ -99,6 +115,7 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
x.erase(x.begin(), boost::next(x.begin()));
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
x.begin()->first == 1 && x.begin()->second == value);
test::check_equivalent_keys(x);
}
{
@ -107,6 +124,7 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
x.erase(boost::next(x.begin()), x.end());
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
x.begin()->first == 1 && x.begin()->second == value);
test::check_equivalent_keys(x);
}
}
@ -128,6 +146,8 @@ 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));
x.erase(boost::next(x.begin(), start), boost::next(x.begin(), end));
test::check_equivalent_keys(x);
return compare(l, x);
}
@ -190,4 +210,11 @@ UNORDERED_AUTO_TEST(exhaustive_collide2_tests)
std::cout<<"\n";
}
UNORDERED_AUTO_TEST(exhaustive_collide3_tests)
{
std::cout<<"exhaustive_collide3_tests:\n";
exhaustive_erase_tests((collide_map3*) 0, 8, 4);
std::cout<<"\n";
}
RUN_TESTS()

View File

@ -4,9 +4,10 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
@ -14,22 +15,25 @@
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/helpers.hpp"
#include "../helpers/invariants.hpp"
#include <iostream>
namespace erase_tests
{
test::seed_t seed(85638);
test::seed_t initialize_seed(85638);
template <class Container>
void erase_tests1(Container*,
test::random_generator generator = test::default_generator)
void erase_tests1(Container*, test::random_generator generator)
{
std::cerr<<"Erase by key.\n";
{
test::check_instances check_;
test::random_values<Container> v(1000, generator);
Container x(v.begin(), v.end());
int iterations = 0;
for(BOOST_DEDUCED_TYPENAME test::random_values<Container>::iterator
it = v.begin(); it != v.end(); ++it)
{
@ -39,14 +43,18 @@ void erase_tests1(Container*,
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());
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
}
}
std::cerr<<"erase(begin()).\n";
{
test::check_instances check_;
test::random_values<Container> v(1000, generator);
Container x(v.begin(), v.end());
std::size_t size = x.size();
int iterations = 0;
while(size > 0 && !x.empty())
{
BOOST_DEDUCED_TYPENAME Container::key_type
@ -58,15 +66,19 @@ void erase_tests1(Container*,
BOOST_TEST(pos == x.begin());
BOOST_TEST(x.count(key) == count - 1);
BOOST_TEST(x.size() == size);
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
}
BOOST_TEST(x.empty());
}
std::cerr<<"erase(random position).\n";
{
test::check_instances check_;
test::random_values<Container> v(1000, generator);
Container x(v.begin(), v.end());
std::size_t size = x.size();
int iterations = 0;
while(size > 0 && !x.empty())
{
using namespace std;
@ -90,12 +102,15 @@ void erase_tests1(Container*,
next == boost::next(prev));
BOOST_TEST(x.count(key) == count - 1);
BOOST_TEST(x.size() == size);
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
}
BOOST_TEST(x.empty());
}
std::cerr<<"erase(ranges).\n";
{
test::check_instances check_;
test::random_values<Container> v(500, generator);
Container x(v.begin(), v.end());
@ -108,19 +123,25 @@ void erase_tests1(Container*,
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);
test::check_equivalent_keys(x);
BOOST_TEST(x.erase(x.begin(), x.end()) == x.end());
BOOST_TEST(x.empty());
BOOST_TEST(x.begin() == x.end());
test::check_equivalent_keys(x);
BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin());
test::check_equivalent_keys(x);
}
std::cerr<<"quick_erase(begin()).\n";
{
test::check_instances check_;
test::random_values<Container> v(1000, generator);
Container x(v.begin(), v.end());
std::size_t size = x.size();
int iterations = 0;
while(size > 0 && !x.empty())
{
BOOST_DEDUCED_TYPENAME Container::key_type
@ -130,15 +151,19 @@ void erase_tests1(Container*,
--size;
BOOST_TEST(x.count(key) == count - 1);
BOOST_TEST(x.size() == size);
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
}
BOOST_TEST(x.empty());
}
std::cerr<<"quick_erase(random position).\n";
{
test::check_instances check_;
test::random_values<Container> v(1000, generator);
Container x(v.begin(), v.end());
std::size_t size = x.size();
int iterations = 0;
while(size > 0 && !x.empty())
{
using namespace std;
@ -162,6 +187,7 @@ void erase_tests1(Container*,
next == boost::next(prev));
BOOST_TEST(x.count(key) == count - 1);
BOOST_TEST(x.size() == size);
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
}
BOOST_TEST(x.empty());
}
@ -169,6 +195,8 @@ void erase_tests1(Container*,
std::cerr<<"clear().\n";
{
test::check_instances check_;
test::random_values<Container> v(500, generator);
Container x(v.begin(), v.end());
x.clear();
@ -181,16 +209,16 @@ void erase_tests1(Container*,
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_set;
test::allocator1<test::object> >* test_set;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multiset;
test::allocator2<test::object> >* test_multiset;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_map;
test::allocator1<test::object> >* test_map;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multimap;
test::allocator2<test::object> >* test_multimap;
using test::default_generator;
using test::generate_collisions;

View File

@ -4,9 +4,10 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
@ -16,14 +17,16 @@
namespace find_tests
{
test::seed_t seed(78937);
test::seed_t initialize_seed(78937);
template <class X>
void find_tests1(X*, test::random_generator generator = test::default_generator)
void find_tests1(X*, test::random_generator generator)
{
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
{
test::check_instances check_;
test::random_values<X> v(500, generator);
X x(v.begin(), v.end());
X const& x_const = x;
@ -69,6 +72,8 @@ void find_tests1(X*, test::random_generator generator = test::default_generator)
}
{
test::check_instances check_;
X x;
test::random_values<X> v2(5, generator);
@ -110,8 +115,7 @@ struct compatible_predicate
};
template <class X>
void find_compatible_keys_test(X*,
test::random_generator generator = test::default_generator)
void find_compatible_keys_test(X*, test::random_generator generator)
{
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
@ -137,16 +141,16 @@ void find_compatible_keys_test(X*,
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_set;
test::allocator2<test::object> >* test_set;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multiset;
test::allocator1<test::object> >* test_multiset;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_map;
test::allocator2<test::object> >* test_map;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multimap;
test::allocator1<test::object> >* test_multimap;
using test::default_generator;
using test::generate_collisions;

View File

@ -4,40 +4,57 @@
// 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>
#include "../helpers/postfix.hpp"
typedef boost::unordered_map<int, int> int_map;
void call_swap(int_map& x, int_map& y) {
template <typename T>
void call_swap(boost::unordered_map<T,T>& x,
boost::unordered_map<T,T>& y)
{
swap(x,y);
}
bool call_equals(int_map& x, int_map& y) {
template <typename T>
bool call_equals(boost::unordered_map<T,T>& x,
boost::unordered_map<T,T>& y)
{
return x == y;
}
bool call_not_equals(int_map& x, int_map& y) {
template <typename T>
bool call_not_equals(boost::unordered_map<T,T>& x,
boost::unordered_map<T,T>& y)
{
return x != y;
}
typedef boost::unordered_multimap<int, int> int_multimap;
void call_swap(int_multimap& x, int_multimap& y) {
template <typename T>
void call_swap(boost::unordered_multimap<T,T>& x,
boost::unordered_multimap<T,T>& y)
{
swap(x,y);
}
bool call_equals(int_multimap& x, int_multimap& y) {
template <typename T>
bool call_equals(boost::unordered_multimap<T,T>& x,
boost::unordered_multimap<T,T>& y)
{
return x == y;
}
bool call_not_equals(int_multimap& x, int_multimap& y) {
template <typename T>
bool call_not_equals(boost::unordered_multimap<T,T>& x,
boost::unordered_multimap<T,T>& y)
{
return x != y;
}
#include <boost/unordered_map.hpp>
#include "../helpers/test.hpp"
typedef boost::unordered_map<int, int> int_map;
typedef boost::unordered_multimap<int, int> int_multimap;
UNORDERED_AUTO_TEST(use_map_fwd_declared_function) {
int_map x, y;
x[1] = 2;

View File

@ -4,8 +4,8 @@
// 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>
#include "../helpers/postfix.hpp"
struct true_type { char x[100]; };
struct false_type { char x; };
@ -16,36 +16,53 @@ 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) {
template<typename T>
void call_swap(boost::unordered_set<T>& x,
boost::unordered_set<T>& y)
{
swap(x,y);
}
bool call_equals(int_set& x, int_set& y) {
template<typename T>
bool call_equals(boost::unordered_set<T>& x,
boost::unordered_set<T>& y)
{
return x == y;
}
bool call_not_equals(int_set& x, int_set& y) {
template<typename T>
bool call_not_equals(boost::unordered_set<T>& x,
boost::unordered_set<T>& y)
{
return x != y;
}
typedef boost::unordered_multiset<int> int_multiset;
void call_swap(int_multiset& x, int_multiset& y) {
template<typename T>
void call_swap(boost::unordered_multiset<T>& x,
boost::unordered_multiset<T>& y)
{
swap(x,y);
}
bool call_equals(int_multiset& x, int_multiset& y) {
template<typename T>
bool call_equals(boost::unordered_multiset<T>& x,
boost::unordered_multiset<T>& y)
{
return x == y;
}
bool call_not_equals(int_multiset& x, int_multiset& y) {
template<typename T>
bool call_not_equals(boost::unordered_multiset<T>& x,
boost::unordered_multiset<T>& y)
{
return x != y;
}
#include "../helpers/test.hpp"
typedef boost::unordered_set<int> int_set;
typedef boost::unordered_multiset<int> int_multiset;
UNORDERED_AUTO_TEST(use_fwd_declared_trait_without_definition) {
BOOST_TEST(sizeof(is_unordered_set_impl((int_set*) 0))
== sizeof(true_type));

View File

@ -4,35 +4,36 @@
// 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>
#include "../helpers/postfix.hpp"
#include <utility>
namespace x
{
struct D { boost::unordered_map<D, D> x; };
}
namespace test
namespace incomplete_test
{
// Declare, but don't define some types.
struct value;
struct hash;
struct equals;
template <class T>
struct malloc_allocator;
template <class T> struct allocator;
// Declare some instances
typedef boost::unordered_map<value, value, hash, equals,
malloc_allocator<std::pair<value const, value> > > map;
allocator<std::pair<value const, value> > > map;
typedef boost::unordered_multimap<value, value, hash, equals,
malloc_allocator<std::pair<value const, value> > > multimap;
allocator<std::pair<value const, value> > > multimap;
typedef boost::unordered_set<value, hash, equals,
malloc_allocator<value> > set;
allocator<value> > set;
typedef boost::unordered_multiset<value, hash, equals,
malloc_allocator<value> > multiset;
allocator<value> > multiset;
// Now define the types which are stored as members, as they are needed for
// declaring struct members.
@ -47,12 +48,17 @@ namespace test
bool operator()(T const&, T const&) const { return true; }
};
}
// This is a dubious way to implement an allocator, but good enough
// for this test.
template <typename T>
struct allocator : std::allocator<T> {
allocator() {}
#include "../helpers/allocator.hpp"
template <typename T2>
allocator(const allocator<T2>& other) :
std::allocator<T>(other) {}
};
namespace test
{
// Declare some members of a structs.
//
// Incomplete hash, equals and allocator aren't here supported at the
@ -60,19 +66,19 @@ namespace test
struct struct1 {
boost::unordered_map<struct1, struct1, hash, equals,
malloc_allocator<std::pair<struct1 const, struct1> > > x;
allocator<std::pair<struct1 const, struct1> > > x;
};
struct struct2 {
boost::unordered_multimap<struct2, struct2, hash, equals,
malloc_allocator<std::pair<struct2 const, struct2> > > x;
allocator<std::pair<struct2 const, struct2> > > x;
};
struct struct3 {
boost::unordered_set<struct3, hash, equals,
malloc_allocator<struct3> > x;
allocator<struct3> > x;
};
struct struct4 {
boost::unordered_multiset<struct4, hash, equals,
malloc_allocator<struct4> > x;
allocator<struct4> > x;
};
// Now define the value type.
@ -81,15 +87,15 @@ namespace test
// Create some instances.
test::map m1;
test::multimap m2;
test::set s1;
test::multiset s2;
incomplete_test::map m1;
incomplete_test::multimap m2;
incomplete_test::set s1;
incomplete_test::multiset s2;
test::struct1 c1;
test::struct2 c2;
test::struct3 c3;
test::struct4 c4;
incomplete_test::struct1 c1;
incomplete_test::struct2 c2;
incomplete_test::struct3 c3;
incomplete_test::struct4 c4;
// Now declare, but don't define, the operators required for comparing
// elements.
@ -111,7 +117,7 @@ namespace test
void use_types()
{
test::value x;
incomplete_test::value x;
m1[x] = x;
m2.insert(std::make_pair(x, x));
s1.insert(x);
@ -143,5 +149,5 @@ 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();
incomplete_test::use_types();
}

View File

@ -4,9 +4,10 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include <iostream>

View File

@ -4,9 +4,10 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
@ -15,17 +16,19 @@
#include "../helpers/equivalent.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/input_iterator.hpp"
#include "../helpers/helpers.hpp"
#include <iostream>
namespace insert_tests {
test::seed_t seed(243432);
test::seed_t initialize_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::check_instances check_;
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef test::ordered<X> ordered;
@ -52,7 +55,7 @@ void unique_insert_tests1(X*,
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -60,11 +63,13 @@ void unique_insert_tests1(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)
{
std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
test::check_instances check_;
X x;
test::ordered<X> tracker = test::create_ordered(x);
@ -83,7 +88,7 @@ void equivalent_insert_tests1(X*,
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -91,8 +96,7 @@ void equivalent_insert_tests1(X*,
}
template <class X>
void insert_tests2(X*,
test::random_generator generator = test::default_generator)
void insert_tests2(X*, test::random_generator generator)
{
typedef BOOST_DEDUCED_TYPENAME test::ordered<X> tracker_type;
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
@ -102,6 +106,8 @@ void insert_tests2(X*,
std::cerr<<"insert(begin(), value) tests.\n";
{
test::check_instances check_;
X x;
tracker_type tracker = test::create_ordered(x);
@ -118,7 +124,7 @@ void insert_tests2(X*,
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -128,6 +134,8 @@ void insert_tests2(X*,
std::cerr<<"insert(end(), value) tests.\n";
{
test::check_instances check_;
X x;
X const& x_const = x;
tracker_type tracker = test::create_ordered(x);
@ -145,7 +153,7 @@ void insert_tests2(X*,
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -155,6 +163,8 @@ void insert_tests2(X*,
std::cerr<<"insert(pos, value) tests.\n";
{
test::check_instances check_;
X x;
const_iterator pos = x.begin();
tracker_type tracker = test::create_ordered(x);
@ -172,7 +182,7 @@ void insert_tests2(X*,
BOOST_TEST(*pos == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -182,6 +192,8 @@ void insert_tests2(X*,
std::cerr<<"insert single item range tests.\n";
{
test::check_instances check_;
X x;
tracker_type tracker = test::create_ordered(x);
@ -197,7 +209,7 @@ void insert_tests2(X*,
tracker.insert(*it);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -207,6 +219,8 @@ void insert_tests2(X*,
std::cerr<<"insert range tests.\n";
{
test::check_instances check_;
X x;
test::random_values<X> v(1000, generator);
@ -216,9 +230,29 @@ void insert_tests2(X*,
test::check_equivalent_keys(x);
}
std::cerr<<"insert range with rehash tests.\n";
{
test::check_instances check_;
X x;
test::random_values<X> v(1000, generator);
x.insert(*v.begin());
x.clear();
x.insert(v.begin(), v.end());
test::check_container(x, v);
test::check_equivalent_keys(x);
}
std::cerr<<"insert input iterator range tests.\n";
{
test::check_instances check_;
X x;
test::random_values<X> v(1000, generator);
@ -233,6 +267,8 @@ void insert_tests2(X*,
std::cerr<<"insert copy iterator range tests.\n";
{
test::check_instances check_;
X x;
test::random_values<X> v(1000, generator);
@ -241,13 +277,25 @@ void insert_tests2(X*,
test::check_equivalent_keys(x);
}
std::cerr<<"insert copy iterator range test 2.\n";
{
test::check_instances check_;
X x;
test::random_values<X> v1(500, generator);
test::random_values<X> v2(500, generator);
x.insert(test::copy_iterator(v1.begin()), test::copy_iterator(v1.end()));
x.insert(test::copy_iterator(v2.begin()), test::copy_iterator(v2.end()));
test::check_equivalent_keys(x);
}
}
#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)
{
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef test::ordered<X> ordered;
@ -275,7 +323,7 @@ void unique_emplace_tests1(X*,
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -283,8 +331,7 @@ void unique_emplace_tests1(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)
{
std::cerr<<"emplace(value) tests for containers with equivalent keys.\n";
@ -306,17 +353,83 @@ void equivalent_emplace_tests1(X*,
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
#endif
template <class X>
void move_emplace_tests(X*, test::random_generator generator)
{
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef test::ordered<X> ordered;
std::cerr<<"emplace(move(value)) tests for containers with unique keys.\n";
X x;
test::ordered<X> 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)
{
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
typename X::value_type value = *it;
x.emplace(boost::move(value));
tracker.insert(*it);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
tracker.compare(x);
}
template <class X>
void map_tests(X*, test::random_generator generator = test::default_generator)
void default_emplace_tests(X*, test::random_generator)
{
std::cerr<<"emplace() tests.\n";
bool is_unique = test::has_unique_keys<X>::value;
X x;
x.emplace();
BOOST_TEST(x.size() == 1);
x.emplace();
BOOST_TEST(x.size() == is_unique ? 1: 2);
x.emplace();
BOOST_TEST(x.size() == is_unique ? 1: 3);
typename X::value_type y;
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 3);
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
x.emplace(y);
BOOST_TEST(x.size() == is_unique ? 1: 4);
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 4);
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
x.clear();
BOOST_TEST(x.empty());
x.emplace(y);
BOOST_TEST(x.size() == 1);
x.emplace(y);
BOOST_TEST(x.size() == is_unique ? 1: 2);
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 2);
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
}
template <class X>
void map_tests(X*, test::random_generator generator)
{
std::cerr<<"map tests.\n";
@ -335,7 +448,7 @@ void map_tests(X*, test::random_generator generator = test::default_generator)
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -346,11 +459,12 @@ void map_tests(X*, test::random_generator generator = test::default_generator)
// value type.
template <class X>
void map_insert_range_test1(X*,
test::random_generator generator = test::default_generator)
void map_insert_range_test1(X*, test::random_generator generator)
{
std::cerr<<"map_insert_range_test1\n";
test::check_instances check_;
typedef test::list<
std::pair<
BOOST_DEDUCED_TYPENAME X::key_type,
@ -366,16 +480,17 @@ void map_insert_range_test1(X*,
}
template <class X>
void map_insert_range_test2(X*,
test::random_generator generator = test::default_generator)
void map_insert_range_test2(X*, test::random_generator generator)
{
std::cerr<<"map_insert_range_test2\n";
test::check_instances check_;
typedef test::list<
std::pair<BOOST_DEDUCED_TYPENAME X::key_type const, int>
std::pair<BOOST_DEDUCED_TYPENAME X::key_type const, test::implicitly_convertible>
> list;
test::random_values<
boost::unordered_map<BOOST_DEDUCED_TYPENAME X::key_type, int>
boost::unordered_map<BOOST_DEDUCED_TYPENAME X::key_type, test::implicitly_convertible>
> v(1000, generator);
list l(v.begin(), v.end());
@ -384,48 +499,65 @@ void map_insert_range_test2(X*,
test::check_equivalent_keys(x);
}
boost::unordered_set<test::object,
boost::unordered_set<test::movable,
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;
std::allocator<test::movable> >* test_set_std_alloc;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multimap;
std::allocator<test::object> >* test_multimap_std_alloc;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::allocator1<test::object> >* test_set;
boost::unordered_multiset<test::movable,
test::hash, test::equal_to,
test::allocator2<test::movable> >* test_multiset;
boost::unordered_map<test::movable, test::movable,
test::hash, test::equal_to,
test::allocator2<test::movable> >* test_map;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator1<test::object> >* test_multimap;
using test::default_generator;
using test::generate_collisions;
UNORDERED_TEST(unique_insert_tests1,
((test_set)(test_map))
((test_set_std_alloc)(test_set)(test_map))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(equivalent_insert_tests1,
((test_multiset)(test_multimap))
((test_multimap_std_alloc)(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(insert_tests2,
((test_set)(test_multiset)(test_map)(test_multimap))
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
)
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
UNORDERED_TEST(unique_emplace_tests1,
((test_set)(test_map))
((test_set_std_alloc)(test_set)(test_map))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(equivalent_emplace_tests1,
((test_multiset)(test_multimap))
((test_multimap_std_alloc)(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(move_emplace_tests,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(default_emplace_tests,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
)
#endif
UNORDERED_TEST(map_tests,
((test_map))
@ -433,17 +565,31 @@ UNORDERED_TEST(map_tests,
)
UNORDERED_TEST(map_insert_range_test1,
((test_map)(test_multimap))
((test_multimap_std_alloc)(test_map)(test_multimap))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(map_insert_range_test2,
((test_map)(test_multimap))
((test_multimap_std_alloc)(test_map)(test_multimap))
((default_generator)(generate_collisions))
)
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
!defined(BOOST_NO_INITIALIZER_LISTS)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
struct initialize_from_two_ints
{
int a, b;
friend std::size_t hash_value(initialize_from_two_ints const& x)
{
return x.a + x.b;
}
bool operator==(initialize_from_two_ints const& x) const
{
return a == x.a && b == x.b;
}
};
UNORDERED_AUTO_TEST(insert_initializer_list_set)
{
@ -452,6 +598,30 @@ UNORDERED_AUTO_TEST(insert_initializer_list_set)
BOOST_TEST_EQ(set.size(), 3u);
BOOST_TEST(set.find(1) != set.end());
BOOST_TEST(set.find(4) == set.end());
boost::unordered_set<initialize_from_two_ints> set2;
set2.insert({1, 2});
BOOST_TEST(set2.size() == 1);
BOOST_TEST(set2.find({1,2}) != set2.end());
BOOST_TEST(set2.find({2,1}) == set2.end());
set2.insert({{3,4},{5,6},{7,8}});
BOOST_TEST(set2.size() == 4);
BOOST_TEST(set2.find({1,2}) != set2.end());
BOOST_TEST(set2.find({3,4}) != set2.end());
BOOST_TEST(set2.find({5,6}) != set2.end());
BOOST_TEST(set2.find({7,8}) != set2.end());
BOOST_TEST(set2.find({8,7}) == set2.end());
set2.insert({{2, 1}, {3,4}});
BOOST_TEST(set2.size() == 5);
BOOST_TEST(set2.find({1,2}) != set2.end());
BOOST_TEST(set2.find({2,1}) != set2.end());
BOOST_TEST(set2.find({3,4}) != set2.end());
BOOST_TEST(set2.find({5,6}) != set2.end());
BOOST_TEST(set2.find({7,8}) != set2.end());
BOOST_TEST(set2.find({8,7}) == set2.end());
}
UNORDERED_AUTO_TEST(insert_initializer_list_multiset)
@ -491,6 +661,124 @@ UNORDERED_AUTO_TEST(insert_initializer_list_multimap)
#endif
struct overloaded_constructor
{
overloaded_constructor(int x1 = 1, int x2 = 2, int x3 = 3, int x4 = 4)
: x1(x1), x2(x2), x3(x3), x4(x4) {}
int x1, x2, x3, x4;
bool operator==(overloaded_constructor const& rhs) const
{
return x1 == rhs.x1 && x2 == rhs.x2 && x3 == rhs.x3 && x4 == rhs.x4;
}
friend std::size_t hash_value(overloaded_constructor const& x)
{
std::size_t hash = 0;
boost::hash_combine(hash, x.x1);
boost::hash_combine(hash, x.x2);
boost::hash_combine(hash, x.x3);
boost::hash_combine(hash, x.x4);
return hash;
}
};
UNORDERED_AUTO_TEST(map_emplace_test)
{
boost::unordered_map<int, overloaded_constructor> x;
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
x.emplace();
BOOST_TEST(x.find(0) != x.end() &&
x.find(0)->second == overloaded_constructor());
#endif
x.emplace(2, 3);
BOOST_TEST(x.find(2) != x.end() &&
x.find(2)->second == overloaded_constructor(3));
}
UNORDERED_AUTO_TEST(set_emplace_test)
{
boost::unordered_set<overloaded_constructor> x;
overloaded_constructor check;
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
x.emplace();
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
#endif
x.clear();
x.emplace(1);
check = overloaded_constructor(1);
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
x.clear();
x.emplace(2, 3);
check = overloaded_constructor(2, 3);
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
x.clear();
x.emplace(4, 5, 6);
check = overloaded_constructor(4, 5, 6);
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
x.clear();
x.emplace(7, 8, 9, 10);
check = overloaded_constructor(7, 8, 9, 10);
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
}
struct derived_from_piecewise_construct_t :
boost::unordered::piecewise_construct_t {};
derived_from_piecewise_construct_t piecewise_rvalue() {
return derived_from_piecewise_construct_t();
}
struct convertible_to_piecewise {
operator boost::unordered::piecewise_construct_t() const {
return boost::unordered::piecewise_construct;
}
};
UNORDERED_AUTO_TEST(map_emplace_test2)
{
boost::unordered_map<overloaded_constructor, overloaded_constructor> x;
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), boost::make_tuple());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second == overloaded_constructor());
x.emplace(convertible_to_piecewise(), boost::make_tuple(1), boost::make_tuple());
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second == overloaded_constructor());
x.emplace(piecewise_rvalue(), boost::make_tuple(2,3), boost::make_tuple(4,5,6));
BOOST_TEST(x.find(overloaded_constructor(2,3)) != x.end() &&
x.find(overloaded_constructor(2,3))->second == overloaded_constructor(4,5,6));
derived_from_piecewise_construct_t d;
x.emplace(d, boost::make_tuple(9,3,1), boost::make_tuple(10));
BOOST_TEST(x.find(overloaded_constructor(9,3,1)) != x.end() &&
x.find(overloaded_constructor(9,3,1))->second == overloaded_constructor(10));
}
UNORDERED_AUTO_TEST(set_emplace_test2)
{
boost::unordered_set<std::pair<overloaded_constructor, overloaded_constructor> > x;
std::pair<overloaded_constructor, overloaded_constructor> check;
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), boost::make_tuple());
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
x.clear();
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(1), boost::make_tuple(2,3));
check = std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3));;
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
}
}
RUN_TESTS()

View File

@ -4,9 +4,9 @@
// 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/postfix.hpp"
void foo(boost::unordered_set<int>&,
boost::unordered_map<int, int>&,

View File

@ -4,9 +4,9 @@
// 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/postfix.hpp"
void foo(boost::unordered_set<int>& x1,
boost::unordered_map<int, int>& x2,

View File

@ -4,9 +4,10 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/limits.hpp>
#include "../helpers/random_values.hpp"
@ -19,10 +20,10 @@
namespace load_factor_tests
{
test::seed_t seed(783656);
test::seed_t initialize_seed(783656);
template <class X>
void set_load_factor_tests(X* = 0)
void set_load_factor_tests(X*)
{
X x;
@ -36,8 +37,7 @@ void set_load_factor_tests(X* = 0)
}
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)
{
X x;
x.max_load_factor(mlf);
@ -51,22 +51,24 @@ void insert_test(X*, float mlf,
BOOST_DEDUCED_TYPENAME X::size_type old_size = x.size(),
old_bucket_count = x.bucket_count();
x.insert(*it);
if(old_size + 1 < b * old_bucket_count)
if(static_cast<double>(old_size + 1) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
}
template <class X>
void load_factor_insert_tests(X* ptr = 0)
void load_factor_insert_tests(X* ptr, test::random_generator generator)
{
insert_test(ptr, 1.0f);
insert_test(ptr, 0.1f);
insert_test(ptr, 100.0f);
insert_test(ptr, 1.0f, generator);
insert_test(ptr, 0.1f, generator);
insert_test(ptr, 100.0f, generator);
insert_test(ptr, (std::numeric_limits<float>::min)());
insert_test(ptr, (std::numeric_limits<float>::min)(),
generator);
if(std::numeric_limits<float>::has_infinity)
insert_test(ptr, std::numeric_limits<float>::infinity());
insert_test(ptr, std::numeric_limits<float>::infinity(),
generator);
}
boost::unordered_set<int>* int_set_ptr;
@ -74,12 +76,16 @@ boost::unordered_multiset<int>* int_multiset_ptr;
boost::unordered_map<int, int>* int_map_ptr;
boost::unordered_multimap<int, int>* int_multimap_ptr;
using test::default_generator;
using test::generate_collisions;
UNORDERED_TEST(set_load_factor_tests,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
)
UNORDERED_TEST(load_factor_insert_tests,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
)
}

View File

@ -0,0 +1,95 @@
// Copyright 2011 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered/detail/allocate.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>
#include "../objects/test.hpp"
template <class Tp>
struct SimpleAllocator
{
typedef Tp value_type;
SimpleAllocator()
{
}
template <class T> SimpleAllocator(const SimpleAllocator<T>& other)
{
}
Tp *allocate(std::size_t n)
{
return static_cast<Tp*>(::operator new(n * sizeof(Tp)));
}
void deallocate(Tp* p, std::size_t)
{
::operator delete((void*) p);
}
};
template <typename T>
void test_simple_allocator()
{
test::check_instances check_;
typedef boost::unordered::detail::allocator_traits<
SimpleAllocator<T> > traits;
BOOST_STATIC_ASSERT((boost::is_same<typename traits::allocator_type, SimpleAllocator<T> >::value));
BOOST_STATIC_ASSERT((boost::is_same<typename traits::value_type, T>::value));
BOOST_STATIC_ASSERT((boost::is_same<typename traits::pointer, T* >::value));
BOOST_STATIC_ASSERT((boost::is_same<typename traits::const_pointer, T const*>::value));
//BOOST_STATIC_ASSERT((boost::is_same<typename traits::void_pointer, void* >::value));
//BOOST_STATIC_ASSERT((boost::is_same<typename traits::const_void_pointer, void const*>::value));
BOOST_STATIC_ASSERT((boost::is_same<typename traits::difference_type, std::ptrdiff_t>::value));
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
BOOST_STATIC_ASSERT((boost::is_same<typename traits::size_type,
std::make_unsigned<std::ptrdiff_t>::type>::value));
#else
BOOST_STATIC_ASSERT((boost::is_same<typename traits::size_type, std::size_t>::value));
#endif
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
BOOST_TEST(!traits::propagate_on_container_swap::value);
// rebind_alloc
// rebind_traits
SimpleAllocator<T> a;
T* ptr1 = traits::allocate(a, 1);
//T* ptr2 = traits::allocate(a, 1, static_cast<void const*>(ptr1));
traits::construct(a, ptr1, T(10));
//traits::construct(a, ptr2, T(30), ptr1);
BOOST_TEST(*ptr1 == T(10));
//BOOST_TEST(*ptr2 == T(30));
traits::destroy(a, ptr1);
//traits::destroy(a, ptr2);
//traits::deallocate(a, ptr2, 1);
traits::deallocate(a, ptr1, 1);
traits::max_size(a);
}
int main()
{
test_simple_allocator<int>();
test_simple_allocator<test::object>();
return boost::report_errors();
}

View File

@ -4,19 +4,30 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../objects/cxx11_allocator.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/invariants.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable:4127) // conditional expression is constant
#endif
namespace move_tests
{
test::seed_t seed(98624);
test::seed_t initialize_seed(98624);
#if defined(BOOST_UNORDERED_USE_MOVE) || !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#define BOOST_UNORDERED_TEST_MOVING 1
#else
#define BOOST_UNORDERED_TEST_MOVING 0
#endif
template<class T>
T empty(T*) {
@ -46,14 +57,15 @@ 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)
{
BOOST_DEDUCED_TYPENAME T::hasher hf;
BOOST_DEDUCED_TYPENAME T::key_equal eq;
BOOST_DEDUCED_TYPENAME T::allocator_type al;
{
test::check_instances check_;
T y(empty(ptr));
BOOST_TEST(y.empty());
BOOST_TEST(test::equivalent(y.hash_function(), hf));
@ -64,6 +76,8 @@ namespace move_tests
}
{
test::check_instances check_;
test::random_values<T> v(1000, generator);
test::object_count count;
T y(create(v, count));
@ -76,15 +90,16 @@ namespace move_tests
}
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::check_instances check_;
test::random_values<T> v(500, generator);
test::object_count count;
T y;
y = create(v, count);
#if defined(BOOST_HAS_NRVO)
#if BOOST_UNORDERED_TEST_MOVING && defined(BOOST_HAS_NRVO)
BOOST_TEST(count == test::global_object_count);
#endif
test::check_container(y, v);
@ -93,8 +108,7 @@ namespace move_tests
}
template <class T>
void move_construct_tests2(T*,
test::random_generator const& generator = test::default_generator)
void move_construct_tests2(T*, test::random_generator const& generator)
{
BOOST_DEDUCED_TYPENAME T::hasher hf(1);
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
@ -104,6 +118,8 @@ namespace move_tests
test::object_count count;
{
test::check_instances check_;
test::random_values<T> v(500, generator);
T y(create(v, count, hf, eq, al, 0.5));
#if defined(BOOST_HAS_NRVO)
@ -118,6 +134,8 @@ namespace move_tests
}
{
test::check_instances check_;
// TODO: To do this correctly requires the fancy new allocator
// stuff.
test::random_values<T> v(500, generator);
@ -130,16 +148,27 @@ namespace move_tests
BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required.
test::check_equivalent_keys(y);
}
/*
{
test::check_instances check_;
test::random_values<T> v(25, generator);
T y(create(v, count, hf, eq, al, 1.0), al);
#if !defined(BOOST_NO_RVALUE_REFERENCES)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
BOOST_TEST(count == test::global_object_count);
#elif defined(BOOST_HAS_NRVO)
BOOST_TEST(
static_cast<std::size_t>(test::global_object_count.constructions
- count.constructions) <=
(test::is_set<T>::value ? 1 : 2) *
(test::has_unique_keys<T>::value ? 25 : v.size()));
BOOST_TEST(count.instances == test::global_object_count.instances);
#else
BOOST_TEST(
test::global_object_count.constructions - count.constructions <=
(test::is_map<T>::value ? 50 : 25));
static_cast<std::size_t>(test::global_object_count.constructions
- count.constructions) <=
(test::is_set<T>::value ? 2 : 4) *
(test::has_unique_keys<T>::value ? 25 : v.size()));
BOOST_TEST(count.instances == test::global_object_count.instances);
#endif
test::check_container(y, v);
@ -149,32 +178,226 @@ namespace move_tests
BOOST_TEST(y.max_load_factor() == 1.0); // Not necessarily required.
test::check_equivalent_keys(y);
}
*/ }
}
template <class T>
void move_assign_tests2(T*, test::random_generator const& generator)
{
BOOST_DEDUCED_TYPENAME T::hasher hf(1);
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
{
test::random_values<T> v(500, generator);
test::random_values<T> v2(0, generator);
T y(v.begin(), v.end(), 0, hf, eq, al1);
test::object_count count;
y = create(v2, count, hf, eq, al2, 2.0);
BOOST_TEST(y.empty());
test::check_container(y, v2);
test::check_equivalent_keys(y);
BOOST_TEST(y.max_load_factor() == 2.0);
#if defined(BOOST_HAS_NRVO)
if (BOOST_UNORDERED_TEST_MOVING ?
(bool) allocator_type::is_propagate_on_move :
(bool) allocator_type::is_propagate_on_assign)
{
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
}
else {
BOOST_TEST(test::equivalent(y.get_allocator(), al1));
}
#endif
}
{
test::random_values<T> v(500, generator);
test::object_count count;
T y(0, hf, eq, al1);
y = create(v, count, hf, eq, al2, 0.5);
#if defined(BOOST_HAS_NRVO)
if (BOOST_UNORDERED_TEST_MOVING &&
allocator_type::is_propagate_on_move)
{
BOOST_TEST(count == test::global_object_count);
}
#endif
test::check_container(y, v);
test::check_equivalent_keys(y);
BOOST_TEST(y.max_load_factor() == 0.5);
#if defined(BOOST_HAS_NRVO)
if (BOOST_UNORDERED_TEST_MOVING ?
(bool) allocator_type::is_propagate_on_move :
(bool) allocator_type::is_propagate_on_assign)
{
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
}
else {
BOOST_TEST(test::equivalent(y.get_allocator(), al1));
}
#endif
}
{
test::check_instances check_;
test::random_values<T> v(500, generator);
T y(0, hf, eq, al1);
T x(0, hf, eq, al2);
x.max_load_factor(0.25);
x.insert(v.begin(), v.end());
test::object_count count = test::global_object_count;
y = boost::move(x);
if (BOOST_UNORDERED_TEST_MOVING &&
allocator_type::is_propagate_on_move)
{
BOOST_TEST(count == test::global_object_count);
}
test::check_container(y, v);
test::check_equivalent_keys(y);
BOOST_TEST(y.max_load_factor() == 0.25);
if (BOOST_UNORDERED_TEST_MOVING ?
(bool) allocator_type::is_propagate_on_move :
(bool) allocator_type::is_propagate_on_assign)
{
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
}
else {
BOOST_TEST(test::equivalent(y.get_allocator(), al1));
}
}
{
test::check_instances check_;
test::random_values<T> v1(1000, generator);
test::random_values<T> v2(200, generator);
T x(0, hf, eq, al2);
x.max_load_factor(0.5);
x.insert(v2.begin(), v2.end());
test::object_count count1 = test::global_object_count;
T y(v1.begin(), v1.end(), 0, hf, eq, al1);
y = boost::move(x);
test::object_count count2 = test::global_object_count;
if (BOOST_UNORDERED_TEST_MOVING &&
allocator_type::is_propagate_on_move)
{
BOOST_TEST(count1.instances ==
test::global_object_count.instances);
BOOST_TEST(count2.constructions ==
test::global_object_count.constructions);
}
test::check_container(y, v2);
test::check_equivalent_keys(y);
BOOST_TEST(y.max_load_factor() == 0.5);
if (BOOST_UNORDERED_TEST_MOVING ?
(bool) allocator_type::is_propagate_on_move :
(bool) allocator_type::is_propagate_on_assign)
{
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
}
else {
BOOST_TEST(test::equivalent(y.get_allocator(), al1));
}
}
}
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
std::allocator<test::object> >* test_map_std_alloc;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_set;
test::allocator2<test::object> >* test_set;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multiset;
test::allocator1<test::object> >* test_multiset;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_map;
test::allocator1<test::object> >* test_map;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator<test::object> >* test_multimap;
test::allocator2<test::object> >* test_multimap;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_move> >*
test_set_prop_move;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_move> >*
test_multiset_prop_move;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_move> >*
test_map_prop_move;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_move> >*
test_multimap_prop_move;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_move> >*
test_set_no_prop_move;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_move> >*
test_multiset_no_prop_move;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_move> >*
test_map_no_prop_move;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_move> >*
test_multimap_no_prop_move;
using test::default_generator;
using test::generate_collisions;
UNORDERED_TEST(move_construct_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
UNORDERED_TEST(move_construct_tests1, (
(test_map_std_alloc)
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
)
UNORDERED_TEST(move_assign_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
UNORDERED_TEST(move_assign_tests1, (
(test_map_std_alloc)
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
)
UNORDERED_TEST(move_construct_tests2,
((test_set)(test_multiset)(test_map)(test_multimap))
UNORDERED_TEST(move_construct_tests2, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
)
UNORDERED_TEST(move_assign_tests2, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
)
}

View File

@ -0,0 +1,125 @@
// Copyright 2013 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/postfix.hpp"
#include "../helpers/test.hpp"
namespace noexcept_tests
{
// Test the noexcept is set correctly for the move constructor.
struct hash_possible_exception : boost::hash<int>
{
hash_possible_exception(hash_possible_exception const&) {}
};
struct equal_to_possible_exception : std::equal_to<int>
{
equal_to_possible_exception(equal_to_possible_exception const&) {}
};
UNORDERED_AUTO_TEST(test_noexcept)
{
#if !defined(BOOST_NO_CXX11_NOEXCEPT)
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_set<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multiset<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_map<int, int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multimap<int, int> >::value));
#endif
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_set<int, hash_possible_exception>
>::value));
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_multiset<int, boost::hash<int>,
equal_to_possible_exception>
>::value));
}
// Test that the move constructor does actually move without throwing
// an exception when it claims to.
struct test_exception {};
bool throwing_test_exception = false;
void test_throw(char const* name) {
if (throwing_test_exception) {
std::cerr << "Throw exception in: " << name << std::endl;
throw test_exception();
}
}
class hash_nothrow_move : boost::hash<int>
{
BOOST_COPYABLE_AND_MOVABLE(hash_nothrow_move)
typedef boost::hash<int> base;
public:
hash_nothrow_move(BOOST_RV_REF(hash_nothrow_move))
BOOST_NOEXCEPT {}
hash_nothrow_move() { test_throw("Constructor"); }
hash_nothrow_move(hash_nothrow_move const& x) { test_throw("Copy"); }
hash_nothrow_move& operator=(hash_nothrow_move const&)
{ test_throw("Assign"); return *this; }
std::size_t operator()(int x) const
{ test_throw("Operator"); return static_cast<base const&>(*this)(x); }
};
class equal_to_nothrow_move : std::equal_to<int>
{
BOOST_COPYABLE_AND_MOVABLE(equal_to_nothrow_move)
typedef std::equal_to<int> base;
public:
equal_to_nothrow_move(BOOST_RV_REF(equal_to_nothrow_move))
BOOST_NOEXCEPT {}
equal_to_nothrow_move() { test_throw("Constructor"); }
equal_to_nothrow_move(equal_to_nothrow_move const& x)
{ test_throw("Copy"); }
equal_to_nothrow_move& operator=(equal_to_nothrow_move const&)
{ test_throw("Assign"); return *this; }
std::size_t operator()(int x, int y) const
{ test_throw("Operator"); return static_cast<base const&>(*this)(x, y); }
};
UNORDERED_AUTO_TEST(test_no_throw_when_noexcept)
{
typedef boost::unordered_set<int,
hash_nothrow_move, equal_to_nothrow_move> throwing_set;
if (boost::is_nothrow_move_constructible<throwing_set>::value)
{
throwing_test_exception = false;
throwing_set x1;
x1.insert(10);
x1.insert(50);
try {
throwing_test_exception = true;
throwing_set x2 = boost::move(x1);
BOOST_TEST(x2.size() == 2);
BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
} catch(test_exception) {
BOOST_TEST(false);
}
throwing_test_exception = false;
}
}
}
RUN_TESTS()

View File

@ -4,27 +4,31 @@
// 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/postfix.hpp"
#include "../helpers/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/metafunctions.hpp"
#include "../objects/test.hpp"
namespace rehash_tests
{
test::seed_t seed(2974);
test::seed_t initialize_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() &&
return static_cast<double>(x.bucket_count()) >
static_cast<double>(x.size()) / x.max_load_factor() &&
x.bucket_count() >= n;
}
template <class X>
void rehash_empty_test1(X* = 0)
void rehash_empty_test1(X*)
{
X x;
@ -33,11 +37,13 @@ void rehash_empty_test1(X* = 0)
x.rehash(0);
BOOST_TEST(postcondition(x, 0));
x.rehash(10000000);
BOOST_TEST(postcondition(x, 10000000));
}
template <class X>
void rehash_empty_test2(X* = 0,
test::random_generator generator = test::default_generator)
void rehash_empty_test2(X*, test::random_generator generator)
{
test::random_values<X> v(1000, generator);
test::ordered<X> tracker;
@ -52,11 +58,14 @@ void rehash_empty_test2(X* = 0,
tracker.compare(x);
BOOST_TEST(postcondition(x, 10000));
x.rehash(10000000);
tracker.compare(x);
BOOST_TEST(postcondition(x, 10000000));
}
template <class X>
void rehash_empty_test3(X* = 0,
test::random_generator generator = test::default_generator)
void rehash_empty_test3(X*, test::random_generator generator)
{
test::random_values<X> v(1000, generator);
test::ordered<X> tracker;
@ -73,10 +82,8 @@ void rehash_empty_test3(X* = 0,
BOOST_TEST(postcondition(x, 0));
}
template <class X>
void rehash_test1(X* = 0,
test::random_generator generator = test::default_generator)
void rehash_test1(X*, test::random_generator generator)
{
test::random_values<X> v(1000, generator);
test::ordered<X> tracker;
@ -98,22 +105,141 @@ void rehash_test1(X* = 0,
tracker.compare(x);
}
template <class X>
void reserve_empty_test1(X*)
{
X x;
x.reserve(10000);
BOOST_TEST(x.bucket_count() >= 10000);
x.reserve(0);
x.reserve(10000000);
BOOST_TEST(x.bucket_count() >= 10000000);
}
template <class X>
void reserve_empty_test2(X*)
{
X x;
x.max_load_factor(0.25);
x.reserve(10000);
BOOST_TEST(x.bucket_count() >= 40000);
x.reserve(0);
x.reserve(10000000);
BOOST_TEST(x.bucket_count() >= 40000000);
}
template <class X>
void reserve_test1(X*, test::random_generator generator)
{
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
{
for (int i = 1; i < 2000; i += i < 50 ? 1 : 13)
{
test::random_values<X> v(i, generator);
test::ordered<X> tracker;
tracker.insert_range(v.begin(), v.end());
X x;
x.max_load_factor(random_mlf ?
static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f : 1.0f);
// For the current standard this should reserve i+1, I've
// submitted a defect report and will assume it's a defect
// for now.
x.reserve(test::has_unique_keys<X>::value ? i : v.size());
// Insert an element before the range insert, otherwise there are
// no iterators to invalidate in the range insert, and it can
// rehash.
typename test::random_values<X>::iterator it = v.begin();
x.insert(*it);
++it;
std::size_t bucket_count = x.bucket_count();
x.insert(it, v.end());
BOOST_TEST(bucket_count == x.bucket_count());
tracker.compare(x);
}
}
}
template <class X>
void reserve_test2(X*, test::random_generator generator)
{
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
{
for (int i = 0; i < 2000; i += i < 50 ? 1 : 13)
{
test::random_values<X> v(i, generator);
test::ordered<X> tracker;
tracker.insert_range(v.begin(), v.end());
X x;
x.max_load_factor(random_mlf ?
static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f : 1.0f);
x.reserve(test::has_unique_keys<X>::value ? i : v.size());
std::size_t bucket_count = x.bucket_count();
for (typename test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it)
{
x.insert(*it);
}
BOOST_TEST(bucket_count == x.bucket_count());
tracker.compare(x);
}
}
}
boost::unordered_set<int>* int_set_ptr;
boost::unordered_multiset<int>* int_multiset_ptr;
boost::unordered_map<int, int>* int_map_ptr;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::allocator2<test::object> >* test_multiset_ptr;
boost::unordered_map<test::movable, test::movable,
test::hash, test::equal_to,
test::allocator2<test::movable> >* test_map_ptr;
boost::unordered_multimap<int, int>* int_multimap_ptr;
using test::default_generator;
using test::generate_collisions;
UNORDERED_TEST(rehash_empty_test1,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
)
UNORDERED_TEST(rehash_empty_test2,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(rehash_empty_test3,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(rehash_test1,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(reserve_empty_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
)
UNORDERED_TEST(reserve_empty_test2,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
)
UNORDERED_TEST(reserve_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
)
UNORDERED_TEST(reserve_test2,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
)
}

View File

@ -6,9 +6,10 @@
// This test checks the runtime requirements of containers.
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <cstdlib>
#include <algorithm>

View File

@ -4,22 +4,28 @@
// 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/postfix.hpp"
#include <boost/config.hpp>
#include <algorithm>
#include <iterator>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../objects/cxx11_allocator.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/invariants.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable:4127) // conditional expression is constant
#endif
namespace swap_tests
{
test::seed_t seed(783472);
test::seed_t initialize_seed(783472);
template <class X>
void swap_test_impl(X& x1, X& x2)
@ -34,19 +40,25 @@ void swap_test_impl(X& x1, X& x2)
}
template <class X>
void swap_tests1(X*, test::random_generator generator = test::default_generator)
void swap_tests1(X*, test::random_generator generator)
{
{
test::check_instances check_;
X x;
swap_test_impl(x, x);
}
{
test::check_instances check_;
X x,y;
swap_test_impl(x, y);
}
{
test::check_instances check_;
test::random_values<X> v(1000, generator);
X x, y(v.begin(), v.end());
swap_test_impl(x, y);
@ -54,6 +66,8 @@ void swap_tests1(X*, test::random_generator generator = test::default_generator)
}
{
test::check_instances check_;
test::random_values<X> vx(1000, generator), vy(1000, generator);
X x(vx.begin(), vx.end()), y(vy.begin(), vy.end());
swap_test_impl(x, y);
@ -62,22 +76,25 @@ 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, test::random_generator generator)
{
swap_tests1(ptr);
swap_tests1(ptr, generator);
typedef BOOST_DEDUCED_TYPENAME X::hasher hasher;
typedef BOOST_DEDUCED_TYPENAME X::key_equal key_equal;
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
{
test::check_instances check_;
X x(0, hasher(1), key_equal(1));
X y(0, hasher(2), key_equal(2));
swap_test_impl(x, y);
}
{
test::check_instances check_;
test::random_values<X> v(1000, generator);
X x(v.begin(), v.end(), 0, hasher(1), key_equal(1));
X y(0, hasher(2), key_equal(2));
@ -85,6 +102,8 @@ void swap_tests2(X* ptr = 0,
}
{
test::check_instances check_;
test::random_values<X> vx(100, generator), vy(50, generator);
X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1));
X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2));
@ -92,56 +111,124 @@ void swap_tests2(X* ptr = 0,
swap_test_impl(x, y);
}
#if BOOST_UNORDERED_SWAP_METHOD == 1
{
test::random_values<X> vx(100, generator), vy(50, generator);
X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
try {
swap_test_impl(x, y);
BOOST_ERROR("Using swap method 1, "
"swapping with unequal allocators didn't throw.");
} catch (std::runtime_error) {}
}
#else
{
test::force_equal_allocator force_(
!allocator_type::is_propagate_on_swap);
test::check_instances check_;
test::random_values<X> vx(50, generator), vy(100, generator);
X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
swap_test_impl(x, y);
if (allocator_type::is_propagate_on_swap ||
x.get_allocator() == y.get_allocator())
{
swap_test_impl(x, y);
}
}
{
test::force_equal_allocator force_(
!allocator_type::is_propagate_on_swap);
test::check_instances check_;
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));
swap_test_impl(x, y);
swap_test_impl(x, y);
if (allocator_type::is_propagate_on_swap ||
x.get_allocator() == y.get_allocator())
{
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;
test::hash, test::equal_to,
std::allocator<test::object> >* test_map_std_alloc;
UNORDERED_TEST(swap_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::allocator1<test::object> >* test_set;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::allocator2<test::object> >* test_multiset;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::allocator1<test::object> >* test_map;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::allocator2<test::object> >* test_multimap;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_swap> >*
test_set_prop_swap;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_swap> >*
test_multiset_prop_swap;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_swap> >*
test_map_prop_swap;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::propagate_swap> >*
test_multimap_prop_swap;
boost::unordered_set<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
test_set_no_prop_swap;
boost::unordered_multiset<test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
test_multiset_no_prop_swap;
boost::unordered_map<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
test_map_no_prop_swap;
boost::unordered_multimap<test::object, test::object,
test::hash, test::equal_to,
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
test_multimap_no_prop_swap;
template <typename T>
bool is_propagate(T*)
{
return T::allocator_type::is_propagate_on_swap;
}
using test::default_generator;
using test::generate_collisions;
UNORDERED_AUTO_TEST(check_traits)
{
BOOST_TEST(!is_propagate(test_set));
BOOST_TEST(is_propagate(test_set_prop_swap));
BOOST_TEST(!is_propagate(test_set_no_prop_swap));
}
UNORDERED_TEST(swap_tests1, (
(test_map_std_alloc)
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
(test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
)
((default_generator)(generate_collisions))
)
UNORDERED_TEST(swap_tests2,
((test_set)(test_multiset)(test_map)(test_multimap))
UNORDERED_TEST(swap_tests2, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
(test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
)
((default_generator)(generate_collisions))
)
}

View File

@ -4,19 +4,33 @@
// 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/postfix.hpp"
#include <iostream>
#include "../helpers/test.hpp"
namespace unnecessary_copy_tests
{
struct count_copies
{
private:
BOOST_COPYABLE_AND_MOVABLE(count_copies)
public:
static int copies;
static int moves;
count_copies() : tag_(0) { ++copies; }
explicit count_copies(int tag) : tag_(tag) { ++copies; }
static int id_count;
count_copies() : tag_(0), id_(++id_count) {
++copies;
trace_op("Default construct");
}
explicit count_copies(int tag) : tag_(tag), id_(++id_count) {
++copies;
trace_op("Tag construct");
}
// This bizarre constructor is an attempt to confuse emplace.
//
@ -28,17 +42,52 @@ namespace unnecessary_copy_tests
// The second emplace should use the single argument contructor for
// the key, and this constructor for the value.
count_copies(count_copies const&, count_copies const& x)
: tag_(x.tag_) { ++copies; }
count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; }
#if !defined(BOOST_NO_RVALUE_REFERENCES)
count_copies(count_copies&& x) : tag_(x.tag_) {
x.tag_ = -1; ++moves;
: tag_(x.tag_), id_(++id_count)
{
++copies;
trace_op("Pair construct");
}
#endif
int tag_;
private:
count_copies& operator=(count_copies const&);
count_copies(count_copies const& x) : tag_(x.tag_), id_(++id_count)
{
++copies;
trace_op("Copy construct");
}
count_copies(BOOST_RV_REF(count_copies) x) :
tag_(x.tag_), id_(++id_count)
{
x.tag_ = -1; ++moves;
trace_op("Move construct");
}
count_copies& operator=(BOOST_COPY_ASSIGN_REF(count_copies) p) // Copy assignment
{
tag_ = p.tag_;
++copies;
trace_op("Copy assign");
return *this;
}
count_copies& operator=(BOOST_RV_REF(count_copies) p) //Move assignment
{
tag_ = p.tag_;
++moves;
trace_op("Move assign");
return *this;
}
~count_copies() {
trace_op("Destruct");
}
void trace_op(char const* str) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << str << ": " << tag_
<< " (#" << id_ << ")" <<std::endl;
}
int tag_;
int id_;
};
bool operator==(count_copies const& x, count_copies const& y) {
@ -53,6 +102,9 @@ namespace unnecessary_copy_tests
void reset() {
count_copies::copies = 0;
count_copies::moves = 0;
BOOST_LIGHTWEIGHT_TEST_OSTREAM
<< "\nReset\n" << std::endl;
}
}
@ -68,31 +120,37 @@ namespace unnecessary_copy_tests
}
#define COPY_COUNT(n) \
if(count_copies::copies != n) { \
if(::unnecessary_copy_tests::count_copies::copies != n) { \
BOOST_ERROR("Wrong number of copies."); \
std::cerr \
<< "Number of copies: " << count_copies::copies \
<< "Number of copies: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: " << n << std::endl; \
}
#define MOVE_COUNT(n) \
if(count_copies::moves != n) { \
if(::unnecessary_copy_tests::count_copies::moves != n) { \
BOOST_ERROR("Wrong number of moves."); \
std::cerr \
<< "Number of moves: " << count_copies::moves \
<< "Number of moves: " \
<< ::unnecessary_copy_tests::count_copies::moves \
<< " expecting: " <<n << std::endl; \
}
#define COPY_COUNT_RANGE(a, b) \
if(count_copies::copies < a || count_copies::copies > b) { \
if(::unnecessary_copy_tests::count_copies::copies < a || \
::unnecessary_copy_tests::count_copies::copies > b) { \
BOOST_ERROR("Wrong number of copies."); \
std::cerr \
<< "Number of copies: " << count_copies::copies \
<< "Number of copies: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
}
#define MOVE_COUNT_RANGE(a, b) \
if(count_copies::moves < a || count_copies::moves > b) { \
if(::unnecessary_copy_tests::count_copies::moves < a || \
::unnecessary_copy_tests::count_copies::moves > b) { \
BOOST_ERROR("Wrong number of moves."); \
std::cerr \
<< "Number of moves: " << count_copies::copies \
<< "Number of moves: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
}
@ -100,6 +158,7 @@ namespace unnecessary_copy_tests
{
int count_copies::copies;
int count_copies::moves;
int count_copies::id_count;
template <class T>
void unnecessary_copy_insert_test(T*)
@ -136,7 +195,7 @@ 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)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(1);
#else
COPY_COUNT(2);
@ -148,7 +207,6 @@ namespace unnecessary_copy_tests
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*)
{
@ -156,17 +214,62 @@ namespace unnecessary_copy_tests
T x;
BOOST_DEDUCED_TYPENAME T::value_type a;
COPY_COUNT(1); MOVE_COUNT(0);
x.emplace(std::move(a));
x.emplace(boost::move(a));
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(1); MOVE_COUNT(1);
#else
// Since std::pair isn't movable, move only works for sets.
COPY_COUNT_RANGE(1, 2); MOVE_COUNT_RANGE(0, 1);
#endif
}
UNORDERED_TEST(unnecessary_copy_emplace_move_test,
((set)(multiset)(map)(multimap)))
template <class T>
void unnecessary_copy_emplace_boost_move_set_test(T*)
{
reset();
T x;
BOOST_DEDUCED_TYPENAME T::value_type a;
COPY_COUNT(1); MOVE_COUNT(0);
x.emplace(boost::move(a));
COPY_COUNT(1); MOVE_COUNT(1);
}
UNORDERED_TEST(unnecessary_copy_emplace_boost_move_set_test,
((set)(multiset)))
template <class T>
void unnecessary_copy_emplace_boost_move_map_test(T*)
{
reset();
T x;
COPY_COUNT(0); MOVE_COUNT(0);
BOOST_DEDUCED_TYPENAME T::value_type a;
COPY_COUNT(1); MOVE_COUNT(0);
x.emplace(boost::move(a));
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(2); MOVE_COUNT(0);
#else
COPY_COUNT(1); MOVE_COUNT(1);
#endif
}
UNORDERED_TEST(unnecessary_copy_emplace_boost_move_map_test,
((map)(multimap)))
UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
{
// When calling 'source' the object is moved on some compilers, but not
// others. So count that here to adjust later.
reset();
source<count_copies>();
int source_cost = ::unnecessary_copy_tests::count_copies::moves;
//
reset();
boost::unordered_set<count_copies> x;
count_copies a;
@ -177,11 +280,19 @@ namespace unnecessary_copy_tests
// 0 arguments
//
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
// The container will have to create a copy in order to compare with
// the existing element.
reset();
x.emplace();
COPY_COUNT(1); MOVE_COUNT(0);
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
// source_cost doesn't make much sense here, but it seems to fit.
COPY_COUNT(1); MOVE_COUNT(source_cost);
#else
COPY_COUNT(1); MOVE_COUNT(1 + source_cost);
#endif
#endif
//
// 1 argument
@ -197,16 +308,18 @@ namespace unnecessary_copy_tests
// copied.
reset();
x.emplace(source<count_copies>());
COPY_COUNT(1); MOVE_COUNT(0);
COPY_COUNT(1); MOVE_COUNT(source_cost);
#if !defined(BOOST_NO_RVALUE_REFERENCES)
// No move should take place.
reset();
x.emplace(std::move(a));
x.emplace(boost::move(a));
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(0); MOVE_COUNT(0);
#else
COPY_COUNT(0); MOVE_COUNT(1);
#endif
// Just in case a did get moved...
// Use a new value for cases where a did get moved...
count_copies b;
// The container will have to create a copy in order to compare with
@ -233,6 +346,19 @@ namespace unnecessary_copy_tests
UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test)
{
// When calling 'source' the object is moved on some compilers, but not
// others. So count that here to adjust later.
reset();
source<count_copies>();
int source_cost = ::unnecessary_copy_tests::count_copies::moves;
reset();
source<std::pair<count_copies, count_copies> >();
int source_pair_cost = ::unnecessary_copy_tests::count_copies::moves;
//
reset();
boost::unordered_map<count_copies, count_copies> x;
// TODO: Run tests for pairs without const etc.
@ -244,10 +370,28 @@ namespace unnecessary_copy_tests
// 0 arguments
//
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
// COPY_COUNT(1) would be okay here.
reset();
x.emplace();
# if BOOST_WORKAROUND(BOOST_MSVC, == 1700)
// This is a little odd, Visual C++ 11 seems to move the pair, which
// results in one copy (for the const key) and one move (for the
// non-const mapped value). Since 'emplace(boost::move(a))' (see below)
// has the normal result, it must be some odd consequence of how
// Visual C++ 11 handles calling move for default arguments.
COPY_COUNT(3); MOVE_COUNT(1);
# else
COPY_COUNT(2); MOVE_COUNT(0);
# endif
#endif
reset();
x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(),
boost::make_tuple());
COPY_COUNT(2); MOVE_COUNT(0);
//
// 1 argument
@ -261,45 +405,88 @@ namespace unnecessary_copy_tests
// copied.
reset();
x.emplace(source<std::pair<count_copies, count_copies> >());
COPY_COUNT(2); MOVE_COUNT(source_pair_cost);
#if (defined(__GNUC__) && __GNUC__ > 4) || \
(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 2) || \
(defined(BOOST_MSVC) && BOOST_MSVC >= 1600 )
count_copies part;
reset();
std::pair<count_copies const&, count_copies const&> a_ref(part, part);
x.emplace(a_ref);
COPY_COUNT(2); 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);
#endif
#if !defined(BOOST_NO_RVALUE_REFERENCES)
// No move should take place.
// (since a is already in the container)
reset();
x.emplace(std::move(a));
x.emplace(boost::move(a));
COPY_COUNT(0); MOVE_COUNT(0);
#endif
//
// 2 arguments
//
std::pair<count_copies const, count_copies> b;
reset();
x.emplace(b.first, b.second);
COPY_COUNT(0); MOVE_COUNT(0);
reset();
x.emplace(source<count_copies>(), source<count_copies>());
COPY_COUNT(2); MOVE_COUNT(0);
COPY_COUNT(2); MOVE_COUNT(source_cost * 2);
// source<count_copies> creates a single copy.
reset();
x.emplace(b.first, source<count_copies>());
COPY_COUNT(1); MOVE_COUNT(0);
COPY_COUNT(1); MOVE_COUNT(source_cost);
reset();
x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_));
COPY_COUNT(2); MOVE_COUNT(0);
reset();
x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(boost::ref(b.first)),
boost::make_tuple(boost::ref(b.second)));
COPY_COUNT(0); MOVE_COUNT(0);
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE)
reset();
x.emplace(boost::unordered::piecewise_construct,
std::make_tuple(std::ref(b.first)),
std::make_tuple(std::ref(b.second)));
COPY_COUNT(0); MOVE_COUNT(0);
std::pair<count_copies const, count_copies> move_source_trial;
reset();
std::make_tuple(std::move(move_source_trial.first));
std::make_tuple(std::move(move_source_trial.second));
int tuple_move_cost = ::unnecessary_copy_tests::count_copies::moves;
int tuple_copy_cost = ::unnecessary_copy_tests::count_copies::copies;
std::pair<count_copies const, count_copies> move_source;
reset();
x.emplace(boost::unordered::piecewise_construct,
std::make_tuple(std::move(move_source.first)),
std::make_tuple(std::move(move_source.second)));
COPY_COUNT(tuple_copy_cost);
MOVE_COUNT(tuple_move_cost);
#if defined(__GNUC__) && __GNUC__ > 4 || \
defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 6
reset();
x.emplace(boost::unordered::piecewise_construct,
std::forward_as_tuple(b.first),
std::forward_as_tuple(b.second));
COPY_COUNT(0); MOVE_COUNT(0);
#endif
#endif
}
}