Compare commits

..

154 Commits

Author SHA1 Message Date
Daniel James 929982357a Merge branch 'develop' 2017-06-11 20:54:52 +01:00
Daniel James 5190a5d7f8 Stop dereferencing pointers to uninitialized memory
It's undefined behaviour. Still happens for piecewise construction
emultation for std::pair, I don't think there's anyway to avoid it.
I had considered using offsetof to get a pointer to a member, but that's
also undefined behaviour when a pair member doesn't have standard
layout. Piecewise construction emulation has other problems anyway.

So, this mostly fixes PR #5.

I also stopped using addressof in self-asssignment checks as operator&
is fine.
2017-06-04 08:47:02 +01:00
Daniel James 7775aa83df Decrease the limit for SunOS workaround
We have tests for 12.5 (5,20,0), and 12.5_next (5,21,0), I think both
are good enough to not require workarounds.
2017-05-25 08:53:34 +01:00
Daniel James fc1604f2c8 Don't use allocator_traits::construct on GCC 4.6
Piecewise construction doesn't work uncopyable types.
2017-05-19 17:24:44 +01:00
Daniel James 5b97fbc292 Make insert from node_handle move only on old GCC 2017-05-19 09:42:56 +01:00
Daniel James 4f5a2dabe9 Try to fix std::tuple on old Sun compilers
In order to use the workaround for both `boost::tuple` and `std::tuple`
the function would need to detect which was being used, in order to
decide whether to use `boost::tuples::length` or `std::tuple_size`.
Probably not difficult, but I don't have any way to test an
implementation.

So instead Just assume that if `std::tuple` is available it will work
without any workaround. Presumably once the compiler was able to support
`std::tuple` it will also support the necessary overloads.

I've left the version check as 5.21 so that failures will still show up
in the tests, but I'm sure it can be 5.20 and probably earlier.  Will
change before release.
2017-05-19 09:03:08 +01:00
Daniel James e0227618bb Move a few things around to match the order in the standard 2017-05-17 16:47:57 +01:00
Daniel James ee9a5a2c77 Add a configuration macro for Sun C++ workarounds 2017-05-16 19:01:50 +01:00
Daniel James 6fffc738f7 Require std::tuple for full C++11 construction 2017-05-16 18:15:56 +01:00
Daniel James dc611fc828 Run fewer test in merge_exception_tests
It's timing out on some platforms because it's too slow. This reduces
the tag combinations for 9 to 3, which should reduce the execution time
by a third. Also slightly reduces the count combinations, but that won't
make much of a difference really - the slowest tests are still there
(when the right hand side is large).
2017-05-14 02:59:22 +01:00
Daniel James 12ee29579d Don't use full construction on Sun C++ w. libstdc++
There's an exception safety issue. Which is a pity as other than that it
seems fine. I'd assumed that support would be pretty good on all C++11
compilers, so I made it an 'all or nothing' feature, partly because
there are issues with pre-C++11 allocators, but this suggests partial
support might be desirable. Not sure I'll be able to (or want to) put
the time in though.
2017-05-12 21:58:52 +01:00
Daniel James a897843f6c Try to work around an MSVC bug
Although, perhaps I shouldn't be generating over 1000 runs for a test.
2017-05-11 00:36:31 +01:00
Daniel James 80de85f217 Move test state + functions into single class 2017-05-10 19:02:47 +01:00
Daniel James 242e91a9fd "Sub-test" reporting mechanism 2017-05-10 19:02:47 +01:00
Daniel James ca80237191 Create fewer classes in merge_exception_tests
Will need better error reporting capabilities. Makes RUN_TESTS_QUIET
redundant?
2017-05-10 19:02:47 +01:00
Daniel James b95ef6de04 Generate less output in merge_exception_tests 2017-05-10 19:02:47 +01:00
Daniel James 76e7322262 Use streams from lightweight test 2017-05-10 19:02:47 +01:00
Daniel James 3c42138e45 Fix testing piecewise_construct and tuple
For when std::piecewise_construct is available, but std::tuple isn't. In
order to test better, just repeat the tests with the four possible
combinations.
2017-05-08 18:42:53 +01:00
Daniel James 1b0b38a519 try_emplace, insert_or_assign exception tests 2017-05-07 18:47:59 +01:00
Daniel James 9119a42b7d Factor insert_exception_tests for better code reuse 2017-05-07 18:47:24 +01:00
Daniel James 8af4b37d14 Rewrite insert exception tests
Not going to do this for all the tests. It's more effort than I
expected.
2017-05-07 17:54:34 +01:00
Daniel James 31c5b5bfa1 Merge exception tests 2017-05-07 17:54:34 +01:00
Daniel James b6c6bfbe7f Statically handle 'is_unique' in assignments 2017-05-06 04:58:57 +01:00
Daniel James 6e074d7165 Get rid of delete_nodes 2017-05-06 04:58:57 +01:00
Daniel James 0489069419 Use 'limited_range' to catch error in exception tests
This would have caught the error fixed in 3fe259a79e.
2017-05-06 04:47:59 +01:00
Daniel James 597eb5a3fd Repeat the assign/insert exception tests a few times 2017-05-06 04:47:59 +01:00
Daniel James 3fe259a79e Fix creating exception::less from exception::equal_to 2017-05-05 12:58:26 +01:00
Daniel James 6ef17a0f0e Remember to disable exceptions before checking final value 2017-05-05 00:46:07 +01:00
Daniel James 47a8c3fc67 Fix exception handling in rehash_impl
And improve tests so they will catch the error, and other similar errors.
2017-05-04 19:30:18 +01:00
Daniel James d49d0e90a8 Delete nodes directly instead of through previous node 2017-05-04 00:14:08 +01:00
Daniel James 77bd45b1fa Make second parameter of delete_nodes a node_pointer 2017-05-04 00:14:05 +01:00
Daniel James 622dff50df Fix some code that could be using next_node 2017-05-03 23:36:09 +01:00
Daniel James 41f6a051ef Some more configuration comments 2017-05-03 04:21:53 +01:00
Daniel James d05619095c Workaround problems with forward_as_tuple in older versions of clang 2017-05-03 04:21:52 +01:00
Daniel James 2f8492d720 Fix libc++ configuration 2017-05-03 04:21:52 +01:00
Daniel James 7911f491f6 Try using own allocator_traits with Sun compiler
The good news is that the old Sun workarounds aren't needed any more.
Unfortunately, there are a lot of exception test errors for
unordered_map and unordered_multimap when using libstdc++, which
probably means that std::pair isn't exception safe, which is a bit odd.
But first try using our allocator_traits implementation instead of the
standard one to see if that makes a difference. If it doesn't then I'll
probably just disable C++11 construction on this compiler, which should
fix the problem but will make allocators less useful.
2017-05-03 04:21:52 +01:00
Daniel James d84a57441b Use the unordered container for the fake merge in merge test
The merge tests into containers with unique keys are failing on some
platforms. My guess is that because of differences between ordering of
nodes with equivalent keys that different nodes are being 'merged' in
the unordered containers and the tracker containers. So when creating
the fake merge, use the unordered container as a reference. This is a
little less pure, but should be a good enough test.
2017-05-01 22:16:13 +01:00
Daniel James b8c754d230 Set the high bit in bucket_info_ to false for first node in group
And true for the reset, so that in containers with unique keys
bucket_info_ is always just the bucket index.
2017-05-01 21:03:11 +01:00
Daniel James 338a94e577 Better rvalue emulation support in extractors
Means that inserting rvalues into unordered_set/unordered_map won't
create a node if no insert is required.
2017-05-01 21:03:11 +01:00
Daniel James 2e14c340a8 Reformat 2017-05-01 21:03:11 +01:00
Daniel James 35522d3ee0 Fix merging between containers with different hash/equality
This reverts commit 20b0c0a6d8.
2017-04-30 14:29:05 +01:00
Daniel James 8c139940e7 More merge tests between compatible containers 2017-04-30 14:29:05 +01:00
Daniel James 7b5f73f6c2 Disable all sunpro workarounds on latest version
I have no idea if they're still working. I wasn't able to run the latest
solaris in a virtual machine on my computer, so this is the only way to
test.
2017-04-30 10:44:54 +01:00
Daniel James e7a3487df4 Remove policy template parameter from local iterators 2017-04-30 10:44:54 +01:00
Daniel James c243895fc0 Remove odd check that should never be true
I think it was left over from the old grouped node implementation.
2017-04-30 10:44:54 +01:00
Daniel James 451d0f2fc5 Constructing nodes is nothrow, so no need to track 2017-04-30 10:43:06 +01:00
Daniel James c75b332240 Cleaner create_buckets implementation 2017-04-30 10:43:06 +01:00
Daniel James 899248acbf Avoid shadow warning on older versions off GCC 2017-04-29 09:31:17 +01:00
Daniel James cae6b121b2 Improve test coverage a little 2017-04-28 21:26:21 +01:00
Daniel James 5f6ee3da9c Use coveralls 2017-04-28 09:53:50 +01:00
Daniel James bfcdd51b4a Fix try_emplace overload 2017-04-28 09:53:50 +01:00
Daniel James 10b736d407 Remove BOOST_UNORDERED_CALL_CONSTRUCT0 2017-04-28 09:53:50 +01:00
Daniel James 0b61e6defb Stop using allocators to construct/destroy internal types
The standard doesn't allow it. I should have known that.
2017-04-27 19:02:10 +01:00
Daniel James 28f529100d Merge branch 'feature/simpler-data-structure' into develop
C++17 requires that unordered_map has the same type of node as
unordered_multimap, and that unordered_set has the same type of node as
unordered_multiset. This didn't seem particularly useful to me and
contradicts the old implementation which had different nodes, I put a
lot of effort into trying to abstract out the difference and make it
selectable using a macro, so that the old implementation would still by
available for anyone who doesn't care about strict compatibility.

But I think that was a mistake, it was making things too complicated and
for too little gain. The default would still be inefficient containers
for equivalent keys, and using the macro could lead to problems down the
line.

So I've switched to using a much simpler implementation which just marks
the first node in a group of equivalent nodes. This isn't as fast when
there are a lot of elements with equivalent keys - it can't skip to the
end of a group of nodes, but at least it avoids having to do a lot of
potentially expensive comparisons.

It's also a lot closer to the intent of the standard, even if I disagree
with that intent.
2017-04-27 18:22:53 +01:00
Daniel James 6466ce0b51 Make table the same for unique and equivalent keys 2017-04-27 18:22:44 +01:00
Daniel James 03baef8b28 Remove Types::is_unique 2017-04-27 18:22:44 +01:00
Daniel James f1435d53d4 Remove 'init' method from nodes 2017-04-27 18:22:44 +01:00
Daniel James 20b0c0a6d8 Only consider one node from each group in merge_unique 2017-04-27 18:22:44 +01:00
Daniel James a1b1df84a0 Store bucket + whether first in group in node
Instead of the hash value.
2017-04-27 18:22:44 +01:00
Daniel James 408ebd0a0a Add node_bucket function 2017-04-27 18:22:44 +01:00
Daniel James e9c4696544 Get rid of node_algo 2017-04-27 18:22:43 +01:00
Daniel James ea64f2e46e Remove the grouped node stuff 2017-04-27 18:22:43 +01:00
Daniel James 94a3a9baf9 Fix some quickbook markup 2017-04-25 21:14:11 +01:00
Daniel James da27ae4de6 Group together similar overloads of try_emplace 2017-04-25 20:20:11 +01:00
Daniel James ed326e2c87 Expand out more preprocessor repeats 2017-04-25 20:20:11 +01:00
Daniel James bea4c6e29b undef some macros 2017-04-25 20:20:11 +01:00
Daniel James 61df9479e5 Rename unique_node 2017-04-25 20:20:11 +01:00
Daniel James e3ab7b5d2e Remove BOOST_UNORDERED_EMPLACE_ARGSn macros
They're not used anywhere now.
2017-04-25 20:20:11 +01:00
Daniel James 679b73098e Option to use grouped nodes everywhere
Seems to work okay, but I'm not happy with and of the options. So I'm
going to look into doing something else before the next release.
2017-04-25 09:54:28 +01:00
Daniel James cba643fc51 Make setting max_load_ a tad more consistent 2017-04-25 09:54:28 +01:00
Daniel James 1c8edf0298 Remove early exit for empty containers 2017-04-25 09:54:28 +01:00
Daniel James 07b9a7d60e Fix incorrect try_emplace call 2017-04-25 01:39:30 +01:00
Daniel James 9c8980e6a1 Write out epoint that threw an exception after failure 2017-04-25 01:21:44 +01:00
Daniel James 60127d86e0 After 5 failures stop running an exception test 2017-04-25 01:10:53 +01:00
Daniel James 0c3c738614 Better C++ version info 2017-04-25 01:09:07 +01:00
Daniel James c8bacbcb00 Merge branch 'feature/combine-unique-equiv-tables' into develop
Expanding a lot of the call to the implementation methods. While working
on some recent changes, I felt the call chains in error messages were
too long, this reduces that a little. It also should make debugging a
tad easier and I think it makes the methods a little more informative,
as you can see what they're doing without hunting around the
implementation file. Also reduces the number of symbols when compiling,
although I'm not sure if that will make much of a difference.

Does make the code a little long, and duplicated, but I don't think it's
particularly harmful.
2017-04-24 09:46:05 +01:00
Daniel James b070bb5e49 Move everything from table_unique/table_equiv into table 2017-04-24 09:46:05 +01:00
Daniel James e518120104 Rename some copy/assign/move methods
But with a hack so that the static casts will work until there's a
better method.
2017-04-24 09:46:05 +01:00
Daniel James 84f1ef6d2d Move constructor implementation into containers 2017-04-24 09:46:05 +01:00
Daniel James 77bf2b5e33 Rename methods to be different for unique/equiv keys
So that the implementation can be moved into a single class. Still some
other methods to rename. Some methods didn't need to be renamed (e.g.
try_emplace is only used with unique keys), but still renamed for
consistency.
2017-04-24 09:46:05 +01:00
Daniel James 8229aa6b3c Stop throwing exception in allocator copy/assignment
The standard specifies that all of these "shall not exit via an
exception". The containers have been exception safe when these throw,
but the 'noexcept' attribute on 'get_allocator' will terminate if an
exception is thrown in the copy constructor.

The standard doesn't specify a default constructor, so that is allowed
to throw an exception (not just pedantry, this makes sense if an
allocator has shared data that's allocated in the initial constructor).
2017-04-23 11:01:04 +01:00
Daniel James fc08f62d6a Remove a TODO 2017-04-23 10:51:17 +01:00
Daniel James 1254520438 Merge branch 'feature/expand-calls' into develop
Expanding a lot of the call to the implementation methods. While working
on some recent changes, I felt the call chains in error messages were
too long, this reduces that a little. It also should make debugging a
tad easier and I think it makes the methods a little more informative,
as you can see what they're doing without hunting around the
implementation file. Also reduces the number of symbols when compiling,
although I'm not sure if that will make much of a difference.

Does make the code a little long, and duplicated, but I don't think it's
particularly harmful.
2017-04-23 10:46:27 +01:00
Daniel James 7941771d61 Expand calls to at implementation 2017-04-23 10:09:18 +01:00
Daniel James 4f1c6e1ebf Expand calls to init/move_init 2017-04-23 10:09:18 +01:00
Daniel James 13ff1e7fb1 Expand calls to count and equal_range implementation 2017-04-23 10:09:18 +01:00
Daniel James 25b0b66e52 Expand calls to erase implementation
Doesn't work as well as the previous changes.
2017-04-23 10:09:18 +01:00
Daniel James da835e88b8 Expand calls to insert_range 2017-04-23 10:09:18 +01:00
Daniel James b6c229e2bb Expand calls to reserve implementation 2017-04-23 10:09:18 +01:00
Daniel James 19a45e028a Expand calls to generic_find_node 2017-04-23 10:09:18 +01:00
Daniel James 435b7450d4 Expand calls to max_size implementation 2017-04-23 10:09:18 +01:00
Daniel James a41a0f3a06 Expand calls to load_factor implementation 2017-04-23 10:09:18 +01:00
Daniel James 814926ef31 Expand calls to clear implementation 2017-04-23 10:09:18 +01:00
Daniel James f6f5ecdc00 Expand calls to emplace implementation
Also manually call the emplace macro up to 9 arguments, nicer error
messages for little effort.

Does it matter that there's no longer a nice backend for
`please_ignore_this_overload`? I don't think so, I was worried that it
would be confusing if triggered, but I'm not really aware of that ever
happening.
2017-04-23 10:09:18 +01:00
Daniel James 42b6b13943 Use the preprocessor to increment emplace limit
So that there's no need to add one.
2017-04-23 10:04:28 +01:00
Daniel James cfe4c26f99 Explicitly write out boost::tuple template arguments
GCC 4.6 doesn't support using variadic arguments for a fixed length template.
There's a config macro for this, but might as well use the same code
everywhere.
2017-04-23 09:31:18 +01:00
Daniel James 3117611a55 New tuple implementation
Adjusts to use less arguments on Visual C++ 11, which will hopefully fix
it on that compiler. Also changed to be a little less preprocessor
heavy. I'm not sure about the __SUNPRO_CC support, hopefully recent
versions of that compiler will have better support, and can use the
normal implementation. Will check that later.
2017-04-22 18:31:10 +01:00
Daniel James 1e491533fa More consistent std::tuple configuration
Was getting a weird test failure for Visual C++ 11,
BOOST_NO_CXX11_HDR_TUPLE is defined, so the code doesn't support
std::tuple, but BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT was also
true, and so there are functions for constructing using
std::piecewise_construct/std::tuple, which don't work.

So, I'm assuming that if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT is true,
then there must be a std::tuple. I guess it doesn't have full C++11 support,
which is why BOOST_NO_CXX11_HDR_TUPLE is defined, but it appears to be
good enough for us. If not, this will break things.
2017-04-21 20:32:56 +01:00
Daniel James a119caaa1b Stop travis build after first failure 2017-04-20 23:39:44 +01:00
Daniel James 96f8f85eef Use environment variable to set user-config.jam 2017-04-20 23:39:44 +01:00
Daniel James 2add451d63 Use boost 1.64.0 on travis 2017-04-20 23:11:28 +01:00
Daniel James 3effedb728 Merge branch 'feature/standards-checking-and-cleanup' into develop
Rearrange the definitions to be a closer match to the standard, this
should make it easier to check how standards compliant it is. Also, some
minor code clean-ups that I noticed while doing this.
2017-04-20 23:01:09 +01:00
Daniel James b067e65731 Clean table forward declarations 2017-04-20 22:59:00 +01:00
Daniel James f3b179d451 Remove pointless duplication of move constructor 2017-04-20 22:59:00 +01:00
Daniel James de5373413b Missing rvalue overload of at 2017-04-20 22:59:00 +01:00
Daniel James fedf533699 Move index functions into place 2017-04-20 22:59:00 +01:00
Daniel James 9cd673c71d Specify clear as noexcept 2017-04-20 22:59:00 +01:00
Daniel James 85a834cf62 Comment on changes needed for C++17 support 2017-04-20 22:59:00 +01:00
Daniel James 5167c970af Swap order of swap/clear to match standard 2017-04-20 22:59:00 +01:00
Daniel James bf7a65010c Add new erase(iterator) overloads
Not for unordered_set/unordered_multiset as they use the same type for
iterator and const_iterator.
2017-04-20 22:59:00 +01:00
Daniel James 461ac96a2c Reorder insert_or_assign to match standard 2017-04-20 22:59:00 +01:00
Daniel James 5eb10fd0b2 Move extract into place 2017-04-20 22:59:00 +01:00
Daniel James e2e9959389 Split up emplace and emplace_hint code
Busywork I guess, but I think it's more readable this way. The emplace
macros are still unreadable, but I think they're rarely used.

Btw. a bit weird that clang format has removed the indentation on the
'// emplace' comment, not sure why that is.
2017-04-20 22:59:00 +01:00
Daniel James d8969c71fc Move 'try_emplace' into same order as draft standard 2017-04-20 22:59:00 +01:00
Daniel James ab76814aa6 Move 'insert_or_assign' into same order as draft standard 2017-04-20 22:59:00 +01:00
Daniel James 1a18cd2196 Move capacity functions to match order in standard 2017-04-20 22:59:00 +01:00
Daniel James e4a00980f8 Commented out noexcept for move assignment 2017-04-20 22:59:00 +01:00
Daniel James af94e6a40e Reorder the constructors to match the draft standard
In order to make it easier to check against the standard.  This includes
collapsing some of the input iterator overloads into one constructor.
2017-04-20 22:59:00 +01:00
Daniel James ee73a53497 Disable failing tests on gcc 4.6/4.7 c++11 mode
Works fine on later versions of GCC, I suspect it's a bug in their
noexcept support.
2017-04-20 10:11:01 +01:00
Daniel James 6bdf1ba244 Fix a comment 2017-04-19 10:21:13 +01:00
Daniel James d47754acac Include unordered macro values in test output 2017-04-19 10:21:13 +01:00
Daniel James cee94e9fcb Fix unused parameter warning 2017-04-19 09:20:31 +01:00
Daniel James 3ae9930979 Merge branch 'feature/better-construction' into develop 2017-04-18 10:14:53 +01:00
Daniel James 2effcfa195 Intro to compliance section
Needs more info on C++17 compliance - particularly `noexecpt`.
2017-04-18 10:14:26 +01:00
Daniel James 8c9080f11f Document changes to allocator use 2017-04-18 10:14:26 +01:00
Daniel James ef05493c83 Test that construct/destroy aren't used when C++11 isn't available 2017-04-18 10:14:26 +01:00
Daniel James 7a0a598649 Don't track construction when using boost::tuple
Because it doesn't quiet work on C++11 compilers onwards.
2017-04-18 10:14:26 +01:00
Daniel James cafd236a18 Test more memory tracking 2017-04-18 10:14:26 +01:00
Daniel James e0054c7dd0 Remove alloc parameter from construct_value 2017-04-18 10:14:26 +01:00
Daniel James 3414e6628a Use allocator to construct/destroy nodes 2017-04-18 10:14:26 +01:00
Daniel James 08ce2c98e0 Rename call_construct to construct_value 2017-04-18 10:14:26 +01:00
Daniel James 6d79a322e2 Use macros to reduce call chain 2017-04-18 10:14:26 +01:00
Daniel James 9e70680044 Bypass construct_value/call_destroy_in a few places 2017-04-18 10:14:26 +01:00
Daniel James 7de8c91301 Remove calls to const_cast_pointer
It was needed because std::allocator_traits::construct doesn't work with
a const pointer (e.g. pointer to the first member of a std::pair). But
now we're only calling construct if BOOST_UNORDERED_CXX11_CONSTRUCTION
is true, so the allocator_traits::construct is no longer used here.
2017-04-18 10:14:26 +01:00
Daniel James c333a7f9fc Use piecewise construction where possible 2017-04-18 10:14:26 +01:00
Daniel James bc36a06a2d Comment about call_construct 2017-04-18 10:14:26 +01:00
Daniel James e62ac22f0b Replace BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT with BOOST_UNORDERED_CXX11_CONSTRUCTION
Require good construct support and piecewise construction. I don't know
if there are any platforms with good construct support, but no piecewise
construction, if there are then they'll no longer use
'allocator_traits::construct'/'allocator_traits::destruct'.
2017-04-18 10:14:26 +01:00
Daniel James 1092c972c9 Use allocator_traits to construct/destruct buckets 2017-04-18 10:14:26 +01:00
Daniel James 7e5520f974 Increase template depth for GCC
This appears to be an unavoidable problem with GCC's tuple
implementation. For example:

http://stackoverflow.com/q/23374953/2434

Appears to be okay in later versions of GCC though.
2017-04-18 10:14:26 +01:00
Daniel James 2b01bdbc25 More general deprecated check
`__has_cpp_attribute(deprecated)` returns true for C++11, but then warns
that it's a C++14 attribute, so only check in C++14 mode.
2017-04-16 16:34:22 +01:00
Daniel James 64a3be7d3e Use aligned_storage's address method to get pointer 2017-04-16 10:37:10 +01:00
Daniel James c0e03c3640 Add some more details to change log 2017-04-15 20:52:00 +01:00
Daniel James ed8c0f9ecd Add deprecated attributes to deprecated functions 2017-04-15 17:35:09 +01:00
Daniel James 2bfc59c461 Make node_handler constructor private + additional compile tests 2017-04-15 17:35:09 +01:00
Daniel James 727e36e6a6 Comment about clear_buckets/create_buckets awkwardness.
They both leave the container in an invalid state that needs to be
cleaned up immediately. This confused me slightly.
2017-04-15 17:35:09 +01:00
Daniel James 09bddd8df4 Clear buckets before deleting nodes in clear.
The order shouldn't really matter as nothing throws an exception, but it
seems cleaner to never have any dangling pointers.
2017-04-15 17:35:08 +01:00
Daniel James f089adc160 Change get_key to have node parameter 2017-04-15 17:35:08 +01:00
Daniel James 97b68ea05e Rename (grouped_)table_impl to table_unique/equiv
The old names don't make sense any more as either style can be used for
containers with equivalent keys, due to the use of node_algo.
2017-04-15 17:35:08 +01:00
Daniel James 972ac220f5 Add missing insert(P&&) methods to unordered_map/unordered_multimap 2017-04-15 17:35:08 +01:00
Daniel James 5d98f3d0f0 Noexcept specs for swap free functions 2017-04-15 17:35:08 +01:00
Daniel James 51cd1cd2af Some more typos 2017-04-12 08:25:14 +01:00
Daniel James 7e940e6e45 Fix some typos 2017-04-12 08:01:10 +01:00
Daniel James 2f4d286a51 Merge branch 'feature/doc-clarification' into develop 2017-04-11 23:40:48 +01:00
Daniel James c2d2be021a Don't test inserting from initializer list in old clang
There's a problem with it causing an ambiguous overload. I don't think
there's anything we can do to fix that, so just don't test it.

There's another bug where a std::pair doesn't get correctly constructed
from an rvalue when using Clang 3.1 in C++11 mode. But I can't see any
way to easily fix that, and it's a pretty old compiler now.
2017-04-08 06:17:43 +01:00
49 changed files with 5397 additions and 3995 deletions
+28 -30
View File
@@ -18,49 +18,47 @@ addons:
matrix:
include:
- compiler: gcc
env: BJAM_TOOLSET=gcc
env: |
label="gcc C++03";
user_config="using gcc : : g++-4.8 --coverage -fsanitize=address -Werror --std=c++03 ;"
enable_coverage=1
- compiler: gcc
env: BJAM_TOOLSET=gcc-std11
#- compiler: gcc
# env: BJAM_TOOLSET=gcc-m32
env: |
label="gcc C++11";
user_config="using gcc : : g++-4.8 --coverage -fsanitize=address -Werror --std=c++11 ;"
enable_coverage=1
- compiler: gcc
env: BJAM_TOOLSET=gcc-std11m32
#- compiler: clang
# env: BJAM_TOOLSET=clang
env: |
label="gcc 32 bit C++11";
user_config="using gcc : : g++-4.8 -m32 -fsanitize=address -Werror --std=c++11 ;"
- compiler: clang
env: BJAM_TOOLSET=clang-std11
env: |
label="clang C++11";
user_config="using clang : : clang++ -fsanitize=address -Werror --std=c++11 ;"
# sanitized=address not available for 32-bit clang on travis.
- compiler: clang
env: BJAM_TOOLSET=clang-m32
#- compiler: clang
# env: BJAM_TOOLSET=clang-std11m32
- compiler: gcc
env: BJAM_TOOLSET=gcc-interopable
- compiler: clang
env: BJAM_TOOLSET=clang-interopable
env: |
label="clang 32 bit";
user_config="using clang : : clang++ -m32 -Werror --std=c++03 ;"
before_install:
- if [ -n $enable_coverage ]; then pip install --user cpp-coveralls; fi
before_script:
- cd ${TRAVIS_BUILD_DIR}
- touch Jamroot.jam
- cd $HOME
- |
echo "using gcc : : g++-4.8 -Werror --std=c++03 -fsanitize=address ;" > ~/user-config.jam
echo "using gcc : std11 : g++-4.8 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam
echo "using gcc : m32 : g++-4.8 -m32 -Werror -fsanitize=address ;" >> ~/user-config.jam
echo "using gcc : std11m32 : g++-4.8 -m32 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam
echo "using clang : : clang++ -Werror --std=c++03 -fsanitize=address ;" >> ~/user-config.jam
echo "using clang : std11 : clang++ -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam
# sanitized=address not available for 32-bit clang on travis.
echo "using clang : m32 : clang++ -m32 -Werror --std=c++03 ;" >> ~/user-config.jam
echo "using clang : std11m32 : clang++ -m32 -Werror --std=c++11 ;" >> ~/user-config.jam
echo "using gcc : interopable : g++-4.8 -Werror --std=c++03 -fsanitize=address -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" >> ~/user-config.jam
echo "using clang : interopable : clang++ -Werror --std=c++11 -fsanitize=address -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" >> ~/user-config.jam
- echo $user_config > ~/user-config.jam
- cat ~/user-config.jam
- wget -O boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.63.0/boost_1_63_0.tar.bz2
- wget -O boost.tar.bz2 https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2
- tar -xjf boost.tar.bz2
- mv boost_1_63_0 boost
- mv boost_1_64_0 boost
- rm -r boost/boost/unordered
after_success:
if [ -n $enable_coverage ]; then coveralls -r ${TRAVIS_BUILD_DIR} -b ${TRAVIS_BUILD_DIR}/test --gcov-options '\-lp' --include include/boost/unordered/ ; fi
script:
- cd ${TRAVIS_BUILD_DIR}/test
- bjam ${BJAM_TOOLSET} include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include
- bjam -q include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include
- xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml
+12 -4
View File
@@ -99,7 +99,7 @@ First official release.
has been rewritten to use templates instead of macros for the implementation
classes.
* The container objcet is now smaller thanks to using `boost::compressed_pair`
* The container object is now smaller thanks to using `boost::compressed_pair`
for EBO and a slightly different function buffer - now using a bool instead
of a member pointer.
@@ -170,7 +170,7 @@ C++11 support has resulted in some breaking changes:
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
the variadic constructors define
`BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT`.
[h2 Boost 1.49.0]
@@ -207,7 +207,7 @@ C++11 support has resulted in some breaking changes:
* 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]).
* Adjust SFINAE use to try to support g++ 3.4 ([ticket 7175]).
* Updated to use the new config macros.
[h2 Boost 1.52.0]
@@ -307,9 +307,17 @@ C++11 support has resulted in some breaking changes:
* Initial support for new C++17 member functions:
`insert_or_assign` and `try_emplace` in `unordered_map`,
* Initial support for `merge` and `extract`.
Does not include transfering nodes between
Does not include transferring nodes between
`unordered_map` and `unordered_multimap` or between `unordered_set` and
`unordered_multiset` yet. That will hopefully be in the next version of
Boost.
[h2 Boost 1.65.0]
* Add deprecated attributes to `quick_erase` and `erase_return_void`.
I really will remove them in a future version this time.
* Small standards compliance fixes:
* `noexpect` specs for `swap` free functions.
* Add missing `insert(P&&)` methods.
[endsect]
+31 -15
View File
@@ -2,7 +2,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) ]
[section:compliance C++11 Compliance]
[section:compliance Standard Compliance]
The intent of Boost.Unordered is to implement a close (but inperfect)
implementation of the C++17 standard, that will work with C++98 upwards.
The wide compatibility does mean some comprimises have to be made.
With a compiler and library that fully support C++11, the differences should
be minor.
[section:move Move emulation]
@@ -51,23 +57,32 @@ 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.
[endsect]
In C++11 the allocator's construct function has the signature:
[section:construction Construction/Destruction using allocators]
template <class U, class... Args>
void construct(U* p, Args&&... args);
The following support is required for full use of C++11 style
construction/destruction:
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.
* Variadic templates.
* Piecewise construction of `std::pair`.
* Either `std::allocator_traits` or expression SFINAE.
This is detected using Boost.Config. The macro
`BOOST_UNORDERED_CXX11_CONSTRUCTION` will be set to 1 if it is found, or 0
otherwise.
When this is the case `allocator_traits::construct` and
`allocator_traits::destroy` will always be used, apart from when piecewise
constructing a `std::pair` using `boost::tuple` (see [link
unordered.compliance.pairs below]), but that should be easily avoided.
When support is not available `allocator_traits::construct` and
`allocator_traits::destroy` are never called.
[endsect]
[section:pointer_traits Pointer Traits]
`pointer_traits` aren't used. Instead, pointer types are obtained from
rebound allocators, this can cause problems if the allocator can't be
@@ -77,6 +92,7 @@ is used to obtain a const pointer.
[endsect]
[#unordered.compliance.pairs]
[section:pairs Pairs]
Since the containers use `std::pair` they're limited to the version
+2 -2
View File
@@ -13,7 +13,7 @@ containers in the draft standard, so the interface was fixed. But there are
still some implementation decisions to make. The priorities are
conformance to the standard and portability.
The [@http://en.wikipedia.org/wiki/Hash_table wikipedia article on hash tables]
The [@http://en.wikipedia.org/wiki/Hash_table Wikipedia article on hash tables]
has a good summary of the implementation issues for hash tables in general.
[h2 Data Structure]
@@ -100,7 +100,7 @@ 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.
Currently this is only done on 64 bit architecures, where prime number
Currently this is only done on 64 bit architectures, where prime number
modulus can be expensive. Although this varies depending on the architecture,
so I probably should revisit it.
+3 -1
View File
@@ -20,7 +20,7 @@
#endif
#elif defined(_LIBCPP_VERSION)
// https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206
#if LIBCPP_VERSION >= 3000
#if _LIBCPP_VERSION >= 3000
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
#endif
#elif defined(BOOST_MSVC)
@@ -32,6 +32,8 @@
#endif
#endif
// TODO: Use piecewise construction by default? Is it safe to assume that an
// unknown library has it?
#if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 0
#endif
File diff suppressed because it is too large Load Diff
+3 -46
View File
@@ -27,65 +27,22 @@ template <typename A, typename K, typename M, typename H, typename P> struct map
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef typename pick::node_algo node_algo;
typedef boost::unordered::detail::table_impl<types> table;
typedef boost::unordered::detail::table<types> table;
typedef boost::unordered::detail::map_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
typedef boost::unordered::iterator_detail::iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::l_iterator<node, policy>
l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
cl_iterator;
typedef boost::unordered::iterator_detail::l_iterator<node> l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node> cl_iterator;
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
typedef boost::unordered::insert_return_type_map<node, K, M, A>
insert_return_type;
};
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 std::pair<K const, M> value_type;
typedef H hasher;
typedef P key_equal;
typedef K const const_key_type;
typedef typename ::boost::unordered::detail::rebind_wrap<A,
value_type>::type value_allocator;
typedef boost::unordered::detail::allocator_traits<value_allocator>
value_allocator_traits;
#if BOOST_UNORDERED_INTEROPERABLE_NODES
typedef boost::unordered::detail::pick_node<A, value_type> pick;
#else
typedef boost::unordered::detail::pick_grouped_node<A, value_type> pick;
#endif
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef typename pick::node_algo node_algo;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::map_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
typedef boost::unordered::iterator_detail::iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::l_iterator<node, policy>
l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
cl_iterator;
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
};
template <typename K, typename M, typename H, typename P, typename A>
class instantiate_map
{
+3 -45
View File
@@ -27,64 +27,22 @@ template <typename A, typename T, typename H, typename P> struct set
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef typename pick::node_algo node_algo;
typedef boost::unordered::detail::table_impl<types> table;
typedef boost::unordered::detail::table<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
typedef boost::unordered::iterator_detail::c_iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
cl_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node> l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node> cl_iterator;
typedef boost::unordered::node_handle_set<node, T, A> node_type;
typedef boost::unordered::insert_return_type_set<node, T, A>
insert_return_type;
};
template <typename A, typename T, typename H, typename P> struct multiset
{
typedef boost::unordered::detail::multiset<A, T, H, P> types;
typedef T value_type;
typedef H hasher;
typedef P key_equal;
typedef T const const_key_type;
typedef typename ::boost::unordered::detail::rebind_wrap<A,
value_type>::type value_allocator;
typedef boost::unordered::detail::allocator_traits<value_allocator>
value_allocator_traits;
#if BOOST_UNORDERED_INTEROPERABLE_NODES
typedef boost::unordered::detail::pick_node<A, value_type> pick;
#else
typedef boost::unordered::detail::pick_grouped_node<A, value_type> pick;
#endif
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef typename pick::node_algo node_algo;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
typedef boost::unordered::iterator_detail::c_iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
cl_iterator;
typedef boost::unordered::node_handle_set<node, T, A> node_type;
};
template <typename T, typename H, typename P, typename A> class instantiate_set
{
typedef boost::unordered_set<T, H, P, A> container;
File diff suppressed because it is too large Load Diff
@@ -30,7 +30,9 @@ 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>&);
inline void swap(
unordered_map<K, T, H, P, A>& m1, unordered_map<K, T, H, P, A>& m2)
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
template <class K, class T, class H = boost::hash<K>,
class P = std::equal_to<K>,
@@ -44,8 +46,9 @@ 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>&);
inline void swap(unordered_multimap<K, T, H, P, A>& m1,
unordered_multimap<K, T, H, P, A>& m2)
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
template <class N, class K, class T, class A> class node_handle_map;
template <class N, class K, class T, class A> struct insert_return_type_map;
File diff suppressed because it is too large Load Diff
@@ -29,7 +29,8 @@ 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);
inline void swap(unordered_set<T, H, P, A>& m1, unordered_set<T, H, P, A>& m2)
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
template <class T, class H = boost::hash<T>, class P = std::equal_to<T>,
class A = std::allocator<T> >
@@ -43,7 +44,8 @@ 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);
unordered_multiset<T, H, P, A>& m1, unordered_multiset<T, H, P, A>& m2)
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
template <class N, class T, class A> class node_handle_set;
template <class N, class T, class A> struct insert_return_type_set;
+4 -1
View File
@@ -15,6 +15,7 @@ project unordered-test/unordered
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
<toolset>clang:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow"
<toolset>msvc:<cxxflags>"/wd4494"
<toolset>gcc:<c++-template-depth>500
;
#alias framework : /boost/test//boost_unit_test_framework ;
@@ -45,7 +46,7 @@ test-suite unordered
[ run unordered/insert_hint_tests.cpp ]
[ run unordered/emplace_tests.cpp ]
[ run unordered/unnecessary_copy_tests.cpp ]
[ run unordered/erase_tests.cpp ]
[ run unordered/erase_tests.cpp : : : <define>BOOST_UNORDERED_SUPPRESS_DEPRECATED ]
[ run unordered/erase_equiv_tests.cpp ]
[ run unordered/extract_tests.cpp ]
[ run unordered/node_handle_tests.cpp ]
@@ -61,6 +62,7 @@ test-suite unordered
[ run unordered/rehash_tests.cpp ]
[ run unordered/equality_tests.cpp ]
[ run unordered/swap_tests.cpp ]
[ run unordered/detail_tests.cpp ]
[ run unordered/compile_set.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
@@ -90,4 +92,5 @@ test-suite unordered-exception
[ run exception/rehash_exception_tests.cpp framework ]
[ run exception/swap_exception_tests.cpp framework : : :
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
[ run exception/merge_exception_tests.cpp framework ]
;
+57 -10
View File
@@ -7,6 +7,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable : 4512) // assignment operator could not be generated
@@ -17,11 +18,22 @@ test::seed_t initialize_seed(12847);
template <class T> struct self_assign_base : public test::exception_base
{
test::random_values<T> values;
self_assign_base(std::size_t count = 0) : values(count) {}
self_assign_base(std::size_t count = 0) : values(count, test::limited_range)
{
}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
void run(T& x) const { x = x; }
void run(T& x) const
{
x = x;
DISABLE_EXCEPTIONS;
test::check_container(x, values);
test::check_equivalent_keys(x);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
test::check_equivalent_keys(x);
@@ -57,7 +69,16 @@ template <class T> struct assign_base : public test::exception_base
typedef T data_type;
T init() const { return T(x); }
void run(T& x1) const { x1 = y; }
void run(T& x1) const
{
x1 = y;
DISABLE_EXCEPTIONS;
test::check_container(x1, y_values);
test::check_equivalent_keys(x1);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
{
test::check_equivalent_keys(x1);
@@ -76,11 +97,12 @@ template <class T> struct assign_base : public test::exception_base
template <class T> struct assign_values : assign_base<T>
{
assign_values(unsigned int count1, unsigned int count2, int tag1, int tag2,
float mlf1 = 1.0, float mlf2 = 1.0)
test::random_generator gen = test::default_generator, float mlf1 = 1.0,
float mlf2 = 1.0)
: assign_base<T>(tag1, tag2, mlf1, mlf2)
{
this->x_values.fill(count1);
this->y_values.fill(count2);
this->x_values.fill(count1, gen);
this->y_values.fill(count2, gen);
this->x.insert(this->x_values.begin(), this->x_values.end());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
@@ -96,11 +118,21 @@ template <class T> struct assign_test2 : assign_values<T>
assign_test2() : assign_values<T>(60, 0, 0, 0) {}
};
template <class T> struct assign_test2a : assign_values<T>
{
assign_test2a() : assign_values<T>(60, 0, 0, 0, test::limited_range) {}
};
template <class T> struct assign_test3 : assign_values<T>
{
assign_test3() : assign_values<T>(0, 60, 0, 0) {}
};
template <class T> struct assign_test3a : assign_values<T>
{
assign_test3a() : assign_values<T>(0, 60, 0, 0, test::limited_range) {}
};
template <class T> struct assign_test4 : assign_values<T>
{
assign_test4() : assign_values<T>(10, 10, 1, 2) {}
@@ -111,9 +143,17 @@ template <class T> struct assign_test4a : assign_values<T>
assign_test4a() : assign_values<T>(10, 100, 1, 2) {}
};
template <class T> struct assign_test4b : assign_values<T>
{
assign_test4b() : assign_values<T>(10, 100, 1, 2, test::limited_range) {}
};
template <class T> struct assign_test5 : assign_values<T>
{
assign_test5() : assign_values<T>(5, 60, 0, 0, 1.0f, 0.1f) {}
assign_test5()
: assign_values<T>(5, 60, 0, 0, test::default_generator, 1.0f, 0.1f)
{
}
};
template <class T> struct equivalent_test1 : assign_base<T>
@@ -131,8 +171,15 @@ template <class T> struct equivalent_test1 : assign_base<T>
}
};
EXCEPTION_TESTS((self_assign_test1)(self_assign_test2)(assign_test1)(
assign_test2)(assign_test3)(assign_test4)(assign_test4a)(
assign_test5)(equivalent_test1),
// clang-format off
EXCEPTION_TESTS_REPEAT(5,
(self_assign_test1)(self_assign_test2)
(assign_test1)(assign_test2)(assign_test2a)
(assign_test3)(assign_test3a)
(assign_test4)(assign_test4a)(assign_test4b)
(assign_test5)
(equivalent_test1),
CONTAINER_SEQ)
// clang-format on
RUN_TESTS()
+56 -15
View File
@@ -6,7 +6,9 @@
#include "./containers.hpp"
#include "../helpers/input_iterator.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
template <typename T> inline void avoid_unused_warning(T const&) {}
@@ -25,7 +27,10 @@ template <class T> struct construct_test1 : public objects, test::exception_base
void run() const
{
T x;
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@@ -34,7 +39,10 @@ template <class T> struct construct_test2 : public objects, test::exception_base
void run() const
{
T x(300);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@@ -43,7 +51,10 @@ template <class T> struct construct_test3 : public objects, test::exception_base
void run() const
{
T x(0, hash);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@@ -52,7 +63,10 @@ template <class T> struct construct_test4 : public objects, test::exception_base
void run() const
{
T x(0, hash, equal_to);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@@ -61,7 +75,10 @@ template <class T> struct construct_test5 : public objects, test::exception_base
void run() const
{
T x(50, hash, equal_to, allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@@ -70,7 +87,10 @@ template <class T> struct construct_test6 : public objects, test::exception_base
void run() const
{
T x(allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@@ -78,8 +98,8 @@ template <class T> struct range : public test::exception_base
{
test::random_values<T> values;
range() : values(5) {}
range(unsigned int count) : values(count) {}
range() : values(5, test::limited_range) {}
range(unsigned int count) : values(count, test::limited_range) {}
};
template <class T> struct range_construct_test1 : public range<T>, objects
@@ -87,7 +107,10 @@ template <class T> struct range_construct_test1 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end());
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@@ -96,7 +119,10 @@ template <class T> struct range_construct_test2 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end(), 0);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@@ -105,7 +131,10 @@ template <class T> struct range_construct_test3 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end(), 0, hash);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@@ -114,7 +143,10 @@ template <class T> struct range_construct_test4 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end(), 100, hash, equal_to);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@@ -128,7 +160,10 @@ template <class T> struct range_construct_test5 : public range<T>, objects
{
T x(this->values.begin(), this->values.end(), 0, hash, equal_to,
allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@@ -143,7 +178,10 @@ template <class T> struct input_range_construct_test : public range<T>, objects
end = this->values.end();
T x(test::input_iterator(begin), test::input_iterator(end), 0, hash,
equal_to, allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@@ -156,7 +194,10 @@ template <class T> struct copy_range_construct_test : public range<T>, objects
T x(test::copy_iterator(this->values.begin()),
test::copy_iterator(this->values.end()), 0, hash, equal_to,
allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
+47 -6
View File
@@ -5,7 +5,9 @@
#include "./containers.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
template <typename T> inline void avoid_unused_warning(T const&) {}
@@ -18,7 +20,10 @@ template <class T> struct copy_test1 : public test::exception_base
void run() const
{
T y(x);
avoid_unused_warning(y);
DISABLE_EXCEPTIONS;
BOOST_TEST(y.empty());
test::check_equivalent_keys(y);
}
};
@@ -27,12 +32,18 @@ template <class T> struct copy_test2 : public test::exception_base
test::random_values<T> values;
T x;
copy_test2() : values(5), x(values.begin(), values.end()) {}
copy_test2()
: values(5, test::limited_range), x(values.begin(), values.end())
{
}
void run() const
{
T y(x);
avoid_unused_warning(y);
DISABLE_EXCEPTIONS;
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
@@ -46,7 +57,30 @@ template <class T> struct copy_test3 : public test::exception_base
void run() const
{
T y(x);
avoid_unused_warning(y);
DISABLE_EXCEPTIONS;
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
template <class T> struct copy_test3a : public test::exception_base
{
test::random_values<T> values;
T x;
copy_test3a()
: values(100, test::limited_range), x(values.begin(), values.end())
{
}
void run() const
{
T y(x);
DISABLE_EXCEPTIONS;
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
@@ -61,10 +95,17 @@ template <class T> struct copy_with_allocator_test : public test::exception_base
void run() const
{
T y(x, allocator);
avoid_unused_warning(y);
DISABLE_EXCEPTIONS;
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
EXCEPTION_TESTS((copy_test1)(copy_test2)(copy_test3)(copy_with_allocator_test),
// clang-format off
EXCEPTION_TESTS(
(copy_test1)(copy_test2)(copy_test3)(copy_test3a)(copy_with_allocator_test),
CONTAINER_SEQ)
// clang-format on
RUN_TESTS()
+7 -1
View File
@@ -14,7 +14,9 @@ test::seed_t initialize_seed(835193);
template <class T> struct erase_test_base : public test::exception_base
{
test::random_values<T> values;
erase_test_base(unsigned int count = 5) : values(count) {}
erase_test_base(unsigned int count = 5) : values(count, test::limited_range)
{
}
typedef T data_type;
@@ -43,6 +45,10 @@ template <class T> struct erase_by_key_test1 : public erase_test_base<T>
it != end; ++it) {
x.erase(test::get_key<T>(*it));
}
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
+374 -266
View File
@@ -2,306 +2,414 @@
// Copyright 2006-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./containers.hpp"
#include "../helpers/helpers.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/strong.hpp"
#include "../helpers/tracker.hpp"
#include <cmath>
#include <string>
test::seed_t initialize_seed(747373);
template <class T> struct insert_test_base : public test::exception_base
// Fill in a container so that it's about to rehash
template <typename T> void rehash_prep(T& x)
{
test::random_values<T> values;
insert_test_base(unsigned int count = 5)
: values(count, test::limited_range)
{
using namespace std;
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
x.max_load_factor(0.25);
size_type bucket_count = x.bucket_count();
size_type initial_elements = static_cast<size_type>(
ceil((double)bucket_count * (double)x.max_load_factor()) - 1);
test::random_values<T> v(initial_elements);
x.insert(v.begin(), v.end());
BOOST_TEST(bucket_count == x.bucket_count());
}
// Overload to generate inserters that need type information.
template <typename Inserter, typename T>
Inserter generate(Inserter inserter, T&)
{
return inserter;
}
// Get the iterator returned from an insert/emplace.
template <typename T> T get_iterator(T const& x) { return x; }
template <typename T> T get_iterator(std::pair<T, bool> const& x)
{
return x.first;
}
// Generic insert exception test for typical single element inserts..
template <typename T, typename Inserter, typename Values>
void insert_exception_test_impl(T x, Inserter insert, Values const& v)
{
test::strong<T> strong;
test::ordered<T> tracker;
tracker.insert(x.begin(), x.end());
try {
ENABLE_EXCEPTIONS;
for (typename Values::const_iterator it = v.begin(); it != v.end();
++it) {
strong.store(x, test::detail::tracker.count_allocations);
insert(x, it);
}
} catch (...) {
test::check_equivalent_keys(x);
insert.exception_check(x, strong);
throw;
}
typedef T data_type;
typedef test::strong<T> strong_type;
test::check_equivalent_keys(x);
insert.track(tracker, v.begin(), v.end());
tracker.compare(x);
}
data_type init() const { return T(); }
// Simple insert exception test
void check BOOST_PREVENT_MACRO_SUBSTITUTION(
T const& x, strong_type const& strong) const
template <typename T, typename Inserter>
void insert_exception_test(T*, Inserter insert, test::random_generator gen)
{
for (int i = 0; i < 5; ++i) {
test::random_values<T> v(10, gen);
T x;
EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v));
}
}
// Insert into a container which is about to hit its max load, so that it
// rehashes.
template <typename T, typename Inserter>
void insert_rehash_exception_test(
T*, Inserter insert, test::random_generator gen)
{
for (int i = 0; i < 5; ++i) {
T x;
rehash_prep(x);
test::random_values<T> v2(5, gen);
EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v2));
}
}
// Various methods for inserting a single element
struct inserter_base
{
template <typename T> void exception_check(T& x, test::strong<T>& strong)
{
std::string scope(test::scope);
if (scope.find("hash::operator()") == std::string::npos)
strong.test(x, test::detail::tracker.count_allocations);
}
template <typename T, typename Iterator>
void track(T& tracker, Iterator begin, Iterator end)
{
tracker.insert(begin, end);
}
};
struct insert_lvalue_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert(*it);
}
} insert_lvalue;
struct insert_lvalue_begin_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert(x.begin(), *it);
}
} insert_lvalue_begin;
struct insert_lvalue_end_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert(x.end(), *it);
}
} insert_lvalue_end;
struct insert_lvalue_pos_type
{
template <typename T> struct impl : inserter_base
{
typename T::iterator pos;
impl(T& x) : pos(x.begin()) {}
template <typename Iterator> void operator()(T& x, Iterator it)
{
pos = get_iterator(x.insert(pos, *it));
}
};
template <typename T> friend impl<T> generate(insert_lvalue_pos_type, T& x)
{
return impl<T>(x);
}
} insert_lvalue_pos;
struct insert_single_item_range_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert(it, test::next(it));
}
} insert_single_item_range;
struct emplace_lvalue_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace(*it);
}
} emplace_lvalue;
struct emplace_lvalue_begin_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace_hint(x.begin(), *it);
}
} emplace_lvalue_begin;
struct emplace_lvalue_end_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace_hint(x.end(), *it);
}
} emplace_lvalue_end;
struct emplace_lvalue_pos_type
{
template <typename T> struct impl : inserter_base
{
typename T::iterator pos;
impl(T& x) : pos(x.begin()) {}
template <typename Iterator> void operator()(T& x, Iterator it)
{
pos = get_iterator(x.emplace_hint(pos, *it));
}
};
template <typename T> friend impl<T> generate(emplace_lvalue_pos_type, T& x)
{
return impl<T>(x);
}
} emplace_lvalue_pos;
// Run the exception tests in various combinations.
test_set* test_set_;
test_multiset* test_multiset_;
test_map* test_map_;
test_multimap* test_multimap_;
using test::default_generator;
using test::limited_range;
using test::generate_collisions;
// clang-format off
UNORDERED_TEST(insert_exception_test,
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
(insert_lvalue_pos)(insert_single_item_range)
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
(emplace_lvalue_pos)
)
((default_generator)(limited_range)(generate_collisions))
)
UNORDERED_TEST(insert_rehash_exception_test,
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
(insert_lvalue_pos)(insert_single_item_range)
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
(emplace_lvalue_pos)
)
((default_generator)(limited_range)(generate_collisions))
)
// clang-format on
// Repeat insert tests with pairs
struct pair_emplace_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(it->first), boost::make_tuple(it->second));
}
} pair_emplace;
struct pair_emplace2_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace_hint(x.begin(), boost::unordered::piecewise_construct,
boost::make_tuple(it->first),
boost::make_tuple(it->second.tag1_, it->second.tag2_));
}
} pair_emplace2;
test_pair_set* test_pair_set_;
test_pair_multiset* test_pair_multiset_;
// clang-format off
UNORDERED_TEST(insert_exception_test,
((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
((pair_emplace)(pair_emplace2))
((default_generator)(limited_range)(generate_collisions))
)
UNORDERED_TEST(insert_rehash_exception_test,
((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
((pair_emplace)(pair_emplace2))
((default_generator)(limited_range)(generate_collisions))
)
// clang-format on
// Test inserting using operator[]
struct try_emplace_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.try_emplace(it->first, it->second);
}
} try_emplace;
struct try_emplace2_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.try_emplace(it->first, it->second.tag1_, it->second.tag2_);
}
} try_emplace2;
struct map_inserter_base
{
template <typename T> void exception_check(T& x, test::strong<T>& strong)
{
std::string scope(test::scope);
if (scope.find("hash::operator()") == std::string::npos &&
scope.find("::operator=") == std::string::npos)
strong.test(x, test::detail::tracker.count_allocations);
}
template <typename T, typename Iterator>
void track(T& tracker, Iterator begin, Iterator end)
{
for (; begin != end; ++begin) {
tracker[begin->first] = begin->second;
}
}
};
struct map_insert_operator_type : map_inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x[it->first] = it->second;
}
} map_insert_operator;
struct map_insert_or_assign_type : map_inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert_or_assign(it->first, it->second);
}
} map_insert_or_assign;
// clang-format off
UNORDERED_TEST(insert_exception_test,
((test_map_))
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
((default_generator)(limited_range)(generate_collisions))
)
UNORDERED_TEST(insert_rehash_exception_test,
((test_map_))
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
((default_generator)(limited_range)(generate_collisions))
)
// clang-format on
// Range insert tests
template <typename T, typename Values>
void insert_range_exception_test_impl(T x, Values const& v)
{
test::ordered<T> tracker;
tracker.insert(x.begin(), x.end());
try {
ENABLE_EXCEPTIONS;
x.insert(v.begin(), v.end());
} catch (...) {
test::check_equivalent_keys(x);
throw;
}
};
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
test::check_equivalent_keys(x);
tracker.insert(v.begin(), v.end());
tracker.compare(x);
}
template <class T> struct emplace_test1 : public insert_test_base<T>
template <typename T>
void insert_range_exception_test(T*, test::random_generator gen)
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.emplace(*it);
}
}
};
#endif
template <class T> struct insert_test1 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.insert(*it);
}
}
};
template <class T> struct insert_test2 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.insert(x.begin(), *it);
}
}
};
template <class T> struct insert_test3 : public insert_test_base<T>
{
void run(T& x) const { x.insert(this->values.begin(), this->values.end()); }
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
test::check_equivalent_keys(x);
}
};
template <class T> struct insert_test4 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.insert(it, test::next(it));
}
}
};
template <class T> struct insert_test_rehash1 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
insert_test_rehash1() : insert_test_base<T>(1000) {}
T init() const
{
using namespace std;
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
for (int i = 0; i < 5; ++i) {
test::random_values<T> v(10, gen);
T x;
x.max_load_factor(0.25);
// TODO: This doesn't really work is bucket_count is 0
size_type bucket_count = x.bucket_count();
size_type initial_elements = static_cast<size_type>(
ceil((double)bucket_count * (double)x.max_load_factor()) - 1);
BOOST_TEST(initial_elements < this->values.size());
x.insert(this->values.begin(),
test::next(this->values.begin(), initial_elements));
BOOST_TEST(bucket_count == x.bucket_count());
return x;
EXCEPTION_LOOP(insert_range_exception_test_impl(x, v));
}
}
void run(T& x, strong_type& strong) const
{
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
int count = 0;
BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin();
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count) {
strong.store(x, test::detail::tracker.count_allocations);
pos = x.insert(pos, *it);
}
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_TEST(x.bucket_count() != bucket_count);
}
};
template <class T> struct insert_test_rehash2 : public insert_test_rehash1<T>
template <typename T>
void insert_range_rehash_exception_test(T*, test::random_generator gen)
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
int count = 0;
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count) {
strong.store(x, test::detail::tracker.count_allocations);
x.insert(*it);
}
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_TEST(x.bucket_count() != bucket_count);
}
};
template <class T> struct insert_test_rehash3 : public insert_test_base<T>
{
BOOST_DEDUCED_TYPENAME T::size_type mutable rehash_bucket_count,
original_bucket_count;
insert_test_rehash3() : insert_test_base<T>(1000) {}
T init() const
{
using namespace std;
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
for (int i = 0; i < 5; ++i) {
T x;
x.max_load_factor(0.25);
rehash_prep(x);
original_bucket_count = x.bucket_count();
rehash_bucket_count =
static_cast<size_type>(ceil(
(double)original_bucket_count * (double)x.max_load_factor())) -
1;
size_type initial_elements =
rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1;
BOOST_TEST(initial_elements < this->values.size());
x.insert(this->values.begin(),
test::next(this->values.begin(), initial_elements));
BOOST_TEST(original_bucket_count == x.bucket_count());
return x;
test::random_values<T> v2(5, gen);
EXCEPTION_LOOP(insert_range_exception_test_impl(x, v2));
}
}
void run(T& x) const
{
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
// clang-format off
UNORDERED_TEST(insert_range_exception_test,
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
((default_generator)(limited_range)(generate_collisions))
)
x.insert(test::next(this->values.begin(), x.size()),
test::next(this->values.begin(), x.size() + 20));
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_TEST(x.bucket_count() != bucket_count);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
if (x.size() < rehash_bucket_count) {
// BOOST_TEST(x.bucket_count() == original_bucket_count);
}
test::check_equivalent_keys(x);
}
};
#define BASIC_TESTS \
(insert_test1)(insert_test2)(insert_test3)(insert_test4)( \
insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3)
#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
EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ)
template <class T> struct pair_emplace_test1 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(it->first), boost::make_tuple(it->second));
}
}
};
template <class T> struct pair_emplace_test2 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(it->first),
boost::make_tuple(it->second.tag1_, it->second.tag2_));
}
}
};
EXCEPTION_TESTS((pair_emplace_test1)(pair_emplace_test2), CONTAINER_PAIR_SEQ)
template <class T> struct index_insert_test1 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x[it->first];
}
}
};
EXCEPTION_TESTS((index_insert_test1), (test_map))
UNORDERED_TEST(insert_range_rehash_exception_test,
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
((default_generator)(limited_range)(generate_collisions))
)
// clang-format on
RUN_TESTS()
+103
View File
@@ -0,0 +1,103 @@
#include "../helpers/exception_test.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/metafunctions.hpp"
#include "../helpers/random_values.hpp"
#include "./containers.hpp"
template <typename T1, typename T2> void merge_exception_test(T1 x, T2 y)
{
std::size_t size = x.size() + y.size();
try {
ENABLE_EXCEPTIONS;
x.merge(y);
} catch (...) {
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
throw;
}
// Not a full check, just want to make sure the merge completed.
BOOST_TEST(size == x.size() + y.size());
if (y.size()) {
BOOST_TEST(test::has_unique_keys<T1>::value);
for (typename T2::iterator it = y.begin(); it != y.end(); ++it) {
BOOST_TEST(x.find(test::get_key<T2>(*it)) != x.end());
}
}
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
}
template <typename T1, typename T2>
void merge_exception_test(T1 const*, T2 const*, std::size_t count12, int tag12,
test::random_generator gen1, test::random_generator gen2)
{
std::size_t count1 = count12 / 256;
std::size_t count2 = count12 % 256;
int tag1 = tag12 / 256;
int tag2 = tag12 % 256;
test::random_values<T1> v1(count1, gen1);
test::random_values<T2> v2(count2, gen2);
T1 x(v1.begin(), v1.end(), 0, test::exception::hash(tag1),
test::exception::equal_to(tag1));
T2 y(v2.begin(), v2.end(), 0, test::exception::hash(tag2),
test::exception::equal_to(tag2));
EXCEPTION_LOOP(merge_exception_test(x, y))
}
boost::unordered_set<test::exception::object, test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> >* test_set_;
boost::unordered_multiset<test::exception::object, test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> >* test_multiset_;
boost::unordered_map<test::exception::object, test::exception::object,
test::exception::hash, test::exception::equal_to,
test::exception::allocator2<test::exception::object> >* test_map_;
boost::unordered_multimap<test::exception::object, test::exception::object,
test::exception::hash, test::exception::equal_to,
test::exception::allocator2<test::exception::object> >* test_multimap_;
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
// clang-format off
UNORDERED_MULTI_TEST(set_merge, merge_exception_test,
((test_set_)(test_multiset_))
((test_set_)(test_multiset_))
((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232))
((0x0000)(0x0001)(0x0102))
((default_generator)(limited_range))
((default_generator)(limited_range))
)
UNORDERED_MULTI_TEST(map_merge, merge_exception_test,
((test_map_)(test_multimap_))
((test_map_)(test_multimap_))
((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232))
((0x0101)(0x0200)(0x0201))
((default_generator)(limited_range))
((default_generator)(limited_range))
)
// Run fewer generate_collisions tests, as they're slow.
UNORDERED_MULTI_TEST(set_merge_collisions, merge_exception_test,
((test_set_)(test_multiset_))
((test_set_)(test_multiset_))
((0x0a0a))
((0x0202)(0x0100)(0x0201))
((generate_collisions))
((generate_collisions))
)
UNORDERED_MULTI_TEST(map_merge_collisions, merge_exception_test,
((test_map_)(test_multimap_))
((test_map_)(test_multimap_))
((0x0a0a))
((0x0000)(0x0002)(0x0102))
((generate_collisions))
((generate_collisions))
)
// clang-format on
RUN_TESTS_QUIET()
+10 -5
View File
@@ -7,7 +7,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include <iostream>
#include "../helpers/tracker.hpp"
#if defined(BOOST_MSVC)
#pragma warning( \
@@ -42,7 +42,12 @@ template <class T> struct move_assign_base : public test::exception_base
T y1 = y;
disable_exceptions.release();
x1 = boost::move(y1);
DISABLE_EXCEPTIONS;
test::check_container(x1, y_values);
test::check_equivalent_keys(x1);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
{
test::check_equivalent_keys(x1);
@@ -64,8 +69,8 @@ template <class T> struct move_assign_values : move_assign_base<T>
int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
: move_assign_base<T>(tag1, tag2, mlf1, mlf2)
{
this->x_values.fill(count1);
this->y_values.fill(count2);
this->x_values.fill(count1, test::limited_range);
this->y_values.fill(count2, test::limited_range);
this->x.insert(this->x_values.begin(), this->x_values.end());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
@@ -105,10 +110,10 @@ template <class T> struct equivalent_test1 : move_assign_base<T>
{
equivalent_test1() : move_assign_base<T>(0, 0)
{
test::random_values<T> x_values2(10);
test::random_values<T> x_values2(10, test::limited_range);
this->x_values.insert(x_values2.begin(), x_values2.end());
this->x_values.insert(x_values2.begin(), x_values2.end());
test::random_values<T> y_values2(10);
test::random_values<T> y_values2(10, test::limited_range);
this->y_values.insert(y_values2.begin(), y_values2.end());
this->y_values.insert(y_values2.begin(), y_values2.end());
this->x.insert(this->x_values.begin(), this->x_values.end());
+57 -10
View File
@@ -8,10 +8,9 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/strong.hpp"
#include "../helpers/tracker.hpp"
#include <string>
#include <iostream>
test::seed_t initialize_seed(3298597);
template <class T> struct rehash_test_base : public test::exception_base
@@ -19,7 +18,7 @@ template <class T> struct rehash_test_base : public test::exception_base
test::random_values<T> values;
unsigned int n;
rehash_test_base(unsigned int count = 100, unsigned int n_ = 0)
: values(count), n(n_)
: values(count, test::limited_range), n(n_)
{
}
@@ -49,34 +48,82 @@ template <class T> struct rehash_test_base : public test::exception_base
template <class T> struct rehash_test0 : rehash_test_base<T>
{
rehash_test0() : rehash_test_base<T>(0) {}
void run(T& x) const { x.rehash(0); }
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test1 : rehash_test_base<T>
{
rehash_test1() : rehash_test_base<T>(0) {}
void run(T& x) const { x.rehash(200); }
void run(T& x) const
{
x.rehash(200);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test2 : rehash_test_base<T>
{
rehash_test2() : rehash_test_base<T>(0, 200) {}
void run(T& x) const { x.rehash(0); }
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test3 : rehash_test_base<T>
{
rehash_test3() : rehash_test_base<T>(10, 0) {}
void run(T& x) const { x.rehash(200); }
void run(T& x) const
{
x.rehash(200);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test4 : rehash_test_base<T>
{
rehash_test4() : rehash_test_base<T>(10, 200) {}
void run(T& x) const { x.rehash(0); }
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
EXCEPTION_TESTS(
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4),
template <class T> struct rehash_test5 : rehash_test_base<T>
{
rehash_test5() : rehash_test_base<T>(200, 10) {}
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
EXCEPTION_TESTS((rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(
rehash_test4)(rehash_test5),
CONTAINER_SEQ)
RUN_TESTS()
+23 -3
View File
@@ -7,6 +7,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable : 4512) // assignment operator could not be generated
@@ -17,11 +18,22 @@ test::seed_t initialize_seed(9387);
template <class T> struct self_swap_base : public test::exception_base
{
test::random_values<T> values;
self_swap_base(std::size_t count = 0) : values(count) {}
self_swap_base(std::size_t count = 0) : values(count, test::limited_range)
{
}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
void run(T& x) const { x.swap(x); }
void run(T& x) const
{
x.swap(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
std::string scope(test::scope);
@@ -55,7 +67,8 @@ template <class T> struct swap_base : public test::exception_base
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
swap_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
: x_values(count1), y_values(count2),
: x_values(count1, test::limited_range),
y_values(count2, test::limited_range),
initial_x(x_values.begin(), x_values.end(), 0, hasher(tag1),
key_equal(tag1), allocator_type(tag1)),
initial_y(
@@ -82,7 +95,14 @@ template <class T> struct swap_base : public test::exception_base
d.x.swap(d.y);
} catch (std::runtime_error) {
}
DISABLE_EXCEPTIONS;
test::check_container(d.x, this->y_values);
test::check_equivalent_keys(d.x);
test::check_container(d.y, this->x_values);
test::check_equivalent_keys(d.y);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const
{
std::string scope(test::scope);
-1
View File
@@ -7,7 +7,6 @@
#define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
namespace test {
struct object_count
+84 -3
View File
@@ -241,8 +241,10 @@ template <class Test> void exception_safety(Test const& f, char const* /*name*/)
iteration = 0;
bool success = false;
unsigned int failure_count = 0;
char const* error_msg = 0;
do {
int error_count = boost::detail::test_errors();
++iteration;
count = 0;
@@ -252,19 +254,98 @@ template <class Test> void exception_safety(Test const& f, char const* /*name*/)
} catch (test_failure) {
error_msg = "test_failure caught.";
break;
} catch (test_exception) {
continue;
} catch (test_exception e) {
if (error_count != boost::detail::test_errors()) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM
<< "Iteration: " << iteration
<< " Error found for epoint: " << e.name << std::endl;
}
} catch (...) {
error_msg = "Unexpected exception.";
break;
}
} while (!success);
if (error_count != boost::detail::test_errors()) {
++failure_count;
}
} while (!success && failure_count < 5);
if (error_msg) {
BOOST_ERROR(error_msg);
}
runner.end();
}
//
// An alternative way to run exception tests.
// See merge_exception_tests.cpp for an example.
struct exception_looper
{
bool success;
unsigned int failure_count;
char const* error_msg;
int error_count;
exception_looper() : success(false), failure_count(0), error_msg(0) {}
void start() { iteration = 0; }
bool loop_condition() const
{
return !error_msg && !success && failure_count < 5;
}
void start_iteration()
{
error_count = boost::detail::test_errors();
++iteration;
count = 0;
}
void successful_run() { success = true; }
void test_failure_caught(test_failure const&)
{
error_msg = "test_failure caught.";
}
void test_exception_caught(test_exception const& e)
{
if (error_count != boost::detail::test_errors()) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM
<< "Iteration: " << iteration
<< " Error found for epoint: " << e.name << std::endl;
}
}
void unexpected_exception_caught() { error_msg = "Unexpected exception."; }
void end()
{
if (error_msg) {
BOOST_ERROR(error_msg);
}
}
};
#define EXCEPTION_LOOP(op) \
test::lightweight::exception_looper looper; \
looper.start(); \
while (looper.loop_condition()) { \
looper.start_iteration(); \
try { \
op; \
looper.successful_run(); \
} catch (test::lightweight::test_failure e) { \
looper.test_failure_caught(e); \
} catch (test::lightweight::test_exception e) { \
looper.test_exception_caught(e); \
} catch (...) { \
looper.unexpected_exception_caught(); \
} \
} \
looper.end();
}
}
+21 -13
View File
@@ -63,20 +63,28 @@ template <class X> void check_equivalent_keys(X const& x1)
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)
unsigned int count_checked = 0;
for (; lit != lend && !eq(get_key<X>(*lit), key); ++lit) {
++count_checked;
}
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;
std::cerr << "Checked: " << count_checked << " elements"
<< std::endl;
} else {
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;
}
}
}
};
+36 -5
View File
@@ -60,12 +60,16 @@ struct memory_tracker
unsigned int count_allocators;
unsigned int count_allocations;
unsigned int count_constructions;
bool tracking_constructions;
memory_tracker()
: count_allocators(0), count_allocations(0), count_constructions(0)
: count_allocators(0), count_allocations(0), count_constructions(0),
tracking_constructions(true)
{
}
~memory_tracker() { BOOST_TEST(count_allocators == 0); }
void allocator_ref()
{
if (count_allocators == 0) {
@@ -131,14 +135,18 @@ struct memory_tracker
void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
{
++count_constructions;
if (tracking_constructions) {
++count_constructions;
}
}
void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
{
BOOST_TEST(count_constructions > 0);
if (count_constructions > 0)
--count_constructions;
if (tracking_constructions) {
BOOST_TEST(count_constructions > 0);
if (count_constructions > 0)
--count_constructions;
}
}
};
}
@@ -153,6 +161,29 @@ namespace {
test::detail::memory_tracker tracker;
}
}
namespace detail {
struct disable_construction_tracking
{
bool old_value;
disable_construction_tracking()
: old_value(detail::tracker.tracking_constructions)
{
test::detail::tracker.tracking_constructions = false;
}
~disable_construction_tracking()
{
test::detail::tracker.tracking_constructions = old_value;
}
private:
disable_construction_tracking(disable_construction_tracking const&);
disable_construction_tracking& operator=(
disable_construction_tracking const&);
};
}
}
#endif
+121 -41
View File
@@ -9,7 +9,6 @@
#include <boost/detail/lightweight_test.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <iostream>
#define UNORDERED_AUTO_TEST(x) \
struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base \
@@ -17,7 +16,7 @@
BOOST_PP_CAT(x, _type) \
() : ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \
{ \
::test::test_list::add_test(this); \
::test::get_state().add_test(this); \
} \
void run(); \
}; \
@@ -27,12 +26,27 @@
#define RUN_TESTS() \
int main(int, char**) \
{ \
::test::write_compiler_info(); \
::test::test_list::run_tests(); \
BOOST_UNORDERED_TEST_COMPILER_INFO() \
::test::get_state().run_tests(); \
return boost::report_errors(); \
}
#define RUN_TESTS_QUIET() \
int main(int, char**) \
{ \
BOOST_UNORDERED_TEST_COMPILER_INFO() \
::test::get_state().run_tests(true); \
return boost::report_errors(); \
}
#define UNORDERED_SUB_TEST(x) \
for (int UNORDERED_SUB_TEST_VALUE = ::test::get_state().start_sub_test(x); \
UNORDERED_SUB_TEST_VALUE; \
UNORDERED_SUB_TEST_VALUE = \
::test::get_state().end_sub_test(x, UNORDERED_SUB_TEST_VALUE))
namespace test {
struct registered_test_base
{
registered_test_base* next;
@@ -42,56 +56,95 @@ struct registered_test_base
virtual ~registered_test_base() {}
};
namespace test_list {
static inline registered_test_base*& first()
struct state
{
static registered_test_base* ptr = 0;
return ptr;
}
bool is_quiet;
registered_test_base* first_test;
registered_test_base* last_test;
static inline registered_test_base*& last()
{
static registered_test_base* ptr = 0;
return ptr;
}
state() : is_quiet(false), first_test(0), last_test(0) {}
static inline void add_test(registered_test_base* test)
{
if (last()) {
last()->next = test;
} else {
first() = test;
void add_test(registered_test_base* test)
{
if (last_test) {
last_test->next = test;
} else {
first_test = test;
}
last_test = test;
}
last() = test;
}
void run_tests(bool quiet = false)
{
is_quiet = quiet;
static inline void run_tests()
{
for (registered_test_base* i = first(); i; i = i->next) {
std::cout << "Running " << i->name << "\n" << std::flush;
i->run();
std::cerr << std::flush;
std::cout << std::flush;
for (registered_test_base* i = first_test; i; i = i->next) {
int error_count = boost::detail::test_errors();
if (!quiet) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n"
<< std::flush;
}
i->run();
BOOST_LIGHTWEIGHT_TEST_OSTREAM << std::flush;
if (quiet && error_count != boost::detail::test_errors()) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in: " << i->name
<< "\n"
<< std::flush;
}
}
}
int start_sub_test(char const* name)
{
if (!is_quiet) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Sub-test: " << name << "\n"
<< std::flush;
}
// Add one because it's used as a loop condition.
return boost::detail::test_errors() + 1;
}
int end_sub_test(char const* name, int value)
{
if (is_quiet && value != boost::detail::test_errors() + 1) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in sub-test: " << name
<< "\n"
<< std::flush;
}
return 0;
}
};
// Get the currnet translation unit's test state.
static inline state& get_state()
{
static state instance;
return instance;
}
}
inline void write_compiler_info()
{
#if defined(BOOST_GCC_CXX11)
char const* cpp11 = "true";
#if defined(__cplusplus)
#define BOOST_UNORDERED_CPLUSPLUS __cplusplus
#else
char const* cpp11 = "false";
#define BOOST_UNORDERED_CPLUSPLUS "(not defined)"
#endif
std::cout << "Compiler: " << BOOST_COMPILER << "\n"
<< "Library: " << BOOST_STDLIB << "\n"
<< "C++11: " << cpp11 << "\n"
<< "\n"
<< std::flush;
}
}
#define BOOST_UNORDERED_TEST_COMPILER_INFO() \
{ \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Compiler: " << BOOST_COMPILER << "\n" \
<< "Library: " << BOOST_STDLIB << "\n" \
<< "__cplusplus: " << BOOST_UNORDERED_CPLUSPLUS << "\n\n" \
<< "BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT: " \
<< BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \
<< "BOOST_UNORDERED_EMPLACE_LIMIT: " \
<< BOOST_UNORDERED_EMPLACE_LIMIT << "\n" \
<< "BOOST_UNORDERED_USE_ALLOCATOR_TRAITS: " \
<< BOOST_UNORDERED_USE_ALLOCATOR_TRAITS << "\n" \
<< "BOOST_UNORDERED_CXX11_CONSTRUCTION: " \
<< BOOST_UNORDERED_CXX11_CONSTRUCTION << "\n\n" \
<< std::flush; \
}
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/fold_left.hpp>
@@ -122,4 +175,31 @@ inline void write_compiler_info()
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem))
#define UNORDERED_MULTI_TEST(name, impl, parameters) \
UNORDERED_MULTI_TEST_REPEAT(name, impl, 1, parameters)
#define UNORDERED_MULTI_TEST_REPEAT(name, impl, n, parameters) \
UNORDERED_AUTO_TEST(name) \
{ \
BOOST_PP_SEQ_FOR_EACH_PRODUCT( \
UNORDERED_MULTI_TEST_OP, ((impl))((n))parameters) \
}
#define UNORDERED_MULTI_TEST_OP(r, product) \
UNORDERED_MULTI_TEST_OP2(BOOST_PP_SEQ_ELEM(0, product), \
BOOST_PP_SEQ_ELEM(1, product), \
BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product)))
// Need to wrap UNORDERED_SUB_TEST in a block to avoid an msvc bug.
// https://support.microsoft.com/en-gb/help/315481/bug-too-many-unnested-loops-incorrectly-causes-a-c1061-compiler-error-in-visual-c
#define UNORDERED_MULTI_TEST_OP2(name, n, params) \
{ \
UNORDERED_SUB_TEST(BOOST_PP_STRINGIZE( \
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params))) \
{ \
for (int i = 0; i < n; ++i) \
name BOOST_PP_SEQ_TO_TUPLE(params); \
} \
}
#endif
+63 -35
View File
@@ -10,10 +10,11 @@
#include "../helpers/count.hpp"
#include "../helpers/fwd.hpp"
#include "../helpers/generators.hpp"
#include "../helpers/memory.hpp"
#include "./fwd.hpp"
#include <boost/limits.hpp>
#include <cstddef>
#include <iostream>
#include <new>
namespace test {
@@ -225,6 +226,55 @@ class hash
}
};
class less
{
int tag_;
public:
less(int t = 0) : tag_(t) {}
less(less const& x) : tag_(x.tag_) {}
bool operator()(object const& x1, object const& x2) const
{
return less_impl(x1, x2);
}
bool operator()(std::pair<object, object> const& x1,
std::pair<object, object> const& x2) const
{
if (less_impl(x1.first, x2.first)) {
return true;
}
if (!less_impl(x1.first, x2.first)) {
return false;
}
return less_impl(x1.second, x2.second);
}
bool less_impl(object const& x1, object const& x2) const
{
switch (tag_) {
case 1:
return x1.tag1_ < x2.tag1_;
case 2:
return x1.tag2_ < x2.tag2_;
default:
return x1 < x2;
}
}
friend bool operator==(less const& x1, less const& x2)
{
return x1.tag_ == x2.tag_;
}
friend bool operator!=(less const& x1, less const& x2)
{
return x1.tag_ != x2.tag_;
}
};
class equal_to
{
int tag_;
@@ -309,6 +359,8 @@ class equal_to
}
return x1.tag_ != x2.tag_;
}
friend less create_compare(equal_to x) { return less(x.tag_); }
};
template <class T> class allocator
@@ -339,19 +391,11 @@ template <class T> class allocator
template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator::allocator())
{
UNORDERED_EPOINT("Mock allocator template copy constructor.");
}
test::detail::tracker.allocator_ref();
}
allocator(allocator const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator::allocator())
{
UNORDERED_EPOINT("Mock allocator copy constructor.");
}
test::detail::tracker.allocator_ref();
}
@@ -359,11 +403,7 @@ template <class T> class allocator
allocator& operator=(allocator const& x)
{
UNORDERED_SCOPE(allocator::allocator())
{
UNORDERED_EPOINT("Mock allocator assignment operator.");
tag_ = x.tag_;
}
tag_ = x.tag_;
return *this;
}
@@ -530,42 +570,22 @@ template <class T> class allocator2
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;
}
allocator2& operator=(allocator2 const&) { 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
@@ -704,6 +724,14 @@ inline bool operator!=(allocator2<T> const& x, allocator2<T> const& y)
}
}
namespace test {
template <typename X> struct equals_to_compare;
template <> struct equals_to_compare<test::exception::equal_to>
{
typedef test::exception::less type;
};
}
// Workaround for ADL deficient compilers
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace test {
+23 -7
View File
@@ -391,21 +391,37 @@ template <class T> class allocator1
::operator delete((void*)p);
}
void construct(T* p, T const& t)
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
template <typename U, typename... Args> void construct(U* p, Args&&... args)
{
// Don't count constructions here as it isn't always called.
// detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new (p) T(t);
detail::tracker.track_construct((void*)p, sizeof(U), tag_);
new (p) U(boost::forward<Args>(args)...);
}
void destroy(T* p)
template <typename U> void destroy(U* p)
{
// detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
p->~T();
detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
p->~U();
// Work around MSVC buggy unused parameter warning.
ignore_variable(&p);
}
#else
private:
// I'm going to claim in the documentation that construct/destroy
// is never used when C++11 support isn't available, so might as
// well check that in the text.
// TODO: Or maybe just disallow them for values?
template <typename U> void construct(U* p);
template <typename U, typename A0> void construct(U* p, A0 const&);
template <typename U, typename A0, typename A1>
void construct(U* p, A0 const&, A1 const&);
template <typename U, typename A0, typename A1, typename A2>
void construct(U* p, A0 const&, A1 const&, A2 const&);
template <typename U> void destroy(U* p);
public:
#endif
bool operator==(allocator1 const& x) const { return tag_ == x.tag_; }
+10 -12
View File
@@ -17,8 +17,6 @@
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include <iostream>
#if defined(BOOST_MSVC)
#pragma warning(disable : 4127) // conditional expression is constant
#endif
@@ -32,7 +30,7 @@ template <class T> 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";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.1\n";
{
test::check_instances check_;
@@ -43,7 +41,7 @@ template <class T> void assign_tests1(T*, test::random_generator generator)
BOOST_TEST(test::equivalent(x.key_eq(), eq));
}
std::cerr << "assign_tests1.2\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.2\n";
{
test::check_instances check_;
@@ -79,7 +77,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
std::cerr << "assign_tests2.0 - empty container\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.0 - empty container\n";
{
test::check_instances check_;
@@ -93,7 +91,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
test::check_container(x1, x2);
}
std::cerr << "assign_tests2.1\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1\n";
{
test::check_instances check_;
@@ -110,7 +108,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr << "assign_tests2.1a\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1a\n";
{
test::check_instances check_;
@@ -128,7 +126,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr << "assign_tests2.2\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.2\n";
{
test::check_instances check_;
@@ -150,7 +148,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr << "assign_tests2.3\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.3\n";
{
test::check_instances check_;
@@ -172,7 +170,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr << "assign_tests2.4\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.4\n";
{
test::check_instances check_;
@@ -271,7 +269,7 @@ UNORDERED_TEST(
UNORDERED_AUTO_TEST(assign_default_initializer_list)
{
std::cerr << "Initializer List Tests\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n";
std::initializer_list<std::pair<int const, int> > init;
boost::unordered_map<int, int> x1;
x1[25] = 3;
@@ -286,7 +284,7 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST(assign_initializer_list)
{
std::cerr << "Initializer List Tests\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n";
boost::unordered_set<int> x;
x.insert(10);
+23
View File
@@ -19,6 +19,21 @@ UNORDERED_AUTO_TEST(at_tests)
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl;
boost::unordered_map<std::string, int> x;
boost::unordered_map<std::string, int> const& x_const(x);
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check empty container" << std::endl;
try {
x.at("one");
BOOST_ERROR("Should have thrown.");
} catch (std::out_of_range) {
}
try {
x_const.at("one");
BOOST_ERROR("Should have thrown.");
} catch (std::out_of_range) {
}
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Add elements" << std::endl;
@@ -29,6 +44,8 @@ UNORDERED_AUTO_TEST(at_tests)
BOOST_TEST(x.at("one") == 1);
BOOST_TEST(x.at("two") == 2);
BOOST_TEST(x_const.at("one") == 1);
BOOST_TEST(x_const.at("two") == 2);
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check missing element" << std::endl;
@@ -38,6 +55,12 @@ UNORDERED_AUTO_TEST(at_tests)
} catch (std::out_of_range) {
}
try {
x_const.at("three");
BOOST_ERROR("Should have thrown.");
} catch (std::out_of_range) {
}
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Finished" << std::endl;
}
}
+2 -1
View File
@@ -37,7 +37,8 @@ template <class X> void tests(X*, test::random_generator generator)
BOOST_TEST(x.bucket_count() <= x.max_bucket_count());
if (!(x.bucket_count() <= x.max_bucket_count())) {
std::cerr << x.bucket_count() << "<=" << x.max_bucket_count() << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << x.bucket_count()
<< "<=" << x.max_bucket_count() << "\n";
}
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator
+38 -7
View File
@@ -12,7 +12,6 @@
#include "../helpers/postfix.hpp"
// clang-format on
#include <iostream>
#include "../helpers/test.hpp"
#include "../objects/minimal.hpp"
#include "./compile_tests.hpp"
@@ -46,7 +45,7 @@ UNORDERED_AUTO_TEST(test0)
value_type;
value_type value(x, x);
std::cout << "Test unordered_map.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
boost::unordered_map<int, int> int_map;
@@ -64,7 +63,7 @@ UNORDERED_AUTO_TEST(test0)
container_test(int_map2, std::pair<int const, int>(0, 0));
container_test(map, value);
std::cout << "Test unordered_multimap.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
boost::unordered_multimap<int, int> int_multimap;
@@ -139,7 +138,7 @@ UNORDERED_AUTO_TEST(test1)
int value = 0;
std::pair<int const, int> map_value(0, 0);
std::cout << "Test unordered_map.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
boost::unordered_map<int, int> map;
@@ -157,7 +156,7 @@ UNORDERED_AUTO_TEST(test1)
unordered_copyable_test(map2, value, map_value, hash, equal_to);
unordered_map_functions(map2, value, value);
std::cout << "Test unordered_multimap.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
boost::unordered_multimap<int, int> multimap;
@@ -188,7 +187,7 @@ UNORDERED_AUTO_TEST(test2)
map_value_type;
map_value_type map_value(assignable, assignable);
std::cout << "Test unordered_map.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
boost::unordered_map<test::minimal::assignable, test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
@@ -212,7 +211,7 @@ UNORDERED_AUTO_TEST(test2)
unordered_map_functions(map2, assignable, default_assignable);
std::cout << "Test unordered_multimap.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
boost::unordered_multimap<test::minimal::assignable,
test::minimal::assignable,
@@ -227,4 +226,36 @@ UNORDERED_AUTO_TEST(test2)
unordered_map_member_test(multimap, map_value);
}
// Test for ambiguity when using key convertible from iterator
// See LWG2059
struct lwg2059_key
{
int value;
template <typename T> lwg2059_key(T v) : value(v) {}
};
std::size_t hash_value(lwg2059_key x)
{
return static_cast<std::size_t>(x.value);
}
bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
UNORDERED_AUTO_TEST(lwg2059)
{
{
boost::unordered_map<lwg2059_key, int> x;
x.emplace(lwg2059_key(10), 5);
x.erase(x.begin());
}
{
boost::unordered_multimap<lwg2059_key, int> x;
x.emplace(lwg2059_key(10), 5);
x.erase(x.begin());
}
}
RUN_TESTS()
+44 -13
View File
@@ -12,7 +12,6 @@
#include "../helpers/postfix.hpp"
// clang-format on
#include <iostream>
#include "../helpers/test.hpp"
#include "../objects/minimal.hpp"
#include "./compile_tests.hpp"
@@ -42,7 +41,7 @@ UNORDERED_AUTO_TEST(test0)
test::minimal::assignable assignable(x);
std::cout << "Test unordered_set.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<int> int_set;
@@ -60,7 +59,7 @@ UNORDERED_AUTO_TEST(test0)
container_test(int_set2, 0);
container_test(set, assignable);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<int> int_multiset;
@@ -128,7 +127,7 @@ UNORDERED_AUTO_TEST(test1)
std::equal_to<int> equal_to;
int value = 0;
std::cout << "Test unordered_set." << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set." << std::endl;
boost::unordered_set<int> set;
@@ -144,7 +143,7 @@ UNORDERED_AUTO_TEST(test1)
unordered_set_test(set2, value);
unordered_copyable_test(set2, value, value, hash, equal_to);
std::cout << "Test unordered_multiset." << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset." << std::endl;
boost::unordered_multiset<int> multiset;
@@ -170,7 +169,7 @@ UNORDERED_AUTO_TEST(test2)
test::minimal::hash<test::minimal::assignable> hash(x);
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
std::cout << "Test unordered_set.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
@@ -183,7 +182,7 @@ UNORDERED_AUTO_TEST(test2)
unordered_copyable_test(set, assignable, assignable, hash, equal_to);
unordered_set_member_test(set, assignable);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
@@ -205,7 +204,7 @@ UNORDERED_AUTO_TEST(movable1_tests)
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_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<test::minimal::movable1,
test::minimal::hash<test::minimal::movable1>,
@@ -217,7 +216,7 @@ UNORDERED_AUTO_TEST(movable1_tests)
unordered_set_test(set, movable1);
unordered_movable_test(set, movable1, movable1, hash, equal_to);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<test::minimal::movable1,
test::minimal::hash<test::minimal::movable1>,
@@ -238,7 +237,7 @@ UNORDERED_AUTO_TEST(movable2_tests)
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_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<test::minimal::movable2,
test::minimal::hash<test::minimal::movable2>,
@@ -250,7 +249,7 @@ UNORDERED_AUTO_TEST(movable2_tests)
unordered_set_test(set, movable2);
unordered_movable_test(set, movable2, movable2, hash, equal_to);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<test::minimal::movable2,
test::minimal::hash<test::minimal::movable2>,
@@ -271,7 +270,7 @@ UNORDERED_AUTO_TEST(destructible_tests)
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_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<test::minimal::destructible,
test::minimal::hash<test::minimal::destructible>,
@@ -280,7 +279,7 @@ UNORDERED_AUTO_TEST(destructible_tests)
unordered_destructible_test(set);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<test::minimal::destructible,
test::minimal::hash<test::minimal::destructible>,
@@ -290,4 +289,36 @@ UNORDERED_AUTO_TEST(destructible_tests)
unordered_destructible_test(multiset);
}
// Test for ambiguity when using key convertible from iterator
// See LWG2059
struct lwg2059_key
{
int value;
template <typename T> lwg2059_key(T v) : value(v) {}
};
std::size_t hash_value(lwg2059_key x)
{
return static_cast<std::size_t>(x.value);
}
bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
UNORDERED_AUTO_TEST(lwg2059)
{
{
boost::unordered_set<lwg2059_key> x;
x.emplace(lwg2059_key(10));
x.erase(x.begin());
}
{
boost::unordered_multiset<lwg2059_key> x;
x.emplace(lwg2059_key(10));
x.erase(x.begin());
}
}
RUN_TESTS()
+76 -7
View File
@@ -19,7 +19,9 @@
#include "../helpers/check_return_type.hpp"
#include <boost/iterator/iterator_traits.hpp>
#include <boost/limits.hpp>
#include <boost/predef.h>
#include <boost/static_assert.hpp>
#include <boost/type_traits/cv_traits.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/swap.hpp>
@@ -30,6 +32,23 @@ 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(); }
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
template <class T> T implicit_construct() { return {}; }
#else
template <class T> int implicit_construct()
{
T x;
sink(x);
return 0;
}
#endif
#if !defined(BOOST_NO_CXX11_NOEXCEPT)
#define TEST_NOEXCEPT_EXPR(x) BOOST_STATIC_ASSERT((BOOST_NOEXCEPT_EXPR(x)));
#else
#define TEST_NOEXCEPT_EXPR(x)
#endif
template <class X, class T> void container_test(X& r, T const&)
{
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
@@ -52,6 +71,8 @@ template <class X, class T> void container_test(X& r, T const&)
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
// value_type
BOOST_STATIC_ASSERT((boost::is_same<T, value_type>::value));
@@ -75,7 +96,9 @@ template <class X, class T> void container_test(X& r, T const&)
BOOST_STATIC_ASSERT((boost::is_same<T, const_iterator_value_type>::value));
// node_type
// TODO?
BOOST_STATIC_ASSERT((boost::is_same<allocator_type,
BOOST_DEDUCED_TYPENAME node_type::allocator_type>::value));
// difference_type
@@ -134,7 +157,6 @@ template <class X, class T> void container_test(X& r, T const&)
// Allocator
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
test::check_return_type<allocator_type>::equals(a_const.get_allocator());
allocator_type m = a.get_allocator();
@@ -147,21 +169,30 @@ template <class X, class T> void container_test(X& r, T const&)
// node_type
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
BOOST_STATIC_ASSERT((boost::is_same<allocator_type,
BOOST_DEDUCED_TYPENAME node_type::allocator_type>::value));
implicit_construct<node_type const>();
#if !BOOST_COMP_GNUC || BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4, 8, 0)
TEST_NOEXCEPT_EXPR(node_type());
#endif
node_type n1;
node_type n2(rvalue_default<node_type>());
#if !BOOST_COMP_GNUC || BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4, 8, 0)
TEST_NOEXCEPT_EXPR(node_type(boost::move(n1)));
#endif
node_type n3;
n3 = boost::move(n2);
n1.swap(n3);
swap(n1, n3);
// TODO: noexcept for swap?
// value, key, mapped tests in map and set specific testing.
node_type const n_const;
BOOST_TEST(n_const ? 0 : 1);
TEST_NOEXCEPT_EXPR(n_const ? 0 : 1);
test::check_return_type<bool>::equals(!n_const);
test::check_return_type<bool>::equals(n_const.empty());
TEST_NOEXCEPT_EXPR(!n_const);
TEST_NOEXCEPT_EXPR(n_const.empty());
// Avoid unused variable warnings:
@@ -302,14 +333,22 @@ void unordered_map_test(X& r, Key const& k, T const& v)
BOOST_STATIC_ASSERT((boost::is_same<Key, node_key_type>::value));
BOOST_STATIC_ASSERT((boost::is_same<T, node_mapped_type>::value));
// Superfluous,but just to make sure.
BOOST_STATIC_ASSERT((!boost::is_const<node_key_type>::value));
// Calling functions
r.insert(std::pair<Key const, T>(k, v));
r.insert(r.begin(), std::pair<Key const, T>(k, v));
std::pair<Key const, T> const value(k, v);
r.insert(value);
r.insert(r.end(), value);
Key k_lvalue(k);
T v_lvalue(v);
// Emplace
r.emplace(k, v);
r.emplace(k_lvalue, v_lvalue);
r.emplace(rvalue(k), rvalue(v));
@@ -317,6 +356,17 @@ void unordered_map_test(X& r, Key const& k, T const& v)
r.emplace(boost::unordered::piecewise_construct, boost::make_tuple(k),
boost::make_tuple(v));
// Emplace with hint
r.emplace_hint(r.begin(), k, v);
r.emplace_hint(r.begin(), k_lvalue, v_lvalue);
r.emplace_hint(r.begin(), rvalue(k), rvalue(v));
r.emplace_hint(r.begin(), boost::unordered::piecewise_construct,
boost::make_tuple(k), boost::make_tuple(v));
// Extract
test::check_return_type<node_type>::equals(r.extract(r.begin()));
r.emplace(k, v);
@@ -327,8 +377,16 @@ void unordered_map_test(X& r, Key const& k, T const& v)
test::check_return_type<key_type>::equals_ref(n1.key());
test::check_return_type<T>::equals_ref(n1.mapped());
r.insert(boost::move(n1));
node_type n2 = boost::move(n1);
r.insert(boost::move(n2));
r.insert(r.extract(r.begin()));
n2 = r.extract(r.begin());
r.insert(r.begin(), boost::move(n2));
r.insert(r.end(), r.extract(r.begin()));
node_type n = r.extract(r.begin());
test::check_return_type<node_key_type>::equals_ref(n.key());
test::check_return_type<node_mapped_type>::equals_ref(n.mapped());
}
template <class X> void equality_test(X& r)
@@ -385,6 +443,7 @@ void unordered_map_functions(X&, Key const& k, T const& v)
X a;
test::check_return_type<mapped_type>::equals_ref(a[k]);
test::check_return_type<mapped_type>::equals_ref(a[rvalue(k)]);
test::check_return_type<mapped_type>::equals_ref(a.at(k));
test::check_return_type<std::pair<iterator, bool> >::equals(
a.try_emplace(k, v));
@@ -517,6 +576,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
const_iterator q1 = a.cbegin(), q2 = a.cend();
test::check_return_type<iterator>::equals(a.erase(q1, q2));
TEST_NOEXCEPT_EXPR(a.clear());
a.clear();
X const b;
@@ -627,6 +687,13 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
sink(X(b, m));
X a9a(b, m);
X b1;
b1.insert(t);
X a9b(b1);
sink(a9b);
X a9c(b1, m);
sink(a9c);
const_iterator q = a.cbegin();
test::check_return_type<iterator>::equals(a.insert(q, t));
@@ -638,7 +705,9 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
a.insert(list);
a.insert({t, t, t});
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) && \
(!defined(__clang__) || __clang_major__ >= 4 || \
(__clang_major__ == 3 && __clang_minor__ >= 4))
a.insert({});
a.insert({t});
a.insert({t, t});
+27 -31
View File
@@ -28,7 +28,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
BOOST_DEDUCED_TYPENAME T::key_equal eq;
BOOST_DEDUCED_TYPENAME T::allocator_type al;
std::cerr << "Construct 1\n";
UNORDERED_SUB_TEST("Construct 1")
{
test::check_instances check_;
@@ -40,7 +40,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 2\n";
UNORDERED_SUB_TEST("Construct 2")
{
test::check_instances check_;
@@ -53,7 +53,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 3\n";
UNORDERED_SUB_TEST("Construct 3")
{
test::check_instances check_;
@@ -66,7 +66,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 4\n";
UNORDERED_SUB_TEST("Construct 4")
{
test::check_instances check_;
@@ -78,7 +78,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 5\n";
UNORDERED_SUB_TEST("Construct 5")
{
test::check_instances check_;
@@ -92,7 +92,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 6\n";
UNORDERED_SUB_TEST("Construct 6")
{
test::check_instances check_;
@@ -106,7 +106,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 7\n";
UNORDERED_SUB_TEST("Construct 7")
{
test::check_instances check_;
@@ -120,7 +120,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 8\n";
UNORDERED_SUB_TEST("Construct 8")
{
test::check_instances check_;
@@ -133,7 +133,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 9\n";
UNORDERED_SUB_TEST("Construct 9")
{
test::check_instances check_;
@@ -145,7 +145,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 10\n";
UNORDERED_SUB_TEST("Construct 10")
{
test::check_instances check_;
@@ -159,7 +159,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 11\n";
UNORDERED_SUB_TEST("Construct 11")
{
test::check_instances check_;
@@ -185,7 +185,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
std::cerr << "Construct 1\n";
UNORDERED_SUB_TEST("Construct 1")
{
test::check_instances check_;
T x(10000, hf1, eq1);
@@ -196,7 +196,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 2\n";
UNORDERED_SUB_TEST("Construct 2")
{
test::check_instances check_;
T x(100, hf1);
@@ -208,7 +208,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 3\n";
UNORDERED_SUB_TEST("Construct 3")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@@ -220,7 +220,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 4\n";
UNORDERED_SUB_TEST("Construct 4")
{
test::check_instances check_;
test::random_values<T> v(5, generator);
@@ -233,7 +233,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 5\n";
UNORDERED_SUB_TEST("Construct 5")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@@ -245,7 +245,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 6\n";
UNORDERED_SUB_TEST("Construct 6")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@@ -257,7 +257,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 7\n";
UNORDERED_SUB_TEST("Construct 7")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@@ -269,7 +269,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 8 - from input iterator\n";
UNORDERED_SUB_TEST("Construct 8 - from input iterator")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@@ -288,7 +288,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 8.5 - from copy iterator\n";
UNORDERED_SUB_TEST("Construct 8.5 - from copy iterator")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@@ -302,7 +302,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 9\n";
UNORDERED_SUB_TEST("Construct 9")
{
test::check_instances check_;
@@ -320,7 +320,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
#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";
UNORDERED_SUB_TEST("Initializer list construct 1")
{
test::check_instances check_;
@@ -331,7 +331,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
std::cerr << "Initializer list construct 2\n";
UNORDERED_SUB_TEST("Initializer list construct 2")
{
test::check_instances check_;
@@ -343,7 +343,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
std::cerr << "Initializer list construct 3\n";
UNORDERED_SUB_TEST("Initializer list construct 3")
{
test::check_instances check_;
@@ -355,7 +355,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
std::cerr << "Initializer list construct 4\n";
UNORDERED_SUB_TEST("Initializer list construct 4")
{
test::check_instances check_;
@@ -367,7 +367,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
std::cerr << "Initializer list construct 5\n";
UNORDERED_SUB_TEST("Initializer list construct 5")
{
test::check_instances check_;
@@ -384,8 +384,6 @@ void constructor_tests2(T*, test::random_generator const& generator)
template <class T>
void map_constructor_test(T*, test::random_generator const& generator)
{
std::cerr << "map_constructor_test\n";
typedef test::list<std::pair<BOOST_DEDUCED_TYPENAME T::key_type,
BOOST_DEDUCED_TYPENAME T::mapped_type> >
list;
@@ -429,7 +427,6 @@ UNORDERED_TEST(map_constructor_test,
UNORDERED_AUTO_TEST(test_default_initializer_list)
{
std::cerr << "Initializer List Tests\n";
std::initializer_list<int> init;
boost::unordered_set<int> x1 = init;
BOOST_TEST(x1.empty());
@@ -441,7 +438,6 @@ UNORDERED_AUTO_TEST(test_default_initializer_list)
UNORDERED_AUTO_TEST(test_initializer_list)
{
std::cerr << "Initializer List Tests\n";
boost::unordered_set<int> x1 = {2, 10, 45, -5};
BOOST_TEST(x1.find(10) != x1.end());
BOOST_TEST(x1.find(46) == x1.end());
@@ -450,4 +446,4 @@ UNORDERED_AUTO_TEST(test_initializer_list)
#endif
}
RUN_TESTS()
RUN_TESTS_QUIET()
+102
View File
@@ -0,0 +1,102 @@
// Copyright 2017 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)
// clang-format off
#include "../helpers/prefix.hpp"
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "../helpers/postfix.hpp"
// clang-format on
#include "../helpers/test.hpp"
#include <map>
// Pretty inefficient, but the test is fast enough.
// Might be too slow if we had larger primes?
bool is_prime(std::size_t x)
{
if (x == 2) {
return true;
} else if (x == 1 || x % 2 == 0) {
return false;
} else {
// y*y <= x had rounding errors, so instead use y <= (x/y).
for (std::size_t y = 3; y <= (x / y); y += 2) {
if (x % y == 0) {
return false;
break;
}
}
return true;
}
}
void test_next_prime(std::size_t value)
{
std::size_t x = boost::unordered::detail::next_prime(value);
BOOST_TEST(is_prime(x));
BOOST_TEST(x >= value);
}
void test_prev_prime(std::size_t value)
{
std::size_t x = boost::unordered::detail::prev_prime(value);
BOOST_TEST(is_prime(x));
BOOST_TEST(x <= value);
if (x > value) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << x << "," << value << std::endl;
}
}
UNORDERED_AUTO_TEST(next_prime_test)
{
BOOST_TEST(!is_prime(0));
BOOST_TEST(!is_prime(1));
BOOST_TEST(is_prime(2));
BOOST_TEST(is_prime(3));
BOOST_TEST(is_prime(13));
BOOST_TEST(!is_prime(4));
BOOST_TEST(!is_prime(100));
BOOST_TEST(boost::unordered::detail::next_prime(0) > 0);
// test_prev_prime doesn't work for values less than 17.
// Which should be okay, unless an allocator has a really tiny
// max_size?
const std::size_t min_prime = 17;
// test_next_prime doesn't work for values greater than this,
// which might be a problem if you've got terrabytes of memory?
// I seriously doubt the container would work well at such sizes
// regardless.
const std::size_t max_prime = 4294967291ul;
std::size_t i;
BOOST_TEST(is_prime(min_prime));
BOOST_TEST(is_prime(max_prime));
for (i = 0; i < 10000; ++i) {
if (i < min_prime) {
BOOST_TEST(boost::unordered::detail::prev_prime(i) == min_prime);
} else {
test_prev_prime(i);
}
test_next_prime(i);
}
std::size_t last = i - 1;
for (; i > last; last = i, i += i / 5) {
if (i > max_prime) {
BOOST_TEST(boost::unordered::detail::next_prime(i) == max_prime);
} else {
test_next_prime(i);
}
test_prev_prime(i);
}
}
RUN_TESTS()
-2
View File
@@ -17,8 +17,6 @@
#include "../helpers/tracker.hpp"
#include "../helpers/invariants.hpp"
#include <iostream>
template <class Container, class Iterator>
void test_equal_insertion(Iterator begin, Iterator end)
{
+13 -12
View File
@@ -17,7 +17,6 @@
#include "../helpers/invariants.hpp"
#include "../helpers/helpers.hpp"
#include <set>
#include <iostream>
#include <iterator>
#include "../objects/test.hpp"
@@ -31,14 +30,15 @@ struct write_pair_type
template <class X1, class X2>
void operator()(std::pair<X1, X2> const& x) const
{
std::cout << "(" << x.first << "," << x.second << ")";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "(" << x.first << "," << x.second
<< ")";
}
} write_pair;
template <class Container> void write_container(Container const& x)
{
std::for_each(x.begin(), x.end(), write_pair);
std::cout << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
// Make everything collide - for testing erase in a single bucket.
@@ -165,8 +165,8 @@ template <class Container> void erase_subrange_tests(Container const& x)
collide_list init(y.begin(), y.end());
if (!general_erase_range_test(y, position, position + length)) {
BOOST_ERROR("general_erase_range_test failed.");
std::cout << "Erase: [" << position << "," << position + length
<< ")\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase: [" << position << ","
<< position + length << ")\n";
write_container(init);
write_container(y);
}
@@ -185,7 +185,8 @@ void x_by_y_erase_range_tests(Container*, int values, int duplicates)
}
}
std::cout << "Values: " << values << ", Duplicates: " << duplicates << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Values: " << values
<< ", Duplicates: " << duplicates << "\n";
erase_subrange_tests(y);
}
@@ -201,24 +202,24 @@ void exhaustive_erase_tests(Container* x, int num_values, int num_duplicated)
UNORDERED_AUTO_TEST(exhaustive_collide_tests)
{
std::cout << "exhaustive_collide_tests:\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide_tests:\n";
collide_map m;
exhaustive_erase_tests((collide_map*)0, 4, 4);
std::cout << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
UNORDERED_AUTO_TEST(exhaustive_collide2_tests)
{
std::cout << "exhaustive_collide2_tests:\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide2_tests:\n";
exhaustive_erase_tests((collide_map2*)0, 8, 4);
std::cout << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
UNORDERED_AUTO_TEST(exhaustive_collide3_tests)
{
std::cout << "exhaustive_collide3_tests:\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide3_tests:\n";
exhaustive_erase_tests((collide_map3*)0, 8, 4);
std::cout << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
RUN_TESTS()
+13 -12
View File
@@ -18,7 +18,6 @@
#include "../helpers/helpers.hpp"
#include "../helpers/invariants.hpp"
#include <vector>
#include <iostream>
#include <cstdlib>
namespace erase_tests {
@@ -31,7 +30,7 @@ void erase_tests1(Container*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME Container::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME Container::const_iterator c_iterator;
std::cerr << "Erase by key.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase by key.\n";
{
test::check_instances check_;
@@ -52,7 +51,7 @@ void erase_tests1(Container*, test::random_generator generator)
}
}
std::cerr << "erase(begin()).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(begin()).\n";
{
test::check_instances check_;
@@ -75,7 +74,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "erase(random position).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random position).\n";
{
test::check_instances check_;
@@ -104,7 +103,8 @@ void erase_tests1(Container*, test::random_generator generator)
index == 0 ? next == x.begin() : next == test::next(prev));
BOOST_TEST(x.count(key) == count - 1);
if (x.count(key) != count - 1) {
std::cerr << count << " => " << x.count(key) << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => "
<< x.count(key) << std::endl;
}
BOOST_TEST(x.size() == size);
if (++iterations % 20 == 0)
@@ -113,7 +113,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "erase(ranges).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(ranges).\n";
{
test::check_instances check_;
@@ -140,7 +140,7 @@ void erase_tests1(Container*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "erase(random ranges).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random ranges).\n";
{
test::check_instances check_;
Container x;
@@ -179,7 +179,7 @@ void erase_tests1(Container*, test::random_generator generator)
}
}
std::cerr << "quick_erase(begin()).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(begin()).\n";
{
test::check_instances check_;
@@ -201,7 +201,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "quick_erase(random position).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(random position).\n";
{
test::check_instances check_;
@@ -230,7 +230,8 @@ void erase_tests1(Container*, test::random_generator generator)
index == 0 ? next == x.begin() : next == test::next(prev));
BOOST_TEST(x.count(key) == count - 1);
if (x.count(key) != count - 1) {
std::cerr << count << " => " << x.count(key) << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => "
<< x.count(key) << std::endl;
}
BOOST_TEST(x.size() == size);
if (++iterations % 20 == 0)
@@ -239,7 +240,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "clear().\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "clear().\n";
{
test::check_instances check_;
@@ -250,7 +251,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.begin() == x.end());
}
std::cerr << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
boost::unordered_set<test::object, test::hash, test::equal_to,
+4 -6
View File
@@ -19,8 +19,6 @@
#include "../objects/test.hpp"
#include <boost/next_prior.hpp>
#include <iostream>
namespace extract_tests {
test::seed_t initialize_seed(85638);
@@ -28,7 +26,7 @@ test::seed_t initialize_seed(85638);
template <class Container>
void extract_tests1(Container*, test::random_generator generator)
{
std::cerr << "Extract by key.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Extract by key.\n";
{
test::check_instances check_;
@@ -58,7 +56,7 @@ void extract_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "extract(begin()).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(begin()).\n";
{
test::check_instances check_;
@@ -81,7 +79,7 @@ void extract_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "extract(random position).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(random position).\n";
{
test::check_instances check_;
@@ -117,7 +115,7 @@ void extract_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
boost::unordered_set<test::object, test::hash, test::equal_to,
+5
View File
@@ -65,6 +65,11 @@ template <typename T> struct allocator : std::allocator<T>
allocator(const allocator<T2>& other) : std::allocator<T>(other)
{
}
template <typename T2>
allocator(const std::allocator<T2>& other) : std::allocator<T>(other)
{
}
};
// Declare some members of a structs.
-1
View File
@@ -15,7 +15,6 @@
#include <map>
#include <set>
#include <iostream>
namespace insert_hint {
UNORDERED_AUTO_TEST(insert_hint_empty)
+3 -5
View File
@@ -12,8 +12,6 @@
#include "../helpers/test.hpp"
#include <iostream>
namespace insert_stable {
struct member
{
@@ -47,9 +45,9 @@ std::size_t hash_value(insert_stable::member const& x)
}
}
// This is now only supported when using grouped nodes. I can't see any
// efficient way to do it otherwise.
#if !BOOST_UNORDERED_INTEROPERABLE_NODES
// This is no longer supported, as there's no longer an efficient way to get to
// the end of a group of equivalent nodes.
#if 0
UNORDERED_AUTO_TEST(stable_insert_test1)
{
+452 -135
View File
@@ -3,6 +3,8 @@
// 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(PIECEWISE_TEST_NAME)
// clang-format off
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
@@ -19,8 +21,6 @@
#include "../helpers/input_iterator.hpp"
#include "../helpers/helpers.hpp"
#include <iostream>
namespace insert_tests {
test::seed_t initialize_seed(243432);
@@ -33,66 +33,138 @@ void unique_insert_tests1(X*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef test::ordered<X> ordered;
std::cerr << "insert(value) tests for containers with unique keys.\n";
UNORDERED_SUB_TEST("insert(value) tests for containers with unique keys")
{
X x;
test::ordered<X> tracker = test::create_ordered(x);
X x;
test::ordered<X> tracker = test::create_ordered(x);
test::random_values<X> v(1000, generator);
test::random_values<X> v(1000, generator);
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it =
v.begin();
it != v.end(); ++it) {
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it) {
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count =
x.bucket_count();
float b = x.max_load_factor();
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
std::pair<iterator, bool> r1 = x.insert(*it);
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool> r2 =
tracker.insert(*it);
std::pair<iterator, bool> r1 = x.insert(*it);
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool> r2 =
tracker.insert(*it);
BOOST_TEST(r1.second == r2.second);
BOOST_TEST(*r1.first == *r2.first);
BOOST_TEST(r1.second == r2.second);
BOOST_TEST(*r1.first == *r2.first);
tracker.compare_key(x, *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);
}
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);
}
test::check_equivalent_keys(x);
UNORDERED_SUB_TEST("insert(rvalue) tests for containers with unique keys")
{
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;
std::pair<iterator, bool> r1 = x.insert(boost::move(value));
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool> r2 =
tracker.insert(*it);
BOOST_TEST(r1.second == r2.second);
BOOST_TEST(*r1.first == *r2.first);
tracker.compare_key(x, *it);
if (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);
}
}
template <class X>
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);
UNORDERED_SUB_TEST(
"insert(value) tests for containers with equivalent keys")
{
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();
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();
BOOST_DEDUCED_TYPENAME X::iterator r1 = x.insert(*it);
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2 =
tracker.insert(*it);
BOOST_DEDUCED_TYPENAME X::iterator r1 = x.insert(*it);
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2 =
tracker.insert(*it);
BOOST_TEST(*r1 == *r2);
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *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);
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);
}
test::check_equivalent_keys(x);
UNORDERED_SUB_TEST(
"insert(rvalue) tests for containers with equivalent keys")
{
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;
BOOST_DEDUCED_TYPENAME X::iterator r1 =
x.insert(boost::move(value));
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2 =
tracker.insert(*it);
BOOST_TEST(*r1 == *r2);
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);
}
}
template <class X> void insert_tests2(X*, test::random_generator generator)
@@ -102,8 +174,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME tracker_type::iterator tracker_iterator;
std::cerr << "insert(begin(), value) tests.\n";
UNORDERED_SUB_TEST("insert(begin(), value) tests")
{
test::check_instances check_;
@@ -132,8 +203,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert(end(), value) tests.\n";
UNORDERED_SUB_TEST("insert(end(), value) tests")
{
test::check_instances check_;
@@ -163,8 +233,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert(pos, value) tests.\n";
UNORDERED_SUB_TEST("insert(pos, value) tests")
{
test::check_instances check_;
@@ -194,8 +263,38 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert single item range tests.\n";
UNORDERED_SUB_TEST("insert(pos, rvalue) tests")
{
test::check_instances check_;
X x;
const_iterator pos = x.begin();
tracker_type tracker = test::create_ordered(x);
test::random_values<X> v(1000, generator);
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it =
v.begin();
it != v.end(); ++it) {
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count =
x.bucket_count();
float b = x.max_load_factor();
typename X::value_type value = *it;
pos = x.insert(pos, boost::move(value));
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
BOOST_TEST(*pos == *r2);
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);
}
tracker.compare(x);
test::check_equivalent_keys(x);
}
UNORDERED_SUB_TEST("insert single item range tests")
{
test::check_instances check_;
@@ -223,8 +322,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert range tests.\n";
UNORDERED_SUB_TEST("insert range tests")
{
test::check_instances check_;
@@ -237,8 +335,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert range with rehash tests.\n";
UNORDERED_SUB_TEST("insert range with rehash tests")
{
test::check_instances check_;
@@ -255,8 +352,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert input iterator range tests.\n";
UNORDERED_SUB_TEST("insert input iterator range tests")
{
test::check_instances check_;
@@ -272,8 +368,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert copy iterator range tests.\n";
UNORDERED_SUB_TEST("insert copy iterator range tests")
{
test::check_instances check_;
@@ -286,8 +381,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert copy iterator range test 2.\n";
UNORDERED_SUB_TEST("insert copy iterator range test 2")
{
test::check_instances check_;
@@ -303,8 +397,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert various ranges.\n";
UNORDERED_SUB_TEST("insert various ranges")
{
for (int i = 0; i < 100; ++i) {
X x;
@@ -350,8 +443,6 @@ void unique_emplace_tests1(X*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef test::ordered<X> ordered;
std::cerr << "emplace(value) tests for containers with unique keys.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
@@ -384,8 +475,6 @@ void unique_emplace_tests1(X*, test::random_generator generator)
template <class X>
void equivalent_emplace_tests1(X*, test::random_generator generator)
{
std::cerr << "emplace(value) tests for containers with equivalent keys.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
@@ -414,9 +503,6 @@ void equivalent_emplace_tests1(X*, test::random_generator generator)
template <class X> void move_emplace_tests(X*, test::random_generator generator)
{
std::cerr
<< "emplace(move(value)) tests for containers with unique keys.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
@@ -444,8 +530,7 @@ template <class X> void move_emplace_tests(X*, test::random_generator generator)
template <class X> void default_emplace_tests(X*, test::random_generator)
{
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
std::cerr << "emplace() tests.\n";
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
bool is_unique = test::has_unique_keys<X>::value;
X x;
@@ -480,8 +565,6 @@ template <class X> void default_emplace_tests(X*, test::random_generator)
template <class X> void map_tests(X*, test::random_generator generator)
{
std::cerr << "map tests.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
@@ -508,8 +591,8 @@ template <class X> void map_tests(X*, test::random_generator generator)
template <class X> void map_tests2(X*, test::random_generator generator)
{
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
std::cerr << "insert_or_assign\n";
UNORDERED_SUB_TEST("insert_or_assign")
{
test::check_instances check_;
@@ -540,8 +623,7 @@ template <class X> void map_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert_or_assign(begin)\n";
UNORDERED_SUB_TEST("insert_or_assign(begin)")
{
test::check_instances check_;
@@ -571,8 +653,7 @@ template <class X> void map_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert_or_assign(end)\n";
UNORDERED_SUB_TEST("insert_or_assign(end)")
{
test::check_instances check_;
@@ -602,8 +683,7 @@ template <class X> void map_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert_or_assign(last)\n";
UNORDERED_SUB_TEST("insert_or_assign(last)")
{
test::check_instances check_;
@@ -639,10 +719,9 @@ template <class X> void map_tests2(X*, test::random_generator generator)
template <class X> void try_emplace_tests(X*, test::random_generator generator)
{
std::cerr << "try_emplace(key, value)\n";
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
UNORDERED_SUB_TEST("try_emplace(key, value)")
{
test::check_instances check_;
@@ -682,10 +761,9 @@ template <class X> void try_emplace_tests(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "try_emplace(begin(), key, value)\n";
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
UNORDERED_SUB_TEST("try_emplace(begin(), key, value)")
{
test::check_instances check_;
@@ -722,10 +800,9 @@ template <class X> void try_emplace_tests(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "try_emplace(end(), key, value)\n";
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
UNORDERED_SUB_TEST("try_emplace(end(), key, value)")
{
test::check_instances check_;
@@ -762,10 +839,9 @@ template <class X> void try_emplace_tests(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "try_emplace(pos, key, value)\n";
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
UNORDERED_SUB_TEST("try_emplace(pos, key, value)")
{
test::check_instances check_;
@@ -808,8 +884,6 @@ template <class X> void try_emplace_tests(X*, test::random_generator generator)
template <class X>
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,
@@ -827,8 +901,6 @@ void map_insert_range_test1(X*, test::random_generator generator)
template <class X>
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,
@@ -1030,21 +1102,43 @@ struct overloaded_constructor
UNORDERED_AUTO_TEST(map_emplace_test)
{
boost::unordered_map<int, overloaded_constructor> x;
{
boost::unordered_map<int, overloaded_constructor, test::hash,
test::equal_to,
test::allocator1<std::pair<int const, 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());
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
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));
x.emplace(2, 3);
BOOST_TEST(x.find(2) != x.end() &&
x.find(2)->second == overloaded_constructor(3));
x.try_emplace(5);
BOOST_TEST(
x.find(5) != x.end() && x.find(5)->second == overloaded_constructor());
x.try_emplace(5);
BOOST_TEST(x.find(5) != x.end() &&
x.find(5)->second == overloaded_constructor());
}
{
boost::unordered_multimap<int, overloaded_constructor, test::hash,
test::equal_to,
test::allocator1<std::pair<int const, overloaded_constructor> > >
x;
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
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)
@@ -1052,7 +1146,7 @@ UNORDERED_AUTO_TEST(set_emplace_test)
boost::unordered_set<overloaded_constructor> x;
overloaded_constructor check;
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
x.emplace();
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
#endif
@@ -1098,48 +1192,109 @@ struct convertible_to_piecewise
UNORDERED_AUTO_TEST(map_emplace_test2)
{
boost::unordered_map<overloaded_constructor, overloaded_constructor> x;
// Emulating piecewise construction with boost::tuple bypasses the
// allocator's construct method, but still uses test destroy method.
test::detail::disable_construction_tracking _scoped;
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());
{
boost::unordered_map<overloaded_constructor, overloaded_constructor,
boost::hash<overloaded_constructor>,
std::equal_to<overloaded_constructor>,
test::allocator1<std::pair<overloaded_constructor const,
overloaded_constructor> > >
x;
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(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(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));
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());
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));
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));
x.clear();
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));
x.try_emplace(overloaded_constructor());
BOOST_TEST(
x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second == overloaded_constructor());
x.clear();
x.try_emplace(1);
BOOST_TEST(
x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second == overloaded_constructor());
x.try_emplace(overloaded_constructor());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.try_emplace(overloaded_constructor(2, 3), 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));
x.try_emplace(1);
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.try_emplace(overloaded_constructor(2, 3), 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));
x.clear();
x.try_emplace(x.begin(), overloaded_constructor());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.try_emplace(x.end(), 1);
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.try_emplace(x.begin(), overloaded_constructor(2, 3), 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));
}
{
boost::unordered_multimap<overloaded_constructor,
overloaded_constructor, boost::hash<overloaded_constructor>,
std::equal_to<overloaded_constructor>,
test::allocator1<std::pair<overloaded_constructor const,
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)
@@ -1158,9 +1313,171 @@ UNORDERED_AUTO_TEST(set_emplace_test2)
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);
}
// Use the preprocessor to generate tests using different combinations of
// boost/std piecewise_construct_t/tuple.
#define PIECEWISE_TEST_NAME boost_tuple_piecewise_tests
#define PIECEWISE_NAMESPACE boost::unordered
#define TUPLE_NAMESPACE boost
#define EMULATING_PIECEWISE_CONSTRUCTION 1
#include "./insert_tests.cpp"
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
#define PIECEWISE_TEST_NAME boost_tuple_std_piecewise_tests
#define PIECEWISE_NAMESPACE std
#define TUPLE_NAMESPACE boost
#define EMULATING_PIECEWISE_CONSTRUCTION 1
#include "./insert_tests.cpp"
#endif
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
#define PIECEWISE_TEST_NAME std_tuple_boost_piecewise_tests
#define PIECEWISE_NAMESPACE boost::unordered
#define TUPLE_NAMESPACE std
#define EMULATING_PIECEWISE_CONSTRUCTION 0
#include "./insert_tests.cpp"
#endif
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && \
BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
#define PIECEWISE_TEST_NAME std_piecewise_tests
#define PIECEWISE_NAMESPACE std
#define TUPLE_NAMESPACE std
#define EMULATING_PIECEWISE_CONSTRUCTION 0
#include "./insert_tests.cpp"
#endif
}
RUN_TESTS()
RUN_TESTS_QUIET()
#else // PIECEWISE_TEST_NAME
UNORDERED_AUTO_TEST(PIECEWISE_TEST_NAME)
{
#if EMULATING_PIECEWISE_CONSTRUCTION
test::detail::disable_construction_tracking _scoped;
#endif
{
boost::unordered_map<overloaded_constructor, overloaded_constructor,
boost::hash<overloaded_constructor>,
std::equal_to<overloaded_constructor>,
test::allocator1<std::pair<overloaded_constructor const,
overloaded_constructor> > >
x;
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1),
TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3),
TUPLE_NAMESPACE::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, TUPLE_NAMESPACE::make_tuple(9, 3, 1),
TUPLE_NAMESPACE::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));
x.clear();
x.try_emplace(overloaded_constructor());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.try_emplace(1);
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.try_emplace(overloaded_constructor(2, 3), 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));
}
{
boost::unordered_multimap<overloaded_constructor,
overloaded_constructor, boost::hash<overloaded_constructor>,
std::equal_to<overloaded_constructor>,
test::allocator1<std::pair<overloaded_constructor const,
overloaded_constructor> > >
x;
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1),
TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3),
TUPLE_NAMESPACE::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, TUPLE_NAMESPACE::make_tuple(9, 3, 1),
TUPLE_NAMESPACE::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(BOOST_PP_CAT(PIECEWISE_TEST_NAME, 2))
{
#if EMULATING_PIECEWISE_CONSTRUCTION
test::detail::disable_construction_tracking _scoped;
#endif
boost::unordered_set<
std::pair<overloaded_constructor, overloaded_constructor> >
x;
std::pair<overloaded_constructor, overloaded_constructor> check;
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
x.clear();
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
TUPLE_NAMESPACE::make_tuple(1), TUPLE_NAMESPACE::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);
}
#undef PIECEWISE_TEST_NAME
#undef PIECEWISE_NAMESPACE
#undef TUPLE_NAMESPACE
#undef EMULATING_PIECEWISE_CONSTRUCTION
#endif
+122 -37
View File
@@ -99,7 +99,6 @@ UNORDERED_AUTO_TEST(merge_multiset)
test::check_equivalent_keys(y);
}
#if BOOST_UNORDERED_INTEROPERABLE_NODES
UNORDERED_AUTO_TEST(merge_set_and_multiset)
{
boost::unordered_set<int> x;
@@ -139,14 +138,15 @@ UNORDERED_AUTO_TEST(merge_set_and_multiset)
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
}
#endif
template <class X> void merge_empty_test(X*, test::random_generator generator)
template <class X1, class X2>
void merge_empty_test(X1*, X2*, test::random_generator generator)
{
test::check_instances check_;
test::random_values<X> v(1000, generator);
X x1(v.begin(), v.end()), x2;
test::random_values<X1> v(1000, generator);
X1 x1(v.begin(), v.end());
X2 x2;
x1.merge(x2);
test::check_container(x1, v);
BOOST_TEST(x2.empty());
@@ -160,7 +160,8 @@ void merge_into_empty_test(X*, test::random_generator generator)
test::check_instances check_;
test::random_values<X> v(1000, generator);
X x1, x2(v.begin(), v.end());
X x1;
X x2(v.begin(), v.end());
x1.merge(x2);
test::check_container(x1, v);
BOOST_TEST(x2.empty());
@@ -168,89 +169,173 @@ void merge_into_empty_test(X*, test::random_generator generator)
test::check_equivalent_keys(x2);
}
template <class X> void unique_merge_test(X*, test::random_generator generator)
template <class X1, class X2>
void merge_into_unique_keys_test(X1*, X2*, int hash_equal1, int hash_equal2,
test::random_generator generator)
{
test::check_instances check_;
test::random_values<X> v1(1000, generator);
test::random_values<X> v2(1000, generator);
test::random_values<X1> v1(1000, generator);
test::random_values<X2> v2(1000, generator);
v1.insert(v2.begin(), boost::next(v2.begin(), 100));
v2.insert(v1.begin(), boost::next(v1.begin(), 100));
X x1(v1.begin(), v1.end()), x2(v2.begin(), v2.end());
x1.merge(x2);
X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1),
test::equal_to(hash_equal1));
X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2),
test::equal_to(hash_equal2));
test::ordered<X> tracker1 = test::create_ordered(x1);
test::ordered<X> tracker2 = test::create_ordered(x2);
test::ordered<X> tracker_tmp = test::create_ordered(x2);
test::ordered<X1> tracker1 = test::create_ordered(x1);
test::ordered<X2> tracker2 = test::create_ordered(x2);
tracker1.insert(v1.begin(), v1.end());
tracker_tmp.insert(v2.begin(), v2.end());
for (BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator it =
tracker_tmp.begin();
it != tracker_tmp.end(); ++it) {
for (typename X2::iterator it = x2.begin(); it != x2.end(); ++it) {
if (!tracker1.insert(*it).second) {
tracker2.insert(*it);
}
}
x1.merge(x2);
tracker1.compare(x1);
tracker2.compare(x2);
test::check_equivalent_keys(x1);
test::check_equivalent_keys(x2);
}
template <class X> void equiv_merge_test(X*, test::random_generator generator)
template <class X1, class X2>
void merge_into_equiv_keys_test(X1*, X2*, int hash_equal1, int hash_equal2,
test::random_generator generator)
{
test::check_instances check_;
test::random_values<X> v1(1000, generator);
test::random_values<X> v2(1000, generator);
test::random_values<X1> v1(1000, generator);
test::random_values<X2> v2(1000, generator);
v1.insert(v2.begin(), boost::next(v2.begin(), 100));
v2.insert(v1.begin(), boost::next(v1.begin(), 100));
X x1(v1.begin(), v1.end()), x2(v2.begin(), v2.end());
X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1),
test::equal_to(hash_equal1));
X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2),
test::equal_to(hash_equal2));
x1.merge(x2);
test::ordered<X> tracker1 = test::create_ordered(x1);
test::ordered<X1> tracker1 = test::create_ordered(x1);
test::ordered<X2> tracker2 = test::create_ordered(x2);
tracker1.insert(v1.begin(), v1.end());
tracker1.insert(v2.begin(), v2.end());
tracker2.insert(v2.begin(), v2.end());
tracker1.insert(tracker2.begin(), tracker2.end());
tracker2.clear();
tracker1.compare(x1);
BOOST_TEST(x2.empty());
tracker2.compare(x2);
test::check_equivalent_keys(x1);
test::check_equivalent_keys(x2);
}
boost::unordered_set<test::movable, test::hash, test::equal_to,
std::allocator<test::movable> >* test_set_std_alloc;
boost::unordered_multiset<test::movable, test::hash, test::equal_to,
std::allocator<test::movable> >* test_multiset_std_alloc;
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
std::allocator<test::object> >* test_map_std_alloc;
boost::unordered_multimap<test::object, test::object, test::hash,
test::equal_to, 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_multiset<test::object, test::hash, test::equal_to,
test::allocator1<test::object> >* 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;
boost::unordered_multimap<test::movable, test::movable, test::hash,
test::equal_to, test::allocator2<test::movable> >* test_multimap;
using test::default_generator;
using test::generate_collisions;
// clang-format off
UNORDERED_TEST(merge_empty_test,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_multiset)(
test_map)(test_multimap))((default_generator)(generate_collisions)))
((test_set_std_alloc)(test_multiset_std_alloc))
((test_set_std_alloc)(test_multiset_std_alloc))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_empty_test,
((test_map_std_alloc)(test_multimap_std_alloc))
((test_map_std_alloc)(test_multimap_std_alloc))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_empty_test,
((test_set)(test_multiset))
((test_set)(test_multiset))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_empty_test,
((test_map)(test_multimap))
((test_map)(test_multimap))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_empty_test,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_multiset)(
test_map)(test_multimap))((default_generator)(generate_collisions)))
((test_set_std_alloc)(test_multiset_std_alloc))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_empty_test,
((test_map_std_alloc)(test_multimap_std_alloc))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_empty_test,
((test_set)(test_multiset))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_empty_test,
((test_map)(test_multimap))
((default_generator)(generate_collisions)))
UNORDERED_TEST(unique_merge_test,
((test_set_std_alloc)(test_set)(test_map))((default_generator)))
UNORDERED_TEST(merge_into_unique_keys_test,
((test_set_std_alloc))
((test_set_std_alloc)(test_multiset_std_alloc))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_unique_keys_test,
((test_map_std_alloc))
((test_map_std_alloc)(test_multimap_std_alloc))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_unique_keys_test,
((test_set))
((test_set)(test_multiset))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_unique_keys_test,
((test_map))
((test_map)(test_multimap))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(equiv_merge_test, ((test_multimap_std_alloc)(test_multiset)(
test_multimap))((default_generator)))
UNORDERED_TEST(merge_into_equiv_keys_test,
((test_multiset_std_alloc))
((test_set_std_alloc)(test_multiset_std_alloc))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_equiv_keys_test,
((test_multimap_std_alloc))
((test_map_std_alloc)(test_multimap_std_alloc))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_equiv_keys_test,
((test_multiset))
((test_set)(test_multiset))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_equiv_keys_test,
((test_multimap))
((test_map)(test_multimap))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
// clang-format on
}
RUN_TESTS()
+2 -1
View File
@@ -36,7 +36,8 @@ bool throwing_test_exception = false;
void test_throw(char const* name)
{
if (throwing_test_exception) {
std::cerr << "Throw exception in: " << name << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Throw exception in: " << name
<< std::endl;
throw test_exception();
}
}
+4 -4
View File
@@ -93,7 +93,7 @@ UNORDERED_AUTO_TEST(simple_tests)
using namespace std;
srand(14878);
std::cout << "Test unordered_set.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<int> set;
simple_test(set);
@@ -102,7 +102,7 @@ UNORDERED_AUTO_TEST(simple_tests)
set.insert(1456);
simple_test(set);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<int> multiset;
simple_test(multiset);
@@ -113,7 +113,7 @@ UNORDERED_AUTO_TEST(simple_tests)
}
simple_test(multiset);
std::cout << "Test unordered_map.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
boost::unordered_map<int, int> map;
for (int i2 = 0; i2 < 1000; ++i2) {
@@ -121,7 +121,7 @@ UNORDERED_AUTO_TEST(simple_tests)
}
simple_test(map);
std::cout << "Test unordered_multimap.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
boost::unordered_multimap<int, int> multimap;
for (int i3 = 0; i3 < 1000; ++i3) {
+69 -27
View File
@@ -10,7 +10,6 @@
#include "../helpers/postfix.hpp"
// clang-format on
#include <iostream>
#include "../helpers/test.hpp"
namespace unnecessary_copy_tests {
@@ -138,32 +137,36 @@ std::size_t hash_value(unnecessary_copy_tests::count_copies const& x)
#define COPY_COUNT(n) \
if (::unnecessary_copy_tests::count_copies::copies != n) { \
BOOST_ERROR("Wrong number of copies."); \
std::cerr << "Number of copies: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: " << n << std::endl; \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Number of copies: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: " << n << std::endl; \
}
#define MOVE_COUNT(n) \
if (::unnecessary_copy_tests::count_copies::moves != n) { \
BOOST_ERROR("Wrong number of moves."); \
std::cerr << "Number of moves: " \
<< ::unnecessary_copy_tests::count_copies::moves \
<< " expecting: " << n << std::endl; \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Number of moves: " \
<< ::unnecessary_copy_tests::count_copies::moves \
<< " expecting: " << n << std::endl; \
}
#define COPY_COUNT_RANGE(a, 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: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Number of copies: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
}
#define MOVE_COUNT_RANGE(a, 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: " \
<< ::unnecessary_copy_tests::count_copies::moves \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Number of moves: " \
<< ::unnecessary_copy_tests::count_copies::moves \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
}
#define COPY_COUNT_EXTRA(a, b) COPY_COUNT_RANGE(a, a + b * EXTRA_CONSTRUCT_COST)
#define MOVE_COUNT_EXTRA(a, b) MOVE_COUNT_RANGE(a, a + b * EXTRA_CONSTRUCT_COST)
@@ -180,6 +183,53 @@ template <class T> void unnecessary_copy_insert_test(T*)
reset();
x.insert(a);
COPY_COUNT(1);
MOVE_COUNT(0);
}
template <class T> void unnecessary_copy_insert_rvalue_set_test(T*)
{
T x;
BOOST_DEDUCED_TYPENAME T::value_type a;
reset();
x.insert(boost::move(a));
COPY_COUNT(0);
MOVE_COUNT(1);
BOOST_DEDUCED_TYPENAME T::value_type a2;
reset();
x.insert(boost::move(a));
COPY_COUNT(0);
MOVE_COUNT((x.size() == 2 ? 1 : 0));
}
template <class T> void unnecessary_copy_insert_rvalue_map_test(T*)
{
// Doesn't currently try to emulate std::pair move construction,
// so std::pair's require a copy. Could try emulating it in
// construct_from_args.
T x;
BOOST_DEDUCED_TYPENAME T::value_type a;
reset();
x.insert(boost::move(a));
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(1);
MOVE_COUNT(0);
#else
COPY_COUNT(0);
MOVE_COUNT(1);
#endif
BOOST_DEDUCED_TYPENAME T::value_type a2;
reset();
x.insert(boost::move(a));
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT((x.size() == 2 ? 1 : 0));
MOVE_COUNT(0);
#else
COPY_COUNT(0);
MOVE_COUNT((x.size() == 2 ? 1 : 0));
#endif
}
boost::unordered_set<count_copies>* set;
@@ -188,6 +238,8 @@ boost::unordered_map<int, count_copies>* map;
boost::unordered_multimap<int, count_copies>* multimap;
UNORDERED_TEST(unnecessary_copy_insert_test, ((set)(multiset)(map)(multimap)))
UNORDERED_TEST(unnecessary_copy_insert_rvalue_set_test, ((set)(multiset)))
UNORDERED_TEST(unnecessary_copy_insert_rvalue_map_test, ((map)(multimap)))
template <class T> void unnecessary_copy_emplace_test(T*)
{
@@ -310,20 +362,15 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
// 0 arguments
//
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
// The container will have to create a copy in order to compare with
// the existing element.
reset();
x.emplace();
#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
//
@@ -347,13 +394,8 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
// No move should take place.
reset();
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
// Use a new value for cases where a did get moved...
count_copies b;
@@ -409,7 +451,7 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test)
// 0 arguments
//
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
// COPY_COUNT(1) would be okay here.
reset();
x.emplace();
@@ -501,7 +543,7 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test)
COPY_COUNT(0);
MOVE_COUNT(0);
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE)
#if BOOST_UNORDERED_TUPLE_ARGS
reset();
x.emplace(boost::unordered::piecewise_construct,