Compare commits

...

118 Commits

Author SHA1 Message Date
Daniel James 76127b6e42 Merge branch 'develop' 2016-12-05 22:48:29 +00:00
Daniel James 03a597983e Change log for last few fixes 2016-12-05 22:48:00 +00:00
Daniel James 33f701dd09 Fix assigning hash/key equality functions for empty containers 2016-11-21 10:24:51 +00:00
Daniel James 3db4654b44 Remove unary/binary_function from examples/documentation
They are being removed from the standard in C++17, and were never really
required.
2016-11-06 10:19:17 +00:00
Daniel James a7546e298e Support 10 arguments in emplace_args
Which was the intent, but only supported up to 9 arguments. I doubt
this will make much of a difference.
2016-11-02 07:30:41 +00:00
Daniel James 8a0592a35d Merge branch 'develop' 2016-10-30 23:17:15 +00:00
Daniel James 98cce956f9 Try to fix a 64-bit powerpc g++ 7 warning
Warning is:

allocate.hpp:335:19: warning: conversion to ???unsigned int??? from
???long unsigned int??? may alter its value [-Wconversion]

I'm not sure, but I think it's because the sizeof is a long unsigned
int, and the template parameter is an unsigned int. The sizeof isn't
even used, it's just there to get a value for expression SFINAE.
2016-10-28 09:06:53 +01:00
Daniel James a34785fa0d Don't 'sink' uncopyable container
Calling sink was causing older versions of gcc to copy the container,
resulting in a compile error. So instead just disambiguate by putting
brackets around the expression.
2016-10-25 18:04:34 +01:00
Daniel James 14ccdbc7b6 Add guards against exceptions that shouldn't happen
I'm getting a couple of "terminate called after throwing an instance of
'test::lightweight::test_exception'" errors on the sun platform. Not
sure where they're happening, so I've made the code a tad more resilient
against exceptions that should not really be thrown.
2016-10-24 09:46:13 +01:00
Daniel James 5b5b46ea1c Disable Visual C++ __declspec(allocator) warning
Visual C++ is warning that memory can't be tracked for allocators whose
pointer types aren't actually pointers, which is a correct warning but
not relevant for our concerns, and is caused by the unit tests, not the
container implementation.
2016-10-23 13:51:58 +01:00
Daniel James e3f534a148 Allocator aware constructors 2016-10-23 13:33:25 +01:00
Daniel James 1bcd5b0003 Make no argument constructor implicit 2016-10-23 13:32:52 +01:00
Daniel James 0d1cfba823 Rename functions in allocate.hpp 2016-10-22 10:28:53 +01:00
Daniel James e986b70981 Stricter iterator types 2016-10-22 10:04:36 +01:00
Daniel James 9b7b485c33 Use node_pointer in equality. 2016-10-22 10:04:36 +01:00
Daniel James c680fa7418 Remove find_matching_node.
FWIW the standard says that equality is undefined behaviour if the Hash
and Pred function objects behave differently. But I think we should
support different hash functions, e.g. so that randomized hash functions
will work.
2016-10-22 10:04:36 +01:00
Daniel James 9772c01161 Replace several uses of iterators with node pointers.
Which is to some extent going in circles, as this is how the containers
were originally implemented. But I think this is cleaner. It also fixes
a minor problem where the internal and external iterator types are
different for some containers, as the external iterators are all const.
2016-10-22 10:04:36 +01:00
Daniel James 6071f9a08b Stop testing no arg emplace when not available 2016-10-22 09:49:14 +01:00
Daniel James ad2256b13c Add const cast for piecewise construction 2016-10-22 09:42:56 +01:00
Daniel James dad0d48c9c Support containers with const value type
Currently just storing the value without a const. Can do better with
C++11 constructors, so maybe should do that, and cast away const on
compilers without support.

Another problem is that std::allocator<const int> doesn't compile for
libstdc++ (and potentially other standard libraries), so
boost::unordered_set<const int> can't compile. I'm not sure if I should
work around that, as it means changing the type of the container
(i.e. to boost::unordered_set<const int,... , std::allocator<int>>).
2016-10-17 08:06:19 +01:00
Daniel James e03a8732a6 Use static_cast for allocator_traits::construct
std::allocator::construct uses a C-style cast to void pointer, so it can
accept const pointers, but allocator_traits::construct uses a static_cast
by default, so const pointers don't work. This means the implementation
needs to cast away const when constructing members of a std::pair. This
wouldn't happen if piecewise construction was used, as the members could
be constructed normally.
2016-10-17 07:54:06 +01:00
Daniel James 7da307c696 Supply explicit test::cxx11_allocator::rebind for old GCC
The rebind mechanism doesn't work for templates with multiple template
parameters on old versions of GCC. But allocators written for that
compiler will have an explicit rebind, so that should be acceptable.
2016-10-17 07:54:06 +01:00
Daniel James 82438a513b Fix allocator traits macro 2016-10-17 07:54:06 +01:00
Daniel James b5205e58aa Change log for allocator support. 2016-10-14 09:29:38 +01:00
Daniel James b907cee691 Use std::allocator_traits where available.
Might have to revert this when implementing C++17 features.
2016-10-14 09:27:40 +01:00
Daniel James da6e8e8041 Better allocator rebind support 2016-10-14 09:27:40 +01:00
Daniel James 3fd4495b2f Merge branch 'develop' 2016-10-14 09:26:19 +01:00
Daniel James 04607dc9f3 Fix for clang. 2016-10-13 17:03:31 +01:00
Daniel James ece4116329 Try to fix another warning 2016-10-13 10:00:26 +01:00
Daniel James 74abdd6973 Replace boost::next with a simpler version
Less optimized, but hopefully it won't cause any warnings.
2016-10-11 13:36:41 +01:00
Daniel James a316d3fa46 Fix more warnings 2016-10-11 10:07:07 +01:00
Rene Rivera 70ce6b4ae7 Add, and update, documentation build targets. 2016-10-10 11:39:54 -05:00
Rene Rivera ade302f0a0 Add, and update, documentation build targets. 2016-10-07 23:07:37 -05:00
Daniel James 147885fec4 Add another random generation style.
This time for a more limited range of values so that equal values turn
up more often.  This is a bit shoddy, but seems like the best way to
improve the existing tests without too much effort.
2016-10-06 21:52:19 +01:00
Daniel James 65aaf27380 Fix accidental fallthrough in switch cases.
This was causing the hash function to be different to the equality
function. For some reason this resulted in a lot of windows test
failures, but none on linux or os x. I'm a bit confused and worried
about that.
2016-10-06 10:53:10 +01:00
Daniel James b1588929cc Fix another sign conversion warning. 2016-10-05 13:52:33 +01:00
Daniel James 094fa38360 Remove -Wsign-conversion, old gcc doesn't support it. 2016-10-05 13:52:17 +01:00
Daniel James 71d19820ac Fix signed conversion warnings. 2016-10-05 09:45:53 +01:00
Daniel James a0dc86ecbc Use the boost snapshot for travis testing. 2016-10-05 09:35:46 +01:00
Daniel James 982685d3a0 Adjust order of variables to see if intel failure changes.
So currently on one intel tester find_tests is failing the 'pos !=
x.end()' test, but not the 'const_pos != x_const.end()' test for
unordered_set (and possibly others, the test results are truncated). I'm
a bit stumped as to why this should be, as for unordered_set the const
and non-const versions are basically the exact same code. See if
changing the order makes any difference to what fails.
2016-10-05 00:57:58 +01:00
Daniel James dadb4486ee Fix calls to std::rand in tests 2016-10-04 15:52:47 +01:00
Daniel James d14c1dec59 Revert "Allocator aware constructors."
This reverts commit b00bc15c3e.

I messed that up a bit, will get back to it later.
2016-10-03 20:58:15 +01:00
Daniel James 21d6d7bc21 Fix detection of is_nothrow_move_constructible support.
I should possibly also check how it handles `throw()`?
2016-10-03 10:49:49 +01:00
Daniel James ff0228e752 Support for std::piecewise_construct. 2016-10-02 17:56:01 +01:00
Daniel James b00bc15c3e Allocator aware constructors. 2016-10-02 17:56:01 +01:00
Daniel James 50c4cbe06c Try to fix the failures in noxcept_tests 2016-10-02 13:04:25 +01:00
Daniel James 573e10665c Use standard boost move style in noexcept_tests. 2016-10-02 13:04:25 +01:00
Daniel James d0acb81f2e Release notes for latest changes. 2016-10-02 13:04:25 +01:00
Daniel James e7b20d2877 Fix exception bug in asssignment.
The hash and key equality functions were assigned before allocating new
buckets. If that allocation failed, then the existing elements would be
left in place - so if accessed after the exception they could be in the
wrong buckets or equivalent elements could be incorrectly grouped
together.
2016-10-02 13:04:25 +01:00
Daniel James 588ad6e69f Travis tests in 32 and 64 bit. 2016-10-01 14:04:01 +01:00
Daniel James 98462fbcc3 Avoid conversion warning. 2016-10-01 13:53:05 +01:00
Daniel James a93331dd96 Fix new emplace tests. 2016-10-01 13:51:25 +01:00
Daniel James e174af2286 Try not using boost::forward in emplace_args constructor.
AFAICT it's not needed since the construct arguments and the members are
the same reference type. Maybe it was for older compilers? And it appears
to be causing issues with string literals in older versions of Visual
C++.
2016-09-30 00:32:19 +01:00
Daniel James 9decbe0cbd Manually write out emplace_args for small numbers.
Still need some macros to handle rvalue reference support.
2016-09-30 00:32:19 +01:00
Daniel James 021817f2b4 Fix Visual C++ version number + use BOOST_WORKAROUND. 2016-09-18 22:56:23 +01:00
Daniel James 13ff69efbf Make 'ordered' container independent. 2016-09-18 12:22:48 +01:00
Daniel James 8fda9113b8 Make 'has_unique_keys' container independent. 2016-09-18 12:22:48 +01:00
Daniel James b881bcfee3 More insert and erase tests 2016-09-18 12:22:48 +01:00
Daniel James 1c606980ec Update tests for standard changes involving bucket count.
It seems my defect report was accepted at some point, and they tweaked
the requirements involving bucket counts. This also makes it possible to
have a bucket count of 0, which I think wasn't allowed in the past. I
don't think I'll change this implementation to do so, but I'd like to be
able to run these tests against standard implementations, so I'm
starting to take that into account.

I believe these changes were made after the C++14 standard, but I've
always been tracking the draft standards, so that doesn't really matter.
2016-09-18 12:22:48 +01:00
Daniel James 0d6e58d9fd Write out some compiler info before test results. 2016-09-18 12:22:48 +01:00
Daniel James 95e477902e Special case for Visual C++ 12 test failure.
Plus some extra tests while I'm at it.
2016-09-18 10:28:21 +01:00
Daniel James cc32bfb96f Pointless change to extract_key. 2016-09-07 09:26:25 +01:00
Daniel James 7c2f11f8e1 Fix signed/unsigned comparisons. 2016-09-07 09:26:25 +01:00
Daniel James d08dcb7465 Run xmllint over reference docs in travis. 2016-09-07 09:26:25 +01:00
Daniel James 2d1d6ccd75 Try using boost 1.61.0 in travis 2016-09-04 10:38:13 +01:00
Daniel James 7f380028cc Hint iterator support was too late for 1.62.0 2016-09-04 10:38:13 +01:00
Daniel James 827f77729f Merge branch 'fixes' into develop 2016-09-04 10:37:38 +01:00
Daniel James 6c81de37f5 Fix closing tag. 2016-09-04 10:37:15 +01:00
Daniel James 86a8a0429a Merge branch 'fixes' into develop 2016-09-04 08:23:52 +01:00
Daniel James 4b00548138 Test+document insertion from initializer lists. 2016-09-04 08:23:32 +01:00
Daniel James 8bb9473443 Document assignment from initializer list. 2016-09-04 08:23:31 +01:00
Daniel James da7a5bf269 Fix insert from range documentation.
Was the same for containers with unique and equivalent keys.
2016-09-04 08:23:31 +01:00
Daniel James 7434e116a7 Try using boost::long_long_type to avoid warning. 2016-08-29 23:03:06 +01:00
Daniel James 8f51dc6082 Fix some test warnings.
And turn on warnings as errors in Travis.
2016-08-19 11:41:19 +01:00
Daniel James 79deac97dd Merge branch 'develop' 2016-08-17 12:11:13 +01:00
Daniel James 9debeadee7 Fix some test warnings.
And turn on warnings as errors in Travis.
2016-08-17 12:08:16 +01:00
Daniel James cae72eec2f Insert/emplace with hint. 2016-08-17 12:08:15 +01:00
Daniel James e58370b4ff Move emplace before emplace_impl in equivalent.hpp 2016-08-17 12:08:15 +01:00
Daniel James e92f7d86c1 Remove array_constructor.
I was using SFINAE for everything because some old compilers had issues.
But that's hopefully in the distant past now.
2016-08-14 20:55:40 +01:00
Daniel James 93a33ba15f Remove a couple of unneeded includes. 2016-08-14 20:55:40 +01:00
Daniel James ad353c8e3d Move some of the includes up into allocate.hpp 2016-08-14 20:55:40 +01:00
Daniel James 09717ffca4 Remove a few unnecessary internal includes. 2016-08-14 20:55:40 +01:00
Daniel James ce4b840299 Map/set details types in individual headers. 2016-08-14 20:55:40 +01:00
Daniel James 5a8df0ebe4 Hopefully a bit more readable. 2016-08-14 20:55:40 +01:00
Daniel James 6029d1cfd0 Trim down node_tmp code. 2016-08-14 20:55:40 +01:00
Daniel James 3fe46a1769 Cleaner emplace_impl in equivalent. 2016-08-14 20:55:40 +01:00
Daniel James 5490bcfe95 Remove node_tmp overload of add_node. 2016-08-14 20:55:40 +01:00
Daniel James 078c562b6c Pull some common code into a function. 2016-08-14 20:55:40 +01:00
Daniel James 88612a8be4 Less faffing around with node_constructor. 2016-08-14 20:55:40 +01:00
Daniel James 37a6903831 Move node construction into allocate.hpp 2016-08-14 20:55:40 +01:00
Daniel James 8017d9e684 Change how node construction works.
Split node_constructor into two classes, one for constructing a node
without a value, and then another for holding it once the value is
constructed.

Do the work of constructing values in convenience functions in
allocate.hpp (construct_value_generic, construct_value, construct_pair).
2016-08-14 20:55:40 +01:00
Daniel James 609ae6cb4e Expand out fill_buckets. 2016-08-14 20:55:40 +01:00
Daniel James 603f785739 Merge branch 'develop' 2016-08-14 20:51:44 +01:00
Daniel James 992f9ccf21 Turn off memory sanitizer on travis.
It's not working at all.
2016-08-14 20:39:46 +01:00
Daniel James e250fb44f6 Merge local develop branch develop
Oops, I merged the wrong 'develop' branch into master. Luckily, there's
not much of a difference, so I'm resolving the merge here, and will
merge into master soon.
2016-08-14 20:02:13 +01:00
Daniel James 9767d86d97 Merge branch 'develop' 2016-08-14 19:59:22 +01:00
Daniel James 7687c99708 Disable clang c++03 memory sanitizer tests. 2016-08-04 13:35:48 +01:00
Daniel James 81cc773013 Try to fix mem/std11 toolset. 2016-08-04 13:35:48 +01:00
Daniel James cdb887e880 Clean up a memory leak in a test. 2016-08-04 13:35:47 +01:00
Daniel James 041fee64df Don't stop Boost.Build on error. 2016-08-04 13:35:46 +01:00
Daniel James e3dd1f276e Use clang and gcc's sanitizers in travis. 2016-08-03 14:24:52 +01:00
Daniel James 0769ecd70d Some more checks.
The intel-linux failures I'm getting now are odd. This find test is
failing for iterator, but not const_iterator. So maybe it's a problem
with the iterator object. The failures I was getting before have
disappeared, so I'm not sure about that.
2016-07-29 12:19:50 +01:00
Daniel James 2be69b3eb9 A little more information in the find_tests.
Now the intel-linux tester that was failing for erase_tests is passing,
but has started failing for find_tests instead. Oddly the test for
non-const find is failing, but the const find is fine - this doesn't
make much sense as they should be the same. Not sure, but it suggests
the problem might be in the way iterators are handled, rather than the
data structure?

Checking the iterators before checking that the keys are equal in order
to tell which part of the test is failing.
2016-07-27 06:51:05 +01:00
Daniel James bc601e34d2 More info on test failure on intel-linux.
The count check is reporting errors, but everything else appears to work
okay.
2016-07-25 15:03:39 +01:00
Daniel James 79e39d9d43 Copy build changes from the develop branch. 2016-07-03 21:36:14 +01:00
Daniel James 6bc57bd398 Typo 2016-07-03 08:46:40 +01:00
Daniel James 1bca2df642 Always explicitly specify standard for travis. 2016-07-03 08:42:25 +01:00
Daniel James 59cbe3d483 Also move exception tests into test/Jamfile.v2
Moving the tests successfully restored the test results, so do it for
the exception tests as well.
2016-07-03 08:42:17 +01:00
Daniel James 21f2522695 Try running the tests from unordered/test. 2016-07-02 22:11:43 +01:00
Daniel James 3720b0be58 Try creating a project for test.
For some reason the unordered test results are not showing up any more.
This is odd, as when I try locally they do run. I don't know why this
is, but it's possible that it's because there isn't an actual project in
the test directory, so try adding one.
2016-07-01 11:12:29 +01:00
Daniel James 413b45a62e Merge remote-tracking branch 'origin/develop' 2016-06-03 00:00:58 +01:00
Daniel James 7b8e3d01de Use argument SFINAE instead of return SFINAE 2016-06-03 00:00:51 +01:00
Daniel James b4a3c6f460 Fix exception safety in assignment for multimap/multiset.
The assignment code seemed like a bit of a premature optimization, I
replaced it with a slightly slower but much simpler implementation.
2016-05-30 15:02:04 +01:00
Daniel James 1d4845d6b8 Stop using predef in test. 2016-05-26 22:39:47 +01:00
Daniel James c26acdba15 Travis 2016-05-26 22:31:43 +01:00
Daniel James 3f42a56bae Remove old deprecated warning. 2016-05-26 09:25:10 +01:00
Daniel James 144a0c1791 Remove BOOST_NO_STD_DISTANCE workaround. 2016-05-26 09:24:25 +01:00
Daniel James cc2b1a1ef1 Stop using deprecated boost::iterator. 2016-05-26 09:24:21 +01:00
69 changed files with 4319 additions and 1360 deletions
+60
View File
@@ -0,0 +1,60 @@
# Copyright (C) 2016 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)
# Use Trusty to get a reasonably recent version of Boost.
sudo: required
dist: trusty
language: c++
addons:
apt:
packages:
- libboost-tools-dev
- libxml2-utils
- g++-multilib
matrix:
include:
- compiler: gcc
env: BJAM_TOOLSET=gcc
- compiler: gcc
env: BJAM_TOOLSET=gcc-std11
#- compiler: gcc
# env: BJAM_TOOLSET=gcc-m32
- compiler: gcc
env: BJAM_TOOLSET=gcc-std11m32
#- compiler: clang
# env: BJAM_TOOLSET=clang
- compiler: clang
env: BJAM_TOOLSET=clang-std11
- compiler: clang
env: BJAM_TOOLSET=clang-m32
#- compiler: clang
# env: BJAM_TOOLSET=clang-std11m32
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
- cat ~/user-config.jam
- wget -O boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/snapshots/master/boost_1_62_0.tar.bz2/download
- tar -xjf boost.tar.bz2
- mv boost_1_62_0 boost
- rm -r boost/boost/unordered
script:
- cd ${TRAVIS_BUILD_DIR}/test
- bjam ${BJAM_TOOLSET} include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include
- xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml
+9
View File
@@ -57,3 +57,12 @@ boostbook standalone : unordered :
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/libs/unordered/doc/html
;
###############################################################################
alias boostdoc
: unordered
:
:
: ;
explicit boostdoc ;
alias boostrelease ;
explicit boostrelease ;
+34
View File
@@ -269,4 +269,38 @@ C++11 support has resulted in some breaking changes:
* Fix potential overflow when calculating number of buckets to allocate
([@https://github.com/boostorg/unordered/pull/4 GitHub #4]).
[h2 Boost 1.62.0]
* Remove use of deprecated `boost::iterator`.
* Remove `BOOST_NO_STD_DISTANCE` workaround.
* Remove `BOOST_UNORDERED_DEPRECATED_EQUALITY` warning.
* Simpler implementation of assignment, fixes an exception safety issue
for `unordered_multiset` and `unordered_multimap`. Might be a little slower.
* Stop using return value SFINAE which some older compilers have issues
with.
[h2 Boost 1.63.0]
* Check hint iterator in `insert`/`emplace_hint`.
* Fix some warnings, mostly in the tests.
* Manually write out `emplace_args` for small numbers of arguments -
should make template error messages a little more bearable.
* Remove superfluous use of `boost::forward` in emplace arguments,
which fixes emplacing string literals in old versions of Visual C++.
* Fix an exception safety issue in assignment. If bucket allocation
throws an exception, it can overwrite the hash and equality functions while
leaving the existing elements in place. This would mean that the function
objects wouldn't match the container elements, so elements might be in the
wrong bucket and equivalent elements would be incorrectly handled.
* Various reference documentation improvements.
* Better allocator support ([ticket 12459]).
* Make the no argument constructors implicit.
* Implement missing allocator aware constructors.
* Fix assigning the hash/key equality functions for empty containers.
* Remove unary/binary_function from the examples in the documentation.
They are removed in C++17.
* Support 10 constructor arguments in emplace. It was meant to support up to 10
arguments, but an off by one error in the preprocessor code meant it only
supports up to 10.
[endsect]
+225 -3
View File
@@ -189,10 +189,22 @@ EOL;
<para>A const_local_iterator object can be used to iterate through a single bucket.</para>
</description>
</typedef>
<constructor>
<postconditions>
<code><methodname>size</methodname>() == 0</code>
</postconditions>
<description>
<para>Constructs an empty container using hasher() as the hash function, key_equal() as the key equality predicate, allocator_type() as the allocator and a maximum load factor of 1.0.</para>
</description>
<requires>
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
</para>
</requires>
</constructor>
<constructor specifiers="explicit">
<parameter name="n">
<paramtype>size_type</paramtype>
<default><emphasis>implementation-defined</emphasis></default>
</parameter>
<parameter name="hf">
<paramtype>hasher const&amp;</paramtype>
@@ -246,7 +258,12 @@ EOL;
<default>allocator_type()</default>
</parameter>
<description>
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it.</para>
<para>Constructs an empty container with at least <code>n</code> buckets,
using <code>hf</code> as the hash function,
<code>eq</code> as the key equality predicate,
<code>a</code> as the allocator and a maximum load factor of 1.0
and inserts the elements from [f, l) into it.
</para>
</description>
<requires>
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
@@ -310,6 +327,168 @@ EOL;
<para>Constructs an container, copying <code>x</code>'s contained elements, hash function, predicate, maximum load factor, but using allocator <code>a</code>.</para>
</description>
</constructor>
<constructor>
<parameter name="x">
<paramtype><?php echo $name; ?> &amp;&amp;</paramtype>
</parameter>
<parameter name="a">
<paramtype>Allocator const&amp;</paramtype>
</parameter>
<description>
<para>Construct a container moving <code>x</code>'s contained elements, and having the hash function, predicate and maximum load factor, but using allocate <code>a</code>.</para>
</description>
<notes>
<para>This is implemented using Boost.Move.</para>
</notes>
<requires>
<para>
<code>value_type</code> is move insertable.
</para>
</requires>
</constructor>
<constructor>
<parameter name="il">
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<parameter name="n">
<paramtype>size_type</paramtype>
<default><emphasis>implementation-defined</emphasis></default>
</parameter>
<parameter name="hf">
<paramtype>hasher const&amp;</paramtype>
<default>hasher()</default>
</parameter>
<parameter name="eq">
<paramtype>key_equal const&amp;</paramtype>
<default>key_equal()</default>
</parameter>
<parameter name="a">
<paramtype>allocator_type const&amp;</paramtype>
<default>allocator_type()</default>
</parameter>
<description>
<para>Constructs an empty container with at least <code>n</code> buckets,
using <code>hf</code> as the hash function,
<code>eq</code> as the key equality predicate,
<code>a</code> as the allocator and a maximum load factor of 1.0
and inserts the elements from <code>il</code> into it.
</para>
</description>
<requires>
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
</para>
</requires>
</constructor>
<constructor>
<parameter name="n">
<paramtype>size_type</paramtype>
</parameter>
<parameter name="a">
<paramtype>allocator_type const&amp;</paramtype>
</parameter>
<postconditions>
<code><methodname>size</methodname>() == 0</code>
</postconditions>
<description>
<para>Constructs an empty container with at least <code>n</code> buckets,
using <code>hf</code> as the hash function,
the default hash function and key equality predicate,
<code>a</code> as the allocator and a maximum load factor of 1.0.</para>
</description>
<requires>
<para><code>hasher</code> and <code>key_equal</code> need to be <code>DefaultConstructible</code>.
</para>
</requires>
</constructor>
<constructor>
<parameter name="n">
<paramtype>size_type</paramtype>
</parameter>
<parameter name="hf">
<paramtype>hasher const&amp;</paramtype>
</parameter>
<parameter name="a">
<paramtype>allocator_type const&amp;</paramtype>
</parameter>
<postconditions>
<code><methodname>size</methodname>() == 0</code>
</postconditions>
<description>
<para>Constructs an empty container with at least <code>n</code> buckets,
using <code>hf</code> as the hash function,
the default key equality predicate,
<code>a</code> as the allocator and a maximum load factor of 1.0.</para>
</description>
<requires>
<para><code>key_equal</code> needs to be <code>DefaultConstructible</code>.
</para>
</requires>
</constructor>
<constructor>
<template>
<template-type-parameter name="InputIterator">
</template-type-parameter>
</template>
<parameter name="f">
<paramtype>InputIterator</paramtype>
</parameter>
<parameter name="l">
<paramtype>InputIterator</paramtype>
</parameter>
<parameter name="n">
<paramtype>size_type</paramtype>
</parameter>
<parameter name="a">
<paramtype>allocator_type const&amp;</paramtype>
</parameter>
<description>
<para>Constructs an empty container with at least <code>n</code> buckets,
using <code>a</code> as the allocator, with the
default hash function and key equality predicate
and a maximum load factor of 1.0
and inserts the elements from [f, l) into it.
</para>
</description>
<requires>
<para><code>hasher</code>, <code>key_equal</code> need to be <code>DefaultConstructible</code>.
</para>
</requires>
</constructor>
<constructor>
<template>
<template-type-parameter name="InputIterator">
</template-type-parameter>
</template>
<parameter name="f">
<paramtype>InputIterator</paramtype>
</parameter>
<parameter name="l">
<paramtype>InputIterator</paramtype>
</parameter>
<parameter name="n">
<paramtype>size_type</paramtype>
</parameter>
<parameter name="hf">
<paramtype>hasher const&amp;</paramtype>
</parameter>
<parameter name="a">
<paramtype>allocator_type const&amp;</paramtype>
</parameter>
<description>
<para>Constructs an empty container with at least <code>n</code> buckets,
using <code>hf</code> as the hash function,
<code>a</code> as the allocator, with the
default key equality predicate
and a maximum load factor of 1.0
and inserts the elements from [f, l) into it.
</para>
</description>
<requires>
<para><code>key_equal</code> needs to be <code>DefaultConstructible</code>.
</para>
</requires>
</constructor>
<destructor>
<notes>
<para>The destructor is applied to every element, and all memory is deallocated</para>
@@ -358,6 +537,21 @@ EOL;
</para>
</requires>
</method>
<method name="operator=">
<parameter>
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type><?php echo $name; ?>&amp;</type>
<description>
<para>Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.</para>
</description>
<requires>
<para>
<code>value_type</code> is <code>CopyInsertable</code> into the container and
<code>CopyAssignable</code>.
</para>
</requires>
</method>
<method name="get_allocator" cv="const">
<type>allocator_type</type>
</method>
@@ -640,7 +834,35 @@ EOL;
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.</para>
<para>Inserts a range of elements into the container.
<?php if (!$equivalent_keys): ?>
Elements are inserted if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
<?php endif; ?>
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
<code>X</code> from <code>*first</code>.</para>
</requires>
<throws>
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
</throws>
<notes>
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
<para>Pointers and references to elements are never invalidated.</para>
</notes>
</method>
<method name="insert">
<parameter name="il">
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container.
<?php if (!$equivalent_keys): ?>
Elements are inserted if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
<?php endif; ?>
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
+879 -11
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -10,7 +10,6 @@
//[case_insensitive_functions
struct iequal_to
: std::binary_function<std::string, std::string, bool>
{
bool operator()(std::string const& x,
std::string const& y) const
@@ -20,7 +19,6 @@
};
struct ihash
: std::unary_function<std::string, std::size_t>
{
std::size_t operator()(std::string const& x) const
{
-1
View File
@@ -18,7 +18,6 @@
}
struct point_hash
: std::unary_function<point, std::size_t>
{
std::size_t operator()(point const& p) const
{
-2
View File
@@ -19,7 +19,6 @@
namespace hash_examples
{
struct iequal_to
: std::binary_function<std::string, std::string, bool>
{
iequal_to() {}
explicit iequal_to(std::locale const& l) : locale_(l) {}
@@ -34,7 +33,6 @@ namespace hash_examples
};
struct ihash
: std::unary_function<std::string, std::size_t>
{
ihash() {}
explicit ihash(std::locale const& l) : locale_(l) {}
+375 -110
View File
@@ -14,23 +14,31 @@
#pragma once
#endif
// Some of these includes are required for other detail headers.
#include <boost/unordered/detail/fwd.hpp>
#include <boost/move/move.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/inc.hpp>
#include <boost/preprocessor/dec.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/type_traits/add_lvalue_reference.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/is_nothrow_move_constructible.hpp>
#include <boost/type_traits/is_nothrow_move_assignable.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/detail/select_type.hpp>
#include <boost/swap.hpp>
#include <boost/assert.hpp>
#include <boost/limits.hpp>
#include <iterator>
#include <utility>
#include <cmath>
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
#include <tuple>
@@ -44,7 +52,8 @@
// will be default-initialized.
#endif
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
// Maximum number of arguments supported by emplace + 1.
#define BOOST_UNORDERED_EMPLACE_LIMIT 11
namespace boost { namespace unordered { namespace detail {
@@ -80,6 +89,16 @@ namespace boost { namespace unordered { namespace detail {
convert_from_anything(T const&);
};
namespace func {
// This is a bit nasty, when constructing the individual members
// of a std::pair, need to cast away 'const'. For modern compilers,
// should be able to use std::piecewise_construct instead.
template <typename T> T* const_cast_pointer(T* x) { return x; }
template <typename T> T* const_cast_pointer(T const* x) {
return const_cast<T*>(x);
}
}
////////////////////////////////////////////////////////////////////////////
// emplace_args
//
@@ -88,26 +107,102 @@ namespace boost { namespace unordered { namespace detail {
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args
#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward<Args>(args)...
#define BOOST_UNORDERED_EMPLACE_ARGS1(a0) a0
#define BOOST_UNORDERED_EMPLACE_ARGS2(a0, a1) a0, a1
#define BOOST_UNORDERED_EMPLACE_ARGS3(a0, a1, a2) a0, a1, a2
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args
#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward<Args>(args)...
#else
#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args
#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args
#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args
#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args
#define BOOST_UNORDERED_EMPLACE_FORWARD args
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
#else
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \
BOOST_PP_CAT(Arg, n); \
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
#endif
template <typename A0>
struct emplace_args1
{
BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
emplace_args1(Arg0 b0) : a0(b0) {}
};
template <typename A0>
inline emplace_args1<A0> create_emplace_args(
BOOST_FWD_REF(A0) b0)
{
emplace_args1<A0> e(b0);
return e;
}
template <typename A0, typename A1>
struct emplace_args2
{
BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
BOOST_UNORDERED_EARGS_MEMBER(1, 1, _)
emplace_args2(Arg0 b0, Arg1 b1) : a0(b0), a1(b1) {}
};
template <typename A0, typename A1>
inline emplace_args2<A0, A1> create_emplace_args(
BOOST_FWD_REF(A0) b0,
BOOST_FWD_REF(A1) b1)
{
emplace_args2<A0, A1> e(b0, b1);
return e;
}
template <typename A0, typename A1, typename A2>
struct emplace_args3
{
BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
BOOST_UNORDERED_EARGS_MEMBER(1, 1, _)
BOOST_UNORDERED_EARGS_MEMBER(1, 2, _)
emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : a0(b0), a1(b1), a2(b2) {}
};
template <typename A0, typename A1, typename A2>
inline emplace_args3<A0, A1, A2> create_emplace_args(
BOOST_FWD_REF(A0) b0,
BOOST_FWD_REF(A1) b1,
BOOST_FWD_REF(A2) b2)
{
emplace_args3<A0, A1, A2> e(b0, b1, b2);
return e;
}
#define BOOST_UNORDERED_FWD_PARAM(z, n, a) \
BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n)
#define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \
boost::forward<BOOST_PP_CAT(A,i)>(BOOST_PP_CAT(a,i))
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n))
#define BOOST_UNORDERED_EARGS(z, n, _) \
template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
struct BOOST_PP_CAT(emplace_args, n) \
@@ -133,33 +228,7 @@ namespace boost { namespace unordered { namespace detail {
return e; \
}
#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args
#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args
#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
BOOST_PP_CAT(a, n)( \
boost::forward<BOOST_PP_CAT(A,n)>(BOOST_PP_CAT(b, n)))
#else
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \
BOOST_PP_CAT(Arg, n); \
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n))
#endif
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
_)
#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS
@@ -179,9 +248,8 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
// 2 = boost::container::allocator_traits
#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS)
# if defined(__GXX_EXPERIMENTAL_CXX0X__) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0
# if !defined(BOOST_NO_CXX11_ALLOCATOR)
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1
# elif defined(BOOST_MSVC)
# if BOOST_MSVC < 1400
// Use container's allocator_traits for older versions of Visual
@@ -258,7 +326,7 @@ namespace boost { namespace unordered { namespace detail {
#if !defined(BOOST_NO_SFINAE_EXPR)
template <typename T, unsigned int> struct expr_test;
template <typename T, long unsigned int> struct expr_test;
template <typename T> struct expr_test<T, sizeof(char)> : T {};
# define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \
@@ -354,11 +422,69 @@ namespace boost { namespace unordered { namespace detail {
namespace boost { namespace unordered { namespace detail {
// TODO: Does this match std::allocator_traits<Alloc>::rebind_alloc<T>?
template <typename Alloc, typename T>
struct rebind_alloc;
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <template<typename, typename...> class Alloc,
typename U, typename T, typename... Args>
struct rebind_alloc<Alloc<U, Args...>, T>
{
typedef Alloc<T, Args...> type;
};
#else
template <
template<typename> class Alloc,
typename U, typename T>
struct rebind_alloc<Alloc<U>, T>
{
typedef Alloc<T> type;
};
template <
template<typename, typename> class Alloc,
typename U, typename T,
typename A0>
struct rebind_alloc<Alloc<U, A0>, T>
{
typedef Alloc<T, A0> type;
};
template <
template<typename, typename, typename> class Alloc,
typename U, typename T,
typename A0, typename A1>
struct rebind_alloc<Alloc<U, A0, A1>, T>
{
typedef Alloc<T, A0, A1> type;
};
#endif
template <typename Alloc, typename T>
struct rebind_wrap
{
typedef typename Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other type;
template <typename X>
static choice1::type test(choice1,
typename X::BOOST_NESTED_TEMPLATE rebind<T>::other* = 0);
template <typename X>
static choice2::type test(choice2, void* = 0);
enum { value = (1 == sizeof(test<Alloc>(choose()))) };
struct fallback {
template <typename U>
struct rebind {
typedef typename rebind_alloc<Alloc, T>::type other;
};
};
typedef typename boost::detail::if_true<value>::
BOOST_NESTED_TEMPLATE then<Alloc, fallback>
::type::BOOST_NESTED_TEMPLATE rebind<T>::other type;
};
# if defined(BOOST_MSVC) && BOOST_MSVC <= 1400
@@ -548,7 +674,14 @@ namespace boost { namespace unordered { namespace detail {
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, size_type, std::size_t)
size_type;
// TODO: rebind_alloc and rebind_traits
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
template <typename T>
using rebind_alloc = typename rebind_wrap<Alloc, T>::type;
template <typename T>
using rebind_traits =
boost::unordered::detail::allocator_traits<rebind_alloc<T> >;
#endif
static pointer allocate(Alloc& a, size_type n)
{ return a.allocate(n); }
@@ -581,7 +714,7 @@ namespace boost { namespace unordered { namespace detail {
::value>::type
construct(Alloc&, T* p, BOOST_FWD_REF(Args)... x)
{
new ((void*) p) T(boost::forward<Args>(x)...);
new (static_cast<void*>(p)) T(boost::forward<Args>(x)...);
}
template <typename T>
@@ -615,7 +748,7 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::has_construct<Alloc, T>::value>::type
construct(Alloc&, T* p, T const& x)
{
new ((void*) p) T(x);
new (static_cast<void*>(p)) T(x);
}
template <typename T>
@@ -657,7 +790,7 @@ namespace boost { namespace unordered { namespace detail {
boost::is_same<T, value_type>::value,
void*>::type = 0)
{
new ((void*) p) T(x);
new (static_cast<void*>(p)) T(x);
}
template <typename T>
@@ -785,7 +918,7 @@ namespace boost { namespace unordered { namespace detail { namespace func {
}
template <typename Alloc, typename T>
inline void destroy_value_impl(Alloc& alloc, T* x) {
inline void call_destroy(Alloc& alloc, T* x) {
boost::unordered::detail::allocator_traits<Alloc>::destroy(alloc, x);
}
@@ -800,7 +933,7 @@ namespace boost { namespace unordered { namespace detail { namespace func {
}
template <typename Alloc, typename T>
inline void destroy_value_impl(Alloc&, T* x) {
inline void call_destroy(Alloc&, T* x) {
boost::unordered::detail::func::destroy(x);
}
@@ -808,9 +941,21 @@ namespace boost { namespace unordered { namespace detail { namespace func {
# endif
#else
template <typename Alloc, typename T>
inline void call_construct(Alloc&, T* address)
{
new ((void*) address) T();
}
template <typename Alloc, typename T, typename A0>
inline void call_construct(Alloc&, T* address,
BOOST_FWD_REF(A0) a0)
{
new ((void*) address) T(boost::forward<A0>(a0));
}
template <typename Alloc, typename T>
inline void destroy_value_impl(Alloc&, T* x) {
inline void call_destroy(Alloc&, T* x) {
boost::unordered::detail::func::destroy(x);
}
@@ -951,7 +1096,7 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
// For the standard pair constructor.
template <typename Alloc, typename T, typename... Args>
inline void construct_value_impl(Alloc& alloc, T* address,
inline void construct_from_args(Alloc& alloc, T* address,
BOOST_FWD_REF(Args)... args)
{
boost::unordered::detail::func::call_construct(alloc,
@@ -966,32 +1111,36 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
template <typename Alloc, typename A, typename B,
typename A0, typename A1, typename A2>
inline typename enable_if<use_piecewise<A0>, void>::type
construct_value_impl(Alloc& alloc, std::pair<A, B>* address,
construct_from_args(Alloc& alloc, std::pair<A, B>* address,
BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
{
boost::unordered::detail::func::construct_from_tuple(alloc,
boost::addressof(address->first), boost::forward<A1>(a1));
boost::unordered::detail::func::const_cast_pointer(
boost::addressof(address->first)),
boost::forward<A1>(a1));
boost::unordered::detail::func::construct_from_tuple(alloc,
boost::addressof(address->second), boost::forward<A2>(a2));
boost::unordered::detail::func::const_cast_pointer(
boost::addressof(address->second)),
boost::forward<A2>(a2));
}
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
////////////////////////////////////////////////////////////////////////////////
// Construct from emplace_args
////////////////////////////////////////////////////////////////////////////
// Construct from emplace_args
// Explicitly write out first three overloads for the sake of sane
// error messages.
template <typename Alloc, typename T, typename A0>
inline void construct_value_impl(Alloc&, T* address,
inline void construct_from_args(Alloc&, T* address,
emplace_args1<A0> const& args)
{
new((void*) address) T(boost::forward<A0>(args.a0));
}
template <typename Alloc, typename T, typename A0, typename A1>
inline void construct_value_impl(Alloc&, T* address,
inline void construct_from_args(Alloc&, T* address,
emplace_args2<A0, A1> const& args)
{
new((void*) address) T(
@@ -1001,7 +1150,7 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
}
template <typename Alloc, typename T, typename A0, typename A1, typename A2>
inline void construct_value_impl(Alloc&, T* address,
inline void construct_from_args(Alloc&, T* address,
emplace_args3<A0, A1, A2> const& args)
{
new((void*) address) T(
@@ -1018,7 +1167,7 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
typename Alloc, typename T, \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
> \
inline void construct_value_impl(Alloc&, T* address, \
inline void construct_from_args(Alloc&, T* address, \
boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
> const& args) \
@@ -1037,14 +1186,18 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
template <typename Alloc, typename A, typename B,
typename A0, typename A1, typename A2>
inline void construct_value_impl(Alloc& alloc, std::pair<A, B>* address,
inline void construct_from_args(Alloc& alloc, std::pair<A, B>* address,
boost::unordered::detail::emplace_args3<A0, A1, A2> const& args,
typename enable_if<use_piecewise<A0>, void*>::type = 0)
{
boost::unordered::detail::func::construct_from_tuple(alloc,
boost::addressof(address->first), args.a1);
boost::unordered::detail::func::const_cast_pointer(
boost::addressof(address->first)),
args.a1);
boost::unordered::detail::func::construct_from_tuple(alloc,
boost::addressof(address->second), args.a2);
boost::unordered::detail::func::const_cast_pointer(
boost::addressof(address->second)),
args.a2);
}
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
@@ -1053,74 +1206,186 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
//
// array_constructor
//
// Allocate and construct an array in an exception safe manner, and
// clean up if an exception is thrown before the container takes charge
// of it.
// Node construction
template <typename Allocator>
struct array_constructor
template <typename NodeAlloc>
struct node_constructor
{
typedef boost::unordered::detail::allocator_traits<Allocator> traits;
typedef typename traits::pointer pointer;
typedef NodeAlloc node_allocator;
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
node_allocator_traits;
typedef typename node_allocator_traits::value_type node;
typedef typename node_allocator_traits::pointer node_pointer;
typedef typename node::value_type value_type;
Allocator& alloc_;
pointer ptr_;
pointer constructed_;
std::size_t length_;
node_allocator& alloc_;
node_pointer node_;
bool node_constructed_;
array_constructor(Allocator& a)
: alloc_(a), ptr_(), constructed_(), length_(0)
node_constructor(node_allocator& n) :
alloc_(n),
node_(),
node_constructed_(false)
{
constructed_ = pointer();
ptr_ = pointer();
}
~array_constructor() {
if (ptr_) {
for(pointer p = ptr_; p != constructed_; ++p) {
boost::unordered::detail::func::destroy(
boost::addressof(*p));
}
~node_constructor();
traits::deallocate(alloc_, ptr_, length_);
}
}
void create_node();
template <typename V>
void construct(V const& v, std::size_t l)
// no throw
node_pointer release()
{
BOOST_ASSERT(!ptr_);
length_ = l;
ptr_ = traits::allocate(alloc_, length_);
pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
for(constructed_ = ptr_; constructed_ != end; ++constructed_) {
new ((void*) boost::addressof(*constructed_)) V(v);
}
}
pointer get() const
{
return ptr_;
}
pointer release()
{
pointer p(ptr_);
ptr_ = pointer();
BOOST_ASSERT(node_ && node_constructed_);
node_pointer p = node_;
node_ = node_pointer();
return p;
}
private:
void reclaim(node_pointer p) {
BOOST_ASSERT(!node_);
node_ = p;
node_constructed_ = true;
boost::unordered::detail::func::call_destroy(alloc_,
node_->value_ptr());
}
array_constructor(array_constructor const&);
array_constructor& operator=(array_constructor const&);
private:
node_constructor(node_constructor const&);
node_constructor& operator=(node_constructor const&);
};
template <typename Alloc>
node_constructor<Alloc>::~node_constructor()
{
if (node_) {
if (node_constructed_) {
boost::unordered::detail::func::destroy(
boost::addressof(*node_));
}
node_allocator_traits::deallocate(alloc_, node_, 1);
}
}
template <typename Alloc>
void node_constructor<Alloc>::create_node()
{
BOOST_ASSERT(!node_);
node_constructed_ = false;
node_ = node_allocator_traits::allocate(alloc_, 1);
new ((void*) boost::addressof(*node_)) node();
node_->init(node_);
node_constructed_ = true;
}
template <typename NodeAlloc>
struct node_tmp
{
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
node_allocator_traits;
typedef typename node_allocator_traits::pointer node_pointer;
NodeAlloc& alloc_;
node_pointer node_;
explicit node_tmp(node_pointer n, NodeAlloc& a):
alloc_(a),
node_(n)
{
}
~node_tmp();
// no throw
node_pointer release()
{
node_pointer p = node_;
node_ = node_pointer();
return p;
}
};
template <typename Alloc>
node_tmp<Alloc>::~node_tmp()
{
if (node_) {
boost::unordered::detail::func::call_destroy(alloc_,
node_->value_ptr());
boost::unordered::detail::func::destroy(
boost::addressof(*node_));
node_allocator_traits::deallocate(alloc_, node_, 1);
}
}
}}}
namespace boost { namespace unordered { namespace detail { namespace func {
// Some nicer construct_node functions, might try to
// improve implementation later.
template <typename Alloc, BOOST_UNORDERED_EMPLACE_TEMPLATE>
inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
construct_node_from_args(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS)
{
node_constructor<Alloc> a(alloc);
a.create_node();
construct_from_args(alloc, a.node_->value_ptr(),
BOOST_UNORDERED_EMPLACE_FORWARD);
return a.release();
}
template <typename Alloc, typename U>
inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
construct_node(Alloc& alloc, BOOST_FWD_REF(U) x)
{
node_constructor<Alloc> a(alloc);
a.create_node();
boost::unordered::detail::func::call_construct(
alloc, a.node_->value_ptr(), boost::forward<U>(x));
return a.release();
}
// TODO: When possible, it might be better to use std::pair's
// constructor for std::piece_construct with std::tuple.
template <typename Alloc, typename Key>
inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k)
{
node_constructor<Alloc> a(alloc);
a.create_node();
boost::unordered::detail::func::call_construct(alloc,
boost::unordered::detail::func::const_cast_pointer(
boost::addressof(a.node_->value_ptr()->first)),
boost::forward<Key>(k));
boost::unordered::detail::func::call_construct(alloc,
boost::unordered::detail::func::const_cast_pointer(
boost::addressof(a.node_->value_ptr()->second)));
return a.release();
}
template <typename Alloc, typename Key, typename Mapped>
inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m)
{
node_constructor<Alloc> a(alloc);
a.create_node();
boost::unordered::detail::func::call_construct(alloc,
boost::unordered::detail::func::const_cast_pointer(
boost::addressof(a.node_->value_ptr()->first)),
boost::forward<Key>(k));
boost::unordered::detail::func::call_construct(alloc,
boost::unordered::detail::func::const_cast_pointer(
boost::addressof(a.node_->value_ptr()->second)),
boost::forward<Mapped>(m));
return a.release();
}
}}}}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
+36 -190
View File
@@ -14,14 +14,6 @@
#include <boost/unordered/detail/util.hpp>
#include <boost/unordered/detail/allocate.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/is_nothrow_move_constructible.hpp>
#include <boost/type_traits/is_nothrow_move_assignable.hpp>
#include <boost/swap.hpp>
#include <boost/assert.hpp>
#include <boost/limits.hpp>
#include <boost/iterator.hpp>
namespace boost { namespace unordered { namespace detail {
@@ -56,7 +48,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
template <typename Node, typename Policy>
struct l_iterator
: public boost::iterator<
: public std::iterator<
std::forward_iterator_tag,
typename Node::value_type,
std::ptrdiff_t,
@@ -69,7 +61,6 @@ namespace boost { namespace unordered { namespace iterator_detail {
private:
#endif
typedef typename Node::node_pointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<Node> n_iterator;
node_pointer ptr_;
std::size_t bucket_;
std::size_t bucket_count_;
@@ -80,8 +71,8 @@ namespace boost { namespace unordered { namespace iterator_detail {
l_iterator() BOOST_NOEXCEPT : ptr_() {}
l_iterator(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT
: ptr_(x.node_), bucket_(b), bucket_count_(c) {}
l_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT
: ptr_(n), bucket_(b), bucket_count_(c) {}
value_type& operator*() const {
return ptr_->value();
@@ -116,7 +107,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
template <typename Node, typename Policy>
struct cl_iterator
: public boost::iterator<
: public std::iterator<
std::forward_iterator_tag,
typename Node::value_type,
std::ptrdiff_t,
@@ -128,7 +119,6 @@ namespace boost { namespace unordered { namespace iterator_detail {
private:
typedef typename Node::node_pointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<Node> n_iterator;
node_pointer ptr_;
std::size_t bucket_;
std::size_t bucket_count_;
@@ -139,8 +129,8 @@ namespace boost { namespace unordered { namespace iterator_detail {
cl_iterator() BOOST_NOEXCEPT : ptr_() {}
cl_iterator(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT :
ptr_(x.node_), bucket_(b), bucket_count_(c) {}
cl_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT :
ptr_(n), bucket_(b), bucket_count_(c) {}
cl_iterator(boost::unordered::iterator_detail::l_iterator<
Node, Policy> const& x) BOOST_NOEXCEPT :
@@ -184,7 +174,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
template <typename Node>
struct iterator
: public boost::iterator<
: public std::iterator<
std::forward_iterator_tag,
typename Node::value_type,
std::ptrdiff_t,
@@ -194,10 +184,6 @@ namespace boost { namespace unordered { namespace iterator_detail {
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename>
friend struct boost::unordered::iterator_detail::c_iterator;
template <typename, typename>
friend struct boost::unordered::iterator_detail::l_iterator;
template <typename, typename>
friend struct boost::unordered::iterator_detail::cl_iterator;
template <typename>
friend struct boost::unordered::detail::table;
template <typename>
@@ -248,7 +234,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
template <typename Node>
struct c_iterator
: public boost::iterator<
: public std::iterator<
std::forward_iterator_tag,
typename Node::value_type,
std::ptrdiff_t,
@@ -317,124 +303,6 @@ namespace boost { namespace unordered { namespace iterator_detail {
namespace boost { namespace unordered { namespace detail {
///////////////////////////////////////////////////////////////////
//
// Node construction
template <typename NodeAlloc>
struct node_constructor
{
private:
typedef NodeAlloc node_allocator;
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
node_allocator_traits;
typedef typename node_allocator_traits::value_type node;
typedef typename node_allocator_traits::pointer node_pointer;
typedef typename node::value_type value_type;
protected:
node_allocator& alloc_;
node_pointer node_;
bool node_constructed_;
bool value_constructed_;
public:
node_constructor(node_allocator& n) :
alloc_(n),
node_(),
node_constructed_(false),
value_constructed_(false)
{
}
~node_constructor();
void construct();
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
void construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS)
{
construct();
boost::unordered::detail::func::construct_value_impl(
alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
value_constructed_ = true;
}
template <typename A0>
void construct_with_value2(BOOST_FWD_REF(A0) a0)
{
construct();
boost::unordered::detail::func::construct_value_impl(
alloc_, node_->value_ptr(),
BOOST_UNORDERED_EMPLACE_ARGS1(boost::forward<A0>(a0)));
value_constructed_ = true;
}
value_type const& value() const {
BOOST_ASSERT(node_ && node_constructed_ && value_constructed_);
return node_->value();
}
// no throw
node_pointer release()
{
BOOST_ASSERT(node_ && node_constructed_);
node_pointer p = node_;
node_ = node_pointer();
return p;
}
private:
node_constructor(node_constructor const&);
node_constructor& operator=(node_constructor const&);
};
template <typename Alloc>
node_constructor<Alloc>::~node_constructor()
{
if (node_) {
if (value_constructed_) {
boost::unordered::detail::func::destroy_value_impl(alloc_,
node_->value_ptr());
}
if (node_constructed_) {
boost::unordered::detail::func::destroy(
boost::addressof(*node_));
}
node_allocator_traits::deallocate(alloc_, node_, 1);
}
}
template <typename Alloc>
void node_constructor<Alloc>::construct()
{
if(!node_) {
node_constructed_ = false;
value_constructed_ = false;
node_ = node_allocator_traits::allocate(alloc_, 1);
new ((void*) boost::addressof(*node_)) node();
node_->init(node_);
node_constructed_ = true;
}
else {
BOOST_ASSERT(node_constructed_);
if (value_constructed_)
{
boost::unordered::detail::func::destroy_value_impl(alloc_,
node_->value_ptr());
value_constructed_ = false;
}
}
}
///////////////////////////////////////////////////////////////////
//
// Node Holder
@@ -442,11 +310,9 @@ namespace boost { namespace unordered { namespace detail {
// Temporary store for nodes. Deletes any that aren't used.
template <typename NodeAlloc>
struct node_holder : private node_constructor<NodeAlloc>
struct node_holder
{
private:
typedef node_constructor<NodeAlloc> base;
typedef NodeAlloc node_allocator;
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
node_allocator_traits;
@@ -456,13 +322,14 @@ namespace boost { namespace unordered { namespace detail {
typedef typename node::link_pointer link_pointer;
typedef boost::unordered::iterator_detail::iterator<node> iterator;
node_constructor<NodeAlloc> constructor_;
node_pointer nodes_;
public:
template <typename Table>
explicit node_holder(Table& b) :
base(b.node_alloc()),
constructor_(b.node_alloc()),
nodes_()
{
if (b.size_) {
@@ -475,61 +342,40 @@ namespace boost { namespace unordered { namespace detail {
~node_holder();
void node_for_assignment()
node_pointer pop_node()
{
if (!this->node_ && nodes_) {
this->node_ = nodes_;
nodes_ = static_cast<node_pointer>(nodes_->next_);
this->node_->init(this->node_);
this->node_->next_ = link_pointer();
this->node_constructed_ = true;
this->value_constructed_ = true;
}
node_pointer n = nodes_;
nodes_ = static_cast<node_pointer>(nodes_->next_);
n->init(n);
n->next_ = link_pointer();
return n;
}
template <typename T>
inline void assign_impl(T const& v) {
if (this->node_ && this->value_constructed_) {
this->node_->value() = v;
inline node_pointer copy_of(T const& v) {
if (nodes_) {
constructor_.reclaim(pop_node());
}
else {
this->construct_with_value2(v);
constructor_.create_node();
}
}
template <typename T1, typename T2>
inline void assign_impl(std::pair<T1 const, T2> const& v) {
this->construct_with_value2(v);
boost::unordered::detail::func::call_construct(
constructor_.alloc_, constructor_.node_->value_ptr(), v);
return constructor_.release();
}
template <typename T>
inline void move_assign_impl(T& v) {
if (this->node_ && this->value_constructed_) {
this->node_->value() = boost::move(v);
inline node_pointer move_copy_of(T& v) {
if (nodes_) {
constructor_.reclaim(pop_node());
}
else {
this->construct_with_value2(boost::move(v));
constructor_.create_node();
}
}
template <typename T1, typename T2>
inline void move_assign_impl(std::pair<T1 const, T2>& v) {
this->construct_with_value2(boost::move(v));
}
node_pointer copy_of(value_type const& v)
{
node_for_assignment();
assign_impl(v);
return base::release();
}
node_pointer move_copy_of(value_type& v)
{
node_for_assignment();
move_assign_impl(v);
return base::release();
boost::unordered::detail::func::call_construct(
constructor_.alloc_, constructor_.node_->value_ptr(),
boost::move(v));
return constructor_.release();
}
iterator begin() const
@@ -545,10 +391,10 @@ namespace boost { namespace unordered { namespace detail {
node_pointer p = nodes_;
nodes_ = static_cast<node_pointer>(p->next_);
boost::unordered::detail::func::destroy_value_impl(this->alloc_,
boost::unordered::detail::func::call_destroy(constructor_.alloc_,
p->value_ptr());
boost::unordered::detail::func::destroy(boost::addressof(*p));
node_allocator_traits::deallocate(this->alloc_, p, 1);
node_allocator_traits::deallocate(constructor_.alloc_, p, 1);
}
}
@@ -700,12 +546,12 @@ namespace boost { namespace unordered { namespace detail {
// TODO: Maybe not if std::size_t is smaller than long long.
#if !defined(BOOST_NO_LONG_LONG)
template <>
struct pick_policy<long long> {
struct pick_policy<boost::long_long_type> {
typedef prime_policy<std::size_t> type;
};
template <>
struct pick_policy<unsigned long long> {
struct pick_policy<boost::ulong_long_type> {
typedef prime_policy<std::size_t> type;
};
#endif
+221 -172
View File
@@ -12,7 +12,6 @@
#pragma once
#endif
#include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/extract_key.hpp>
namespace boost { namespace unordered { namespace detail {
@@ -111,9 +110,11 @@ namespace boost { namespace unordered { namespace detail {
template <typename A, typename T>
struct pick_grouped_node
{
typedef typename boost::remove_const<T>::type nonconst;
typedef boost::unordered::detail::allocator_traits<
typename boost::unordered::detail::rebind_wrap<A,
boost::unordered::detail::grouped_ptr_node<T> >::type
boost::unordered::detail::grouped_ptr_node<nonconst> >::type
> tentative_node_traits;
typedef boost::unordered::detail::allocator_traits<
@@ -121,7 +122,7 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::ptr_bucket >::type
> tentative_bucket_traits;
typedef pick_grouped_node2<A, T,
typedef pick_grouped_node2<A, nonconst,
typename tentative_node_traits::pointer,
typename tentative_bucket_traits::pointer> pick;
@@ -130,55 +131,6 @@ namespace boost { namespace unordered { namespace detail {
typedef typename pick::link_pointer link_pointer;
};
template <typename A, typename T, typename H, typename P>
struct multiset
{
typedef boost::unordered::detail::multiset<A, T, H, P> types;
typedef A allocator;
typedef T value_type;
typedef H hasher;
typedef P key_equal;
typedef T key_type;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
typedef boost::unordered::detail::pick_grouped_node<allocator,
value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
};
template <typename A, typename K, typename M, typename H, typename P>
struct multimap
{
typedef boost::unordered::detail::multimap<A, K, M, H, P> types;
typedef A allocator;
typedef std::pair<K const, M> value_type;
typedef H hasher;
typedef P key_equal;
typedef K key_type;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
typedef boost::unordered::detail::pick_grouped_node<allocator,
value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::map_extractor<key_type, value_type>
extractor;
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
};
template <typename Types>
struct grouped_table_impl : boost::unordered::detail::table<Types>
{
@@ -195,6 +147,7 @@ namespace boost { namespace unordered { namespace detail {
typedef typename table::key_equal key_equal;
typedef typename table::key_type key_type;
typedef typename table::node_constructor node_constructor;
typedef typename table::node_tmp node_tmp;
typedef typename table::extractor extractor;
typedef typename table::iterator iterator;
typedef typename table::c_iterator c_iterator;
@@ -235,48 +188,58 @@ namespace boost { namespace unordered { namespace detail {
this->move_init(x);
}
// Node functions.
static inline node_pointer next_node(link_pointer n) {
return static_cast<node_pointer>(n->next_);
}
static inline node_pointer next_group(node_pointer n) {
return static_cast<node_pointer>(n->group_prev_->next_);
}
// Accessors
template <class Key, class Pred>
iterator find_node_impl(
node_pointer find_node_impl(
std::size_t key_hash,
Key const& k,
Pred const& eq) const
{
std::size_t bucket_index = this->hash_to_bucket(key_hash);
iterator n = this->begin(bucket_index);
node_pointer n = this->begin(bucket_index);
for (;;)
{
if (!n.node_) return n;
if (!n) return n;
std::size_t node_hash = n.node_->hash_;
std::size_t node_hash = n->hash_;
if (key_hash == node_hash)
{
if (eq(k, this->get_key(*n)))
if (eq(k, this->get_key(n->value())))
return n;
}
else
{
if (this->hash_to_bucket(node_hash) != bucket_index)
return iterator();
return node_pointer();
}
n = iterator(n.node_->group_prev_->next_);
n = next_group(n);
}
}
std::size_t count(key_type const& k) const
{
iterator n = this->find_node(k);
if (!n.node_) return 0;
node_pointer n = this->find_node(k);
if (!n) return 0;
std::size_t x = 0;
node_pointer it = n.node_;
node_pointer it = n;
do {
it = it->group_prev_;
++x;
} while(it != n.node_);
} while(it != n);
return x;
}
@@ -284,9 +247,8 @@ namespace boost { namespace unordered { namespace detail {
std::pair<iterator, iterator>
equal_range(key_type const& k) const
{
iterator n = this->find_node(k);
return std::make_pair(
n, n.node_ ? iterator(n.node_->group_prev_->next_) : n);
node_pointer n = this->find_node(k);
return std::make_pair(iterator(n), iterator(n ? next_group(n) : n));
}
// Equality
@@ -295,12 +257,12 @@ namespace boost { namespace unordered { namespace detail {
{
if(this->size_ != other.size_) return false;
for(iterator n1 = this->begin(); n1.node_;)
for(node_pointer n1 = this->begin(); n1;)
{
iterator n2 = other.find_matching_node(n1);
if (!n2.node_) return false;
iterator end1(n1.node_->group_prev_->next_);
iterator end2(n2.node_->group_prev_->next_);
node_pointer n2 = other.find_node(other.get_key(n1->value()));
if (!n2) return false;
node_pointer end1 = next_group(n1);
node_pointer end2 = next_group(n2);
if (!group_equals(n1, end1, n2, end2)) return false;
n1 = end1;
}
@@ -308,24 +270,24 @@ namespace boost { namespace unordered { namespace detail {
return true;
}
static bool group_equals(iterator n1, iterator end1,
iterator n2, iterator end2)
static bool group_equals(node_pointer n1, node_pointer end1,
node_pointer n2, node_pointer end2)
{
for(;;)
{
if (*n1 != *n2) break;
if (n1->value() != n2->value()) break;
++n1;
++n2;
n1 = next_node(n1);
n2 = next_node(n2);
if (n1 == end1) return n2 == end2;
if (n2 == end2) return false;
}
for(iterator n1a = n1, n2a = n2;;)
for(node_pointer n1a = n1, n2a = n2;;)
{
++n1a;
++n2a;
n1a = next_node(n1a);
n2a = next_node(n2a);
if (n1a == end1)
{
@@ -336,41 +298,43 @@ namespace boost { namespace unordered { namespace detail {
if (n2a == end2) return false;
}
iterator start = n1;
for(;n1 != end1; ++n1)
node_pointer start = n1;
for(;n1 != end1; n1 = next_node(n1))
{
value_type const& v = *n1;
if (find(start, n1, v)) continue;
std::size_t matches = count_equal(n2, end2, v);
if (!matches) return false;
iterator next = n1;
++next;
if (matches != 1 + count_equal(next, end1, v)) return false;
value_type const& v = n1->value();
if (!find(start, n1, v)) {
std::size_t matches = count_equal(n2, end2, v);
if (!matches) return false;
if (matches != 1 + count_equal(next_node(n1), end1, v)) return false;
}
}
return true;
}
static bool find(iterator n, iterator end, value_type const& v)
static bool find(node_pointer n, node_pointer end, value_type const& v)
{
for(;n != end; ++n)
if (*n == v)
for(;n != end; n = next_node(n))
if (n->value() == v)
return true;
return false;
}
static std::size_t count_equal(iterator n, iterator end,
static std::size_t count_equal(node_pointer n, node_pointer end,
value_type const& v)
{
std::size_t count = 0;
for(;n != end; ++n)
if (*n == v) ++count;
for(;n != end; n = next_node(n))
if (n->value() == v) ++count;
return count;
}
// Emplace/Insert
static inline void add_after_node(
// Add node 'n' to the group containing 'pos'.
// If 'pos' is the first node in group, add to the end of the group,
// otherwise add before 'pos'.
static inline void add_to_node_group(
node_pointer n,
node_pointer pos)
{
@@ -380,18 +344,17 @@ namespace boost { namespace unordered { namespace detail {
pos->group_prev_ = n;
}
inline iterator add_node(
node_constructor& a,
inline node_pointer add_node(
node_pointer n,
std::size_t key_hash,
iterator pos)
node_pointer pos)
{
node_pointer n = a.release();
n->hash_ = key_hash;
if (pos.node_) {
this->add_after_node(n, pos.node_);
if (pos) {
this->add_to_node_group(n, pos);
if (n->next_) {
std::size_t next_bucket = this->hash_to_bucket(
static_cast<node_pointer>(n->next_)->hash_);
next_node(n)->hash_);
if (next_bucket != this->hash_to_bucket(key_hash)) {
this->get_bucket(next_bucket)->next_ = n;
}
@@ -407,7 +370,7 @@ namespace boost { namespace unordered { namespace detail {
if (start_node->next_) {
this->get_bucket(this->hash_to_bucket(
static_cast<node_pointer>(start_node->next_)->hash_
next_node(start_node)->hash_
))->next_ = n;
}
@@ -422,27 +385,26 @@ namespace boost { namespace unordered { namespace detail {
}
}
++this->size_;
return iterator(n);
return n;
}
iterator emplace_impl(node_constructor& a)
inline node_pointer add_using_hint(
node_pointer n,
node_pointer hint)
{
key_type const& k = this->get_key(a.value());
std::size_t key_hash = this->hash(k);
iterator position = this->find_node(key_hash, k);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
return this->add_node(a, key_hash, position);
n->hash_ = hint->hash_;
this->add_to_node_group(n, hint);
if (n->next_ != hint && n->next_) {
std::size_t next_bucket = this->hash_to_bucket(
next_node(n)->hash_);
if (next_bucket != this->hash_to_bucket(n->hash_)) {
this->get_bucket(next_bucket)->next_ = n;
}
}
++this->size_;
return n;
}
void emplace_impl_no_rehash(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t key_hash = this->hash(k);
this->add_node(a, key_hash, this->find_node(key_hash, k));
}
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
# if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
@@ -452,6 +414,13 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(false);
return iterator();
}
iterator emplace_hint(c_iterator, boost::unordered::detail::emplace_args1<
boost::unordered::detail::please_ignore_this_overload> const&)
{
BOOST_ASSERT(false);
return iterator();
}
# else
iterator emplace(
boost::unordered::detail::please_ignore_this_overload const&)
@@ -459,16 +428,65 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(false);
return iterator();
}
iterator emplace_hint(c_iterator,
boost::unordered::detail::please_ignore_this_overload const&)
{
BOOST_ASSERT(false);
return iterator();
}
# endif
#endif
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS)
{
node_constructor a(this->node_alloc());
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
return iterator(emplace_impl(
boost::unordered::detail::func::construct_node_from_args(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD)));
}
return iterator(emplace_impl(a));
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS)
{
return iterator(emplace_hint_impl(hint,
boost::unordered::detail::func::construct_node_from_args(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD)));
}
iterator emplace_impl(node_pointer n)
{
node_tmp a(n, this->node_alloc());
key_type const& k = this->get_key(a.node_->value());
std::size_t key_hash = this->hash(k);
node_pointer position = this->find_node(key_hash, k);
this->reserve_for_insert(this->size_ + 1);
return iterator(this->add_node(a.release(), key_hash, position));
}
iterator emplace_hint_impl(c_iterator hint, node_pointer n)
{
node_tmp a(n, this->node_alloc());
key_type const& k = this->get_key(a.node_->value());
if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
this->reserve_for_insert(this->size_ + 1);
return iterator(this->add_using_hint(a.release(), hint.node_));
}
else {
std::size_t key_hash = this->hash(k);
node_pointer position = this->find_node(key_hash, k);
this->reserve_for_insert(this->size_ + 1);
return iterator(this->add_node(a.release(), key_hash, position));
}
}
void emplace_impl_no_rehash(node_pointer n)
{
node_tmp a(n, this->node_alloc());
key_type const& k = this->get_key(a.node_->value());
std::size_t key_hash = this->hash(k);
node_pointer position = this->find_node(key_hash, k);
this->add_node(a.release(), key_hash, position);
}
////////////////////////////////////////////////////////////////////////
@@ -477,37 +495,37 @@ namespace boost { namespace unordered { namespace detail {
// if hash function throws, or inserting > 1 element, basic exception
// safety. Strong otherwise
template <class I>
typename boost::unordered::detail::enable_if_forward<I, void>::type
insert_range(I i, I j)
void insert_range(I i, I j, typename
boost::unordered::detail::enable_if_forward<I, void*>::type = 0)
{
if(i == j) return;
std::size_t distance = boost::unordered::detail::distance(i, j);
std::size_t distance = static_cast<std::size_t>(std::distance(i, j));
if(distance == 1) {
node_constructor a(this->node_alloc());
a.construct_with_value2(*i);
emplace_impl(a);
emplace_impl(
boost::unordered::detail::func::construct_node(
this->node_alloc(), *i));
}
else {
// Only require basic exception safety here
this->reserve_for_insert(this->size_ + distance);
node_constructor a(this->node_alloc());
for (; i != j; ++i) {
a.construct_with_value2(*i);
emplace_impl_no_rehash(a);
emplace_impl_no_rehash(
boost::unordered::detail::func::construct_node(
this->node_alloc(), *i));
}
}
}
template <class I>
typename boost::unordered::detail::disable_if_forward<I, void>::type
insert_range(I i, I j)
void insert_range(I i, I j, typename
boost::unordered::detail::disable_if_forward<I, void*>::type = 0)
{
node_constructor a(this->node_alloc());
for (; i != j; ++i) {
a.construct_with_value2(*i);
emplace_impl(a);
emplace_impl(
boost::unordered::detail::func::construct_node(
this->node_alloc(), *i));
}
}
@@ -525,21 +543,21 @@ namespace boost { namespace unordered { namespace detail {
link_pointer prev = this->get_previous_start(bucket_index);
if (!prev) return 0;
node_pointer first_node;
for (;;)
{
if (!prev->next_) return 0;
std::size_t node_hash =
static_cast<node_pointer>(prev->next_)->hash_;
first_node = next_node(prev);
std::size_t node_hash = first_node->hash_;
if (this->hash_to_bucket(node_hash) != bucket_index)
return 0;
if (node_hash == key_hash &&
this->key_eq()(k, this->get_key(
static_cast<node_pointer>(prev->next_)->value())))
this->key_eq()(k, this->get_key(first_node->value())))
break;
prev = static_cast<node_pointer>(prev->next_)->group_prev_;
prev = first_node->group_prev_;
}
node_pointer first_node = static_cast<node_pointer>(prev->next_);
link_pointer end = first_node->group_prev_->next_;
std::size_t deleted_count = this->delete_nodes(prev, end);
@@ -550,10 +568,9 @@ namespace boost { namespace unordered { namespace detail {
iterator erase(c_iterator r)
{
BOOST_ASSERT(r.node_);
iterator next(r.node_);
++next;
erase_nodes(r.node_, next.node_);
return next;
node_pointer next = next_node(r.node_);
erase_nodes(r.node_, next);
return iterator(next);
}
iterator erase_range(c_iterator r1, c_iterator r2)
@@ -578,13 +595,12 @@ namespace boost { namespace unordered { namespace detail {
if (!prev) {
prev = this->get_previous_start(bucket_index);
while (prev->next_ != i)
prev = static_cast<node_pointer>(prev->next_)->group_prev_;
prev = next_node(prev)->group_prev_;
}
// Delete the nodes.
do {
link_pointer group_end =
static_cast<node_pointer>(prev->next_)->group_prev_->next_;
link_pointer group_end = next_group(next_node(prev));
this->delete_nodes(prev, group_end);
bucket_index = this->fix_bucket(bucket_index, prev);
} while(prev->next_ != j);
@@ -621,31 +637,65 @@ namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////
// fill_buckets
template <class NodeCreator>
static void fill_buckets(iterator n, table& dst,
NodeCreator& creator)
{
link_pointer prev = dst.get_previous_start();
void copy_buckets(table const& src) {
this->create_buckets(this->bucket_count_);
while (n.node_) {
std::size_t key_hash = n.node_->hash_;
iterator group_end(n.node_->group_prev_->next_);
node_pointer first_node = creator.create(*n);
node_pointer end = first_node;
first_node->hash_ = key_hash;
prev->next_ = first_node;
++dst.size_;
for (++n; n != group_end; ++n)
for (node_pointer n = src.begin(); n;) {
std::size_t key_hash = n->hash_;
node_pointer group_end(next_group(n));
node_pointer pos = this->add_node(
boost::unordered::detail::func::construct_node(
this->node_alloc(), n->value()), key_hash, node_pointer());
for (n = next_node(n); n != group_end; n = next_node(n))
{
end = creator.create(*n);
end->hash_ = key_hash;
add_after_node(end, first_node);
++dst.size_;
this->add_node(
boost::unordered::detail::func::construct_node(
this->node_alloc(), n->value()), key_hash, pos);
}
}
}
prev = place_in_bucket(dst, prev, end);
void move_buckets(table const& src) {
this->create_buckets(this->bucket_count_);
for (node_pointer n = src.begin(); n;) {
std::size_t key_hash = n->hash_;
node_pointer group_end(next_group(n));
node_pointer pos = this->add_node(
boost::unordered::detail::func::construct_node(
this->node_alloc(), boost::move(n->value())), key_hash, node_pointer());
for (n = next_node(n); n != group_end; n = next_node(n))
{
this->add_node(
boost::unordered::detail::func::construct_node(
this->node_alloc(), boost::move(n->value())), key_hash, pos);
}
}
}
void assign_buckets(table const& src) {
node_holder<node_allocator> holder(*this);
for (node_pointer n = src.begin(); n;) {
std::size_t key_hash = n->hash_;
node_pointer group_end(next_group(n));
node_pointer pos = this->add_node(holder.copy_of(n->value()), key_hash, node_pointer());
for (n = next_node(n); n != group_end; n = next_node(n))
{
this->add_node(holder.copy_of(n->value()), key_hash, pos);
}
}
}
void move_assign_buckets(table& src) {
node_holder<node_allocator> holder(*this);
for (node_pointer n = src.begin(); n;) {
std::size_t key_hash = n->hash_;
node_pointer group_end(next_group(n));
node_pointer pos = this->add_node(holder.move_copy_of(n->value()), key_hash, node_pointer());
for (n = next_node(n); n != group_end; n = next_node(n))
{
this->add_node(holder.move_copy_of(n->value()), key_hash, pos);
}
}
}
@@ -657,8 +707,7 @@ namespace boost { namespace unordered { namespace detail {
this->create_buckets(num_buckets);
link_pointer prev = this->get_previous_start();
while (prev->next_)
prev = place_in_bucket(*this, prev,
static_cast<node_pointer>(prev->next_)->group_prev_);
prev = place_in_bucket(*this, prev, next_node(prev)->group_prev_);
}
// Iterate through the nodes placing them in the correct buckets.
@@ -51,7 +51,7 @@ namespace detail {
typedef ValueType value_type;
typedef ValueType key_type;
static key_type const& extract(key_type const& v)
static key_type const& extract(value_type const& v)
{
return v;
}
+35 -1
View File
@@ -1,5 +1,5 @@
// Copyright (C) 2008-2011 Daniel James.
// Copyright (C) 2008-2016 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -11,12 +11,46 @@
#pragma once
#endif
#if defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
// Already defined.
#elif defined(BOOST_LIBSTDCXX11)
// https://github.com/gcc-mirror/gcc/blob/gcc-4_6-branch/libstdc++-v3/include/bits/stl_pair.h#L70
# if BOOST_LIBSTDCXX_VERSION > 40600
# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
# endif
#elif defined(_LIBCPP_VERSION)
// https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206
# if LIBCPP_VERSION >= 3000
# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
# endif
#elif defined(BOOST_MSVC)
// Apparently C++11 standard supported in Visual Studio 2012
// https://msdn.microsoft.com/en-us/library/hh567368.aspx#stl
// 2012 = VC+11 = BOOST_MSVC 1700 Hopefully!
# if BOOST_MSVC >= 1700
# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
# endif
#endif
#if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 0
#endif
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
#include <utility>
#endif
namespace boost
{
namespace unordered
{
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
using std::piecewise_construct_t;
using std::piecewise_construct;
#else
struct piecewise_construct_t {};
const piecewise_construct_t piecewise_construct = piecewise_construct_t();
#endif
}
}
+79
View File
@@ -0,0 +1,79 @@
// Copyright (C) 2005-2016 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered/unordered_map_fwd.hpp>
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
namespace boost { namespace unordered { namespace detail {
template <typename A, typename K, typename M, typename H, typename P>
struct map
{
typedef boost::unordered::detail::map<A, K, M, H, P> types;
typedef A allocator;
typedef std::pair<K const, M> value_type;
typedef H hasher;
typedef P key_equal;
typedef K key_type;
typedef boost::unordered::detail::allocator_traits<allocator>
traits;
typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::table_impl<types> table;
typedef boost::unordered::detail::map_extractor<key_type, 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;
};
template <typename A, typename K, typename M, typename H, typename P>
struct multimap
{
typedef boost::unordered::detail::multimap<A, K, M, H, P> types;
typedef A allocator;
typedef std::pair<K const, M> value_type;
typedef H hasher;
typedef P key_equal;
typedef K key_type;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
typedef boost::unordered::detail::pick_grouped_node<allocator,
value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::map_extractor<key_type, value_type>
extractor;
typedef 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;
};
}}}
+75
View File
@@ -0,0 +1,75 @@
// Copyright (C) 2005-2016 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered/unordered_set_fwd.hpp>
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
namespace boost { namespace unordered { namespace detail {
template <typename A, typename T, typename H, typename P>
struct set
{
typedef boost::unordered::detail::set<A, T, H, P> types;
typedef A allocator;
typedef T value_type;
typedef H hasher;
typedef P key_equal;
typedef T key_type;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::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;
};
template <typename A, typename T, typename H, typename P>
struct multiset
{
typedef boost::unordered::detail::multiset<A, T, H, P> types;
typedef A allocator;
typedef T value_type;
typedef H hasher;
typedef P key_equal;
typedef T key_type;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
typedef boost::unordered::detail::pick_grouped_node<allocator,
value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef 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;
};
}}}
+83 -162
View File
@@ -13,28 +13,12 @@
#endif
#include <boost/unordered/detail/buckets.hpp>
#include <boost/unordered/detail/util.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <cmath>
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4127) // conditional expression is constant
#endif
#if defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
#if defined(__EDG__)
#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__)
#pragma message("Warning: BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported.")
#elif defined(__GNUC__) || defined(__HP_aCC) || \
defined(__SUNPRO_CC) || defined(__IBMCPP__)
#warning "BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported."
#endif
#endif
namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////////
@@ -80,70 +64,6 @@ namespace boost { namespace unordered { namespace detail {
value_base& operator=(value_base const&);
};
template <typename NodeAlloc>
struct copy_nodes
{
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
node_allocator_traits;
node_constructor<NodeAlloc> constructor;
explicit copy_nodes(NodeAlloc& a) : constructor(a) {}
typename node_allocator_traits::pointer create(
typename node_allocator_traits::value_type::value_type const& v)
{
constructor.construct_with_value2(v);
return constructor.release();
}
};
template <typename NodeAlloc>
struct move_nodes
{
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
node_allocator_traits;
node_constructor<NodeAlloc> constructor;
explicit move_nodes(NodeAlloc& a) : constructor(a) {}
typename node_allocator_traits::pointer create(
typename node_allocator_traits::value_type::value_type& v)
{
constructor.construct_with_value2(boost::move(v));
return constructor.release();
}
};
template <typename Buckets>
struct assign_nodes
{
node_holder<typename Buckets::node_allocator> holder;
explicit assign_nodes(Buckets& b) : holder(b) {}
typename Buckets::node_pointer create(
typename Buckets::value_type const& v)
{
return holder.copy_of(v);
}
};
template <typename Buckets>
struct move_assign_nodes
{
node_holder<typename Buckets::node_allocator> holder;
explicit move_assign_nodes(Buckets& b) : holder(b) {}
typename Buckets::node_pointer create(
typename Buckets::value_type& v)
{
return holder.move_copy_of(v);
}
};
template <typename Types>
struct table :
boost::unordered::detail::functions<
@@ -164,6 +84,10 @@ namespace boost { namespace unordered { namespace detail {
typedef typename Types::table table_impl;
typedef typename Types::link_pointer link_pointer;
typedef typename Types::policy policy;
typedef typename Types::iterator iterator;
typedef typename Types::c_iterator c_iterator;
typedef typename Types::l_iterator l_iterator;
typedef typename Types::cl_iterator cl_iterator;
typedef boost::unordered::detail::functions<
typename Types::hasher,
@@ -187,15 +111,8 @@ namespace boost { namespace unordered { namespace detail {
bucket_pointer;
typedef boost::unordered::detail::node_constructor<node_allocator>
node_constructor;
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::detail::node_tmp<node_allocator>
node_tmp;
////////////////////////////////////////////////////////////////////////
// Members
@@ -208,6 +125,13 @@ namespace boost { namespace unordered { namespace detail {
std::size_t max_load_;
bucket_pointer buckets_;
////////////////////////////////////////////////////////////////////////
// Node functions
static inline node_pointer next_node(link_pointer n) {
return static_cast<node_pointer>(n->next_);
}
////////////////////////////////////////////////////////////////////////
// Data access
@@ -254,16 +178,16 @@ namespace boost { namespace unordered { namespace detail {
return get_bucket(bucket_index)->next_;
}
iterator begin() const
node_pointer begin() const
{
return size_ ? iterator(get_previous_start()->next_) : iterator();
return size_ ? next_node(get_previous_start()) : node_pointer();
}
iterator begin(std::size_t bucket_index) const
node_pointer begin(std::size_t bucket_index) const
{
if (!size_) return iterator();
if (!size_) return node_pointer();
link_pointer prev = get_previous_start(bucket_index);
return prev ? iterator(prev->next_) : iterator();
return prev ? next_node(prev) : node_pointer();
}
std::size_t hash_to_bucket(std::size_t hash_value) const
@@ -280,14 +204,14 @@ namespace boost { namespace unordered { namespace detail {
std::size_t bucket_size(std::size_t index) const
{
iterator it = begin(index);
if (!it.node_) return 0;
node_pointer n = begin(index);
if (!n) return 0;
std::size_t count = 0;
while(it.node_ && hash_to_bucket(it.node_->hash_) == index)
while(n && hash_to_bucket(n->hash_) == index)
{
++count;
++it;
n = next_node(n);
}
return count;
@@ -403,9 +327,7 @@ namespace boost { namespace unordered { namespace detail {
void init(table const& x)
{
if (x.size_) {
create_buckets(bucket_count_);
copy_nodes<node_allocator> node_creator(node_alloc());
table_impl::fill_buckets(x.begin(), *this, node_creator);
static_cast<table_impl*>(this)->copy_buckets(x);
}
}
@@ -416,11 +338,7 @@ namespace boost { namespace unordered { namespace detail {
}
else if(x.size_) {
// TODO: Could pick new bucket size?
create_buckets(bucket_count_);
move_nodes<node_allocator> node_creator(node_alloc());
node_holder<node_allocator> nodes(x);
table_impl::fill_buckets(nodes.begin(), *this, node_creator);
static_cast<table_impl*>(this)->move_buckets(x);
}
}
@@ -429,34 +347,53 @@ namespace boost { namespace unordered { namespace detail {
void create_buckets(std::size_t new_count)
{
boost::unordered::detail::array_constructor<bucket_allocator>
constructor(bucket_alloc());
// Creates an extra bucket to act as the start node.
constructor.construct(bucket(), new_count + 1);
std::size_t length = new_count + 1;
bucket_pointer new_buckets = bucket_allocator_traits::allocate(
bucket_alloc(), length);
bucket_pointer constructed = new_buckets;
if (buckets_)
{
// Copy the nodes to the new buckets, including the dummy
// node if there is one.
(constructor.get() +
static_cast<std::ptrdiff_t>(new_count))->next_ =
(buckets_ + static_cast<std::ptrdiff_t>(
bucket_count_))->next_;
destroy_buckets();
}
else if (bucket::extra_node)
{
node_constructor a(node_alloc());
a.construct();
BOOST_TRY {
bucket_pointer end = new_buckets
+ static_cast<std::ptrdiff_t>(length);
for(; constructed != end; ++constructed) {
new ((void*) boost::addressof(*constructed)) bucket();
}
(constructor.get() +
static_cast<std::ptrdiff_t>(new_count))->next_ =
a.release();
if (buckets_)
{
// Copy the nodes to the new buckets, including the dummy
// node if there is one.
(new_buckets +
static_cast<std::ptrdiff_t>(new_count))->next_ =
(buckets_ + static_cast<std::ptrdiff_t>(
bucket_count_))->next_;
destroy_buckets();
}
else if (bucket::extra_node)
{
node_constructor a(node_alloc());
a.create_node();
(new_buckets +
static_cast<std::ptrdiff_t>(new_count))->next_ =
a.release();
}
}
BOOST_CATCH(...) {
for(bucket_pointer p = new_buckets; p != constructed; ++p) {
boost::unordered::detail::func::destroy(
boost::addressof(*p));
}
bucket_allocator_traits::deallocate(bucket_alloc(),
new_buckets, length);
BOOST_RETHROW;
}
BOOST_CATCH_END
bucket_count_ = new_count;
buckets_ = constructor.release();
buckets_ = new_buckets;
recalculate_max_load();
}
@@ -527,7 +464,7 @@ namespace boost { namespace unordered { namespace detail {
node_pointer n = static_cast<node_pointer>(prev->next_);
prev->next_ = n->next_;
boost::unordered::detail::func::destroy_value_impl(node_alloc(),
boost::unordered::detail::func::call_destroy(node_alloc(),
n->value_ptr());
boost::unordered::detail::func::destroy(boost::addressof(*n));
node_allocator_traits::deallocate(node_alloc(), n, 1);
@@ -649,11 +586,13 @@ namespace boost { namespace unordered { namespace detail {
{
// Strong exception safety.
set_hash_functions new_func_this(*this, x);
new_func_this.commit();
mlf_ = x.mlf_;
recalculate_max_load();
if (!size_ && !x.size_) return;
if (!size_ && !x.size_) {
new_func_this.commit();
return;
}
if (x.size_ >= max_load_) {
create_buckets(min_buckets_for_size(x.size_));
@@ -662,11 +601,8 @@ namespace boost { namespace unordered { namespace detail {
clear_buckets();
}
// assign_nodes takes ownership of the container's elements,
// assigning to them if possible, and deleting any that are
// left over.
assign_nodes<table> node_creator(*this);
table_impl::fill_buckets(x.begin(), *this, node_creator);
new_func_this.commit();
static_cast<table_impl*>(this)->assign_buckets(x);
}
void assign(table const& x, true_type)
@@ -691,9 +627,7 @@ namespace boost { namespace unordered { namespace detail {
// Finally copy the elements.
if (x.size_) {
create_buckets(bucket_count_);
copy_nodes<node_allocator> node_creator(node_alloc());
table_impl::fill_buckets(x.begin(), *this, node_creator);
static_cast<table_impl*>(this)->copy_buckets(x);
}
}
}
@@ -734,11 +668,13 @@ namespace boost { namespace unordered { namespace detail {
}
else {
set_hash_functions new_func_this(*this, x);
new_func_this.commit();
mlf_ = x.mlf_;
recalculate_max_load();
if (!size_ && !x.size_) return;
if (!size_ && !x.size_) {
new_func_this.commit();
return;
}
if (x.size_ >= max_load_) {
create_buckets(min_buckets_for_size(x.size_));
@@ -747,12 +683,8 @@ namespace boost { namespace unordered { namespace detail {
clear_buckets();
}
// move_assign_nodes takes ownership of the container's
// elements, assigning to them if possible, and deleting
// any that are left over.
move_assign_nodes<table> node_creator(*this);
node_holder<node_allocator> nodes(x);
table_impl::fill_buckets(nodes.begin(), *this, node_creator);
new_func_this.commit();
static_cast<table_impl*>(this)->move_assign_buckets(x);
}
}
@@ -771,7 +703,7 @@ namespace boost { namespace unordered { namespace detail {
// Find Node
template <typename Key, typename Hash, typename Pred>
iterator generic_find_node(
node_pointer generic_find_node(
Key const& k,
Hash const& hf,
Pred const& eq) const
@@ -780,7 +712,7 @@ namespace boost { namespace unordered { namespace detail {
find_node_impl(policy::apply_hash(hf, k), k, eq);
}
iterator find_node(
node_pointer find_node(
std::size_t key_hash,
key_type const& k) const
{
@@ -788,23 +720,12 @@ namespace boost { namespace unordered { namespace detail {
find_node_impl(key_hash, k, this->key_eq());
}
iterator find_node(key_type const& k) const
node_pointer find_node(key_type const& k) const
{
return static_cast<table_impl const*>(this)->
find_node_impl(hash(k), k, this->key_eq());
}
iterator find_matching_node(iterator n) const
{
// TODO: Does this apply to C++11?
//
// For some stupid reason, I decided to support equality comparison
// when different hash functions are used. So I can't use the hash
// value from the node here.
return find_node(get_key(*n));
}
// Reserve and rehash
void reserve_for_insert(std::size_t);
+207 -152
View File
@@ -12,7 +12,6 @@
#pragma once
#endif
#include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/extract_key.hpp>
#include <boost/throw_exception.hpp>
#include <stdexcept>
@@ -107,9 +106,11 @@ namespace boost { namespace unordered { namespace detail {
template <typename A, typename T>
struct pick_node
{
typedef typename boost::remove_const<T>::type nonconst;
typedef boost::unordered::detail::allocator_traits<
typename boost::unordered::detail::rebind_wrap<A,
boost::unordered::detail::ptr_node<T> >::type
boost::unordered::detail::ptr_node<nonconst> >::type
> tentative_node_traits;
typedef boost::unordered::detail::allocator_traits<
@@ -117,7 +118,7 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::ptr_bucket >::type
> tentative_bucket_traits;
typedef pick_node2<A, T,
typedef pick_node2<A, nonconst,
typename tentative_node_traits::pointer,
typename tentative_bucket_traits::pointer> pick;
@@ -126,54 +127,6 @@ namespace boost { namespace unordered { namespace detail {
typedef typename pick::link_pointer link_pointer;
};
template <typename A, typename T, typename H, typename P>
struct set
{
typedef boost::unordered::detail::set<A, T, H, P> types;
typedef A allocator;
typedef T value_type;
typedef H hasher;
typedef P key_equal;
typedef T key_type;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::table_impl<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
};
template <typename A, typename K, typename M, typename H, typename P>
struct map
{
typedef boost::unordered::detail::map<A, K, M, H, P> types;
typedef A allocator;
typedef std::pair<K const, M> value_type;
typedef H hasher;
typedef P key_equal;
typedef K key_type;
typedef boost::unordered::detail::allocator_traits<allocator>
traits;
typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef boost::unordered::detail::table_impl<types> table;
typedef boost::unordered::detail::map_extractor<key_type, value_type>
extractor;
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
};
template <typename Types>
struct table_impl : boost::unordered::detail::table<Types>
{
@@ -190,6 +143,7 @@ namespace boost { namespace unordered { namespace detail {
typedef typename table::key_equal key_equal;
typedef typename table::key_type key_type;
typedef typename table::node_constructor node_constructor;
typedef typename table::node_tmp node_tmp;
typedef typename table::extractor extractor;
typedef typename table::iterator iterator;
typedef typename table::c_iterator c_iterator;
@@ -232,47 +186,53 @@ namespace boost { namespace unordered { namespace detail {
this->move_init(x);
}
// Node functions.
static inline node_pointer next_node(link_pointer n) {
return static_cast<node_pointer>(n->next_);
}
// Accessors
template <class Key, class Pred>
iterator find_node_impl(
node_pointer find_node_impl(
std::size_t key_hash,
Key const& k,
Pred const& eq) const
{
std::size_t bucket_index = this->hash_to_bucket(key_hash);
iterator n = this->begin(bucket_index);
node_pointer n = this->begin(bucket_index);
for (;;)
{
if (!n.node_) return n;
if (!n) return n;
std::size_t node_hash = n.node_->hash_;
std::size_t node_hash = n->hash_;
if (key_hash == node_hash)
{
if (eq(k, this->get_key(*n)))
if (eq(k, this->get_key(n->value())))
return n;
}
else
{
if (this->hash_to_bucket(node_hash) != bucket_index)
return iterator();
return node_pointer();
}
++n;
n = next_node(n);
}
}
std::size_t count(key_type const& k) const
{
return this->find_node(k).node_ ? 1 : 0;
return this->find_node(k) ? 1 : 0;
}
value_type& at(key_type const& k) const
{
if (this->size_) {
iterator it = this->find_node(k);
if (it.node_) return *it;
node_pointer n = this->find_node(k);
if (n) return n->value();
}
boost::throw_exception(
@@ -282,10 +242,8 @@ namespace boost { namespace unordered { namespace detail {
std::pair<iterator, iterator>
equal_range(key_type const& k) const
{
iterator n = this->find_node(k);
iterator n2 = n;
if (n2.node_) ++n2;
return std::make_pair(n, n2);
node_pointer n = this->find_node(k);
return std::make_pair(iterator(n), iterator(n ? next_node(n) : n));
}
// equals
@@ -294,11 +252,11 @@ namespace boost { namespace unordered { namespace detail {
{
if(this->size_ != other.size_) return false;
for(iterator n1 = this->begin(); n1.node_; ++n1)
for(node_pointer n1 = this->begin(); n1; n1 = next_node(n1))
{
iterator n2 = other.find_matching_node(n1);
node_pointer n2 = other.find_node(other.get_key(n1->value()));
if (!n2.node_ || *n1 != *n2)
if (!n2 || n1->value() != n2->value())
return false;
}
@@ -307,11 +265,10 @@ namespace boost { namespace unordered { namespace detail {
// Emplace/Insert
inline iterator add_node(
node_constructor& a,
inline node_pointer add_node(
node_pointer n,
std::size_t key_hash)
{
node_pointer n = a.release();
n->hash_ = key_hash;
bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash));
@@ -322,7 +279,7 @@ namespace boost { namespace unordered { namespace detail {
if (start_node->next_) {
this->get_bucket(this->hash_to_bucket(
static_cast<node_pointer>(start_node->next_)->hash_)
next_node(start_node)->hash_)
)->next_ = n;
}
@@ -337,26 +294,28 @@ namespace boost { namespace unordered { namespace detail {
}
++this->size_;
return iterator(n);
return n;
}
inline node_pointer resize_and_add_node(node_pointer n, std::size_t key_hash)
{
node_tmp b(n, this->node_alloc());
this->reserve_for_insert(this->size_ + 1);
return this->add_node(b.release(), key_hash);
}
value_type& operator[](key_type const& k)
{
std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(key_hash, k);
if (pos.node_) return *pos;
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(this->node_alloc());
a.construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS3(
boost::unordered::piecewise_construct,
boost::make_tuple(k),
boost::make_tuple()));
this->reserve_for_insert(this->size_ + 1);
return *add_node(a, key_hash);
node_pointer pos = this->find_node(key_hash, k);
if (pos) {
return pos->value();
}
else {
return this->resize_and_add_node(
boost::unordered::detail::func::construct_node_pair(this->node_alloc(), k),
key_hash)->value();
}
}
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
@@ -365,14 +324,29 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::please_ignore_this_overload> const&)
{
BOOST_ASSERT(false);
return emplace_return(this->begin(), false);
return emplace_return(iterator(), false);
}
iterator emplace_hint(c_iterator,
boost::unordered::detail::emplace_args1<
boost::unordered::detail::please_ignore_this_overload> const&)
{
BOOST_ASSERT(false);
return iterator();
}
# else
emplace_return emplace(
boost::unordered::detail::please_ignore_this_overload const&)
{
BOOST_ASSERT(false);
return emplace_return(this->begin(), false);
return emplace_return(iterator(), false);
}
iterator emplace_hint(c_iterator,
boost::unordered::detail::please_ignore_this_overload const&)
{
BOOST_ASSERT(false);
return iterator();
}
# endif
#endif
@@ -391,6 +365,21 @@ namespace boost { namespace unordered { namespace detail {
#endif
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace_hint(c_iterator hint,
BOOST_UNORDERED_EMPLACE_ARGS)
{
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
return emplace_hint_impl(hint,
extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
BOOST_UNORDERED_EMPLACE_FORWARD);
#else
return emplace_hint_impl(hint,
extractor::extract(args.a0, args.a1),
BOOST_UNORDERED_EMPLACE_FORWARD);
#endif
}
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <typename A0>
emplace_return emplace(
@@ -398,50 +387,86 @@ namespace boost { namespace unordered { namespace detail {
{
return emplace_impl(extractor::extract(args.a0), args);
}
template <typename A0>
iterator emplace_hint(c_iterator hint,
boost::unordered::detail::emplace_args1<A0> const& args)
{
return emplace_hint_impl(hint, extractor::extract(args.a0), args);
}
#endif
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace_hint_impl(c_iterator hint, key_type const& k,
BOOST_UNORDERED_EMPLACE_ARGS)
{
if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
return iterator(hint.node_);
}
else {
return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first;
}
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
emplace_return emplace_impl(key_type const& k,
BOOST_UNORDERED_EMPLACE_ARGS)
{
std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(key_hash, k);
if (pos.node_) return emplace_return(pos, false);
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(this->node_alloc());
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
return emplace_return(this->add_node(a, key_hash), true);
node_pointer pos = this->find_node(key_hash, k);
if (pos) {
return emplace_return(iterator(pos), false);
}
else {
return emplace_return(
iterator(this->resize_and_add_node(
boost::unordered::detail::func::construct_node_from_args(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
key_hash)),
true);
}
}
emplace_return emplace_impl_with_node(node_constructor& a)
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace_hint_impl(c_iterator hint, no_key,
BOOST_UNORDERED_EMPLACE_ARGS)
{
key_type const& k = this->get_key(a.value());
node_tmp b(
boost::unordered::detail::func::construct_node_from_args(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
this->node_alloc());
key_type const& k = this->get_key(b.node_->value());
if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
return iterator(hint.node_);
}
std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(key_hash, k);
if (pos.node_) return emplace_return(pos, false);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
return emplace_return(this->add_node(a, key_hash), true);
node_pointer pos = this->find_node(key_hash, k);
if (pos) {
return iterator(pos);
}
else {
return iterator(this->resize_and_add_node(b.release(), key_hash));
}
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
{
// Don't have a key, so construct the node first in order
// to be able to lookup the position.
node_constructor a(this->node_alloc());
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
return emplace_impl_with_node(a);
node_tmp b(
boost::unordered::detail::func::construct_node_from_args(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
this->node_alloc());
key_type const& k = this->get_key(b.node_->value());
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
if (pos) {
return emplace_return(iterator(pos), false);
}
else {
return emplace_return(
iterator(this->resize_and_add_node(b.release(), key_hash)),
true);
}
}
////////////////////////////////////////////////////////////////////////
@@ -460,9 +485,7 @@ namespace boost { namespace unordered { namespace detail {
template <class InputIt>
void insert_range_impl(key_type const& k, InputIt i, InputIt j)
{
node_constructor a(this->node_alloc());
insert_range_impl2(a, k, i, j);
insert_range_impl2(k, i, j);
while(++i != j) {
// Note: can't use get_key as '*i' might not be value_type - it
@@ -473,26 +496,25 @@ namespace boost { namespace unordered { namespace detail {
// key here. Could be more efficient if '*i' is expensive. Could
// be less efficient if copying the full value_type is
// expensive.
insert_range_impl2(a, extractor::extract(*i), i, j);
insert_range_impl2(extractor::extract(*i), i, j);
}
}
template <class InputIt>
void insert_range_impl2(node_constructor& a, key_type const& k,
InputIt i, InputIt j)
void insert_range_impl2(key_type const& k, InputIt i, InputIt j)
{
// No side effects in this initial code
std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(key_hash, k);
node_pointer pos = this->find_node(key_hash, k);
if (!pos.node_) {
a.construct_with_value2(*i);
if (!pos) {
node_tmp b(
boost::unordered::detail::func::construct_node(this->node_alloc(), *i),
this->node_alloc());
if(this->size_ + 1 > this->max_load_)
this->reserve_for_insert(this->size_ +
boost::unordered::detail::insert_size(i, j));
// Nothing after this point can throw.
this->add_node(a, key_hash);
this->add_node(b.release(), key_hash);
}
}
@@ -502,8 +524,24 @@ namespace boost { namespace unordered { namespace detail {
node_constructor a(this->node_alloc());
do {
a.construct_with_value2(*i);
emplace_impl_with_node(a);
if (!a.node_) { a.create_node(); }
boost::unordered::detail::func::call_construct(
a.alloc_, a.node_->value_ptr(), *i);
node_tmp b(a.release(), a.alloc_);
key_type const& k = this->get_key(b.node_->value());
std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k);
if (pos) {
a.reclaim(b.release());
}
else {
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
this->add_node(b.release(), key_hash);
}
} while(++i != j);
}
@@ -524,18 +562,17 @@ namespace boost { namespace unordered { namespace detail {
for (;;)
{
if (!prev->next_) return 0;
std::size_t node_hash =
static_cast<node_pointer>(prev->next_)->hash_;
std::size_t node_hash = next_node(prev)->hash_;
if (this->hash_to_bucket(node_hash) != bucket_index)
return 0;
if (node_hash == key_hash &&
this->key_eq()(k, this->get_key(
static_cast<node_pointer>(prev->next_)->value())))
next_node(prev)->value())))
break;
prev = prev->next_;
}
link_pointer end = static_cast<node_pointer>(prev->next_)->next_;
link_pointer end = next_node(prev)->next_;
std::size_t deleted_count = this->delete_nodes(prev, end);
this->fix_bucket(bucket_index, prev);
@@ -545,10 +582,9 @@ namespace boost { namespace unordered { namespace detail {
iterator erase(c_iterator r)
{
BOOST_ASSERT(r.node_);
iterator next(r.node_);
++next;
erase_nodes(r.node_, next.node_);
return next;
node_pointer next = next_node(r.node_);
erase_nodes(r.node_, next);
return iterator(next);
}
iterator erase_range(c_iterator r1, c_iterator r2)
@@ -576,20 +612,39 @@ namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////
// fill_buckets
template <class NodeCreator>
static void fill_buckets(iterator n, table& dst,
NodeCreator& creator)
void copy_buckets(table const& src) {
this->create_buckets(this->bucket_count_);
for(node_pointer n = src.begin(); n; n = next_node(n)) {
this->add_node(
boost::unordered::detail::func::construct_node(
this->node_alloc(), n->value()), n->hash_);
}
}
void move_buckets(table const& src) {
this->create_buckets(this->bucket_count_);
for(node_pointer n = src.begin(); n; n = next_node(n)) {
this->add_node(
boost::unordered::detail::func::construct_node(
this->node_alloc(), boost::move(n->value())), n->hash_);
}
}
void assign_buckets(table const& src)
{
link_pointer prev = dst.get_previous_start();
node_holder<node_allocator> holder(*this);
for(node_pointer n = src.begin(); n; n = next_node(n)) {
this->add_node(holder.copy_of(n->value()), n->hash_);
}
}
while (n.node_) {
node_pointer node = creator.create(*n);
node->hash_ = n.node_->hash_;
prev->next_ = node;
++dst.size_;
++n;
prev = place_in_bucket(dst, prev);
void move_assign_buckets(table& src)
{
node_holder<node_allocator> holder(*this);
for(node_pointer n = src.begin(); n; n = next_node(n)) {
this->add_node(holder.move_copy_of(n->value()), n->hash_);
}
}
@@ -608,7 +663,7 @@ namespace boost { namespace unordered { namespace detail {
// pre: prev->next_ is not null.
static link_pointer place_in_bucket(table& dst, link_pointer prev)
{
node_pointer n = static_cast<node_pointer>(prev->next_);
node_pointer n = next_node(prev);
bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_));
if (!b->next_) {
+5 -22
View File
@@ -124,33 +124,16 @@ namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////////
// insert_size/initial_size
#if !defined(BOOST_NO_STD_DISTANCE)
using ::std::distance;
#else
template <class ForwardIterator>
inline std::size_t distance(ForwardIterator i, ForwardIterator j) {
std::size_t x;
std::distance(i, j, x);
return x;
}
#endif
template <class I>
inline typename
boost::unordered::detail::enable_if_forward<I, std::size_t>::type
insert_size(I i, I j)
inline std::size_t insert_size(I i, I j, typename
boost::unordered::detail::enable_if_forward<I, void*>::type = 0)
{
return std::distance(i, j);
return static_cast<std::size_t>(std::distance(i, j));
}
template <class I>
inline typename
boost::unordered::detail::disable_if_forward<I, std::size_t>::type
insert_size(I, I)
inline std::size_t insert_size(I, I, typename
boost::unordered::detail::disable_if_forward<I, void*>::type = 0)
{
return 1;
}
+251 -61
View File
@@ -15,9 +15,7 @@
#endif
#include <boost/unordered/unordered_map_fwd.hpp>
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
#include <boost/unordered/detail/util.hpp>
#include <boost/unordered/detail/map.hpp>
#include <boost/functional/hash.hpp>
#include <boost/move/move.hpp>
@@ -84,12 +82,23 @@ namespace unordered
// constructors
unordered_map();
explicit unordered_map(
size_type = boost::unordered::detail::default_bucket_count,
size_type,
const hasher& = hasher(),
const key_equal& = key_equal(),
const allocator_type& = allocator_type());
explicit unordered_map(
size_type,
const allocator_type&);
explicit unordered_map(
size_type,
const hasher&,
const allocator_type&);
explicit unordered_map(allocator_type const&);
template <class InputIt>
@@ -110,11 +119,25 @@ namespace unordered
const key_equal&,
const allocator_type&);
template <class InputIt>
unordered_map(
InputIt, InputIt,
size_type,
const hasher&,
const allocator_type&);
template <class InputIt>
unordered_map(
InputIt, InputIt,
size_type,
const allocator_type&);
// copy/move constructors
unordered_map(unordered_map const&);
unordered_map(unordered_map const&, allocator_type const&);
unordered_map(BOOST_RV_REF(unordered_map), allocator_type const&);
#if defined(BOOST_UNORDERED_USE_MOVE)
unordered_map(BOOST_RV_REF(unordered_map) other)
@@ -130,10 +153,6 @@ namespace unordered
}
#endif
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_map(unordered_map&&, allocator_type const&);
#endif
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
unordered_map(
std::initializer_list<value_type>,
@@ -141,6 +160,15 @@ namespace unordered
const hasher& = hasher(),
const key_equal&l = key_equal(),
const allocator_type& = allocator_type());
unordered_map(
std::initializer_list<value_type>,
size_type,
const hasher&,
const allocator_type&);
unordered_map(
std::initializer_list<value_type>,
size_type,
const allocator_type&);
#endif
// Destructor
@@ -204,12 +232,12 @@ namespace unordered
iterator begin() BOOST_NOEXCEPT
{
return table_.begin();
return iterator(table_.begin());
}
const_iterator begin() const BOOST_NOEXCEPT
{
return table_.begin();
return const_iterator(table_.begin());
}
iterator end() BOOST_NOEXCEPT
@@ -224,7 +252,7 @@ namespace unordered
const_iterator cbegin() const BOOST_NOEXCEPT
{
return table_.begin();
return const_iterator(table_.begin());
}
const_iterator cend() const BOOST_NOEXCEPT
@@ -242,9 +270,9 @@ namespace unordered
}
template <class... Args>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
return table_.emplace(boost::forward<Args>(args)...).first;
return table_.emplace_hint(hint, boost::forward<Args>(args)...);
}
#else
@@ -283,12 +311,12 @@ namespace unordered
}
template <typename A0>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0))
).first;
);
}
template <typename A0, typename A1>
@@ -304,15 +332,15 @@ namespace unordered
}
template <typename A0, typename A1>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1))
).first;
);
}
template <typename A0, typename A1, typename A2>
@@ -330,17 +358,17 @@ namespace unordered
}
template <typename A0, typename A1, typename A2>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1),
boost::forward<A2>(a2))
).first;
);
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
@@ -362,15 +390,15 @@ namespace unordered
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
const_iterator, \
const_iterator hint, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return table_.emplace( \
return table_.emplace_hint(hint, \
boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
)).first; \
)); \
}
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
@@ -567,12 +595,23 @@ namespace unordered
// constructors
unordered_multimap();
explicit unordered_multimap(
size_type = boost::unordered::detail::default_bucket_count,
size_type,
const hasher& = hasher(),
const key_equal& = key_equal(),
const allocator_type& = allocator_type());
explicit unordered_multimap(
size_type,
const allocator_type&);
explicit unordered_multimap(
size_type,
const hasher&,
const allocator_type&);
explicit unordered_multimap(allocator_type const&);
template <class InputIt>
@@ -593,11 +632,25 @@ namespace unordered
const key_equal&,
const allocator_type&);
template <class InputIt>
unordered_multimap(
InputIt, InputIt,
size_type,
const hasher&,
const allocator_type&);
template <class InputIt>
unordered_multimap(
InputIt, InputIt,
size_type,
const allocator_type&);
// copy/move constructors
unordered_multimap(unordered_multimap const&);
unordered_multimap(unordered_multimap const&, allocator_type const&);
unordered_multimap(BOOST_RV_REF(unordered_multimap), allocator_type const&);
#if defined(BOOST_UNORDERED_USE_MOVE)
unordered_multimap(BOOST_RV_REF(unordered_multimap) other)
@@ -613,10 +666,6 @@ namespace unordered
}
#endif
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_multimap(unordered_multimap&&, allocator_type const&);
#endif
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
unordered_multimap(
std::initializer_list<value_type>,
@@ -624,6 +673,15 @@ namespace unordered
const hasher& = hasher(),
const key_equal&l = key_equal(),
const allocator_type& = allocator_type());
unordered_multimap(
std::initializer_list<value_type>,
size_type,
const hasher&,
const allocator_type&);
unordered_multimap(
std::initializer_list<value_type>,
size_type,
const allocator_type&);
#endif
// Destructor
@@ -688,12 +746,12 @@ namespace unordered
iterator begin() BOOST_NOEXCEPT
{
return table_.begin();
return iterator(table_.begin());
}
const_iterator begin() const BOOST_NOEXCEPT
{
return table_.begin();
return const_iterator(table_.begin());
}
iterator end() BOOST_NOEXCEPT
@@ -708,7 +766,7 @@ namespace unordered
const_iterator cbegin() const BOOST_NOEXCEPT
{
return table_.begin();
return const_iterator(table_.begin());
}
const_iterator cend() const BOOST_NOEXCEPT
@@ -726,9 +784,9 @@ namespace unordered
}
template <class... Args>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
return table_.emplace(boost::forward<Args>(args)...);
return table_.emplace_hint(hint, boost::forward<Args>(args)...);
}
#else
@@ -767,9 +825,9 @@ namespace unordered
}
template <typename A0>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0))
);
@@ -788,11 +846,11 @@ namespace unordered
}
template <typename A0, typename A1>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1))
@@ -814,12 +872,12 @@ namespace unordered
}
template <typename A0, typename A1, typename A2>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1),
@@ -846,11 +904,11 @@ namespace unordered
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
const_iterator, \
const_iterator hint, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return table_.emplace( \
return table_.emplace_hint(hint, \
boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
@@ -1004,6 +1062,13 @@ namespace unordered
////////////////////////////////////////////////////////////////////////////////
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map()
: table_(boost::unordered::detail::default_bucket_count, hasher(),
key_equal(), allocator_type())
{
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
size_type n, const hasher &hf, const key_equal &eql,
@@ -1012,6 +1077,20 @@ namespace unordered
{
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
size_type n, const allocator_type &a)
: table_(n, hasher(), key_equal(), a)
{
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
size_type n, const hasher &hf, const allocator_type &a)
: table_(n, hf, key_equal(), a)
{
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(allocator_type const& a)
: table_(boost::unordered::detail::default_bucket_count,
@@ -1061,6 +1140,31 @@ namespace unordered
table_.insert_range(f, l);
}
template <class K, class T, class H, class P, class A>
template <class InputIt>
unordered_map<K,T,H,P,A>::unordered_map(
InputIt f, InputIt l,
size_type n,
const hasher &hf,
const allocator_type &a)
: table_(boost::unordered::detail::initial_size(f, l, n),
hf, key_equal(), a)
{
table_.insert_range(f, l);
}
template <class K, class T, class H, class P, class A>
template <class InputIt>
unordered_map<K,T,H,P,A>::unordered_map(
InputIt f, InputIt l,
size_type n,
const allocator_type &a)
: table_(boost::unordered::detail::initial_size(f, l, n),
hasher(), key_equal(), a)
{
table_.insert_range(f, l);
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::~unordered_map() BOOST_NOEXCEPT {}
@@ -1071,17 +1175,13 @@ namespace unordered
{
}
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
unordered_map&& other, allocator_type const& a)
BOOST_RV_REF(unordered_map) other, allocator_type const& a)
: table_(other.table_, a, boost::unordered::detail::move_tag())
{
}
#endif
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
template <class K, class T, class H, class P, class A>
@@ -1096,6 +1196,30 @@ namespace unordered
table_.insert_range(list.begin(), list.end());
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
std::initializer_list<value_type> list, size_type n,
const hasher &hf, const allocator_type &a)
: table_(
boost::unordered::detail::initial_size(
list.begin(), list.end(), n),
hf, key_equal(), a)
{
table_.insert_range(list.begin(), list.end());
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
std::initializer_list<value_type> list, size_type n,
const allocator_type &a)
: table_(
boost::unordered::detail::initial_size(
list.begin(), list.end(), n),
hasher(), key_equal(), a)
{
table_.insert_range(list.begin(), list.end());
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>& unordered_map<K,T,H,P,A>::operator=(
std::initializer_list<value_type> list)
@@ -1210,14 +1334,14 @@ namespace unordered
typename unordered_map<K,T,H,P,A>::iterator
unordered_map<K,T,H,P,A>::find(const key_type& k)
{
return table_.find_node(k);
return iterator(table_.find_node(k));
}
template <class K, class T, class H, class P, class A>
typename unordered_map<K,T,H,P,A>::const_iterator
unordered_map<K,T,H,P,A>::find(const key_type& k) const
{
return table_.find_node(k);
return const_iterator(table_.find_node(k));
}
template <class K, class T, class H, class P, class A>
@@ -1229,7 +1353,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq)
{
return table_.generic_find_node(k, hash, eq);
return iterator(table_.generic_find_node(k, hash, eq));
}
template <class K, class T, class H, class P, class A>
@@ -1241,7 +1365,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq) const
{
return table_.generic_find_node(k, hash, eq);
return const_iterator(table_.generic_find_node(k, hash, eq));
}
template <class K, class T, class H, class P, class A>
@@ -1337,6 +1461,13 @@ namespace unordered
////////////////////////////////////////////////////////////////////////////////
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap()
: table_(boost::unordered::detail::default_bucket_count, hasher(),
key_equal(), allocator_type())
{
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
size_type n, const hasher &hf, const key_equal &eql,
@@ -1345,6 +1476,20 @@ namespace unordered
{
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
size_type n, const allocator_type &a)
: table_(n, hasher(), key_equal(), a)
{
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
size_type n, const hasher &hf, const allocator_type &a)
: table_(n, hf, key_equal(), a)
{
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(allocator_type const& a)
: table_(boost::unordered::detail::default_bucket_count,
@@ -1394,6 +1539,31 @@ namespace unordered
table_.insert_range(f, l);
}
template <class K, class T, class H, class P, class A>
template <class InputIt>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
InputIt f, InputIt l,
size_type n,
const hasher &hf,
const allocator_type &a)
: table_(boost::unordered::detail::initial_size(f, l, n),
hf, key_equal(), a)
{
table_.insert_range(f, l);
}
template <class K, class T, class H, class P, class A>
template <class InputIt>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
InputIt f, InputIt l,
size_type n,
const allocator_type &a)
: table_(boost::unordered::detail::initial_size(f, l, n),
hasher(), key_equal(), a)
{
table_.insert_range(f, l);
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::~unordered_multimap() BOOST_NOEXCEPT {}
@@ -1404,17 +1574,13 @@ namespace unordered
{
}
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
unordered_multimap&& other, allocator_type const& a)
BOOST_RV_REF(unordered_multimap) other, allocator_type const& a)
: table_(other.table_, a, boost::unordered::detail::move_tag())
{
}
#endif
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
template <class K, class T, class H, class P, class A>
@@ -1429,6 +1595,30 @@ namespace unordered
table_.insert_range(list.begin(), list.end());
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
std::initializer_list<value_type> list, size_type n,
const hasher &hf, const allocator_type &a)
: table_(
boost::unordered::detail::initial_size(
list.begin(), list.end(), n),
hf, key_equal(), a)
{
table_.insert_range(list.begin(), list.end());
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
std::initializer_list<value_type> list, size_type n,
const allocator_type &a)
: table_(
boost::unordered::detail::initial_size(
list.begin(), list.end(), n),
hasher(), key_equal(), a)
{
table_.insert_range(list.begin(), list.end());
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>& unordered_multimap<K,T,H,P,A>::operator=(
std::initializer_list<value_type> list)
@@ -1522,14 +1712,14 @@ namespace unordered
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::find(const key_type& k)
{
return table_.find_node(k);
return iterator(table_.find_node(k));
}
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K,T,H,P,A>::const_iterator
unordered_multimap<K,T,H,P,A>::find(const key_type& k) const
{
return table_.find_node(k);
return const_iterator(table_.find_node(k));
}
template <class K, class T, class H, class P, class A>
@@ -1541,7 +1731,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq)
{
return table_.generic_find_node(k, hash, eq);
return iterator(table_.generic_find_node(k, hash, eq));
}
template <class K, class T, class H, class P, class A>
@@ -1553,7 +1743,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq) const
{
return table_.generic_find_node(k, hash, eq);
return const_iterator(table_.generic_find_node(k, hash, eq));
}
template <class K, class T, class H, class P, class A>
+248 -59
View File
@@ -14,10 +14,7 @@
#pragma once
#endif
#include <boost/unordered/unordered_set_fwd.hpp>
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
#include <boost/unordered/detail/util.hpp>
#include <boost/unordered/detail/set.hpp>
#include <boost/functional/hash.hpp>
#include <boost/move/move.hpp>
@@ -70,9 +67,9 @@ namespace unordered
typedef std::ptrdiff_t difference_type;
typedef typename table::cl_iterator const_local_iterator;
typedef typename table::cl_iterator local_iterator;
typedef typename table::l_iterator local_iterator;
typedef typename table::c_iterator const_iterator;
typedef typename table::c_iterator iterator;
typedef typename table::iterator iterator;
private:
@@ -82,12 +79,23 @@ namespace unordered
// constructors
unordered_set();
explicit unordered_set(
size_type = boost::unordered::detail::default_bucket_count,
size_type,
const hasher& = hasher(),
const key_equal& = key_equal(),
const allocator_type& = allocator_type());
explicit unordered_set(
size_type,
const allocator_type&);
explicit unordered_set(
size_type,
const hasher&,
const allocator_type&);
explicit unordered_set(allocator_type const&);
template <class InputIt>
@@ -108,11 +116,25 @@ namespace unordered
const key_equal&,
const allocator_type&);
template <class InputIt>
unordered_set(
InputIt, InputIt,
size_type,
const hasher&,
const allocator_type&);
template <class InputIt>
unordered_set(
InputIt, InputIt,
size_type,
const allocator_type&);
// copy/move constructors
unordered_set(unordered_set const&);
unordered_set(unordered_set const&, allocator_type const&);
unordered_set(BOOST_RV_REF(unordered_set), allocator_type const&);
#if defined(BOOST_UNORDERED_USE_MOVE)
unordered_set(BOOST_RV_REF(unordered_set) other)
@@ -128,10 +150,6 @@ namespace unordered
}
#endif
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_set(unordered_set&&, allocator_type const&);
#endif
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
unordered_set(
std::initializer_list<value_type>,
@@ -139,6 +157,15 @@ namespace unordered
const hasher& = hasher(),
const key_equal&l = key_equal(),
const allocator_type& = allocator_type());
unordered_set(
std::initializer_list<value_type>,
size_type,
const hasher&,
const allocator_type&);
unordered_set(
std::initializer_list<value_type>,
size_type,
const allocator_type&);
#endif
// Destructor
@@ -202,12 +229,12 @@ namespace unordered
iterator begin() BOOST_NOEXCEPT
{
return table_.begin();
return iterator(table_.begin());
}
const_iterator begin() const BOOST_NOEXCEPT
{
return table_.begin();
return const_iterator(table_.begin());
}
iterator end() BOOST_NOEXCEPT
@@ -222,7 +249,7 @@ namespace unordered
const_iterator cbegin() const BOOST_NOEXCEPT
{
return table_.begin();
return const_iterator(table_.begin());
}
const_iterator cend() const BOOST_NOEXCEPT
@@ -240,9 +267,9 @@ namespace unordered
}
template <class... Args>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
return table_.emplace(boost::forward<Args>(args)...).first;
return table_.emplace_hint(hint, boost::forward<Args>(args)...);
}
#else
@@ -281,12 +308,12 @@ namespace unordered
}
template <typename A0>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0))
).first;
);
}
template <typename A0, typename A1>
@@ -302,15 +329,15 @@ namespace unordered
}
template <typename A0, typename A1>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1))
).first;
);
}
template <typename A0, typename A1, typename A2>
@@ -328,17 +355,17 @@ namespace unordered
}
template <typename A0, typename A1, typename A2>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1),
boost::forward<A2>(a2))
).first;
);
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
@@ -360,15 +387,15 @@ namespace unordered
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
const_iterator, \
const_iterator hint, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return table_.emplace( \
return table_.emplace_hint(hint, \
boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
)).first; \
)); \
}
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
@@ -539,9 +566,9 @@ namespace unordered
typedef std::ptrdiff_t difference_type;
typedef typename table::cl_iterator const_local_iterator;
typedef typename table::cl_iterator local_iterator;
typedef typename table::l_iterator local_iterator;
typedef typename table::c_iterator const_iterator;
typedef typename table::c_iterator iterator;
typedef typename table::iterator iterator;
private:
@@ -551,12 +578,23 @@ namespace unordered
// constructors
unordered_multiset();
explicit unordered_multiset(
size_type = boost::unordered::detail::default_bucket_count,
size_type,
const hasher& = hasher(),
const key_equal& = key_equal(),
const allocator_type& = allocator_type());
explicit unordered_multiset(
size_type,
const allocator_type&);
explicit unordered_multiset(
size_type,
const hasher&,
const allocator_type&);
explicit unordered_multiset(allocator_type const&);
template <class InputIt>
@@ -577,11 +615,25 @@ namespace unordered
const key_equal&,
const allocator_type&);
template <class InputIt>
unordered_multiset(
InputIt, InputIt,
size_type,
const hasher&,
const allocator_type&);
template <class InputIt>
unordered_multiset(
InputIt, InputIt,
size_type,
const allocator_type&);
// copy/move constructors
unordered_multiset(unordered_multiset const&);
unordered_multiset(unordered_multiset const&, allocator_type const&);
unordered_multiset(BOOST_RV_REF(unordered_multiset), allocator_type const&);
#if defined(BOOST_UNORDERED_USE_MOVE)
unordered_multiset(BOOST_RV_REF(unordered_multiset) other)
@@ -597,10 +649,6 @@ namespace unordered
}
#endif
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
unordered_multiset(unordered_multiset&&, allocator_type const&);
#endif
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
unordered_multiset(
std::initializer_list<value_type>,
@@ -608,6 +656,15 @@ namespace unordered
const hasher& = hasher(),
const key_equal&l = key_equal(),
const allocator_type& = allocator_type());
unordered_multiset(
std::initializer_list<value_type>,
size_type,
const hasher&,
const allocator_type&);
unordered_multiset(
std::initializer_list<value_type>,
size_type,
const allocator_type&);
#endif
// Destructor
@@ -710,9 +767,9 @@ namespace unordered
}
template <class... Args>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
return table_.emplace(boost::forward<Args>(args)...);
return table_.emplace_hint(hint, boost::forward<Args>(args)...);
}
#else
@@ -751,9 +808,9 @@ namespace unordered
}
template <typename A0>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0))
);
@@ -772,11 +829,11 @@ namespace unordered
}
template <typename A0, typename A1>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1))
@@ -798,12 +855,12 @@ namespace unordered
}
template <typename A0, typename A1, typename A2>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1),
@@ -830,11 +887,11 @@ namespace unordered
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
const_iterator, \
const_iterator hint, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
return table_.emplace( \
return table_.emplace_hint(hint, \
boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
@@ -979,6 +1036,13 @@ namespace unordered
////////////////////////////////////////////////////////////////////////////////
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set()
: table_(boost::unordered::detail::default_bucket_count, hasher(),
key_equal(), allocator_type())
{
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
size_type n, const hasher &hf, const key_equal &eql,
@@ -987,6 +1051,20 @@ namespace unordered
{
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
size_type n, const allocator_type &a)
: table_(n, hasher(), key_equal(), a)
{
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
size_type n, const hasher &hf, const allocator_type &a)
: table_(n, hf, key_equal(), a)
{
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(allocator_type const& a)
: table_(boost::unordered::detail::default_bucket_count,
@@ -1036,6 +1114,31 @@ namespace unordered
table_.insert_range(f, l);
}
template <class T, class H, class P, class A>
template <class InputIt>
unordered_set<T,H,P,A>::unordered_set(
InputIt f, InputIt l,
size_type n,
const hasher &hf,
const allocator_type &a)
: table_(boost::unordered::detail::initial_size(f, l, n),
hf, key_equal(), a)
{
table_.insert_range(f, l);
}
template <class T, class H, class P, class A>
template <class InputIt>
unordered_set<T,H,P,A>::unordered_set(
InputIt f, InputIt l,
size_type n,
const allocator_type &a)
: table_(boost::unordered::detail::initial_size(f, l, n),
hasher(), key_equal(), a)
{
table_.insert_range(f, l);
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::~unordered_set() BOOST_NOEXCEPT {}
@@ -1046,17 +1149,13 @@ namespace unordered
{
}
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
unordered_set&& other, allocator_type const& a)
BOOST_RV_REF(unordered_set) other, allocator_type const& a)
: table_(other.table_, a, boost::unordered::detail::move_tag())
{
}
#endif
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
template <class T, class H, class P, class A>
@@ -1071,6 +1170,30 @@ namespace unordered
table_.insert_range(list.begin(), list.end());
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
std::initializer_list<value_type> list, size_type n,
const hasher &hf, const allocator_type &a)
: table_(
boost::unordered::detail::initial_size(
list.begin(), list.end(), n),
hf, key_equal(), a)
{
table_.insert_range(list.begin(), list.end());
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
std::initializer_list<value_type> list, size_type n,
const allocator_type &a)
: table_(
boost::unordered::detail::initial_size(
list.begin(), list.end(), n),
hasher(), key_equal(), a)
{
table_.insert_range(list.begin(), list.end());
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>& unordered_set<T,H,P,A>::operator=(
std::initializer_list<value_type> list)
@@ -1164,7 +1287,7 @@ namespace unordered
typename unordered_set<T,H,P,A>::const_iterator
unordered_set<T,H,P,A>::find(const key_type& k) const
{
return table_.find_node(k);
return const_iterator(table_.find_node(k));
}
template <class T, class H, class P, class A>
@@ -1176,7 +1299,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq) const
{
return table_.generic_find_node(k, hash, eq);
return const_iterator(table_.generic_find_node(k, hash, eq));
}
template <class T, class H, class P, class A>
@@ -1263,6 +1386,13 @@ namespace unordered
////////////////////////////////////////////////////////////////////////////////
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset()
: table_(boost::unordered::detail::default_bucket_count, hasher(),
key_equal(), allocator_type())
{
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
size_type n, const hasher &hf, const key_equal &eql,
@@ -1271,6 +1401,20 @@ namespace unordered
{
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
size_type n, const allocator_type &a)
: table_(n, hasher(), key_equal(), a)
{
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
size_type n, const hasher &hf, const allocator_type &a)
: table_(n, hf, key_equal(), a)
{
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(allocator_type const& a)
: table_(boost::unordered::detail::default_bucket_count,
@@ -1320,6 +1464,31 @@ namespace unordered
table_.insert_range(f, l);
}
template <class T, class H, class P, class A>
template <class InputIt>
unordered_multiset<T,H,P,A>::unordered_multiset(
InputIt f, InputIt l,
size_type n,
const hasher &hf,
const allocator_type &a)
: table_(boost::unordered::detail::initial_size(f, l, n),
hf, key_equal(), a)
{
table_.insert_range(f, l);
}
template <class T, class H, class P, class A>
template <class InputIt>
unordered_multiset<T,H,P,A>::unordered_multiset(
InputIt f, InputIt l,
size_type n,
const allocator_type &a)
: table_(boost::unordered::detail::initial_size(f, l, n),
hasher(), key_equal(), a)
{
table_.insert_range(f, l);
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::~unordered_multiset() BOOST_NOEXCEPT {}
@@ -1330,17 +1499,13 @@ namespace unordered
{
}
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
unordered_multiset&& other, allocator_type const& a)
BOOST_RV_REF(unordered_multiset) other, allocator_type const& a)
: table_(other.table_, a, boost::unordered::detail::move_tag())
{
}
#endif
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
template <class T, class H, class P, class A>
@@ -1355,6 +1520,30 @@ namespace unordered
table_.insert_range(list.begin(), list.end());
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
std::initializer_list<value_type> list, size_type n,
const hasher &hf, const allocator_type &a)
: table_(
boost::unordered::detail::initial_size(
list.begin(), list.end(), n),
hf, key_equal(), a)
{
table_.insert_range(list.begin(), list.end());
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
std::initializer_list<value_type> list, size_type n,
const allocator_type &a)
: table_(
boost::unordered::detail::initial_size(
list.begin(), list.end(), n),
hasher(), key_equal(), a)
{
table_.insert_range(list.begin(), list.end());
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>& unordered_multiset<T,H,P,A>::operator=(
std::initializer_list<value_type> list)
@@ -1448,7 +1637,7 @@ namespace unordered
typename unordered_multiset<T,H,P,A>::const_iterator
unordered_multiset<T,H,P,A>::find(const key_type& k) const
{
return table_.find_node(k);
return const_iterator(table_.find_node(k));
}
template <class T, class H, class P, class A>
@@ -1460,7 +1649,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq) const
{
return table_.generic_find_node(k, hash, eq);
return const_iterator(table_.generic_find_node(k, hash, eq));
}
template <class T, class H, class P, class A>
+79 -2
View File
@@ -5,5 +5,82 @@
import testing ;
build-project unordered ;
build-project exception ;
project unordered-test/unordered
: requirements
<warnings>all
<toolset>intel:<warnings>on
# Would be nice to define -Wundef, but I'm getting warnings from
# Boost.Preprocessor on trunk.
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
<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"
;
#alias framework : /boost/test//boost_unit_test_framework ;
alias framework : ;
test-suite unordered
:
[ run unordered/fwd_set_test.cpp ]
[ run unordered/fwd_map_test.cpp ]
[ run unordered/allocator_traits.cpp ]
[ run unordered/minimal_allocator.cpp ]
[ run unordered/compile_set.cpp ]
[ run unordered/compile_map.cpp ]
[ run unordered/compile_map.cpp : :
: <define>BOOST_UNORDERED_USE_ALLOCATOR_TRAITS=0
: compile_map_unordered_allocator ]
[ run unordered/noexcept_tests.cpp ]
[ run unordered/link_test_1.cpp unordered/link_test_2.cpp ]
[ run unordered/incomplete_test.cpp ]
[ run unordered/simple_tests.cpp ]
[ run unordered/equivalent_keys_tests.cpp ]
[ run unordered/constructor_tests.cpp ]
[ run unordered/copy_tests.cpp ]
[ run unordered/move_tests.cpp ]
[ run unordered/assign_tests.cpp ]
[ run unordered/insert_tests.cpp ]
[ run unordered/insert_stable_tests.cpp ]
[ 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_equiv_tests.cpp ]
[ run unordered/find_tests.cpp ]
[ run unordered/at_tests.cpp ]
[ run unordered/bucket_tests.cpp ]
[ run unordered/load_factor_tests.cpp ]
[ run unordered/rehash_tests.cpp ]
[ run unordered/equality_tests.cpp ]
[ run unordered/swap_tests.cpp ]
[ run unordered/compile_set.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_compile_set ]
[ run unordered/compile_map.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_compile_map ]
[ run unordered/copy_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_copy ]
[ run unordered/move_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_move ]
[ run unordered/assign_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_assign ]
;
test-suite unordered-exception
:
[ run exception/constructor_exception_tests.cpp framework ]
[ run exception/copy_exception_tests.cpp framework ]
[ run exception/assign_exception_tests.cpp framework ]
[ run exception/move_assign_exception_tests.cpp framework ]
[ run exception/insert_exception_tests.cpp framework ]
[ run exception/erase_exception_tests.cpp framework ]
[ run exception/rehash_exception_tests.cpp framework ]
[ run exception/swap_exception_tests.cpp framework : : :
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
;
-29
View File
@@ -1,29 +0,0 @@
# Copyright 2006-2008 Daniel James.
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
import testing ;
#alias framework : /boost/test//boost_unit_test_framework ;
alias framework : ;
project unordered-test/exception-tests
: requirements
<warnings>all
<toolset>intel:<warnings>on
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow -Wno-long-long"
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
;
test-suite unordered-exception
:
[ run constructor_exception_tests.cpp framework ]
[ run copy_exception_tests.cpp framework ]
[ run assign_exception_tests.cpp framework ]
[ run insert_exception_tests.cpp framework ]
[ run erase_exception_tests.cpp framework ]
[ run rehash_exception_tests.cpp framework ]
[ run swap_exception_tests.cpp framework : : :
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
;
+61 -25
View File
@@ -17,7 +17,7 @@ template <class T>
struct self_assign_base : public test::exception_base
{
test::random_values<T> values;
self_assign_base(int count = 0) : values(count) {}
self_assign_base(std::size_t count = 0) : values(count) {}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
@@ -38,21 +38,18 @@ struct self_assign_test2 : self_assign_base<T>
template <class T>
struct assign_base : public test::exception_base
{
const test::random_values<T> x_values, y_values;
test::random_values<T> x_values, y_values;
T x,y;
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2,
float mlf1 = 1.0, float mlf2 = 1.0) :
x_values(count1),
y_values(count2),
x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1),
allocator_type(tag1)),
y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2),
allocator_type(tag2))
assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0) :
x_values(),
y_values(),
x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
{
x.max_load_factor(mlf1);
y.max_load_factor(mlf2);
@@ -66,47 +63,86 @@ struct assign_base : public test::exception_base
test::check_equivalent_keys(x1);
// If the container is empty at the point of the exception, the
// internal structure is hidden, this exposes it.
T& y = const_cast<T&>(x1);
// internal structure is hidden, this exposes it, at the cost of
// messing up the data.
if (x_values.size()) {
y.emplace(*x_values.begin());
test::check_equivalent_keys(y);
T& x2 = const_cast<T&>(x1);
x2.emplace(*x_values.begin());
test::check_equivalent_keys(x2);
}
}
};
template <class T>
struct assign_test1 : assign_base<T>
struct assign_values : assign_base<T>
{
assign_test1() : assign_base<T>(0, 0, 0, 0) {}
assign_values(unsigned int count1, unsigned int count2,
int tag1, int tag2, 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.insert(this->x_values.begin(), this->x_values.end());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
};
template <class T>
struct assign_test2 : assign_base<T>
struct assign_test1 : assign_values<T>
{
assign_test2() : assign_base<T>(60, 0, 0, 0) {}
assign_test1() : assign_values<T>(0, 0, 0, 0) {}
};
template <class T>
struct assign_test3 : assign_base<T>
struct assign_test2 : assign_values<T>
{
assign_test3() : assign_base<T>(0, 60, 0, 0) {}
assign_test2() : assign_values<T>(60, 0, 0, 0) {}
};
template <class T>
struct assign_test4 : assign_base<T>
struct assign_test3 : assign_values<T>
{
assign_test4() : assign_base<T>(10, 10, 1, 2) {}
assign_test3() : assign_values<T>(0, 60, 0, 0) {}
};
template <class T>
struct assign_test5 : assign_base<T>
struct assign_test4 : assign_values<T>
{
assign_test5() : assign_base<T>(5, 60, 0, 0, 1.0, 0.1) {}
assign_test4() : assign_values<T>(10, 10, 1, 2) {}
};
template <class T>
struct assign_test4a : assign_values<T>
{
assign_test4a() : assign_values<T>(10, 100, 1, 2) {}
};
template <class T>
struct assign_test5 : assign_values<T>
{
assign_test5() : assign_values<T>(5, 60, 0, 0, 1.0f, 0.1f) {}
};
template <class T>
struct equivalent_test1 : assign_base<T>
{
equivalent_test1() :
assign_base<T>(0, 0)
{
test::random_values<T> x_values2(10);
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);
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());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
};
EXCEPTION_TESTS(
(self_assign_test1)(self_assign_test2)
(assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test5),
(assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test4a)(assign_test5)
(equivalent_test1),
CONTAINER_SEQ)
RUN_TESTS()
+12 -11
View File
@@ -8,7 +8,7 @@
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/strong.hpp"
#include <boost/utility.hpp>
#include "../helpers/helpers.hpp"
#include <cmath>
test::seed_t initialize_seed(747373);
@@ -17,7 +17,7 @@ template <class T>
struct insert_test_base : public test::exception_base
{
test::random_values<T> values;
insert_test_base(unsigned int count = 5) : values(count) {}
insert_test_base(unsigned int count = 5) : values(count, test::limited_range) {}
typedef T data_type;
typedef test::strong<T> strong_type;
@@ -112,7 +112,7 @@ struct insert_test4 : public insert_test_base<T>
it != end; ++it)
{
strong.store(x, test::detail::tracker.count_allocations);
x.insert(it, boost::next(it));
x.insert(it, test::next(it));
}
}
};
@@ -130,12 +130,13 @@ struct insert_test_rehash1 : public insert_test_base<T>
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(bucket_count * (double) x.max_load_factor()) - 1);
ceil((double) bucket_count * (double) x.max_load_factor()) - 1);
BOOST_TEST(initial_elements < this->values.size());
x.insert(this->values.begin(),
boost::next(this->values.begin(), initial_elements));
test::next(this->values.begin(), initial_elements));
BOOST_TEST(bucket_count == x.bucket_count());
return x;
}
@@ -146,7 +147,7 @@ struct insert_test_rehash1 : public insert_test_base<T>
BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin();
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = boost::next(this->values.begin(), x.size()),
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count)
{
@@ -170,7 +171,7 @@ struct insert_test_rehash2 : public insert_test_rehash1<T>
int count = 0;
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = boost::next(this->values.begin(), x.size()),
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count)
{
@@ -201,14 +202,14 @@ struct insert_test_rehash3 : public insert_test_base<T>
original_bucket_count = x.bucket_count();
rehash_bucket_count = static_cast<size_type>(
ceil(original_bucket_count * (double) x.max_load_factor())) - 1;
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(),
boost::next(this->values.begin(), initial_elements));
test::next(this->values.begin(), initial_elements));
BOOST_TEST(original_bucket_count == x.bucket_count());
return x;
}
@@ -216,8 +217,8 @@ struct insert_test_rehash3 : public insert_test_base<T>
void run(T& x) const {
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
x.insert(boost::next(this->values.begin(), x.size()),
boost::next(this->values.begin(), x.size() + 20));
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.
@@ -0,0 +1,131 @@
// 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 <iostream>
#include "./containers.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable:4512) // move_assignment operator could not be generated
#endif
test::seed_t initialize_seed(12847);
template <class T>
struct move_assign_base : public test::exception_base
{
test::random_values<T> x_values, y_values;
T x,y;
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
move_assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0) :
x_values(),
y_values(),
x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
{
x.max_load_factor(mlf1);
y.max_load_factor(mlf2);
}
typedef T data_type;
T init() const { return T(x); }
void run(T& x1) const {
test::exceptions_enable disable_exceptions(false);
T y1 = y;
disable_exceptions.release();
x1 = boost::move(y1);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
{
test::check_equivalent_keys(x1);
// If the container is empty at the point of the exception, the
// internal structure is hidden, this exposes it, at the cost of
// messing up the data.
if (x_values.size()) {
T& x2 = const_cast<T&>(x1);
x2.emplace(*x_values.begin());
test::check_equivalent_keys(x2);
}
}
};
template <class T>
struct move_assign_values : move_assign_base<T>
{
move_assign_values(unsigned int count1, unsigned int count2,
int tag1, 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.insert(this->x_values.begin(), this->x_values.end());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
};
template <class T>
struct move_assign_test1 : move_assign_values<T>
{
move_assign_test1() : move_assign_values<T>(0, 0, 0, 0) {}
};
template <class T>
struct move_assign_test2 : move_assign_values<T>
{
move_assign_test2() : move_assign_values<T>(60, 0, 0, 0) {}
};
template <class T>
struct move_assign_test3 : move_assign_values<T>
{
move_assign_test3() : move_assign_values<T>(0, 60, 0, 0) {}
};
template <class T>
struct move_assign_test4 : move_assign_values<T>
{
move_assign_test4() : move_assign_values<T>(10, 10, 1, 2) {}
};
template <class T>
struct move_assign_test4a : move_assign_values<T>
{
move_assign_test4a() : move_assign_values<T>(10, 100, 1, 2) {}
};
template <class T>
struct move_assign_test5 : move_assign_values<T>
{
move_assign_test5() : move_assign_values<T>(5, 60, 0, 0, 1.0f, 0.1f) {}
};
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);
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);
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());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
};
EXCEPTION_TESTS(
(move_assign_test1)(move_assign_test2)(move_assign_test3)(move_assign_test4)(move_assign_test4a)(move_assign_test5)
(equivalent_test1),
CONTAINER_SEQ)
RUN_TESTS()
+2 -2
View File
@@ -18,8 +18,8 @@ struct rehash_test_base : public test::exception_base
{
test::random_values<T> values;
unsigned int n;
rehash_test_base(unsigned int count = 100, unsigned int n = 0)
: values(count), n(n)
rehash_test_base(unsigned int count = 100, unsigned int n_ = 0)
: values(count), n(n_)
{}
typedef T data_type;
+3 -3
View File
@@ -17,7 +17,7 @@ template <class T>
struct self_swap_base : public test::exception_base
{
test::random_values<T> values;
self_swap_base(int count = 0) : values(count) {}
self_swap_base(std::size_t count = 0) : values(count) {}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
@@ -66,8 +66,8 @@ struct swap_base : public test::exception_base
{}
struct data_type {
data_type(T const& x, T const& y)
: x(x), y(y) {}
data_type(T const& x_, T const& y_)
: x(x_), y(y_) {}
T x, y;
};
+9 -3
View File
@@ -69,10 +69,16 @@ namespace test {
};
struct check_instances {
int instances;
int instances_;
int constructions_;
check_instances() : instances(global_object_count.instances) {}
~check_instances() { BOOST_TEST(global_object_count.instances == instances); }
check_instances() :
instances_(global_object_count.instances),
constructions_(global_object_count.constructions) {}
~check_instances() { BOOST_TEST(global_object_count.instances == instances_); }
int instances() const { return global_object_count.instances - instances_; }
int constructions() const { return global_object_count.constructions - constructions_; }
};
}
+4 -9
View File
@@ -42,20 +42,15 @@ namespace test
}
struct equivalent_type {
equivalent_type() {}
template <class T1, class T2>
bool operator()(T1 const& x, T2 const& y) {
bool operator()(T1 const& x, T2 const& y) const {
return equivalent_impl(x, y, derived);
}
};
// This won't be a problem as I'm only using a single compile unit
// in each test (this is actually require by the minimal test
// framework).
//
// boostinspect:nounnamed
namespace {
equivalent_type equivalent;
}
const equivalent_type equivalent;
template <class Container>
class unordered_equivalence_tester
+39 -12
View File
@@ -111,16 +111,28 @@ namespace test {
exceptions_enable(exceptions_enable const&);
bool old_value_;
bool released_;
public:
exceptions_enable(bool enable)
: old_value_(exceptions_enabled)
: old_value_(exceptions_enabled), released_(false)
{
exceptions_enabled = enable;
}
~exceptions_enable()
{
exceptions_enabled = old_value_;
if (!released_) {
exceptions_enabled = old_value_;
released_ = true;
}
}
void release()
{
if (!released_) {
exceptions_enabled = old_value_;
released_ = true;
}
}
};
@@ -167,12 +179,13 @@ namespace test {
class test_runner
{
Test const& test_;
bool exception_in_check_;
test_runner(test_runner const&);
test_runner& operator=(test_runner const&);
public:
test_runner(Test const& t) : test_(t) {}
void operator()() const {
test_runner(Test const& t) : test_(t), exception_in_check_(false) {}
void run() {
DISABLE_EXCEPTIONS;
test::scope = "";
BOOST_DEDUCED_TYPENAME Test::data_type x(test_.init());
@@ -187,14 +200,24 @@ namespace test {
>(&Test::run, test_, x, strong);
}
catch(...) {
call_ignore_extra_parameters<
Test,
BOOST_DEDUCED_TYPENAME Test::data_type const,
BOOST_DEDUCED_TYPENAME Test::strong_type const
>(&Test::check, test_, constant(x), constant(strong));
try {
DISABLE_EXCEPTIONS;
call_ignore_extra_parameters<
Test,
BOOST_DEDUCED_TYPENAME Test::data_type const,
BOOST_DEDUCED_TYPENAME Test::strong_type const
>(&Test::check, test_, constant(x), constant(strong));
} catch(...) {
exception_in_check_ = true;
}
throw;
}
}
void end() {
if (exception_in_check_) {
BOOST_ERROR("Unexcpected exception in test_runner check call.");
}
}
};
// Quick exception testing based on lightweight test
@@ -224,26 +247,30 @@ namespace test {
iteration = 0;
bool success = false;
char const* error_msg = 0;
do {
++iteration;
count = 0;
try {
runner();
runner.run();
success = true;
}
catch(test_failure) {
BOOST_ERROR("test_failure caught.");
error_msg = "test_failure caught.";
break;
}
catch(test_exception) {
continue;
}
catch(...) {
BOOST_ERROR("Unexpected exception.");
error_msg = "Unexpected exception.";
break;
}
} while(!success);
if (error_msg) { BOOST_ERROR(error_msg); }
runner.end();
}
}
}
+11 -5
View File
@@ -10,11 +10,17 @@
namespace test
{
int generate(int const*);
char generate(char const*);
signed char generate(signed char const*);
std::string generate(std::string*);
float generate(float const*);
typedef enum {
default_generator,
generate_collisions,
limited_range
} random_generator;
int generate(int const*, random_generator);
char generate(char const*, random_generator);
signed char generate(signed char const*, random_generator);
std::string generate(std::string const*, random_generator);
float generate(float const*, random_generator);
struct base_type {} base;
struct derived_type : base_type {} derived;
+31 -11
View File
@@ -27,25 +27,32 @@ namespace test
}
};
inline int generate(int const*)
{
std::size_t random_value(std::size_t max) {
using namespace std;
return rand();
return static_cast<std::size_t>(rand()) % max;
}
inline char generate(char const*)
inline int generate(int const*, random_generator g)
{
using namespace std;
int value = rand();
if (g == limited_range) { value = value % 100; }
return value;
}
inline char generate(char const*, random_generator)
{
using namespace std;
return static_cast<char>((rand() >> 1) % (128-32) + 32);
}
inline signed char generate(signed char const*)
inline signed char generate(signed char const*, random_generator)
{
using namespace std;
return static_cast<signed char>(rand());
}
inline std::string generate(std::string const*)
inline std::string generate(std::string const*, random_generator g)
{
using namespace std;
@@ -53,17 +60,30 @@ namespace test
std::string result;
int length = rand() % 10;
for(int i = 0; i < length; ++i)
result += generate(char_ptr);
if (g == limited_range) {
std::size_t length = test::random_value(2) + 2;
char const* strings[] = { "'vZh(3~ms", "%m", "_Y%U", "N'Y", "4,J_J" };
for (std::size_t i = 0; i < length; ++i) {
result += strings[random_value(sizeof(strings) / sizeof(strings[0]))];
}
}
else {
std::size_t length = test::random_value(10) + 1;
for (std::size_t i = 0; i < length; ++i) {
result += generate(char_ptr, g);
}
}
return result;
}
float generate(float const*)
float generate(float const*, random_generator g)
{
using namespace std;
return (float) rand() / (float) RAND_MAX;
int x = 0;
int value = generate(&x, g);
return (float) value / (float) RAND_MAX;
}
}
+20
View File
@@ -38,6 +38,26 @@ namespace test
{
return get_key_impl<Container>::get_key(x);
}
// test::next
//
// Increments an iterator by 1 or a given value.
// Like boost::next, but simpler and slower.
template <typename Iterator>
Iterator next(Iterator it)
{
return ++it;
}
template <typename Iterator, typename IntType>
Iterator next(Iterator it, IntType x)
{
for(; x > 0; --x) {
++it;
}
return it;
}
}
#endif
+3 -3
View File
@@ -7,8 +7,8 @@
#define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER
#include <boost/config.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <iterator>
namespace test
{
@@ -28,7 +28,7 @@ namespace test
template <class Iterator>
struct input_iterator_adaptor
: public boost::iterator<
: public std::iterator<
std::input_iterator_tag,
BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type,
std::ptrdiff_t,
@@ -72,7 +72,7 @@ namespace test
template <class Iterator>
struct copy_iterator_adaptor
: public boost::iterator<
: public std::iterator<
BOOST_DEDUCED_TYPENAME boost::iterator_category<Iterator>::type,
BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type,
BOOST_DEDUCED_TYPENAME boost::iterator_difference<Iterator>::type,
+1 -1
View File
@@ -91,7 +91,7 @@ namespace test
// Check the load factor.
float load_factor =
float load_factor = size == 0 ? 0 :
static_cast<float>(size) / static_cast<float>(x1.bucket_count());
using namespace std;
if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)
+3 -3
View File
@@ -11,8 +11,8 @@
#if !defined(UNORDERED_TEST_LIST_HEADER)
#define UNORDERED_TEST_LIST_HEADER
#include <boost/iterator.hpp>
#include <boost/limits.hpp>
#include <iterator>
#include <functional>
namespace test
@@ -83,7 +83,7 @@ namespace test
template <typename T>
class list_iterator
: public boost::iterator<
: public std::iterator<
std::forward_iterator_tag, T,
int, T*, T&>
{
@@ -109,7 +109,7 @@ namespace test
template <typename T>
class list_const_iterator
: public boost::iterator<
: public std::iterator<
std::forward_iterator_tag, T,
int, T const*, T const&>
{
+5 -15
View File
@@ -8,8 +8,6 @@
#include <boost/config.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
namespace test
{
@@ -22,19 +20,11 @@ namespace test
template <class Container>
struct has_unique_keys
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <class V, class H, class P, class A>
struct has_unique_keys<boost::unordered_set<V, H, P, A> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <class K, class M, class H, class P, class A>
struct has_unique_keys<boost::unordered_map<K, M, H, P, A> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
static char flip(BOOST_DEDUCED_TYPENAME Container::iterator const&);
static long flip(std::pair<BOOST_DEDUCED_TYPENAME Container::iterator, bool> const&);
BOOST_STATIC_CONSTANT(bool, value = sizeof(long) == sizeof(
flip(((Container*) 0)->insert(*(BOOST_DEDUCED_TYPENAME Container::value_type*) 0))
));
};
}
+18 -17
View File
@@ -14,11 +14,6 @@
namespace test
{
typedef enum {
default_generator,
generate_collisions
} random_generator;
template <class X>
struct unordered_generator_set
{
@@ -32,16 +27,15 @@ namespace test
template <class T>
void fill(T& x, std::size_t len) {
value_type* value_ptr = 0;
int* int_ptr = 0;
len += x.size();
for (std::size_t i = 0; i < len; ++i) {
value_type value = generate(value_ptr);
value_type value = generate(value_ptr, type_);
int count = type_ == generate_collisions ?
1 + (generate(int_ptr) % 5) : 1;
std::size_t count = type_ == generate_collisions ?
random_value(5) + 1 : 1;
for(int j = 0; j < count; ++j) {
for(std::size_t j = 0; j < count; ++j) {
x.push_back(value);
}
}
@@ -63,17 +57,16 @@ namespace test
void fill(T& x, std::size_t len) {
key_type* key_ptr = 0;
mapped_type* mapped_ptr = 0;
int* int_ptr = 0;
for (std::size_t i = 0; i < len; ++i) {
key_type key = generate(key_ptr);
key_type key = generate(key_ptr, type_);
int count = type_ == generate_collisions ?
1 + (generate(int_ptr) % 5) : 1;
std::size_t count = type_ == generate_collisions ?
random_value(5) + 1 : 1;
for(int j = 0; j < count; ++j) {
for(std::size_t j = 0; j < count; ++j) {
x.push_back(std::pair<key_type const, mapped_type>(
key, generate(mapped_ptr)));
key, generate(mapped_ptr, type_)));
}
}
}
@@ -103,8 +96,16 @@ namespace test
struct random_values
: public test::list<BOOST_DEDUCED_TYPENAME X::value_type>
{
random_values(int count, test::random_generator const& generator =
random_values() {}
explicit random_values(std::size_t count, test::random_generator const& generator =
test::default_generator)
{
fill(count, generator);
}
void fill(std::size_t count, test::random_generator const& generator =
test::default_generator)
{
test::unordered_generator<X> gen(generator);
gen.fill(*this, count);
+20 -1
View File
@@ -24,7 +24,11 @@
void BOOST_PP_CAT(x, _type)::run() \
#define RUN_TESTS() int main(int, char**) \
{ ::test::test_list::run_tests(); return boost::report_errors(); } \
{ \
::test::write_compiler_info(); \
::test::test_list::run_tests(); \
return boost::report_errors(); \
}
namespace test {
struct registered_test_base {
@@ -66,6 +70,21 @@ namespace test {
}
}
}
inline void write_compiler_info() {
#if defined(BOOST_GCC_CXX11)
char const* cpp11 = "true";
#else
char const* cpp11 = "false";
#endif
std::cout
<< "Compiler: " << BOOST_COMPILER << "\n"
<< "Library: " << BOOST_STDLIB << "\n"
<< "C++11: " << cpp11 << "\n"
<< "\n"
<< std::flush;
}
}
#include <boost/preprocessor/seq/for_each_product.hpp>
+25 -18
View File
@@ -13,7 +13,6 @@
#include <map>
#include <iterator>
#include <algorithm>
#include <boost/type_traits/is_same.hpp>
#include "../objects/fwd.hpp"
#include "./metafunctions.hpp"
#include "./helpers.hpp"
@@ -60,38 +59,46 @@ namespace test
values2.begin(), test::equivalent));
}
template <typename X>
template <typename X,
bool is_set = test::is_set<X>::value,
bool has_unique_keys = test::has_unique_keys<X>::value>
struct ordered_base;
template <class V, class H, class P, class A>
struct ordered_base<boost::unordered_set<V, H, P, A> >
template <typename X>
struct ordered_base<X, true, true>
{
typedef std::set<V,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
typedef std::set<
BOOST_DEDUCED_TYPENAME X::value_type,
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
type;
};
template <class V, class H, class P, class A>
struct ordered_base<boost::unordered_multiset<V, H, P, A> >
template <typename X>
struct ordered_base<X, true, false>
{
typedef std::multiset<V,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
typedef std::multiset<
BOOST_DEDUCED_TYPENAME X::value_type,
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
type;
};
template <class K, class M, class H, class P, class A>
struct ordered_base<boost::unordered_map<K, M, H, P, A> >
template <typename X>
struct ordered_base<X, false, true>
{
typedef std::map<K, M,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
typedef std::map<
BOOST_DEDUCED_TYPENAME X::key_type,
BOOST_DEDUCED_TYPENAME X::mapped_type,
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
type;
};
template <class K, class M, class H, class P, class A>
struct ordered_base<boost::unordered_multimap<K, M, H, P, A> >
template <typename X>
struct ordered_base<X, false, false>
{
typedef std::multimap<K, M,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
typedef std::multimap<
BOOST_DEDUCED_TYPENAME X::key_type,
BOOST_DEDUCED_TYPENAME X::mapped_type,
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
type;
};
+5 -1
View File
@@ -148,7 +148,7 @@ namespace test
return ptr;
}
pointer allocate(size_type n, void const* u)
pointer allocate(size_type n, void const*)
{
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
@@ -201,9 +201,11 @@ namespace test
public move_allocator_base<Flags>,
Flags
{
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000)
template <typename U> struct rebind {
typedef cxx11_allocator<U, Flags> other;
};
#endif
explicit cxx11_allocator(int t = 0)
: cxx11_allocator_base<T>(t)
@@ -251,9 +253,11 @@ namespace test
return tmp;
}
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000)
template <typename U> struct rebind {
typedef cxx11_allocator<U, Flags> other;
};
#endif
explicit cxx11_allocator(int t = 0)
: cxx11_allocator_base<T>(t)
+15 -10
View File
@@ -23,7 +23,7 @@ namespace exception
class hash;
class equal_to;
template <class T> class allocator;
object generate(object const*);
object generate(object const*, random_generator);
struct true_type
{
@@ -101,9 +101,9 @@ namespace exception
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
}
friend object generate(object const*) {
friend object generate(object const*, random_generator g) {
int* x = 0;
return object(::test::generate(x), ::test::generate(x));
return object(::test::generate(x, g), ::test::generate(x, g));
}
friend std::ostream& operator<<(std::ostream& out, object const& o)
@@ -146,14 +146,18 @@ namespace exception
UNORDERED_EPOINT("Mock hash function.");
}
int result;
switch(tag_) {
case 1:
return x.tag1_;
result = x.tag1_;
break;
case 2:
return x.tag2_;
result = x.tag2_;
break;
default:
return x.tag1_ + x.tag2_;
result = x.tag1_ + x.tag2_;
}
return static_cast<std::size_t>(result);
}
friend bool operator==(hash const& x1, hash const& x2) {
@@ -314,7 +318,7 @@ namespace exception
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
}
pointer allocate(size_type n, void const* u)
pointer allocate(size_type n, void const*)
{
T* ptr = 0;
UNORDERED_SCOPE(allocator::allocate(size_type, const_pointer)) {
@@ -494,7 +498,7 @@ namespace exception
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
}
pointer allocate(size_type n, void const* u)
pointer allocate(size_type n, void const*)
{
T* ptr = 0;
UNORDERED_SCOPE(allocator2::allocate(size_type, const_pointer)) {
@@ -588,8 +592,9 @@ namespace exception
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace test
{
test::exception::object generate(test::exception::object const* x) {
return test::exception::generate(x);
test::exception::object generate(test::exception::object const* x,
random_generator g) {
return test::exception::generate(x, g);
}
}
#endif
+3 -3
View File
@@ -386,7 +386,7 @@ namespace minimal
}
template <class Y>
pointer allocate(size_type n, const_ptr<Y> u)
pointer allocate(size_type n, const_ptr<Y>)
{
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
}
@@ -447,7 +447,7 @@ namespace minimal
{
public:
typedef T value_type;
template <class U> struct rebind { typedef cxx11_allocator<U> other; };
//template <class U> struct rebind { typedef cxx11_allocator<U> other; };
cxx11_allocator() {}
template <class Y> cxx11_allocator(cxx11_allocator<Y> const&) {}
@@ -462,7 +462,7 @@ namespace minimal
}
template <class Y>
T* allocate(std::size_t n, const_ptr<Y> u) {
T* allocate(std::size_t n, const_ptr<Y>) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
+37 -18
View File
@@ -25,9 +25,9 @@ namespace test
class equal_to;
template <class T> class allocator1;
template <class T> class allocator2;
object generate(object const*);
movable generate(movable const*);
implicitly_convertible generate(implicitly_convertible const*);
object generate(object const*, random_generator);
movable generate(movable const*, random_generator);
implicitly_convertible generate(implicitly_convertible const*, random_generator);
inline void ignore_variable(void const*) {}
@@ -58,9 +58,9 @@ namespace test
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
}
friend object generate(object const*) {
friend object generate(object const*, random_generator g) {
int* x = 0;
return object(generate(x), generate(x));
return object(generate(x, g), generate(x, g));
}
friend std::ostream& operator<<(std::ostream& out, object const& o)
@@ -133,9 +133,9 @@ namespace test
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
}
friend movable generate(movable const*) {
friend movable generate(movable const*, random_generator g) {
int* x = 0;
return movable(generate(x), generate(x));
return movable(generate(x, g), generate(x, g));
}
friend std::ostream& operator<<(std::ostream& out, movable const& o)
@@ -163,9 +163,9 @@ namespace test
return movable(tag1_, tag2_);
}
friend implicitly_convertible generate(implicitly_convertible const*) {
friend implicitly_convertible generate(implicitly_convertible const*, random_generator g) {
int* x = 0;
return implicitly_convertible(generate(x), generate(x));
return implicitly_convertible(generate(x, g), generate(x, g));
}
friend std::ostream& operator<<(std::ostream& out, implicitly_convertible const& o)
@@ -182,29 +182,48 @@ namespace test
explicit hash(int t = 0) : type_(t) {}
std::size_t operator()(object const& x) const {
int result;
switch(type_) {
case 1:
return x.tag1_;
result = x.tag1_;
break;
case 2:
return x.tag2_;
result = x.tag2_;
break;
default:
return x.tag1_ + x.tag2_;
result = x.tag1_ + x.tag2_;
}
return static_cast<std::size_t>(result);
}
std::size_t operator()(movable const& x) const {
int result;
switch(type_) {
case 1:
return x.tag1_;
result = x.tag1_;
break;
case 2:
return x.tag2_;
result = x.tag2_;
break;
default:
return x.tag1_ + x.tag2_;
result = x.tag1_ + x.tag2_;
}
return static_cast<std::size_t>(result);
}
std::size_t operator()(int x) const {
return x;
int result;
switch(type_) {
case 1:
result = x;
break;
case 2:
result = x * 7;
break;
default:
result = x * 256;
}
return static_cast<std::size_t>(result);
}
friend bool operator==(hash const& x1, hash const& x2) {
@@ -347,7 +366,7 @@ namespace test
return ptr;
}
T* allocate(std::size_t n, void const* u)
T* allocate(std::size_t n, void const*)
{
T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
@@ -573,7 +592,7 @@ namespace test
return p;
}
pointer allocate(size_type n, void const* u)
pointer allocate(size_type n, void const*)
{
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
-63
View File
@@ -1,63 +0,0 @@
# Copyright 2006-2008 Daniel James.
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
import testing ;
project unordered-test/unordered
: requirements
<warnings>all
<toolset>intel:<warnings>on
# Would be nice to define -Wundef, but I'm getting warnings from
# Boost.Preprocessor on trunk.
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow -Wno-long-long"
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
;
test-suite unordered
:
[ run fwd_set_test.cpp ]
[ run fwd_map_test.cpp ]
[ run allocator_traits.cpp ]
[ run minimal_allocator.cpp ]
[ run compile_set.cpp ]
[ run compile_map.cpp ]
[ run noexcept_tests.cpp ]
[ run link_test_1.cpp link_test_2.cpp ]
[ run incomplete_test.cpp ]
[ run simple_tests.cpp ]
[ run equivalent_keys_tests.cpp ]
[ run constructor_tests.cpp ]
[ run copy_tests.cpp ]
[ run move_tests.cpp ]
[ run assign_tests.cpp ]
[ run insert_tests.cpp ]
[ run insert_stable_tests.cpp ]
[ run unnecessary_copy_tests.cpp ]
[ run erase_tests.cpp ]
[ run erase_equiv_tests.cpp ]
[ run find_tests.cpp ]
[ run at_tests.cpp ]
[ run bucket_tests.cpp ]
[ run load_factor_tests.cpp ]
[ run rehash_tests.cpp ]
[ run equality_tests.cpp ]
[ run swap_tests.cpp ]
[ run compile_set.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_compile_set ]
[ run compile_map.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_compile_map ]
[ run copy_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_copy ]
[ run move_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_move ]
[ run assign_tests.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
: bmove_assign ]
;
+4 -4
View File
@@ -22,9 +22,9 @@
T const* address(T const& r) { return &r; } \
T* allocate(std::size_t n) \
{ return static_cast<T*>(::operator new(n * sizeof(T))); } \
T* allocate(std::size_t n, void const* u) \
T* allocate(std::size_t n, void const*) \
{ return static_cast<T*>(::operator new(n * sizeof(T))); } \
void deallocate(T* p, std::size_t n) { ::operator delete((void*) p); } \
void deallocate(T* p, std::size_t) { ::operator delete((void*) p); } \
void construct(T* p, T const& t) { new(p) T(t); } \
void destroy(T* p) { p->~T(); } \
std::size_t max_size() const \
@@ -44,9 +44,9 @@
const_pointer address(T const& r) { return &r; } \
pointer allocate(std::size_t n) \
{ return pointer(::operator new(n * sizeof(T))); } \
pointer allocate(std::size_t n, void const* u) \
pointer allocate(std::size_t n, void const*) \
{ return pointer(::operator new(n * sizeof(T))); } \
void deallocate(pointer p, std::size_t n) \
void deallocate(pointer p, std::size_t) \
{ ::operator delete((void*) p); } \
void construct(T* p, T const& t) { new(p) T(t); } \
void destroy(T* p) { p->~T(); } \
+18 -3
View File
@@ -77,7 +77,21 @@ void assign_tests2(T*, test::random_generator generator)
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
std::cerr<<"assign_tests2.0 - empty container\n";
{
test::check_instances check_;
T x1(0, hf1, eq1);
T x2(0, hf2, eq2);
x2 = x1;
BOOST_TEST(test::equivalent(x1.hash_function(), hf1));
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
test::check_container(x1, x2);
}
std::cerr<<"assign_tests2.1\n";
{
test::check_instances check_;
@@ -236,6 +250,7 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
template <typename T>
bool is_propagate(T*)
@@ -256,7 +271,7 @@ UNORDERED_TEST(assign_tests1, (
(test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
(test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(assign_tests2, (
@@ -264,7 +279,7 @@ UNORDERED_TEST(assign_tests2, (
(test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
(test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
-1
View File
@@ -16,7 +16,6 @@ UNORDERED_AUTO_TEST(at_tests) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl;
boost::unordered_map<std::string, int> x;
typedef boost::unordered_map<std::string, int>::iterator iterator;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Add elements" << std::endl;
+7 -4
View File
@@ -34,8 +34,10 @@ void tests(X*, test::random_generator generator)
X x(v.begin(), v.end());
BOOST_TEST(x.bucket_count() < x.max_bucket_count());
std::cerr<<x.bucket_count()<<"<"<<x.max_bucket_count()<<"\n";
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";
}
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator
it = v.begin(), end = v.end(); it != end; ++it)
@@ -43,7 +45,7 @@ void tests(X*, test::random_generator generator)
size_type bucket = x.bucket(test::get_key<X>(*it));
BOOST_TEST(bucket < x.bucket_count());
if(bucket < x.max_bucket_count()) {
if(bucket < x.bucket_count()) {
// lit? lend?? I need a new naming scheme.
const_local_iterator lit = x.begin(bucket), lend = x.end(bucket);
while(lit != lend
@@ -87,10 +89,11 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(tests,
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}
+4 -4
View File
@@ -24,15 +24,15 @@ template class boost::unordered_map<
std::equal_to<int>,
test::minimal::allocator<std::pair<int const, int> > >;
template class boost::unordered_multimap<
int,
int,
int const,
int const,
boost::hash<int>,
std::equal_to<int>,
test::minimal::allocator<std::pair<int const, int> > >;
template class boost::unordered_map<
test::minimal::assignable,
test::minimal::default_assignable,
test::minimal::assignable const,
test::minimal::default_assignable const,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<test::minimal::assignable> >;
+2 -2
View File
@@ -23,13 +23,13 @@ template class boost::unordered_set<
std::equal_to<int>,
test::minimal::allocator<int> >;
template class boost::unordered_multiset<
int,
int const,
boost::hash<int>,
std::equal_to<int>,
test::minimal::allocator<int> >;
template class boost::unordered_set<
test::minimal::assignable,
test::minimal::assignable const,
test::minimal::hash<test::minimal::assignable>,
test::minimal::equal_to<test::minimal::assignable>,
test::minimal::allocator<test::minimal::assignable> >;
+120 -5
View File
@@ -89,8 +89,9 @@ void container_test(X& r, T const&)
// size_type can represent any non-negative value type of difference_type
// I'm not sure about either of these tests...
size_type max_diff((std::numeric_limits<difference_type>::max)());
difference_type converted_diff(max_diff);
size_type max_diff = static_cast<size_type>(
(std::numeric_limits<difference_type>::max)());
difference_type converted_diff(static_cast<difference_type>(max_diff));
BOOST_TEST((std::numeric_limits<difference_type>::max)()
== converted_diff);
@@ -100,7 +101,18 @@ void container_test(X& r, T const&)
static_cast<comparison_type>(
(std::numeric_limits<difference_type>::max)()));
// Constructors
// I don't test the runtime post-conditions here.
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
// It isn't specified in the container requirements that the no argument
// constructor is implicit, but it is defined that way in the concrete
// container specification.
X u_implicit = {};
sink(u_implicit);
#endif
X u;
BOOST_TEST(u.size() == 0);
BOOST_TEST(X().size() == 0);
@@ -111,6 +123,8 @@ void container_test(X& r, T const&)
sink(X(a));
X u2(a);
X u3 = a;
X u4(rvalue(a_const));
X u5 = rvalue(a_const);
a.swap(b);
boost::swap(a, b);
@@ -120,12 +134,25 @@ void container_test(X& r, T const&)
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
test::check_return_type<allocator_type>::equals(a_const.get_allocator());
allocator_type m = a.get_allocator();
sink(X(m));
X c(m);
sink(X(a_const, m));
X c2(a_const, m);
sink(X(rvalue(a_const), m));
X c3(rvalue(a_const), m);
// Avoid unused variable warnings:
sink(u);
sink(u2);
sink(u3);
sink(u4);
sink(u5);
sink(c);
sink(c2);
sink(c3);
}
template <class X>
@@ -148,6 +175,7 @@ void unordered_destructible_test(X&)
X* ptr = new X();
X& a1 = *ptr;
(&a1)->~X();
::operator delete((void*)(&a1));
X a,b;
X const a_const;
@@ -245,6 +273,9 @@ void unordered_map_test(X& r, Key const& k, T const& v)
r.emplace(k, v);
r.emplace(k_lvalue, v_lvalue);
r.emplace(rvalue(k), rvalue(v));
r.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(k), boost::make_tuple(v));
}
template <class X>
@@ -353,6 +384,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
typedef BOOST_DEDUCED_TYPENAME
boost::iterator_reference<const_local_iterator>::type
const_local_iterator_reference;
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
BOOST_STATIC_ASSERT((boost::is_same<Key, key_type>::value));
//boost::function_requires<boost::CopyConstructibleConcept<key_type> >();
@@ -385,8 +417,13 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_reference,
const_iterator_reference>::value));
X a;
allocator_type m = a.get_allocator();
// Constructors
X(10, hf, eq);
X a(10, hf, eq);
X a1(10, hf, eq);
X(10, hf);
X a2(10, hf);
X(10);
@@ -394,6 +431,15 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
X();
X a4;
X(10, hf, eq, m);
X a1a(10, hf, eq, m);
X(10, hf, m);
X a2a(10, hf, m);
X(10, m);
X a3a(10, m);
(X(m));
X a4a(m);
test::check_return_type<size_type>::equals(a.erase(k));
const_iterator q1 = a.cbegin(), q2 = a.cend();
@@ -436,9 +482,14 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
// Avoid unused variable warnings:
sink(a);
sink(a1);
sink(a2);
sink(a3);
sink(a4);
sink(a1a);
sink(a2a);
sink(a3a);
sink(a4a);
}
template <class X, class Key, class T, class Hash, class Pred>
@@ -448,14 +499,17 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
X a;
allocator_type m = a.get_allocator();
BOOST_DEDUCED_TYPENAME X::value_type* i = 0;
BOOST_DEDUCED_TYPENAME X::value_type* j = 0;
X(i, j, 10, hf, eq);
// Constructors
X(i, j, 10, hf, eq);
X a5(i, j, 10, hf, eq);
X(i, j, 10, hf);
X a6(i, j, 10, hf);
@@ -464,17 +518,55 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
X(i, j);
X a8(i, j);
X(i, j, 10, hf, eq, m);
X a5a(i, j, 10, hf, eq, m);
X(i, j, 10, hf, m);
X a6a(i, j, 10, hf, m);
X(i, j, 10, m);
X a7a(i, j, 10, m);
// Not specified for some reason (maybe ambiguity with another constructor?)
//X(i, j, m);
//X a8a(i, j, m);
//sink(a8a);
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
std::size_t min_buckets = 10;
X({t});
X({t}, min_buckets);
X({t}, min_buckets, hf);
X({t}, min_buckets, hf, eq);
//X({t}, m);
X({t}, min_buckets, m);
X({t}, min_buckets, hf, m);
X({t}, min_buckets, hf, eq, m);
#endif
X const b;
sink(X(b));
X a9(b);
a = b;
sink(X(b, m));
X a9a(b, m);
const_iterator q = a.cbegin();
test::check_return_type<iterator>::equals(a.insert(q, t));
test::check_return_type<iterator>::equals(a.emplace_hint(q, t));
a.insert(i, j);
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
std::initializer_list<T> list = {t};
a.insert(list);
a.insert({t,t,t});
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
a.insert({});
a.insert({t});
a.insert({t,t});
#endif
#endif
X a10;
a10.insert(t);
@@ -489,6 +581,10 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
sink(a7);
sink(a8);
sink(a9);
sink(a5a);
sink(a6a);
sink(a7a);
sink(a9a);
}
template <class X, class Key, class T, class Hash, class Pred>
@@ -498,6 +594,7 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq)
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
X x1(rvalue_default<X>());
@@ -506,9 +603,14 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq)
x2 = boost::move(x1);
#endif
X a;
allocator_type m = a.get_allocator();
test::minimal::constructor_param* i = 0;
test::minimal::constructor_param* j = 0;
// Constructors
X(i, j, 10, hf, eq);
X a5(i, j, 10, hf, eq);
X(i, j, 10, hf);
@@ -518,7 +620,17 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq)
X(i, j);
X a8(i, j);
X a;
X(i, j, 10, hf, eq, m);
X a5a(i, j, 10, hf, eq, m);
X(i, j, 10, hf, m);
X a6a(i, j, 10, hf, m);
X(i, j, 10, m);
X a7a(i, j, 10, m);
// Not specified for some reason (maybe ambiguity with another constructor?)
//X(i, j, m);
//X a8a(i, j, m);
//sink(a8a);
const_iterator q = a.cbegin();
@@ -552,6 +664,9 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq)
sink(a6);
sink(a7);
sink(a8);
sink(a5a);
sink(a6a);
sink(a7a);
sink(a10);
}
+4 -3
View File
@@ -418,20 +418,21 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(constructor_tests1,
((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(constructor_tests2,
((test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(map_constructor_test,
((test_map_std_alloc)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
+3 -2
View File
@@ -198,13 +198,14 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(copy_construct_tests1, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(copy_construct_tests2, (
@@ -212,7 +213,7 @@ UNORDERED_TEST(copy_construct_tests2, (
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}
+436
View File
@@ -0,0 +1,436 @@
//
// Copyright 2016 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include <boost/functional/hash/hash.hpp>
#include "../helpers/test.hpp"
#include "../helpers/count.hpp"
#include <string>
// Test that various emplace methods work with different numbers of
// arguments.
namespace emplace_tests {
// Constructible with 2 to 10 arguments
struct emplace_value : private test::counted_object {
typedef int A0;
typedef std::string A1;
typedef char A2;
typedef int A3;
typedef int A4;
typedef int A5;
typedef int A6;
typedef int A7;
typedef int A8;
typedef int A9;
int arg_count;
A0 a0;
A1 a1;
A2 a2;
A3 a3;
A4 a4;
A5 a5;
A6 a6;
A7 a7;
A8 a8;
A9 a9;
emplace_value(
A0 const& b0, A1 const& b1) :
arg_count(2),
a0(b0), a1(b1) {}
emplace_value(
A0 const& b0, A1 const& b1, A2 const& b2) :
arg_count(3),
a0(b0), a1(b1), a2(b2) {}
emplace_value(
A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3) :
arg_count(4),
a0(b0), a1(b1), a2(b2), a3(b3) {}
emplace_value(
A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
A4 const& b4) :
arg_count(5),
a0(b0), a1(b1), a2(b2), a3(b3), a4(b4) {}
emplace_value(
A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
A4 const& b4, A5 const& b5) :
arg_count(6),
a0(b0), a1(b1), a2(b2), a3(b3), a4(b4),
a5(b5) {}
emplace_value(
A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
A4 const& b4, A5 const& b5, A6 const& b6) :
arg_count(7),
a0(b0), a1(b1), a2(b2), a3(b3), a4(b4),
a5(b5), a6(b6) {}
emplace_value(
A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7) :
arg_count(8),
a0(b0), a1(b1), a2(b2), a3(b3), a4(b4),
a5(b5), a6(b6), a7(b7) {}
emplace_value(
A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7,
A8 const& b8) :
arg_count(9),
a0(b0), a1(b1), a2(b2), a3(b3), a4(b4),
a5(b5), a6(b6), a7(b7), a8(b8) {}
emplace_value(
A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7,
A8 const& b8, A9 const& b9) :
arg_count(10),
a0(b0), a1(b1), a2(b2), a3(b3), a4(b4),
a5(b5), a6(b6), a7(b7), a8(b8), a9(b9) {}
friend std::size_t hash_value(emplace_value const& x) {
std::size_t r1 = 23894278u;
if (x.arg_count >= 1) boost::hash_combine(r1, x.a0);
if (x.arg_count >= 2) boost::hash_combine(r1, x.a1);
if (x.arg_count >= 3) boost::hash_combine(r1, x.a2);
if (x.arg_count >= 4) boost::hash_combine(r1, x.a3);
if (x.arg_count >= 5) boost::hash_combine(r1, x.a4);
if (x.arg_count >= 6) boost::hash_combine(r1, x.a5);
if (x.arg_count >= 7) boost::hash_combine(r1, x.a6);
if (x.arg_count >= 8) boost::hash_combine(r1, x.a7);
if (x.arg_count >= 9) boost::hash_combine(r1, x.a8);
if (x.arg_count >= 10) boost::hash_combine(r1, x.a9);
return r1;
}
friend bool operator==(emplace_value const& x, emplace_value const& y) {
if (x.arg_count != y.arg_count) { return false; }
if (x.arg_count >= 1 && x.a0 != y.a0) { return false; }
if (x.arg_count >= 2 && x.a1 != y.a1) { return false; }
if (x.arg_count >= 3 && x.a2 != y.a2) { return false; }
if (x.arg_count >= 4 && x.a3 != y.a3) { return false; }
if (x.arg_count >= 5 && x.a4 != y.a4) { return false; }
if (x.arg_count >= 6 && x.a5 != y.a5) { return false; }
if (x.arg_count >= 7 && x.a6 != y.a6) { return false; }
if (x.arg_count >= 8 && x.a7 != y.a7) { return false; }
if (x.arg_count >= 9 && x.a8 != y.a8) { return false; }
if (x.arg_count >= 10 && x.a9 != y.a9) { return false; }
return true;
}
private:
emplace_value();
emplace_value(emplace_value const&);
};
UNORDERED_AUTO_TEST(emplace_set) {
test::check_instances check_;
typedef boost::unordered_set<emplace_value,
boost::hash<emplace_value> > container;
typedef container::iterator iterator;
typedef std::pair<iterator, bool> return_type;
container x(10);
iterator i1;
return_type r1,r2;
// 2 args
emplace_value v1(10, "x");
r1 = x.emplace(10, std::string("x"));
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST(r1.second);
BOOST_TEST(*r1.first == v1);
BOOST_TEST(r1.first == x.find(v1));
BOOST_TEST_EQ(check_.instances(), 2);
BOOST_TEST_EQ(check_.constructions(), 2);
// 3 args
emplace_value v2(3, "foo", 'a');
r1 = x.emplace(3, "foo", 'a');
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST(r1.second);
BOOST_TEST(*r1.first == v2);
BOOST_TEST(r1.first == x.find(v2));
BOOST_TEST_EQ(check_.instances(), 4);
BOOST_TEST_EQ(check_.constructions(), 4);
// 7 args with hint + duplicate
emplace_value v3(25, "something", 'z', 4, 5, 6, 7);
i1 = x.emplace_hint(r1.first, 25, "something", 'z', 4, 5, 6, 7);
BOOST_TEST_EQ(x.size(), 3u);
BOOST_TEST(*i1 == v3);
BOOST_TEST(i1 == x.find(v3));
BOOST_TEST_EQ(check_.instances(), 6);
BOOST_TEST_EQ(check_.constructions(), 6);
r2 = x.emplace(25, "something", 'z', 4, 5, 6, 7);
BOOST_TEST_EQ(x.size(), 3u);
BOOST_TEST(!r2.second);
BOOST_TEST(i1 == r2.first);
// The container has to construct an object in order to check
// whether it can emplace, so there's an extra cosntruction
// here.
BOOST_TEST_EQ(check_.instances(), 6);
BOOST_TEST_EQ(check_.constructions(), 7);
// 10 args + hint duplicate
std::string s1;
emplace_value v4(10, s1, 'a', 4, 5, 6, 7, 8, 9, 10);
r1 = x.emplace(10, s1, 'a', 4, 5, 6, 7, 8, 9, 10);
BOOST_TEST_EQ(x.size(), 4u);
BOOST_TEST(r1.second);
BOOST_TEST(*r1.first == v4);
BOOST_TEST(r1.first == x.find(v4));
BOOST_TEST_EQ(check_.instances(), 8);
BOOST_TEST_EQ(check_.constructions(), 9);
BOOST_TEST(r1.first ==
x.emplace_hint(r1.first, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10));
BOOST_TEST(r1.first ==
x.emplace_hint(r2.first, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10));
BOOST_TEST(r1.first ==
x.emplace_hint(x.end(), 10, "", 'a', 4, 5, 6, 7, 8, 9, 10));
BOOST_TEST_EQ(check_.instances(), 8);
BOOST_TEST_EQ(check_.constructions(), 12);
BOOST_TEST_EQ(x.size(), 4u);
BOOST_TEST(x.count(v1) == 1);
BOOST_TEST(x.count(v2) == 1);
BOOST_TEST(x.count(v3) == 1);
BOOST_TEST(x.count(v4) == 1);
}
UNORDERED_AUTO_TEST(emplace_multiset) {
test::check_instances check_;
typedef boost::unordered_multiset<emplace_value,
boost::hash<emplace_value> > container;
typedef container::iterator iterator;
container x(10);
iterator i1, i2;
// 2 args.
emplace_value v1(10, "x");
i1 = x.emplace(10, std::string("x"));
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST(i1 == x.find(v1));
BOOST_TEST_EQ(check_.instances(), 2);
BOOST_TEST_EQ(check_.constructions(), 2);
// 4 args + duplicate
emplace_value v2(4, "foo", 'a', 15);
i1 = x.emplace(4, "foo", 'a', 15);
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST(i1 == x.find(v2));
BOOST_TEST_EQ(check_.instances(), 4);
BOOST_TEST_EQ(check_.constructions(), 4);
i2 = x.emplace(4, "foo", 'a', 15);
BOOST_TEST_EQ(x.size(), 3u);
BOOST_TEST(i1 != i2);
BOOST_TEST(*i1 == *i2);
BOOST_TEST(x.count(*i1) == 2);
BOOST_TEST_EQ(check_.instances(), 5);
BOOST_TEST_EQ(check_.constructions(), 5);
// 7 args + duplicate using hint.
emplace_value v3(7, "", 'z', 4, 5, 6, 7);
i1 = x.emplace(7, "", 'z', 4, 5, 6, 7);
BOOST_TEST_EQ(x.size(), 4u);
BOOST_TEST_EQ(i1->a2, 'z');
BOOST_TEST(x.count(*i1) == 1);
BOOST_TEST(i1 == x.find(v3));
BOOST_TEST_EQ(check_.instances(), 7);
BOOST_TEST_EQ(check_.constructions(), 7);
i2 = x.emplace_hint(i1, 7, "", 'z', 4, 5, 6, 7);
BOOST_TEST_EQ(x.size(), 5u);
BOOST_TEST(*i1 == *i2);
BOOST_TEST(i1 != i2);
BOOST_TEST(x.count(*i1) == 2);
BOOST_TEST_EQ(check_.instances(), 8);
BOOST_TEST_EQ(check_.constructions(), 8);
// 10 args with bad hint + duplicate
emplace_value v4(10, "", 'a', 4, 5, 6, 7, 8, 9, 10);
i1 = x.emplace_hint(i2, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10);
BOOST_TEST_EQ(x.size(), 6u);
BOOST_TEST_EQ(i1->arg_count, 10);
BOOST_TEST(i1 == x.find(v4));
BOOST_TEST_EQ(check_.instances(), 10);
BOOST_TEST_EQ(check_.constructions(), 10);
i2 = x.emplace_hint(x.end(), 10, "", 'a', 4, 5, 6, 7, 8, 9, 10);
BOOST_TEST_EQ(x.size(), 7u);
BOOST_TEST(*i1 == *i2);
BOOST_TEST(i1 != i2);
BOOST_TEST(x.count(*i1) == 2);
BOOST_TEST_EQ(check_.instances(), 11);
BOOST_TEST_EQ(check_.constructions(), 11);
BOOST_TEST_EQ(x.count(v1), 1u);
BOOST_TEST_EQ(x.count(v2), 2u);
BOOST_TEST_EQ(x.count(v3), 2u);
}
UNORDERED_AUTO_TEST(emplace_map) {
test::check_instances check_;
typedef boost::unordered_map<emplace_value, emplace_value,
boost::hash<emplace_value> > container;
typedef container::iterator iterator;
typedef std::pair<iterator, bool> return_type;
container x(10);
return_type r1, r2;
// 5/8 args + duplicate
emplace_value k1(5, "", 'b', 4, 5);
emplace_value m1(8, "xxx", 'z', 4, 5, 6, 7, 8);
r1 = x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(5, "", 'b', 4, 5),
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST(r1.second);
BOOST_TEST(x.find(k1) == r1.first);
BOOST_TEST(x.find(k1)->second == m1);
BOOST_TEST_EQ(check_.instances(), 4);
BOOST_TEST_EQ(check_.constructions(), 4);
r2 = x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(5, "", 'b', 4, 5),
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST(!r2.second);
BOOST_TEST(r1.first == r2.first);
BOOST_TEST(x.find(k1)->second == m1);
BOOST_TEST_EQ(check_.instances(), 4);
// constructions could possibly be 5 if the implementation only
// constructed the key.
BOOST_TEST_EQ(check_.constructions(), 6);
// 9/3 args + duplicates with hints, different mapped value.
emplace_value k2(9, "", 'b', 4, 5, 6, 7, 8, 9);
emplace_value m2(3, "aaa", 'm');
r1 = x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
boost::make_tuple(3, "aaa", 'm'));
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST(r1.second);
BOOST_TEST(r1.first->first.arg_count == 9);
BOOST_TEST(r1.first->second.arg_count == 3);
BOOST_TEST(x.find(k2) == r1.first);
BOOST_TEST(x.find(k2)->second == m2);
BOOST_TEST_EQ(check_.instances(), 8);
BOOST_TEST_EQ(check_.constructions(), 10);
BOOST_TEST(r1.first == x.emplace_hint(r1.first,
boost::unordered::piecewise_construct,
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
boost::make_tuple(15, "jkjk")));
BOOST_TEST(r1.first == x.emplace_hint(r2.first,
boost::unordered::piecewise_construct,
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
boost::make_tuple(275, "xxx", 'm', 6)));
BOOST_TEST(r1.first == x.emplace_hint(x.end(),
boost::unordered::piecewise_construct,
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
boost::make_tuple(-10, "blah blah", '\0')));
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST(x.find(k2)->second == m2);
BOOST_TEST_EQ(check_.instances(), 8);
BOOST_TEST_EQ(check_.constructions(), 16);
}
UNORDERED_AUTO_TEST(emplace_multimap) {
test::check_instances check_;
typedef boost::unordered_multimap<emplace_value, emplace_value,
boost::hash<emplace_value> > container;
typedef container::iterator iterator;
container x(10);
iterator i1, i2, i3, i4;
// 5/8 args + duplicate
emplace_value k1(5, "", 'b', 4, 5);
emplace_value m1(8, "xxx", 'z', 4, 5, 6, 7, 8);
i1 = x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(5, "", 'b', 4, 5),
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST(x.find(k1) == i1);
BOOST_TEST(x.find(k1)->second == m1);
BOOST_TEST_EQ(check_.instances(), 4);
BOOST_TEST_EQ(check_.constructions(), 4);
emplace_value m1a(8, "xxx", 'z', 4, 5, 6, 7, 8);
i2 = x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(5, "", 'b', 4, 5),
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST(i1 != i2);
BOOST_TEST(i1->second == m1);
BOOST_TEST(i2->second == m1a);
BOOST_TEST_EQ(check_.instances(), 7);
BOOST_TEST_EQ(check_.constructions(), 7);
// 9/3 args + duplicates with hints, different mapped value.
emplace_value k2(9, "", 'b', 4, 5, 6, 7, 8, 9);
emplace_value m2(3, "aaa", 'm');
i1 = x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
boost::make_tuple(3, "aaa", 'm'));
BOOST_TEST_EQ(x.size(), 3u);
BOOST_TEST(i1->first.arg_count == 9);
BOOST_TEST(i1->second.arg_count == 3);
BOOST_TEST_EQ(check_.instances(), 11);
BOOST_TEST_EQ(check_.constructions(), 11);
emplace_value m2a(15, "jkjk");
i2 = x.emplace_hint(i2,
boost::unordered::piecewise_construct,
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
boost::make_tuple(15, "jkjk"));
emplace_value m2b(275, "xxx", 'm', 6);
i3 = x.emplace_hint(i1,
boost::unordered::piecewise_construct,
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
boost::make_tuple(275, "xxx", 'm', 6));
emplace_value m2c(-10, "blah blah", '\0');
i4 = x.emplace_hint(x.end(),
boost::unordered::piecewise_construct,
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
boost::make_tuple(-10, "blah blah", '\0'));
BOOST_TEST_EQ(x.size(), 6u);
BOOST_TEST(x.find(k2)->second == m2);
BOOST_TEST_EQ(check_.instances(), 20);
BOOST_TEST_EQ(check_.constructions(), 20);
}
}
RUN_TESTS()
+4 -2
View File
@@ -25,9 +25,11 @@ namespace equality_tests
return x % 1000 == y % 1000;
}
int operator()(int x) const
std::size_t operator()(int x) const
{
return alt_hash_ ? x % 250 : (x + 5) % 250;
return alt_hash_ ?
static_cast<std::size_t>(x % 250) :
static_cast<std::size_t>((x + 5) % 250);
}
};
+10 -9
View File
@@ -13,10 +13,10 @@
#include "../helpers/test.hpp"
#include "../helpers/list.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/helpers.hpp"
#include <set>
#include <iostream>
#include <iterator>
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
@@ -43,19 +43,19 @@ void write_container(Container const& x)
// Make everything collide - for testing erase in a single bucket.
struct collision_hash
{
int operator()(int) const { return 0; }
std::size_t operator()(int) const { return 0; }
};
// For testing erase in 2 buckets.
struct collision2_hash
{
int operator()(int x) const { return x & 1; }
std::size_t operator()(int x) const { return static_cast<std::size_t>(x & 1); }
};
// For testing erase in lots of buckets.
struct collision3_hash
{
int operator()(int x) const { return x; }
std::size_t operator()(int x) const { return static_cast<std::size_t>(x); }
};
typedef boost::unordered_multimap<int, int,
@@ -111,8 +111,8 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
{
collide_map x(init.begin(), init.end());
int value = boost::next(x.begin())->second;
x.erase(x.begin(), boost::next(x.begin()));
int value = test::next(x.begin())->second;
x.erase(x.begin(), test::next(x.begin()));
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
x.begin()->first == 1 && x.begin()->second == value);
test::check_equivalent_keys(x);
@@ -121,7 +121,7 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
{
collide_map x(init.begin(), init.end());
int value = x.begin()->second;
x.erase(boost::next(x.begin()), x.end());
x.erase(test::next(x.begin()), x.end());
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
x.begin()->first == 1 && x.begin()->second == value);
test::check_equivalent_keys(x);
@@ -144,8 +144,9 @@ template <class Container>
bool general_erase_range_test(Container& x, std::size_t start, std::size_t end)
{
collide_list l(x.begin(), x.end());
l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end));
x.erase(boost::next(x.begin(), start), boost::next(x.begin(), end));
l.erase(test::next(l.begin(), start), test::next(l.begin(), end));
x.erase(test::next(x.begin(), start), test::next(x.begin(), end));
test::check_equivalent_keys(x);
return compare(l, x);
+66 -18
View File
@@ -9,15 +9,15 @@
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/helpers.hpp"
#include "../helpers/invariants.hpp"
#include <vector>
#include <iostream>
#include <cstdlib>
namespace erase_tests
{
@@ -27,6 +27,9 @@ test::seed_t initialize_seed(85638);
template <class Container>
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";
{
test::check_instances check_;
@@ -60,8 +63,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_DEDUCED_TYPENAME Container::key_type
key = test::get_key<Container>(*x.begin());
std::size_t count = x.count(key);
BOOST_DEDUCED_TYPENAME Container::iterator
pos = x.erase(x.begin());
iterator pos = x.erase(x.begin());
--size;
BOOST_TEST(pos == x.begin());
BOOST_TEST(x.count(key) == count - 1);
@@ -81,26 +83,29 @@ void erase_tests1(Container*, test::random_generator generator)
int iterations = 0;
while(size > 0 && !x.empty())
{
using namespace std;
int index = rand() % (int) x.size();
BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next;
std::size_t index = test::random_value(x.size());
c_iterator prev, pos, next;
if(index == 0) {
prev = pos = x.begin();
}
else {
prev = boost::next(x.begin(), index - 1);
pos = boost::next(prev);
prev = test::next(x.begin(), index - 1);
pos = test::next(prev);
}
next = boost::next(pos);
next = test::next(pos);
BOOST_DEDUCED_TYPENAME Container::key_type
key = test::get_key<Container>(*pos);
std::size_t count = x.count(key);
BOOST_TEST(count > 0);
BOOST_TEST(next == x.erase(pos));
--size;
if(size > 0)
BOOST_TEST(index == 0 ? next == x.begin() :
next == boost::next(prev));
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_TEST(x.size() == size);
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
}
@@ -134,6 +139,45 @@ void erase_tests1(Container*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr<<"erase(random ranges).\n";
{
test::check_instances check_;
Container x;
for (int i = 0; i < 100; ++i) {
test::random_values<Container> v(1000, generator);
x.insert(v.begin(), v.end());
// Note that erase only invalidates the erased iterators.
std::vector<c_iterator> iterators;
for(c_iterator it = x.cbegin(); it != x.cend(); ++it) {
iterators.push_back(it);
}
iterators.push_back(x.cend());
while(iterators.size() > 1) {
std::size_t start = test::random_value(iterators.size());
std::size_t length = test::random_value(iterators.size() - start);
x.erase(iterators[start], iterators[start + length]);
iterators.erase(
test::next(iterators.begin(), start),
test::next(iterators.begin(), start + length));
BOOST_TEST(x.size() == iterators.size() - 1);
BOOST_DEDUCED_TYPENAME std::vector<c_iterator>::const_iterator
i2 = iterators.begin();
for(c_iterator i1 = x.cbegin(); i1 != x.cend(); ++i1) {
BOOST_TEST(i1 == *i2);
++i2;
}
BOOST_TEST(x.cend() == *i2);
test::check_equivalent_keys(x);
}
BOOST_TEST(x.empty());
}
}
std::cerr<<"quick_erase(begin()).\n";
{
test::check_instances check_;
@@ -166,26 +210,29 @@ void erase_tests1(Container*, test::random_generator generator)
int iterations = 0;
while(size > 0 && !x.empty())
{
using namespace std;
int index = rand() % (int) x.size();
std::size_t index = test::random_value(x.size());
BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next;
if(index == 0) {
prev = pos = x.begin();
}
else {
prev = boost::next(x.begin(), index - 1);
pos = boost::next(prev);
prev = test::next(x.begin(), index - 1);
pos = test::next(prev);
}
next = boost::next(pos);
next = test::next(pos);
BOOST_DEDUCED_TYPENAME Container::key_type
key = test::get_key<Container>(*pos);
std::size_t count = x.count(key);
BOOST_TEST(count > 0);
x.quick_erase(pos);
--size;
if(size > 0)
BOOST_TEST(index == 0 ? next == x.begin() :
next == boost::next(prev));
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_TEST(x.size() == size);
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
}
@@ -222,10 +269,11 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(erase_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}
+8 -5
View File
@@ -37,13 +37,15 @@ void find_tests1(X*, test::random_generator generator)
tracker.begin(); it1 != tracker.end(); ++it1)
{
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it1);
iterator pos = x.find(key);
BOOST_DEDUCED_TYPENAME X::const_iterator
const_pos = x_const.find(key);
BOOST_TEST(pos != x.end() &&
x.key_eq()(key, test::get_key<X>(*pos)));
iterator pos = x.find(key);
BOOST_TEST(const_pos != x_const.end());
BOOST_TEST(const_pos != x_const.end() &&
x_const.key_eq()(key, test::get_key<X>(*const_pos)));
BOOST_TEST(pos != x.end());
BOOST_TEST(pos != x.end() &&
x.key_eq()(key, test::get_key<X>(*pos)));
BOOST_TEST(x.count(key) == tracker.count(key));
@@ -153,14 +155,15 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(find_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(find_compatible_keys_test,
((test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}
+118
View File
@@ -0,0 +1,118 @@
// Copyright 2016 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../helpers/invariants.hpp"
#include <map>
#include <set>
#include <iostream>
namespace insert_hint
{
UNORDERED_AUTO_TEST(insert_hint_empty) {
typedef boost::unordered_multiset<int> container;
container x;
x.insert(x.cbegin(), 10);
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST_EQ(x.count(10), 1u);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_empty2) {
typedef boost::unordered_multimap<std::string, int> container;
container x;
x.emplace_hint(x.cbegin(), "hello", 50);
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST_EQ(x.count("hello"), 1u);
BOOST_TEST_EQ(x.find("hello")->second, 50);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_single) {
typedef boost::unordered_multiset<std::string> container;
container x;
x.insert("equal");
x.insert(x.cbegin(), "equal");
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST_EQ(x.count("equal"), 2u);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_single2) {
typedef boost::unordered_multimap<int, std::string> container;
container x;
x.emplace(10, "one");
x.emplace_hint(x.cbegin(), 10, "two");
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST_EQ(x.count(10), 2u);
container::iterator it = x.find(10);
std::string v0 = (it++)->second;
std::string v1 = (it++)->second;
BOOST_TEST(v0 == "one" || v0 == "two");
BOOST_TEST(v1 == "one" || v1 == "two");
BOOST_TEST(v0 != v1);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_multiple) {
for (unsigned int size = 0; size < 10; ++size) {
for (unsigned int offset = 0; offset <= size; ++offset) {
typedef boost::unordered_multiset<std::string> container;
container x;
for (unsigned int i = 0; i < size; ++i) { x.insert("multiple"); }
BOOST_TEST_EQ(x.size(), size);
container::const_iterator position = x.cbegin();
for (unsigned int i = 0; i < offset; ++i) { ++position; }
x.insert(position, "multiple");
BOOST_TEST_EQ(x.size(), size + 1u);
BOOST_TEST_EQ(x.count("multiple"), size + 1u);
test::check_equivalent_keys(x);
}
}
}
UNORDERED_AUTO_TEST(insert_hint_unique) {
typedef boost::unordered_set<int> container;
container x;
x.insert(x.cbegin(), 10);
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST_EQ(x.count(10), 1u);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_unique_single) {
typedef boost::unordered_set<int> container;
container x;
x.insert(10);
x.insert(x.cbegin(), 10);
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST_EQ(x.count(10), 1u);
test::check_equivalent_keys(x);
x.insert(x.cbegin(), 20);
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST_EQ(x.count(10), 1u);
BOOST_TEST_EQ(x.count(20), 1u);
test::check_equivalent_keys(x);
}
}
RUN_TESTS()
+7 -4
View File
@@ -49,6 +49,8 @@ UNORDERED_AUTO_TEST(stable_insert_test1) {
x.insert(insert_stable::member(1,2));
x.insert(insert_stable::member(1,3));
BOOST_TEST(x.count(insert_stable::member(1,4)) == 3);
boost::unordered_multiset<insert_stable::member>::const_iterator
it = x.begin(), end = x.end();
BOOST_TEST(it != end);
@@ -66,10 +68,11 @@ UNORDERED_AUTO_TEST(stable_insert_test2) {
boost::unordered_multimap<insert_stable::member, int>::const_iterator
iterator;
iterator it
= x.insert(x.end(), std::make_pair(insert_stable::member(1,1), 1));
it = x.insert(it, std::make_pair(insert_stable::member(1,2), 2));
it = x.insert(it, std::make_pair(insert_stable::member(1,3), 3));
iterator it = x.emplace(insert_stable::member(1,1), 1);
it = x.emplace(insert_stable::member(1,2), 2);
it = x.emplace(insert_stable::member(1,3), 3);
BOOST_TEST(x.count(insert_stable::member(1,4)) == 3);
it = x.begin();
iterator end = x.end();
+77 -33
View File
@@ -9,8 +9,6 @@
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/predef.h>
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
@@ -56,7 +54,7 @@ void unique_insert_tests1(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -89,7 +87,7 @@ void equivalent_insert_tests1(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -125,10 +123,11 @@ void insert_tests2(X*, test::random_generator generator)
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
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);
}
@@ -154,10 +153,11 @@ void insert_tests2(X*, test::random_generator generator)
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
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);
}
@@ -183,10 +183,11 @@ void insert_tests2(X*, test::random_generator generator)
BOOST_TEST(*pos == *r2);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
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);
}
@@ -206,14 +207,15 @@ void insert_tests2(X*, test::random_generator generator)
old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
x.insert(it, boost::next(it));
x.insert(it, test::next(it));
tracker.insert(*it);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
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);
}
@@ -293,6 +295,42 @@ void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr<<"insert various ranges.\n";
{
for (int i = 0; i < 100; ++i) {
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();)
{
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
next = it;
for (std::size_t j = test::random_value(20); j > 0; ++j) {
++next;
if (next == v.end()) { break; }
}
x.insert(it, next);
tracker.insert(it, next);
it = next;
tracker.compare(x); // Slow, but I can't see any other way.
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>
@@ -324,10 +362,11 @@ void unique_emplace_tests1(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
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);
}
@@ -354,10 +393,11 @@ void equivalent_emplace_tests1(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
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);
}
@@ -383,17 +423,18 @@ void move_emplace_tests(X*, test::random_generator generator)
tracker.insert(*it);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(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);
tracker.compare(x);
test::check_equivalent_keys(x);
}
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";
bool is_unique = test::has_unique_keys<X>::value;
@@ -402,17 +443,17 @@ void default_emplace_tests(X*, test::random_generator)
x.emplace();
BOOST_TEST(x.size() == 1);
x.emplace();
BOOST_TEST(x.size() == is_unique ? 1: 2);
BOOST_TEST(x.size() == (is_unique ? 1u : 2u));
x.emplace();
BOOST_TEST(x.size() == is_unique ? 1: 3);
BOOST_TEST(x.size() == (is_unique ? 1u : 3u));
typename X::value_type y;
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 3);
BOOST_TEST(x.count(test::get_key<X>(y)) == (is_unique ? 1u : 3u));
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
x.emplace(y);
BOOST_TEST(x.size() == is_unique ? 1: 4);
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 4);
BOOST_TEST(x.size() == (is_unique ? 1u : 4u));
BOOST_TEST(x.count(test::get_key<X>(y)) == (is_unique ? 1u : 4u));
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
x.clear();
@@ -420,10 +461,11 @@ void default_emplace_tests(X*, test::random_generator)
x.emplace(y);
BOOST_TEST(x.size() == 1);
x.emplace(y);
BOOST_TEST(x.size() == is_unique ? 1: 2);
BOOST_TEST(x.size() == (is_unique ? 1u : 2u));
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 2);
BOOST_TEST(x.count(test::get_key<X>(y)) == (is_unique ? 1u : 2u));
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
#endif
}
template <class X>
@@ -446,10 +488,11 @@ void map_tests(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
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);
}
@@ -519,57 +562,58 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(unique_insert_tests1,
((test_set_std_alloc)(test_set)(test_map))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(equivalent_insert_tests1,
((test_multimap_std_alloc)(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(insert_tests2,
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(unique_emplace_tests1,
((test_set_std_alloc)(test_set)(test_map))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(equivalent_emplace_tests1,
((test_multimap_std_alloc)(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(move_emplace_tests,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(default_emplace_tests,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(map_tests,
((test_map))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(map_insert_range_test1,
((test_multimap_std_alloc)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(map_insert_range_test2,
((test_multimap_std_alloc)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
@@ -580,7 +624,7 @@ struct initialize_from_two_ints
friend std::size_t hash_value(initialize_from_two_ints const& x)
{
return x.a + x.b;
return static_cast<std::size_t>(x.a + x.b);
}
bool operator==(initialize_from_two_ints const& x) const
@@ -599,7 +643,7 @@ UNORDERED_AUTO_TEST(insert_initializer_list_set)
boost::unordered_set<initialize_from_two_ints> set2;
#if BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4,5,0)
#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5))
set2.insert({{1, 2}});
#else
set2.insert({1, 2});
+3 -2
View File
@@ -51,7 +51,7 @@ void insert_test(X*, float mlf, test::random_generator generator)
BOOST_DEDUCED_TYPENAME X::size_type old_size = x.size(),
old_bucket_count = x.bucket_count();
x.insert(*it);
if(static_cast<double>(old_size + 1) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(old_size + 1) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
}
@@ -78,6 +78,7 @@ boost::unordered_multimap<int, int>* int_multimap_ptr;
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(set_load_factor_tests,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
@@ -85,7 +86,7 @@ UNORDERED_TEST(set_load_factor_tests,
UNORDERED_TEST(load_factor_insert_tests,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}
+1 -1
View File
@@ -18,7 +18,7 @@ struct SimpleAllocator
{
}
template <class T> SimpleAllocator(const SimpleAllocator<T>& other)
template <class T> SimpleAllocator(const SimpleAllocator<T>&)
{
}
+5 -4
View File
@@ -369,6 +369,7 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(move_construct_tests1, (
(test_map_std_alloc)
@@ -376,7 +377,7 @@ boost::unordered_multimap<test::object, test::object,
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(move_assign_tests1, (
(test_map_std_alloc)
@@ -384,21 +385,21 @@ boost::unordered_multimap<test::object, test::object,
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(move_construct_tests2, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(move_assign_tests2, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}
+49 -26
View File
@@ -24,28 +24,6 @@ namespace noexcept_tests
equal_to_possible_exception(equal_to_possible_exception const&) {}
};
UNORDERED_AUTO_TEST(test_noexcept)
{
#if !defined(BOOST_NO_CXX11_NOEXCEPT)
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_set<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multiset<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_map<int, int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multimap<int, int> >::value));
#endif
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_set<int, hash_possible_exception>
>::value));
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_multiset<int, boost::hash<int>,
equal_to_possible_exception>
>::value));
}
// Test that the move constructor does actually move without throwing
// an exception when it claims to.
@@ -70,8 +48,10 @@ namespace noexcept_tests
hash_nothrow_move() { test_throw("Constructor"); }
hash_nothrow_move(hash_nothrow_move const&) { test_throw("Copy"); }
hash_nothrow_move& operator=(hash_nothrow_move const&)
hash_nothrow_move& operator=(BOOST_COPY_ASSIGN_REF(hash_nothrow_move))
{ test_throw("Assign"); return *this; }
hash_nothrow_move& operator=(BOOST_RV_REF(hash_nothrow_move))
{ test_throw("Move Assign"); return *this; }
std::size_t operator()(int x) const
{ test_throw("Operator"); return static_cast<base const&>(*this)(x); }
};
@@ -87,26 +67,69 @@ namespace noexcept_tests
equal_to_nothrow_move() { test_throw("Constructor"); }
equal_to_nothrow_move(equal_to_nothrow_move const&)
{ test_throw("Copy"); }
equal_to_nothrow_move& operator=(equal_to_nothrow_move const&)
equal_to_nothrow_move& operator=(BOOST_COPY_ASSIGN_REF(equal_to_nothrow_move))
{ test_throw("Assign"); return *this; }
equal_to_nothrow_move& operator=(BOOST_RV_REF(equal_to_nothrow_move))
{ test_throw("Move Assign"); return *this; }
std::size_t operator()(int x, int y) const
{ test_throw("Operator"); return static_cast<base const&>(*this)(x, y); }
};
bool have_is_nothrow_move = false;
UNORDERED_AUTO_TEST(check_is_nothrow_move)
{
BOOST_TEST(!boost::is_nothrow_move_constructible<hash_possible_exception>::value);
have_is_nothrow_move = boost::is_nothrow_move_constructible<hash_nothrow_move>::value;
// Copied from boost::is_nothrow_move_constructible implementation
// to make sure this does actually detect it when expected.
//
// The type trait is also available when BOOST_IS_NOTHROW_MOVE_CONSTRUCT
// is defined (for some versions of Visual C++?) but detects 'throw()',
// not noexcept.
#if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
BOOST_TEST(have_is_nothrow_move);
#endif
}
UNORDERED_AUTO_TEST(test_noexcept)
{
if (have_is_nothrow_move) {
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_set<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multiset<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_map<int, int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multimap<int, int> >::value));
}
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_set<int, hash_possible_exception>
>::value));
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_multiset<int, boost::hash<int>,
equal_to_possible_exception>
>::value));
}
UNORDERED_AUTO_TEST(test_no_throw_when_noexcept)
{
typedef boost::unordered_set<int,
hash_nothrow_move, equal_to_nothrow_move> throwing_set;
if (boost::is_nothrow_move_constructible<throwing_set>::value)
if (have_is_nothrow_move)
{
BOOST_TEST(boost::is_nothrow_move_constructible<throwing_set>::value);
throwing_test_exception = false;
throwing_set x1;
x1.insert(10);
x1.insert(50);
try {
throwing_test_exception = true;
+9 -11
View File
@@ -22,7 +22,7 @@ test::seed_t initialize_seed(2974);
template <class X>
bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n)
{
return static_cast<double>(x.bucket_count()) >
return static_cast<double>(x.bucket_count()) >=
static_cast<double>(x.size()) / x.max_load_factor() &&
x.bucket_count() >= n;
}
@@ -139,7 +139,7 @@ void reserve_test1(X*, test::random_generator generator)
{
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
{
for (int i = 1; i < 2000; i += i < 50 ? 1 : 13)
for (std::size_t i = 1; i < 2000; i += i < 50 ? 1 : 13)
{
test::random_values<X> v(i, generator);
@@ -149,9 +149,6 @@ void reserve_test1(X*, test::random_generator generator)
X x;
x.max_load_factor(random_mlf ?
static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f : 1.0f);
// For the current standard this should reserve i+1, I've
// submitted a defect report and will assume it's a defect
// for now.
x.reserve(test::has_unique_keys<X>::value ? i : v.size());
// Insert an element before the range insert, otherwise there are
@@ -174,7 +171,7 @@ void reserve_test2(X*, test::random_generator generator)
{
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
{
for (int i = 0; i < 2000; i += i < 50 ? 1 : 13)
for (std::size_t i = 0; i < 2000; i += i < 50 ? 1 : 13)
{
test::random_values<X> v(i, generator);
@@ -211,21 +208,22 @@ boost::unordered_multimap<int, int>* int_multimap_ptr;
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(rehash_empty_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
)
UNORDERED_TEST(rehash_empty_test2,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(rehash_empty_test3,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(rehash_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(reserve_empty_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
@@ -235,11 +233,11 @@ UNORDERED_TEST(reserve_empty_test2,
)
UNORDERED_TEST(reserve_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(reserve_test2,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}
+3 -2
View File
@@ -206,6 +206,7 @@ bool is_propagate(T*)
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_AUTO_TEST(check_traits)
{
@@ -220,7 +221,7 @@ UNORDERED_TEST(swap_tests1, (
(test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
(test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(swap_tests2, (
@@ -228,7 +229,7 @@ UNORDERED_TEST(swap_tests2, (
(test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
(test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}
+1 -1
View File
@@ -115,7 +115,7 @@ namespace unnecessary_copy_tests
#endif
{
std::size_t hash_value(unnecessary_copy_tests::count_copies const& x) {
return x.tag_;
return static_cast<std::size_t>(x.tag_);
}
}