Merge branch 'develop'

This commit is contained in:
Daniel James
2017-06-11 20:54:52 +01:00
49 changed files with 5397 additions and 3995 deletions

View File

@ -18,49 +18,47 @@ addons:
matrix:
include:
- compiler: gcc
env: BJAM_TOOLSET=gcc
env: |
label="gcc C++03";
user_config="using gcc : : g++-4.8 --coverage -fsanitize=address -Werror --std=c++03 ;"
enable_coverage=1
- compiler: gcc
env: BJAM_TOOLSET=gcc-std11
#- compiler: gcc
# env: BJAM_TOOLSET=gcc-m32
env: |
label="gcc C++11";
user_config="using gcc : : g++-4.8 --coverage -fsanitize=address -Werror --std=c++11 ;"
enable_coverage=1
- compiler: gcc
env: BJAM_TOOLSET=gcc-std11m32
#- compiler: clang
# env: BJAM_TOOLSET=clang
env: |
label="gcc 32 bit C++11";
user_config="using gcc : : g++-4.8 -m32 -fsanitize=address -Werror --std=c++11 ;"
- compiler: clang
env: BJAM_TOOLSET=clang-std11
env: |
label="clang C++11";
user_config="using clang : : clang++ -fsanitize=address -Werror --std=c++11 ;"
# sanitized=address not available for 32-bit clang on travis.
- compiler: clang
env: BJAM_TOOLSET=clang-m32
#- compiler: clang
# env: BJAM_TOOLSET=clang-std11m32
- compiler: gcc
env: BJAM_TOOLSET=gcc-interopable
- compiler: clang
env: BJAM_TOOLSET=clang-interopable
env: |
label="clang 32 bit";
user_config="using clang : : clang++ -m32 -Werror --std=c++03 ;"
before_install:
- if [ -n $enable_coverage ]; then pip install --user cpp-coveralls; fi
before_script:
- cd ${TRAVIS_BUILD_DIR}
- touch Jamroot.jam
- cd $HOME
- |
echo "using gcc : : g++-4.8 -Werror --std=c++03 -fsanitize=address ;" > ~/user-config.jam
echo "using gcc : std11 : g++-4.8 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam
echo "using gcc : m32 : g++-4.8 -m32 -Werror -fsanitize=address ;" >> ~/user-config.jam
echo "using gcc : std11m32 : g++-4.8 -m32 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam
echo "using clang : : clang++ -Werror --std=c++03 -fsanitize=address ;" >> ~/user-config.jam
echo "using clang : std11 : clang++ -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam
# sanitized=address not available for 32-bit clang on travis.
echo "using clang : m32 : clang++ -m32 -Werror --std=c++03 ;" >> ~/user-config.jam
echo "using clang : std11m32 : clang++ -m32 -Werror --std=c++11 ;" >> ~/user-config.jam
echo "using gcc : interopable : g++-4.8 -Werror --std=c++03 -fsanitize=address -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" >> ~/user-config.jam
echo "using clang : interopable : clang++ -Werror --std=c++11 -fsanitize=address -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" >> ~/user-config.jam
- echo $user_config > ~/user-config.jam
- cat ~/user-config.jam
- wget -O boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.63.0/boost_1_63_0.tar.bz2
- wget -O boost.tar.bz2 https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2
- tar -xjf boost.tar.bz2
- mv boost_1_63_0 boost
- mv boost_1_64_0 boost
- rm -r boost/boost/unordered
after_success:
if [ -n $enable_coverage ]; then coveralls -r ${TRAVIS_BUILD_DIR} -b ${TRAVIS_BUILD_DIR}/test --gcov-options '\-lp' --include include/boost/unordered/ ; fi
script:
- cd ${TRAVIS_BUILD_DIR}/test
- bjam ${BJAM_TOOLSET} include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include
- bjam -q include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include
- xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml

View File

@ -99,7 +99,7 @@ First official release.
has been rewritten to use templates instead of macros for the implementation
classes.
* The container objcet is now smaller thanks to using `boost::compressed_pair`
* The container object is now smaller thanks to using `boost::compressed_pair`
for EBO and a slightly different function buffer - now using a bool instead
of a member pointer.
@ -170,7 +170,7 @@ C++11 support has resulted in some breaking changes:
longer does so. It does emulate the new `piecewise_construct`
pair constructors - only you need to use
`boost::piecewise_construct`. To use the old emulation of
the variadic consturctors define
the variadic constructors define
`BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT`.
[h2 Boost 1.49.0]
@ -207,7 +207,7 @@ C++11 support has resulted in some breaking changes:
* Fix construction/destruction issue when using a C++11 compiler with a
C++03 allocator ([ticket 7100]).
* Remove a `try..catch` to support compiling without exceptions.
* Adjust SFINAE use to try to supprt g++ 3.4 ([ticket 7175]).
* Adjust SFINAE use to try to support g++ 3.4 ([ticket 7175]).
* Updated to use the new config macros.
[h2 Boost 1.52.0]
@ -307,9 +307,17 @@ C++11 support has resulted in some breaking changes:
* Initial support for new C++17 member functions:
`insert_or_assign` and `try_emplace` in `unordered_map`,
* Initial support for `merge` and `extract`.
Does not include transfering nodes between
Does not include transferring nodes between
`unordered_map` and `unordered_multimap` or between `unordered_set` and
`unordered_multiset` yet. That will hopefully be in the next version of
Boost.
[h2 Boost 1.65.0]
* Add deprecated attributes to `quick_erase` and `erase_return_void`.
I really will remove them in a future version this time.
* Small standards compliance fixes:
* `noexpect` specs for `swap` free functions.
* Add missing `insert(P&&)` methods.
[endsect]

View File

@ -2,7 +2,13 @@
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
[section:compliance C++11 Compliance]
[section:compliance Standard Compliance]
The intent of Boost.Unordered is to implement a close (but inperfect)
implementation of the C++17 standard, that will work with C++98 upwards.
The wide compatibility does mean some comprimises have to be made.
With a compiler and library that fully support C++11, the differences should
be minor.
[section:move Move emulation]
@ -51,23 +57,32 @@ Due to imperfect move emulation, some assignments might check
`propagate_on_container_copy_assignment` on some compilers and
`propagate_on_container_move_assignment` on others.
The use of the allocator's construct and destruct methods might be a bit
surprising.
Nodes are constructed and destructed using the allocator, but the elements
are stored in aligned space within the node and constructed and destructed
by calling the constructor and destructor directly.
[endsect]
In C++11 the allocator's construct function has the signature:
[section:construction Construction/Destruction using allocators]
template <class U, class... Args>
void construct(U* p, Args&&... args);
The following support is required for full use of C++11 style
construction/destruction:
which supports calling `construct` for the contained object, but
most existing allocators don't support this. If member function detection
was good enough then with old allocators it would fall back to calling
the element's constructor directly but in general, detection isn't good
enough to do this which is why Boost.Unordered just calls the constructor
directly every time. In most cases this will work okay.
* Variadic templates.
* Piecewise construction of `std::pair`.
* Either `std::allocator_traits` or expression SFINAE.
This is detected using Boost.Config. The macro
`BOOST_UNORDERED_CXX11_CONSTRUCTION` will be set to 1 if it is found, or 0
otherwise.
When this is the case `allocator_traits::construct` and
`allocator_traits::destroy` will always be used, apart from when piecewise
constructing a `std::pair` using `boost::tuple` (see [link
unordered.compliance.pairs below]), but that should be easily avoided.
When support is not available `allocator_traits::construct` and
`allocator_traits::destroy` are never called.
[endsect]
[section:pointer_traits Pointer Traits]
`pointer_traits` aren't used. Instead, pointer types are obtained from
rebound allocators, this can cause problems if the allocator can't be
@ -77,6 +92,7 @@ is used to obtain a const pointer.
[endsect]
[#unordered.compliance.pairs]
[section:pairs Pairs]
Since the containers use `std::pair` they're limited to the version

View File

@ -13,7 +13,7 @@ containers in the draft standard, so the interface was fixed. But there are
still some implementation decisions to make. The priorities are
conformance to the standard and portability.
The [@http://en.wikipedia.org/wiki/Hash_table wikipedia article on hash tables]
The [@http://en.wikipedia.org/wiki/Hash_table Wikipedia article on hash tables]
has a good summary of the implementation issues for hash tables in general.
[h2 Data Structure]
@ -100,7 +100,7 @@ knowledge of the number of bits in the hash value, so it isn't portable enough
to use as a default. It can applicable in certain cases so the containers
have a policy based implementation that can use this alternative technique.
Currently this is only done on 64 bit architecures, where prime number
Currently this is only done on 64 bit architectures, where prime number
modulus can be expensive. Although this varies depending on the architecture,
so I probably should revisit it.

View File

@ -20,7 +20,7 @@
#endif
#elif defined(_LIBCPP_VERSION)
// https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206
#if LIBCPP_VERSION >= 3000
#if _LIBCPP_VERSION >= 3000
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
#endif
#elif defined(BOOST_MSVC)
@ -32,6 +32,8 @@
#endif
#endif
// TODO: Use piecewise construction by default? Is it safe to assume that an
// unknown library has it?
#if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 0
#endif

File diff suppressed because it is too large Load Diff

View File

@ -27,65 +27,22 @@ template <typename A, typename K, typename M, typename H, typename P> struct map
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef typename pick::node_algo node_algo;
typedef boost::unordered::detail::table_impl<types> table;
typedef boost::unordered::detail::table<types> table;
typedef boost::unordered::detail::map_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
typedef boost::unordered::iterator_detail::iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::l_iterator<node, policy>
l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
cl_iterator;
typedef boost::unordered::iterator_detail::l_iterator<node> l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node> cl_iterator;
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
typedef boost::unordered::insert_return_type_map<node, K, M, A>
insert_return_type;
};
template <typename A, typename K, typename M, typename H, typename P>
struct multimap
{
typedef boost::unordered::detail::multimap<A, K, M, H, P> types;
typedef std::pair<K const, M> value_type;
typedef H hasher;
typedef P key_equal;
typedef K const const_key_type;
typedef typename ::boost::unordered::detail::rebind_wrap<A,
value_type>::type value_allocator;
typedef boost::unordered::detail::allocator_traits<value_allocator>
value_allocator_traits;
#if BOOST_UNORDERED_INTEROPERABLE_NODES
typedef boost::unordered::detail::pick_node<A, value_type> pick;
#else
typedef boost::unordered::detail::pick_grouped_node<A, value_type> pick;
#endif
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef typename pick::node_algo node_algo;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::map_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
typedef boost::unordered::iterator_detail::iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::l_iterator<node, policy>
l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
cl_iterator;
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
};
template <typename K, typename M, typename H, typename P, typename A>
class instantiate_map
{

View File

@ -27,64 +27,22 @@ template <typename A, typename T, typename H, typename P> struct set
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef typename pick::node_algo node_algo;
typedef boost::unordered::detail::table_impl<types> table;
typedef boost::unordered::detail::table<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
typedef boost::unordered::iterator_detail::c_iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
cl_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node> l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node> cl_iterator;
typedef boost::unordered::node_handle_set<node, T, A> node_type;
typedef boost::unordered::insert_return_type_set<node, T, A>
insert_return_type;
};
template <typename A, typename T, typename H, typename P> struct multiset
{
typedef boost::unordered::detail::multiset<A, T, H, P> types;
typedef T value_type;
typedef H hasher;
typedef P key_equal;
typedef T const const_key_type;
typedef typename ::boost::unordered::detail::rebind_wrap<A,
value_type>::type value_allocator;
typedef boost::unordered::detail::allocator_traits<value_allocator>
value_allocator_traits;
#if BOOST_UNORDERED_INTEROPERABLE_NODES
typedef boost::unordered::detail::pick_node<A, value_type> pick;
#else
typedef boost::unordered::detail::pick_grouped_node<A, value_type> pick;
#endif
typedef typename pick::node node;
typedef typename pick::bucket bucket;
typedef typename pick::link_pointer link_pointer;
typedef typename pick::node_algo node_algo;
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
typedef boost::unordered::iterator_detail::c_iterator<node> iterator;
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
l_iterator;
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
cl_iterator;
typedef boost::unordered::node_handle_set<node, T, A> node_type;
};
template <typename T, typename H, typename P, typename A> class instantiate_set
{
typedef boost::unordered_set<T, H, P, A> container;

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,9 @@ template <class K, class T, class H, class P, class A>
inline bool operator!=(
unordered_map<K, T, H, P, A> const&, unordered_map<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline void swap(unordered_map<K, T, H, P, A>&, unordered_map<K, T, H, P, A>&);
inline void swap(
unordered_map<K, T, H, P, A>& m1, unordered_map<K, T, H, P, A>& m2)
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
template <class K, class T, class H = boost::hash<K>,
class P = std::equal_to<K>,
@ -44,8 +46,9 @@ template <class K, class T, class H, class P, class A>
inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
unordered_multimap<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline void swap(
unordered_multimap<K, T, H, P, A>&, unordered_multimap<K, T, H, P, A>&);
inline void swap(unordered_multimap<K, T, H, P, A>& m1,
unordered_multimap<K, T, H, P, A>& m2)
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
template <class N, class K, class T, class A> class node_handle_map;
template <class N, class K, class T, class A> struct insert_return_type_map;

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,8 @@ template <class T, class H, class P, class A>
inline bool operator!=(
unordered_set<T, H, P, A> const&, unordered_set<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline void swap(unordered_set<T, H, P, A>& m1, unordered_set<T, H, P, A>& m2);
inline void swap(unordered_set<T, H, P, A>& m1, unordered_set<T, H, P, A>& m2)
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
template <class T, class H = boost::hash<T>, class P = std::equal_to<T>,
class A = std::allocator<T> >
@ -43,7 +44,8 @@ inline bool operator!=(unordered_multiset<T, H, P, A> const&,
unordered_multiset<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline void swap(
unordered_multiset<T, H, P, A>& m1, unordered_multiset<T, H, P, A>& m2);
unordered_multiset<T, H, P, A>& m1, unordered_multiset<T, H, P, A>& m2)
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
template <class N, class T, class A> class node_handle_set;
template <class N, class T, class A> struct insert_return_type_set;

View File

@ -15,6 +15,7 @@ project unordered-test/unordered
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
<toolset>clang:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow"
<toolset>msvc:<cxxflags>"/wd4494"
<toolset>gcc:<c++-template-depth>500
;
#alias framework : /boost/test//boost_unit_test_framework ;
@ -45,7 +46,7 @@ test-suite unordered
[ run unordered/insert_hint_tests.cpp ]
[ run unordered/emplace_tests.cpp ]
[ run unordered/unnecessary_copy_tests.cpp ]
[ run unordered/erase_tests.cpp ]
[ run unordered/erase_tests.cpp : : : <define>BOOST_UNORDERED_SUPPRESS_DEPRECATED ]
[ run unordered/erase_equiv_tests.cpp ]
[ run unordered/extract_tests.cpp ]
[ run unordered/node_handle_tests.cpp ]
@ -61,6 +62,7 @@ test-suite unordered
[ run unordered/rehash_tests.cpp ]
[ run unordered/equality_tests.cpp ]
[ run unordered/swap_tests.cpp ]
[ run unordered/detail_tests.cpp ]
[ run unordered/compile_set.cpp : :
: <define>BOOST_UNORDERED_USE_MOVE
@ -90,4 +92,5 @@ test-suite unordered-exception
[ run exception/rehash_exception_tests.cpp framework ]
[ run exception/swap_exception_tests.cpp framework : : :
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
[ run exception/merge_exception_tests.cpp framework ]
;

View File

@ -7,6 +7,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable : 4512) // assignment operator could not be generated
@ -17,11 +18,22 @@ test::seed_t initialize_seed(12847);
template <class T> struct self_assign_base : public test::exception_base
{
test::random_values<T> values;
self_assign_base(std::size_t count = 0) : values(count) {}
self_assign_base(std::size_t count = 0) : values(count, test::limited_range)
{
}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
void run(T& x) const { x = x; }
void run(T& x) const
{
x = x;
DISABLE_EXCEPTIONS;
test::check_container(x, values);
test::check_equivalent_keys(x);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
test::check_equivalent_keys(x);
@ -57,7 +69,16 @@ template <class T> struct assign_base : public test::exception_base
typedef T data_type;
T init() const { return T(x); }
void run(T& x1) const { x1 = y; }
void run(T& x1) const
{
x1 = y;
DISABLE_EXCEPTIONS;
test::check_container(x1, y_values);
test::check_equivalent_keys(x1);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
{
test::check_equivalent_keys(x1);
@ -76,11 +97,12 @@ template <class T> struct assign_base : public test::exception_base
template <class T> struct assign_values : assign_base<T>
{
assign_values(unsigned int count1, unsigned int count2, int tag1, int tag2,
float mlf1 = 1.0, float mlf2 = 1.0)
test::random_generator gen = test::default_generator, float mlf1 = 1.0,
float mlf2 = 1.0)
: assign_base<T>(tag1, tag2, mlf1, mlf2)
{
this->x_values.fill(count1);
this->y_values.fill(count2);
this->x_values.fill(count1, gen);
this->y_values.fill(count2, gen);
this->x.insert(this->x_values.begin(), this->x_values.end());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
@ -96,11 +118,21 @@ template <class T> struct assign_test2 : assign_values<T>
assign_test2() : assign_values<T>(60, 0, 0, 0) {}
};
template <class T> struct assign_test2a : assign_values<T>
{
assign_test2a() : assign_values<T>(60, 0, 0, 0, test::limited_range) {}
};
template <class T> struct assign_test3 : assign_values<T>
{
assign_test3() : assign_values<T>(0, 60, 0, 0) {}
};
template <class T> struct assign_test3a : assign_values<T>
{
assign_test3a() : assign_values<T>(0, 60, 0, 0, test::limited_range) {}
};
template <class T> struct assign_test4 : assign_values<T>
{
assign_test4() : assign_values<T>(10, 10, 1, 2) {}
@ -111,9 +143,17 @@ template <class T> struct assign_test4a : assign_values<T>
assign_test4a() : assign_values<T>(10, 100, 1, 2) {}
};
template <class T> struct assign_test4b : assign_values<T>
{
assign_test4b() : assign_values<T>(10, 100, 1, 2, test::limited_range) {}
};
template <class T> struct assign_test5 : assign_values<T>
{
assign_test5() : assign_values<T>(5, 60, 0, 0, 1.0f, 0.1f) {}
assign_test5()
: assign_values<T>(5, 60, 0, 0, test::default_generator, 1.0f, 0.1f)
{
}
};
template <class T> struct equivalent_test1 : assign_base<T>
@ -131,8 +171,15 @@ template <class T> struct equivalent_test1 : assign_base<T>
}
};
EXCEPTION_TESTS((self_assign_test1)(self_assign_test2)(assign_test1)(
assign_test2)(assign_test3)(assign_test4)(assign_test4a)(
assign_test5)(equivalent_test1),
// clang-format off
EXCEPTION_TESTS_REPEAT(5,
(self_assign_test1)(self_assign_test2)
(assign_test1)(assign_test2)(assign_test2a)
(assign_test3)(assign_test3a)
(assign_test4)(assign_test4a)(assign_test4b)
(assign_test5)
(equivalent_test1),
CONTAINER_SEQ)
// clang-format on
RUN_TESTS()

View File

@ -6,7 +6,9 @@
#include "./containers.hpp"
#include "../helpers/input_iterator.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
template <typename T> inline void avoid_unused_warning(T const&) {}
@ -25,7 +27,10 @@ template <class T> struct construct_test1 : public objects, test::exception_base
void run() const
{
T x;
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -34,7 +39,10 @@ template <class T> struct construct_test2 : public objects, test::exception_base
void run() const
{
T x(300);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -43,7 +51,10 @@ template <class T> struct construct_test3 : public objects, test::exception_base
void run() const
{
T x(0, hash);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -52,7 +63,10 @@ template <class T> struct construct_test4 : public objects, test::exception_base
void run() const
{
T x(0, hash, equal_to);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -61,7 +75,10 @@ template <class T> struct construct_test5 : public objects, test::exception_base
void run() const
{
T x(50, hash, equal_to, allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -70,7 +87,10 @@ template <class T> struct construct_test6 : public objects, test::exception_base
void run() const
{
T x(allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -78,8 +98,8 @@ template <class T> struct range : public test::exception_base
{
test::random_values<T> values;
range() : values(5) {}
range(unsigned int count) : values(count) {}
range() : values(5, test::limited_range) {}
range(unsigned int count) : values(count, test::limited_range) {}
};
template <class T> struct range_construct_test1 : public range<T>, objects
@ -87,7 +107,10 @@ template <class T> struct range_construct_test1 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end());
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -96,7 +119,10 @@ template <class T> struct range_construct_test2 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end(), 0);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -105,7 +131,10 @@ template <class T> struct range_construct_test3 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end(), 0, hash);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -114,7 +143,10 @@ template <class T> struct range_construct_test4 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end(), 100, hash, equal_to);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -128,7 +160,10 @@ template <class T> struct range_construct_test5 : public range<T>, objects
{
T x(this->values.begin(), this->values.end(), 0, hash, equal_to,
allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -143,7 +178,10 @@ template <class T> struct input_range_construct_test : public range<T>, objects
end = this->values.end();
T x(test::input_iterator(begin), test::input_iterator(end), 0, hash,
equal_to, allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -156,7 +194,10 @@ template <class T> struct copy_range_construct_test : public range<T>, objects
T x(test::copy_iterator(this->values.begin()),
test::copy_iterator(this->values.end()), 0, hash, equal_to,
allocator);
avoid_unused_warning(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};

View File

@ -5,7 +5,9 @@
#include "./containers.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
template <typename T> inline void avoid_unused_warning(T const&) {}
@ -18,7 +20,10 @@ template <class T> struct copy_test1 : public test::exception_base
void run() const
{
T y(x);
avoid_unused_warning(y);
DISABLE_EXCEPTIONS;
BOOST_TEST(y.empty());
test::check_equivalent_keys(y);
}
};
@ -27,12 +32,18 @@ template <class T> struct copy_test2 : public test::exception_base
test::random_values<T> values;
T x;
copy_test2() : values(5), x(values.begin(), values.end()) {}
copy_test2()
: values(5, test::limited_range), x(values.begin(), values.end())
{
}
void run() const
{
T y(x);
avoid_unused_warning(y);
DISABLE_EXCEPTIONS;
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
@ -46,7 +57,30 @@ template <class T> struct copy_test3 : public test::exception_base
void run() const
{
T y(x);
avoid_unused_warning(y);
DISABLE_EXCEPTIONS;
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
template <class T> struct copy_test3a : public test::exception_base
{
test::random_values<T> values;
T x;
copy_test3a()
: values(100, test::limited_range), x(values.begin(), values.end())
{
}
void run() const
{
T y(x);
DISABLE_EXCEPTIONS;
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
@ -61,10 +95,17 @@ template <class T> struct copy_with_allocator_test : public test::exception_base
void run() const
{
T y(x, allocator);
avoid_unused_warning(y);
DISABLE_EXCEPTIONS;
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
EXCEPTION_TESTS((copy_test1)(copy_test2)(copy_test3)(copy_with_allocator_test),
// clang-format off
EXCEPTION_TESTS(
(copy_test1)(copy_test2)(copy_test3)(copy_test3a)(copy_with_allocator_test),
CONTAINER_SEQ)
// clang-format on
RUN_TESTS()

View File

@ -14,7 +14,9 @@ test::seed_t initialize_seed(835193);
template <class T> struct erase_test_base : public test::exception_base
{
test::random_values<T> values;
erase_test_base(unsigned int count = 5) : values(count) {}
erase_test_base(unsigned int count = 5) : values(count, test::limited_range)
{
}
typedef T data_type;
@ -43,6 +45,10 @@ template <class T> struct erase_by_key_test1 : public erase_test_base<T>
it != end; ++it) {
x.erase(test::get_key<T>(*it));
}
DISABLE_EXCEPTIONS;
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};

View File

@ -2,306 +2,414 @@
// Copyright 2006-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "./containers.hpp"
#include "../helpers/helpers.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/strong.hpp"
#include "../helpers/tracker.hpp"
#include <cmath>
#include <string>
test::seed_t initialize_seed(747373);
template <class T> struct insert_test_base : public test::exception_base
// Fill in a container so that it's about to rehash
template <typename T> void rehash_prep(T& x)
{
test::random_values<T> values;
insert_test_base(unsigned int count = 5)
: values(count, test::limited_range)
{
using namespace std;
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
x.max_load_factor(0.25);
size_type bucket_count = x.bucket_count();
size_type initial_elements = static_cast<size_type>(
ceil((double)bucket_count * (double)x.max_load_factor()) - 1);
test::random_values<T> v(initial_elements);
x.insert(v.begin(), v.end());
BOOST_TEST(bucket_count == x.bucket_count());
}
// Overload to generate inserters that need type information.
template <typename Inserter, typename T>
Inserter generate(Inserter inserter, T&)
{
return inserter;
}
// Get the iterator returned from an insert/emplace.
template <typename T> T get_iterator(T const& x) { return x; }
template <typename T> T get_iterator(std::pair<T, bool> const& x)
{
return x.first;
}
// Generic insert exception test for typical single element inserts..
template <typename T, typename Inserter, typename Values>
void insert_exception_test_impl(T x, Inserter insert, Values const& v)
{
test::strong<T> strong;
test::ordered<T> tracker;
tracker.insert(x.begin(), x.end());
try {
ENABLE_EXCEPTIONS;
for (typename Values::const_iterator it = v.begin(); it != v.end();
++it) {
strong.store(x, test::detail::tracker.count_allocations);
insert(x, it);
}
} catch (...) {
test::check_equivalent_keys(x);
insert.exception_check(x, strong);
throw;
}
typedef T data_type;
typedef test::strong<T> strong_type;
test::check_equivalent_keys(x);
insert.track(tracker, v.begin(), v.end());
tracker.compare(x);
}
data_type init() const { return T(); }
// Simple insert exception test
void check BOOST_PREVENT_MACRO_SUBSTITUTION(
T const& x, strong_type const& strong) const
template <typename T, typename Inserter>
void insert_exception_test(T*, Inserter insert, test::random_generator gen)
{
for (int i = 0; i < 5; ++i) {
test::random_values<T> v(10, gen);
T x;
EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v));
}
}
// Insert into a container which is about to hit its max load, so that it
// rehashes.
template <typename T, typename Inserter>
void insert_rehash_exception_test(
T*, Inserter insert, test::random_generator gen)
{
for (int i = 0; i < 5; ++i) {
T x;
rehash_prep(x);
test::random_values<T> v2(5, gen);
EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v2));
}
}
// Various methods for inserting a single element
struct inserter_base
{
template <typename T> void exception_check(T& x, test::strong<T>& strong)
{
std::string scope(test::scope);
if (scope.find("hash::operator()") == std::string::npos)
strong.test(x, test::detail::tracker.count_allocations);
}
template <typename T, typename Iterator>
void track(T& tracker, Iterator begin, Iterator end)
{
tracker.insert(begin, end);
}
};
struct insert_lvalue_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert(*it);
}
} insert_lvalue;
struct insert_lvalue_begin_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert(x.begin(), *it);
}
} insert_lvalue_begin;
struct insert_lvalue_end_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert(x.end(), *it);
}
} insert_lvalue_end;
struct insert_lvalue_pos_type
{
template <typename T> struct impl : inserter_base
{
typename T::iterator pos;
impl(T& x) : pos(x.begin()) {}
template <typename Iterator> void operator()(T& x, Iterator it)
{
pos = get_iterator(x.insert(pos, *it));
}
};
template <typename T> friend impl<T> generate(insert_lvalue_pos_type, T& x)
{
return impl<T>(x);
}
} insert_lvalue_pos;
struct insert_single_item_range_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert(it, test::next(it));
}
} insert_single_item_range;
struct emplace_lvalue_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace(*it);
}
} emplace_lvalue;
struct emplace_lvalue_begin_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace_hint(x.begin(), *it);
}
} emplace_lvalue_begin;
struct emplace_lvalue_end_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace_hint(x.end(), *it);
}
} emplace_lvalue_end;
struct emplace_lvalue_pos_type
{
template <typename T> struct impl : inserter_base
{
typename T::iterator pos;
impl(T& x) : pos(x.begin()) {}
template <typename Iterator> void operator()(T& x, Iterator it)
{
pos = get_iterator(x.emplace_hint(pos, *it));
}
};
template <typename T> friend impl<T> generate(emplace_lvalue_pos_type, T& x)
{
return impl<T>(x);
}
} emplace_lvalue_pos;
// Run the exception tests in various combinations.
test_set* test_set_;
test_multiset* test_multiset_;
test_map* test_map_;
test_multimap* test_multimap_;
using test::default_generator;
using test::limited_range;
using test::generate_collisions;
// clang-format off
UNORDERED_TEST(insert_exception_test,
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
(insert_lvalue_pos)(insert_single_item_range)
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
(emplace_lvalue_pos)
)
((default_generator)(limited_range)(generate_collisions))
)
UNORDERED_TEST(insert_rehash_exception_test,
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
(insert_lvalue_pos)(insert_single_item_range)
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
(emplace_lvalue_pos)
)
((default_generator)(limited_range)(generate_collisions))
)
// clang-format on
// Repeat insert tests with pairs
struct pair_emplace_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(it->first), boost::make_tuple(it->second));
}
} pair_emplace;
struct pair_emplace2_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.emplace_hint(x.begin(), boost::unordered::piecewise_construct,
boost::make_tuple(it->first),
boost::make_tuple(it->second.tag1_, it->second.tag2_));
}
} pair_emplace2;
test_pair_set* test_pair_set_;
test_pair_multiset* test_pair_multiset_;
// clang-format off
UNORDERED_TEST(insert_exception_test,
((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
((pair_emplace)(pair_emplace2))
((default_generator)(limited_range)(generate_collisions))
)
UNORDERED_TEST(insert_rehash_exception_test,
((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
((pair_emplace)(pair_emplace2))
((default_generator)(limited_range)(generate_collisions))
)
// clang-format on
// Test inserting using operator[]
struct try_emplace_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.try_emplace(it->first, it->second);
}
} try_emplace;
struct try_emplace2_type : inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.try_emplace(it->first, it->second.tag1_, it->second.tag2_);
}
} try_emplace2;
struct map_inserter_base
{
template <typename T> void exception_check(T& x, test::strong<T>& strong)
{
std::string scope(test::scope);
if (scope.find("hash::operator()") == std::string::npos &&
scope.find("::operator=") == std::string::npos)
strong.test(x, test::detail::tracker.count_allocations);
}
template <typename T, typename Iterator>
void track(T& tracker, Iterator begin, Iterator end)
{
for (; begin != end; ++begin) {
tracker[begin->first] = begin->second;
}
}
};
struct map_insert_operator_type : map_inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x[it->first] = it->second;
}
} map_insert_operator;
struct map_insert_or_assign_type : map_inserter_base
{
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
{
x.insert_or_assign(it->first, it->second);
}
} map_insert_or_assign;
// clang-format off
UNORDERED_TEST(insert_exception_test,
((test_map_))
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
((default_generator)(limited_range)(generate_collisions))
)
UNORDERED_TEST(insert_rehash_exception_test,
((test_map_))
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
((default_generator)(limited_range)(generate_collisions))
)
// clang-format on
// Range insert tests
template <typename T, typename Values>
void insert_range_exception_test_impl(T x, Values const& v)
{
test::ordered<T> tracker;
tracker.insert(x.begin(), x.end());
try {
ENABLE_EXCEPTIONS;
x.insert(v.begin(), v.end());
} catch (...) {
test::check_equivalent_keys(x);
throw;
}
};
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
test::check_equivalent_keys(x);
tracker.insert(v.begin(), v.end());
tracker.compare(x);
}
template <class T> struct emplace_test1 : public insert_test_base<T>
template <typename T>
void insert_range_exception_test(T*, test::random_generator gen)
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.emplace(*it);
}
}
};
#endif
template <class T> struct insert_test1 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.insert(*it);
}
}
};
template <class T> struct insert_test2 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.insert(x.begin(), *it);
}
}
};
template <class T> struct insert_test3 : public insert_test_base<T>
{
void run(T& x) const { x.insert(this->values.begin(), this->values.end()); }
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
test::check_equivalent_keys(x);
}
};
template <class T> struct insert_test4 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.insert(it, test::next(it));
}
}
};
template <class T> struct insert_test_rehash1 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
insert_test_rehash1() : insert_test_base<T>(1000) {}
T init() const
{
using namespace std;
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
for (int i = 0; i < 5; ++i) {
test::random_values<T> v(10, gen);
T x;
x.max_load_factor(0.25);
// TODO: This doesn't really work is bucket_count is 0
size_type bucket_count = x.bucket_count();
size_type initial_elements = static_cast<size_type>(
ceil((double)bucket_count * (double)x.max_load_factor()) - 1);
BOOST_TEST(initial_elements < this->values.size());
x.insert(this->values.begin(),
test::next(this->values.begin(), initial_elements));
BOOST_TEST(bucket_count == x.bucket_count());
return x;
EXCEPTION_LOOP(insert_range_exception_test_impl(x, v));
}
}
void run(T& x, strong_type& strong) const
{
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
int count = 0;
BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin();
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count) {
strong.store(x, test::detail::tracker.count_allocations);
pos = x.insert(pos, *it);
}
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_TEST(x.bucket_count() != bucket_count);
}
};
template <class T> struct insert_test_rehash2 : public insert_test_rehash1<T>
template <typename T>
void insert_range_rehash_exception_test(T*, test::random_generator gen)
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
int count = 0;
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count) {
strong.store(x, test::detail::tracker.count_allocations);
x.insert(*it);
}
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_TEST(x.bucket_count() != bucket_count);
}
};
template <class T> struct insert_test_rehash3 : public insert_test_base<T>
{
BOOST_DEDUCED_TYPENAME T::size_type mutable rehash_bucket_count,
original_bucket_count;
insert_test_rehash3() : insert_test_base<T>(1000) {}
T init() const
{
using namespace std;
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
for (int i = 0; i < 5; ++i) {
T x;
x.max_load_factor(0.25);
rehash_prep(x);
original_bucket_count = x.bucket_count();
rehash_bucket_count =
static_cast<size_type>(ceil(
(double)original_bucket_count * (double)x.max_load_factor())) -
1;
size_type initial_elements =
rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1;
BOOST_TEST(initial_elements < this->values.size());
x.insert(this->values.begin(),
test::next(this->values.begin(), initial_elements));
BOOST_TEST(original_bucket_count == x.bucket_count());
return x;
test::random_values<T> v2(5, gen);
EXCEPTION_LOOP(insert_range_exception_test_impl(x, v2));
}
}
void run(T& x) const
{
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
// clang-format off
UNORDERED_TEST(insert_range_exception_test,
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
((default_generator)(limited_range)(generate_collisions))
)
x.insert(test::next(this->values.begin(), x.size()),
test::next(this->values.begin(), x.size() + 20));
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_TEST(x.bucket_count() != bucket_count);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
if (x.size() < rehash_bucket_count) {
// BOOST_TEST(x.bucket_count() == original_bucket_count);
}
test::check_equivalent_keys(x);
}
};
#define BASIC_TESTS \
(insert_test1)(insert_test2)(insert_test3)(insert_test4)( \
insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#define ALL_TESTS (emplace_test1) BASIC_TESTS
#else
#define ALL_TESTS BASIC_TESTS
#endif
EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ)
template <class T> struct pair_emplace_test1 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(it->first), boost::make_tuple(it->second));
}
}
};
template <class T> struct pair_emplace_test2 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(it->first),
boost::make_tuple(it->second.tag1_, it->second.tag2_));
}
}
};
EXCEPTION_TESTS((pair_emplace_test1)(pair_emplace_test2), CONTAINER_PAIR_SEQ)
template <class T> struct index_insert_test1 : public insert_test_base<T>
{
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
void run(T& x, strong_type& strong) const
{
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = this->values.begin(),
end = this->values.end();
it != end; ++it) {
strong.store(x, test::detail::tracker.count_allocations);
x[it->first];
}
}
};
EXCEPTION_TESTS((index_insert_test1), (test_map))
UNORDERED_TEST(insert_range_rehash_exception_test,
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
((default_generator)(limited_range)(generate_collisions))
)
// clang-format on
RUN_TESTS()

View File

@ -0,0 +1,103 @@
#include "../helpers/exception_test.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/metafunctions.hpp"
#include "../helpers/random_values.hpp"
#include "./containers.hpp"
template <typename T1, typename T2> void merge_exception_test(T1 x, T2 y)
{
std::size_t size = x.size() + y.size();
try {
ENABLE_EXCEPTIONS;
x.merge(y);
} catch (...) {
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
throw;
}
// Not a full check, just want to make sure the merge completed.
BOOST_TEST(size == x.size() + y.size());
if (y.size()) {
BOOST_TEST(test::has_unique_keys<T1>::value);
for (typename T2::iterator it = y.begin(); it != y.end(); ++it) {
BOOST_TEST(x.find(test::get_key<T2>(*it)) != x.end());
}
}
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
}
template <typename T1, typename T2>
void merge_exception_test(T1 const*, T2 const*, std::size_t count12, int tag12,
test::random_generator gen1, test::random_generator gen2)
{
std::size_t count1 = count12 / 256;
std::size_t count2 = count12 % 256;
int tag1 = tag12 / 256;
int tag2 = tag12 % 256;
test::random_values<T1> v1(count1, gen1);
test::random_values<T2> v2(count2, gen2);
T1 x(v1.begin(), v1.end(), 0, test::exception::hash(tag1),
test::exception::equal_to(tag1));
T2 y(v2.begin(), v2.end(), 0, test::exception::hash(tag2),
test::exception::equal_to(tag2));
EXCEPTION_LOOP(merge_exception_test(x, y))
}
boost::unordered_set<test::exception::object, test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> >* test_set_;
boost::unordered_multiset<test::exception::object, test::exception::hash,
test::exception::equal_to,
test::exception::allocator<test::exception::object> >* test_multiset_;
boost::unordered_map<test::exception::object, test::exception::object,
test::exception::hash, test::exception::equal_to,
test::exception::allocator2<test::exception::object> >* test_map_;
boost::unordered_multimap<test::exception::object, test::exception::object,
test::exception::hash, test::exception::equal_to,
test::exception::allocator2<test::exception::object> >* test_multimap_;
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
// clang-format off
UNORDERED_MULTI_TEST(set_merge, merge_exception_test,
((test_set_)(test_multiset_))
((test_set_)(test_multiset_))
((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232))
((0x0000)(0x0001)(0x0102))
((default_generator)(limited_range))
((default_generator)(limited_range))
)
UNORDERED_MULTI_TEST(map_merge, merge_exception_test,
((test_map_)(test_multimap_))
((test_map_)(test_multimap_))
((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232))
((0x0101)(0x0200)(0x0201))
((default_generator)(limited_range))
((default_generator)(limited_range))
)
// Run fewer generate_collisions tests, as they're slow.
UNORDERED_MULTI_TEST(set_merge_collisions, merge_exception_test,
((test_set_)(test_multiset_))
((test_set_)(test_multiset_))
((0x0a0a))
((0x0202)(0x0100)(0x0201))
((generate_collisions))
((generate_collisions))
)
UNORDERED_MULTI_TEST(map_merge_collisions, merge_exception_test,
((test_map_)(test_multimap_))
((test_map_)(test_multimap_))
((0x0a0a))
((0x0000)(0x0002)(0x0102))
((generate_collisions))
((generate_collisions))
)
// clang-format on
RUN_TESTS_QUIET()

View File

@ -7,7 +7,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include <iostream>
#include "../helpers/tracker.hpp"
#if defined(BOOST_MSVC)
#pragma warning( \
@ -42,7 +42,12 @@ template <class T> struct move_assign_base : public test::exception_base
T y1 = y;
disable_exceptions.release();
x1 = boost::move(y1);
DISABLE_EXCEPTIONS;
test::check_container(x1, y_values);
test::check_equivalent_keys(x1);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
{
test::check_equivalent_keys(x1);
@ -64,8 +69,8 @@ template <class T> struct move_assign_values : move_assign_base<T>
int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
: move_assign_base<T>(tag1, tag2, mlf1, mlf2)
{
this->x_values.fill(count1);
this->y_values.fill(count2);
this->x_values.fill(count1, test::limited_range);
this->y_values.fill(count2, test::limited_range);
this->x.insert(this->x_values.begin(), this->x_values.end());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
@ -105,10 +110,10 @@ template <class T> struct equivalent_test1 : move_assign_base<T>
{
equivalent_test1() : move_assign_base<T>(0, 0)
{
test::random_values<T> x_values2(10);
test::random_values<T> x_values2(10, test::limited_range);
this->x_values.insert(x_values2.begin(), x_values2.end());
this->x_values.insert(x_values2.begin(), x_values2.end());
test::random_values<T> y_values2(10);
test::random_values<T> y_values2(10, test::limited_range);
this->y_values.insert(y_values2.begin(), y_values2.end());
this->y_values.insert(y_values2.begin(), y_values2.end());
this->x.insert(this->x_values.begin(), this->x_values.end());

View File

@ -8,10 +8,9 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/strong.hpp"
#include "../helpers/tracker.hpp"
#include <string>
#include <iostream>
test::seed_t initialize_seed(3298597);
template <class T> struct rehash_test_base : public test::exception_base
@ -19,7 +18,7 @@ template <class T> struct rehash_test_base : public test::exception_base
test::random_values<T> values;
unsigned int n;
rehash_test_base(unsigned int count = 100, unsigned int n_ = 0)
: values(count), n(n_)
: values(count, test::limited_range), n(n_)
{
}
@ -49,34 +48,82 @@ template <class T> struct rehash_test_base : public test::exception_base
template <class T> struct rehash_test0 : rehash_test_base<T>
{
rehash_test0() : rehash_test_base<T>(0) {}
void run(T& x) const { x.rehash(0); }
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test1 : rehash_test_base<T>
{
rehash_test1() : rehash_test_base<T>(0) {}
void run(T& x) const { x.rehash(200); }
void run(T& x) const
{
x.rehash(200);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test2 : rehash_test_base<T>
{
rehash_test2() : rehash_test_base<T>(0, 200) {}
void run(T& x) const { x.rehash(0); }
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test3 : rehash_test_base<T>
{
rehash_test3() : rehash_test_base<T>(10, 0) {}
void run(T& x) const { x.rehash(200); }
void run(T& x) const
{
x.rehash(200);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test4 : rehash_test_base<T>
{
rehash_test4() : rehash_test_base<T>(10, 200) {}
void run(T& x) const { x.rehash(0); }
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
EXCEPTION_TESTS(
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4),
template <class T> struct rehash_test5 : rehash_test_base<T>
{
rehash_test5() : rehash_test_base<T>(200, 10) {}
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
EXCEPTION_TESTS((rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(
rehash_test4)(rehash_test5),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -7,6 +7,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable : 4512) // assignment operator could not be generated
@ -17,11 +18,22 @@ test::seed_t initialize_seed(9387);
template <class T> struct self_swap_base : public test::exception_base
{
test::random_values<T> values;
self_swap_base(std::size_t count = 0) : values(count) {}
self_swap_base(std::size_t count = 0) : values(count, test::limited_range)
{
}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
void run(T& x) const { x.swap(x); }
void run(T& x) const
{
x.swap(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
std::string scope(test::scope);
@ -55,7 +67,8 @@ template <class T> struct swap_base : public test::exception_base
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
swap_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
: x_values(count1), y_values(count2),
: x_values(count1, test::limited_range),
y_values(count2, test::limited_range),
initial_x(x_values.begin(), x_values.end(), 0, hasher(tag1),
key_equal(tag1), allocator_type(tag1)),
initial_y(
@ -82,7 +95,14 @@ template <class T> struct swap_base : public test::exception_base
d.x.swap(d.y);
} catch (std::runtime_error) {
}
DISABLE_EXCEPTIONS;
test::check_container(d.x, this->y_values);
test::check_equivalent_keys(d.x);
test::check_container(d.y, this->x_values);
test::check_equivalent_keys(d.y);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const
{
std::string scope(test::scope);

View File

@ -7,7 +7,6 @@
#define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
namespace test {
struct object_count

View File

@ -241,8 +241,10 @@ template <class Test> void exception_safety(Test const& f, char const* /*name*/)
iteration = 0;
bool success = false;
unsigned int failure_count = 0;
char const* error_msg = 0;
do {
int error_count = boost::detail::test_errors();
++iteration;
count = 0;
@ -252,19 +254,98 @@ template <class Test> void exception_safety(Test const& f, char const* /*name*/)
} catch (test_failure) {
error_msg = "test_failure caught.";
break;
} catch (test_exception) {
continue;
} catch (test_exception e) {
if (error_count != boost::detail::test_errors()) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM
<< "Iteration: " << iteration
<< " Error found for epoint: " << e.name << std::endl;
}
} catch (...) {
error_msg = "Unexpected exception.";
break;
}
} while (!success);
if (error_count != boost::detail::test_errors()) {
++failure_count;
}
} while (!success && failure_count < 5);
if (error_msg) {
BOOST_ERROR(error_msg);
}
runner.end();
}
//
// An alternative way to run exception tests.
// See merge_exception_tests.cpp for an example.
struct exception_looper
{
bool success;
unsigned int failure_count;
char const* error_msg;
int error_count;
exception_looper() : success(false), failure_count(0), error_msg(0) {}
void start() { iteration = 0; }
bool loop_condition() const
{
return !error_msg && !success && failure_count < 5;
}
void start_iteration()
{
error_count = boost::detail::test_errors();
++iteration;
count = 0;
}
void successful_run() { success = true; }
void test_failure_caught(test_failure const&)
{
error_msg = "test_failure caught.";
}
void test_exception_caught(test_exception const& e)
{
if (error_count != boost::detail::test_errors()) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM
<< "Iteration: " << iteration
<< " Error found for epoint: " << e.name << std::endl;
}
}
void unexpected_exception_caught() { error_msg = "Unexpected exception."; }
void end()
{
if (error_msg) {
BOOST_ERROR(error_msg);
}
}
};
#define EXCEPTION_LOOP(op) \
test::lightweight::exception_looper looper; \
looper.start(); \
while (looper.loop_condition()) { \
looper.start_iteration(); \
try { \
op; \
looper.successful_run(); \
} catch (test::lightweight::test_failure e) { \
looper.test_failure_caught(e); \
} catch (test::lightweight::test_exception e) { \
looper.test_exception_caught(e); \
} catch (...) { \
looper.unexpected_exception_caught(); \
} \
} \
looper.end();
}
}

View File

@ -63,20 +63,28 @@ template <class X> void check_equivalent_keys(X const& x1)
BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key);
BOOST_DEDUCED_TYPENAME X::const_local_iterator lit = x1.begin(bucket),
lend = x1.end(bucket);
for (; lit != lend && !eq(get_key<X>(*lit), key); ++lit)
continue;
if (lit == lend)
unsigned int count_checked = 0;
for (; lit != lend && !eq(get_key<X>(*lit), key); ++lit) {
++count_checked;
}
if (lit == lend) {
BOOST_ERROR("Unable to find element with a local_iterator");
unsigned int count2 = 0;
for (; lit != lend && eq(get_key<X>(*lit), key); ++lit)
++count2;
if (count != count2)
BOOST_ERROR("Element count doesn't match local_iterator.");
for (; lit != lend; ++lit) {
if (eq(get_key<X>(*lit), key)) {
BOOST_ERROR("Non-adjacent element with equivalent key "
"in bucket.");
break;
std::cerr << "Checked: " << count_checked << " elements"
<< std::endl;
} else {
unsigned int count2 = 0;
for (; lit != lend && eq(get_key<X>(*lit), key); ++lit)
++count2;
if (count != count2)
BOOST_ERROR("Element count doesn't match local_iterator.");
for (; lit != lend; ++lit) {
if (eq(get_key<X>(*lit), key)) {
BOOST_ERROR("Non-adjacent element with equivalent key "
"in bucket.");
break;
}
}
}
};

View File

@ -60,12 +60,16 @@ struct memory_tracker
unsigned int count_allocators;
unsigned int count_allocations;
unsigned int count_constructions;
bool tracking_constructions;
memory_tracker()
: count_allocators(0), count_allocations(0), count_constructions(0)
: count_allocators(0), count_allocations(0), count_constructions(0),
tracking_constructions(true)
{
}
~memory_tracker() { BOOST_TEST(count_allocators == 0); }
void allocator_ref()
{
if (count_allocators == 0) {
@ -131,14 +135,18 @@ struct memory_tracker
void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
{
++count_constructions;
if (tracking_constructions) {
++count_constructions;
}
}
void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
{
BOOST_TEST(count_constructions > 0);
if (count_constructions > 0)
--count_constructions;
if (tracking_constructions) {
BOOST_TEST(count_constructions > 0);
if (count_constructions > 0)
--count_constructions;
}
}
};
}
@ -153,6 +161,29 @@ namespace {
test::detail::memory_tracker tracker;
}
}
namespace detail {
struct disable_construction_tracking
{
bool old_value;
disable_construction_tracking()
: old_value(detail::tracker.tracking_constructions)
{
test::detail::tracker.tracking_constructions = false;
}
~disable_construction_tracking()
{
test::detail::tracker.tracking_constructions = old_value;
}
private:
disable_construction_tracking(disable_construction_tracking const&);
disable_construction_tracking& operator=(
disable_construction_tracking const&);
};
}
}
#endif

View File

@ -9,7 +9,6 @@
#include <boost/detail/lightweight_test.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <iostream>
#define UNORDERED_AUTO_TEST(x) \
struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base \
@ -17,7 +16,7 @@
BOOST_PP_CAT(x, _type) \
() : ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \
{ \
::test::test_list::add_test(this); \
::test::get_state().add_test(this); \
} \
void run(); \
}; \
@ -27,12 +26,27 @@
#define RUN_TESTS() \
int main(int, char**) \
{ \
::test::write_compiler_info(); \
::test::test_list::run_tests(); \
BOOST_UNORDERED_TEST_COMPILER_INFO() \
::test::get_state().run_tests(); \
return boost::report_errors(); \
}
#define RUN_TESTS_QUIET() \
int main(int, char**) \
{ \
BOOST_UNORDERED_TEST_COMPILER_INFO() \
::test::get_state().run_tests(true); \
return boost::report_errors(); \
}
#define UNORDERED_SUB_TEST(x) \
for (int UNORDERED_SUB_TEST_VALUE = ::test::get_state().start_sub_test(x); \
UNORDERED_SUB_TEST_VALUE; \
UNORDERED_SUB_TEST_VALUE = \
::test::get_state().end_sub_test(x, UNORDERED_SUB_TEST_VALUE))
namespace test {
struct registered_test_base
{
registered_test_base* next;
@ -42,56 +56,95 @@ struct registered_test_base
virtual ~registered_test_base() {}
};
namespace test_list {
static inline registered_test_base*& first()
struct state
{
static registered_test_base* ptr = 0;
return ptr;
}
bool is_quiet;
registered_test_base* first_test;
registered_test_base* last_test;
static inline registered_test_base*& last()
{
static registered_test_base* ptr = 0;
return ptr;
}
state() : is_quiet(false), first_test(0), last_test(0) {}
static inline void add_test(registered_test_base* test)
{
if (last()) {
last()->next = test;
} else {
first() = test;
void add_test(registered_test_base* test)
{
if (last_test) {
last_test->next = test;
} else {
first_test = test;
}
last_test = test;
}
last() = test;
}
void run_tests(bool quiet = false)
{
is_quiet = quiet;
static inline void run_tests()
{
for (registered_test_base* i = first(); i; i = i->next) {
std::cout << "Running " << i->name << "\n" << std::flush;
i->run();
std::cerr << std::flush;
std::cout << std::flush;
for (registered_test_base* i = first_test; i; i = i->next) {
int error_count = boost::detail::test_errors();
if (!quiet) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n"
<< std::flush;
}
i->run();
BOOST_LIGHTWEIGHT_TEST_OSTREAM << std::flush;
if (quiet && error_count != boost::detail::test_errors()) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in: " << i->name
<< "\n"
<< std::flush;
}
}
}
int start_sub_test(char const* name)
{
if (!is_quiet) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Sub-test: " << name << "\n"
<< std::flush;
}
// Add one because it's used as a loop condition.
return boost::detail::test_errors() + 1;
}
int end_sub_test(char const* name, int value)
{
if (is_quiet && value != boost::detail::test_errors() + 1) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in sub-test: " << name
<< "\n"
<< std::flush;
}
return 0;
}
};
// Get the currnet translation unit's test state.
static inline state& get_state()
{
static state instance;
return instance;
}
}
inline void write_compiler_info()
{
#if defined(BOOST_GCC_CXX11)
char const* cpp11 = "true";
#if defined(__cplusplus)
#define BOOST_UNORDERED_CPLUSPLUS __cplusplus
#else
char const* cpp11 = "false";
#define BOOST_UNORDERED_CPLUSPLUS "(not defined)"
#endif
std::cout << "Compiler: " << BOOST_COMPILER << "\n"
<< "Library: " << BOOST_STDLIB << "\n"
<< "C++11: " << cpp11 << "\n"
<< "\n"
<< std::flush;
}
}
#define BOOST_UNORDERED_TEST_COMPILER_INFO() \
{ \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Compiler: " << BOOST_COMPILER << "\n" \
<< "Library: " << BOOST_STDLIB << "\n" \
<< "__cplusplus: " << BOOST_UNORDERED_CPLUSPLUS << "\n\n" \
<< "BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT: " \
<< BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \
<< "BOOST_UNORDERED_EMPLACE_LIMIT: " \
<< BOOST_UNORDERED_EMPLACE_LIMIT << "\n" \
<< "BOOST_UNORDERED_USE_ALLOCATOR_TRAITS: " \
<< BOOST_UNORDERED_USE_ALLOCATOR_TRAITS << "\n" \
<< "BOOST_UNORDERED_CXX11_CONSTRUCTION: " \
<< BOOST_UNORDERED_CXX11_CONSTRUCTION << "\n\n" \
<< std::flush; \
}
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/fold_left.hpp>
@ -122,4 +175,31 @@ inline void write_compiler_info()
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem))
#define UNORDERED_MULTI_TEST(name, impl, parameters) \
UNORDERED_MULTI_TEST_REPEAT(name, impl, 1, parameters)
#define UNORDERED_MULTI_TEST_REPEAT(name, impl, n, parameters) \
UNORDERED_AUTO_TEST(name) \
{ \
BOOST_PP_SEQ_FOR_EACH_PRODUCT( \
UNORDERED_MULTI_TEST_OP, ((impl))((n))parameters) \
}
#define UNORDERED_MULTI_TEST_OP(r, product) \
UNORDERED_MULTI_TEST_OP2(BOOST_PP_SEQ_ELEM(0, product), \
BOOST_PP_SEQ_ELEM(1, product), \
BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product)))
// Need to wrap UNORDERED_SUB_TEST in a block to avoid an msvc bug.
// https://support.microsoft.com/en-gb/help/315481/bug-too-many-unnested-loops-incorrectly-causes-a-c1061-compiler-error-in-visual-c
#define UNORDERED_MULTI_TEST_OP2(name, n, params) \
{ \
UNORDERED_SUB_TEST(BOOST_PP_STRINGIZE( \
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params))) \
{ \
for (int i = 0; i < n; ++i) \
name BOOST_PP_SEQ_TO_TUPLE(params); \
} \
}
#endif

View File

@ -10,10 +10,11 @@
#include "../helpers/count.hpp"
#include "../helpers/fwd.hpp"
#include "../helpers/generators.hpp"
#include "../helpers/memory.hpp"
#include "./fwd.hpp"
#include <boost/limits.hpp>
#include <cstddef>
#include <iostream>
#include <new>
namespace test {
@ -225,6 +226,55 @@ class hash
}
};
class less
{
int tag_;
public:
less(int t = 0) : tag_(t) {}
less(less const& x) : tag_(x.tag_) {}
bool operator()(object const& x1, object const& x2) const
{
return less_impl(x1, x2);
}
bool operator()(std::pair<object, object> const& x1,
std::pair<object, object> const& x2) const
{
if (less_impl(x1.first, x2.first)) {
return true;
}
if (!less_impl(x1.first, x2.first)) {
return false;
}
return less_impl(x1.second, x2.second);
}
bool less_impl(object const& x1, object const& x2) const
{
switch (tag_) {
case 1:
return x1.tag1_ < x2.tag1_;
case 2:
return x1.tag2_ < x2.tag2_;
default:
return x1 < x2;
}
}
friend bool operator==(less const& x1, less const& x2)
{
return x1.tag_ == x2.tag_;
}
friend bool operator!=(less const& x1, less const& x2)
{
return x1.tag_ != x2.tag_;
}
};
class equal_to
{
int tag_;
@ -309,6 +359,8 @@ class equal_to
}
return x1.tag_ != x2.tag_;
}
friend less create_compare(equal_to x) { return less(x.tag_); }
};
template <class T> class allocator
@ -339,19 +391,11 @@ template <class T> class allocator
template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator::allocator())
{
UNORDERED_EPOINT("Mock allocator template copy constructor.");
}
test::detail::tracker.allocator_ref();
}
allocator(allocator const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator::allocator())
{
UNORDERED_EPOINT("Mock allocator copy constructor.");
}
test::detail::tracker.allocator_ref();
}
@ -359,11 +403,7 @@ template <class T> class allocator
allocator& operator=(allocator const& x)
{
UNORDERED_SCOPE(allocator::allocator())
{
UNORDERED_EPOINT("Mock allocator assignment operator.");
tag_ = x.tag_;
}
tag_ = x.tag_;
return *this;
}
@ -530,42 +570,22 @@ template <class T> class allocator2
allocator2(allocator<T> const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator2::allocator2())
{
UNORDERED_EPOINT("Mock allocator2 constructor from allocator.");
}
test::detail::tracker.allocator_ref();
}
template <class Y> allocator2(allocator2<Y> const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator2::allocator2())
{
UNORDERED_EPOINT("Mock allocator2 template copy constructor.");
}
test::detail::tracker.allocator_ref();
}
allocator2(allocator2 const& x) : tag_(x.tag_)
{
UNORDERED_SCOPE(allocator2::allocator2())
{
UNORDERED_EPOINT("Mock allocator2 copy constructor.");
}
test::detail::tracker.allocator_ref();
}
~allocator2() { test::detail::tracker.allocator_unref(); }
allocator2& operator=(allocator2 const& x)
{
UNORDERED_SCOPE(allocator2::allocator2())
{
UNORDERED_EPOINT("Mock allocator2 assignment operator.");
tag_ = x.tag_;
}
return *this;
}
allocator2& operator=(allocator2 const&) { return *this; }
// If address throws, then it can't be used in erase or the
// destructor, which is very limiting. I need to check up on
@ -704,6 +724,14 @@ inline bool operator!=(allocator2<T> const& x, allocator2<T> const& y)
}
}
namespace test {
template <typename X> struct equals_to_compare;
template <> struct equals_to_compare<test::exception::equal_to>
{
typedef test::exception::less type;
};
}
// Workaround for ADL deficient compilers
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace test {

View File

@ -391,21 +391,37 @@ template <class T> class allocator1
::operator delete((void*)p);
}
void construct(T* p, T const& t)
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
template <typename U, typename... Args> void construct(U* p, Args&&... args)
{
// Don't count constructions here as it isn't always called.
// detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new (p) T(t);
detail::tracker.track_construct((void*)p, sizeof(U), tag_);
new (p) U(boost::forward<Args>(args)...);
}
void destroy(T* p)
template <typename U> void destroy(U* p)
{
// detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
p->~T();
detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
p->~U();
// Work around MSVC buggy unused parameter warning.
ignore_variable(&p);
}
#else
private:
// I'm going to claim in the documentation that construct/destroy
// is never used when C++11 support isn't available, so might as
// well check that in the text.
// TODO: Or maybe just disallow them for values?
template <typename U> void construct(U* p);
template <typename U, typename A0> void construct(U* p, A0 const&);
template <typename U, typename A0, typename A1>
void construct(U* p, A0 const&, A1 const&);
template <typename U, typename A0, typename A1, typename A2>
void construct(U* p, A0 const&, A1 const&, A2 const&);
template <typename U> void destroy(U* p);
public:
#endif
bool operator==(allocator1 const& x) const { return tag_ == x.tag_; }

View File

@ -17,8 +17,6 @@
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include <iostream>
#if defined(BOOST_MSVC)
#pragma warning(disable : 4127) // conditional expression is constant
#endif
@ -32,7 +30,7 @@ template <class T> void assign_tests1(T*, test::random_generator generator)
BOOST_DEDUCED_TYPENAME T::hasher hf;
BOOST_DEDUCED_TYPENAME T::key_equal eq;
std::cerr << "assign_tests1.1\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.1\n";
{
test::check_instances check_;
@ -43,7 +41,7 @@ template <class T> void assign_tests1(T*, test::random_generator generator)
BOOST_TEST(test::equivalent(x.key_eq(), eq));
}
std::cerr << "assign_tests1.2\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.2\n";
{
test::check_instances check_;
@ -79,7 +77,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
std::cerr << "assign_tests2.0 - empty container\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.0 - empty container\n";
{
test::check_instances check_;
@ -93,7 +91,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
test::check_container(x1, x2);
}
std::cerr << "assign_tests2.1\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1\n";
{
test::check_instances check_;
@ -110,7 +108,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr << "assign_tests2.1a\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1a\n";
{
test::check_instances check_;
@ -128,7 +126,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr << "assign_tests2.2\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.2\n";
{
test::check_instances check_;
@ -150,7 +148,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr << "assign_tests2.3\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.3\n";
{
test::check_instances check_;
@ -172,7 +170,7 @@ template <class T> void assign_tests2(T*, test::random_generator generator)
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
}
std::cerr << "assign_tests2.4\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.4\n";
{
test::check_instances check_;
@ -271,7 +269,7 @@ UNORDERED_TEST(
UNORDERED_AUTO_TEST(assign_default_initializer_list)
{
std::cerr << "Initializer List Tests\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n";
std::initializer_list<std::pair<int const, int> > init;
boost::unordered_map<int, int> x1;
x1[25] = 3;
@ -286,7 +284,7 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST(assign_initializer_list)
{
std::cerr << "Initializer List Tests\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n";
boost::unordered_set<int> x;
x.insert(10);

View File

@ -19,6 +19,21 @@ UNORDERED_AUTO_TEST(at_tests)
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl;
boost::unordered_map<std::string, int> x;
boost::unordered_map<std::string, int> const& x_const(x);
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check empty container" << std::endl;
try {
x.at("one");
BOOST_ERROR("Should have thrown.");
} catch (std::out_of_range) {
}
try {
x_const.at("one");
BOOST_ERROR("Should have thrown.");
} catch (std::out_of_range) {
}
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Add elements" << std::endl;
@ -29,6 +44,8 @@ UNORDERED_AUTO_TEST(at_tests)
BOOST_TEST(x.at("one") == 1);
BOOST_TEST(x.at("two") == 2);
BOOST_TEST(x_const.at("one") == 1);
BOOST_TEST(x_const.at("two") == 2);
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check missing element" << std::endl;
@ -38,6 +55,12 @@ UNORDERED_AUTO_TEST(at_tests)
} catch (std::out_of_range) {
}
try {
x_const.at("three");
BOOST_ERROR("Should have thrown.");
} catch (std::out_of_range) {
}
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Finished" << std::endl;
}
}

View File

@ -37,7 +37,8 @@ template <class X> void tests(X*, test::random_generator generator)
BOOST_TEST(x.bucket_count() <= x.max_bucket_count());
if (!(x.bucket_count() <= x.max_bucket_count())) {
std::cerr << x.bucket_count() << "<=" << x.max_bucket_count() << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << x.bucket_count()
<< "<=" << x.max_bucket_count() << "\n";
}
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator

View File

@ -12,7 +12,6 @@
#include "../helpers/postfix.hpp"
// clang-format on
#include <iostream>
#include "../helpers/test.hpp"
#include "../objects/minimal.hpp"
#include "./compile_tests.hpp"
@ -46,7 +45,7 @@ UNORDERED_AUTO_TEST(test0)
value_type;
value_type value(x, x);
std::cout << "Test unordered_map.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
boost::unordered_map<int, int> int_map;
@ -64,7 +63,7 @@ UNORDERED_AUTO_TEST(test0)
container_test(int_map2, std::pair<int const, int>(0, 0));
container_test(map, value);
std::cout << "Test unordered_multimap.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
boost::unordered_multimap<int, int> int_multimap;
@ -139,7 +138,7 @@ UNORDERED_AUTO_TEST(test1)
int value = 0;
std::pair<int const, int> map_value(0, 0);
std::cout << "Test unordered_map.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
boost::unordered_map<int, int> map;
@ -157,7 +156,7 @@ UNORDERED_AUTO_TEST(test1)
unordered_copyable_test(map2, value, map_value, hash, equal_to);
unordered_map_functions(map2, value, value);
std::cout << "Test unordered_multimap.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
boost::unordered_multimap<int, int> multimap;
@ -188,7 +187,7 @@ UNORDERED_AUTO_TEST(test2)
map_value_type;
map_value_type map_value(assignable, assignable);
std::cout << "Test unordered_map.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
boost::unordered_map<test::minimal::assignable, test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
@ -212,7 +211,7 @@ UNORDERED_AUTO_TEST(test2)
unordered_map_functions(map2, assignable, default_assignable);
std::cout << "Test unordered_multimap.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
boost::unordered_multimap<test::minimal::assignable,
test::minimal::assignable,
@ -227,4 +226,36 @@ UNORDERED_AUTO_TEST(test2)
unordered_map_member_test(multimap, map_value);
}
// Test for ambiguity when using key convertible from iterator
// See LWG2059
struct lwg2059_key
{
int value;
template <typename T> lwg2059_key(T v) : value(v) {}
};
std::size_t hash_value(lwg2059_key x)
{
return static_cast<std::size_t>(x.value);
}
bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
UNORDERED_AUTO_TEST(lwg2059)
{
{
boost::unordered_map<lwg2059_key, int> x;
x.emplace(lwg2059_key(10), 5);
x.erase(x.begin());
}
{
boost::unordered_multimap<lwg2059_key, int> x;
x.emplace(lwg2059_key(10), 5);
x.erase(x.begin());
}
}
RUN_TESTS()

View File

@ -12,7 +12,6 @@
#include "../helpers/postfix.hpp"
// clang-format on
#include <iostream>
#include "../helpers/test.hpp"
#include "../objects/minimal.hpp"
#include "./compile_tests.hpp"
@ -42,7 +41,7 @@ UNORDERED_AUTO_TEST(test0)
test::minimal::assignable assignable(x);
std::cout << "Test unordered_set.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<int> int_set;
@ -60,7 +59,7 @@ UNORDERED_AUTO_TEST(test0)
container_test(int_set2, 0);
container_test(set, assignable);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<int> int_multiset;
@ -128,7 +127,7 @@ UNORDERED_AUTO_TEST(test1)
std::equal_to<int> equal_to;
int value = 0;
std::cout << "Test unordered_set." << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set." << std::endl;
boost::unordered_set<int> set;
@ -144,7 +143,7 @@ UNORDERED_AUTO_TEST(test1)
unordered_set_test(set2, value);
unordered_copyable_test(set2, value, value, hash, equal_to);
std::cout << "Test unordered_multiset." << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset." << std::endl;
boost::unordered_multiset<int> multiset;
@ -170,7 +169,7 @@ UNORDERED_AUTO_TEST(test2)
test::minimal::hash<test::minimal::assignable> hash(x);
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
std::cout << "Test unordered_set.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
@ -183,7 +182,7 @@ UNORDERED_AUTO_TEST(test2)
unordered_copyable_test(set, assignable, assignable, hash, equal_to);
unordered_set_member_test(set, assignable);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<test::minimal::assignable,
test::minimal::hash<test::minimal::assignable>,
@ -205,7 +204,7 @@ UNORDERED_AUTO_TEST(movable1_tests)
test::minimal::hash<test::minimal::movable1> hash(x);
test::minimal::equal_to<test::minimal::movable1> equal_to(x);
std::cout << "Test unordered_set.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<test::minimal::movable1,
test::minimal::hash<test::minimal::movable1>,
@ -217,7 +216,7 @@ UNORDERED_AUTO_TEST(movable1_tests)
unordered_set_test(set, movable1);
unordered_movable_test(set, movable1, movable1, hash, equal_to);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<test::minimal::movable1,
test::minimal::hash<test::minimal::movable1>,
@ -238,7 +237,7 @@ UNORDERED_AUTO_TEST(movable2_tests)
test::minimal::hash<test::minimal::movable2> hash(x);
test::minimal::equal_to<test::minimal::movable2> equal_to(x);
std::cout << "Test unordered_set.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<test::minimal::movable2,
test::minimal::hash<test::minimal::movable2>,
@ -250,7 +249,7 @@ UNORDERED_AUTO_TEST(movable2_tests)
unordered_set_test(set, movable2);
unordered_movable_test(set, movable2, movable2, hash, equal_to);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<test::minimal::movable2,
test::minimal::hash<test::minimal::movable2>,
@ -271,7 +270,7 @@ UNORDERED_AUTO_TEST(destructible_tests)
test::minimal::hash<test::minimal::destructible> hash(x);
test::minimal::equal_to<test::minimal::destructible> equal_to(x);
std::cout << "Test unordered_set.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<test::minimal::destructible,
test::minimal::hash<test::minimal::destructible>,
@ -280,7 +279,7 @@ UNORDERED_AUTO_TEST(destructible_tests)
unordered_destructible_test(set);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<test::minimal::destructible,
test::minimal::hash<test::minimal::destructible>,
@ -290,4 +289,36 @@ UNORDERED_AUTO_TEST(destructible_tests)
unordered_destructible_test(multiset);
}
// Test for ambiguity when using key convertible from iterator
// See LWG2059
struct lwg2059_key
{
int value;
template <typename T> lwg2059_key(T v) : value(v) {}
};
std::size_t hash_value(lwg2059_key x)
{
return static_cast<std::size_t>(x.value);
}
bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
UNORDERED_AUTO_TEST(lwg2059)
{
{
boost::unordered_set<lwg2059_key> x;
x.emplace(lwg2059_key(10));
x.erase(x.begin());
}
{
boost::unordered_multiset<lwg2059_key> x;
x.emplace(lwg2059_key(10));
x.erase(x.begin());
}
}
RUN_TESTS()

View File

@ -19,7 +19,9 @@
#include "../helpers/check_return_type.hpp"
#include <boost/iterator/iterator_traits.hpp>
#include <boost/limits.hpp>
#include <boost/predef.h>
#include <boost/static_assert.hpp>
#include <boost/type_traits/cv_traits.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/swap.hpp>
@ -30,6 +32,23 @@ template <class T> void sink(T const&) {}
template <class T> T rvalue(T const& v) { return v; }
template <class T> T rvalue_default() { return T(); }
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
template <class T> T implicit_construct() { return {}; }
#else
template <class T> int implicit_construct()
{
T x;
sink(x);
return 0;
}
#endif
#if !defined(BOOST_NO_CXX11_NOEXCEPT)
#define TEST_NOEXCEPT_EXPR(x) BOOST_STATIC_ASSERT((BOOST_NOEXCEPT_EXPR(x)));
#else
#define TEST_NOEXCEPT_EXPR(x)
#endif
template <class X, class T> void container_test(X& r, T const&)
{
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
@ -52,6 +71,8 @@ template <class X, class T> void container_test(X& r, T const&)
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
// value_type
BOOST_STATIC_ASSERT((boost::is_same<T, value_type>::value));
@ -75,7 +96,9 @@ template <class X, class T> void container_test(X& r, T const&)
BOOST_STATIC_ASSERT((boost::is_same<T, const_iterator_value_type>::value));
// node_type
// TODO?
BOOST_STATIC_ASSERT((boost::is_same<allocator_type,
BOOST_DEDUCED_TYPENAME node_type::allocator_type>::value));
// difference_type
@ -134,7 +157,6 @@ template <class X, class T> void container_test(X& r, T const&)
// Allocator
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
test::check_return_type<allocator_type>::equals(a_const.get_allocator());
allocator_type m = a.get_allocator();
@ -147,21 +169,30 @@ template <class X, class T> void container_test(X& r, T const&)
// node_type
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
BOOST_STATIC_ASSERT((boost::is_same<allocator_type,
BOOST_DEDUCED_TYPENAME node_type::allocator_type>::value));
implicit_construct<node_type const>();
#if !BOOST_COMP_GNUC || BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4, 8, 0)
TEST_NOEXCEPT_EXPR(node_type());
#endif
node_type n1;
node_type n2(rvalue_default<node_type>());
#if !BOOST_COMP_GNUC || BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4, 8, 0)
TEST_NOEXCEPT_EXPR(node_type(boost::move(n1)));
#endif
node_type n3;
n3 = boost::move(n2);
n1.swap(n3);
swap(n1, n3);
// TODO: noexcept for swap?
// value, key, mapped tests in map and set specific testing.
node_type const n_const;
BOOST_TEST(n_const ? 0 : 1);
TEST_NOEXCEPT_EXPR(n_const ? 0 : 1);
test::check_return_type<bool>::equals(!n_const);
test::check_return_type<bool>::equals(n_const.empty());
TEST_NOEXCEPT_EXPR(!n_const);
TEST_NOEXCEPT_EXPR(n_const.empty());
// Avoid unused variable warnings:
@ -302,14 +333,22 @@ void unordered_map_test(X& r, Key const& k, T const& v)
BOOST_STATIC_ASSERT((boost::is_same<Key, node_key_type>::value));
BOOST_STATIC_ASSERT((boost::is_same<T, node_mapped_type>::value));
// Superfluous,but just to make sure.
BOOST_STATIC_ASSERT((!boost::is_const<node_key_type>::value));
// Calling functions
r.insert(std::pair<Key const, T>(k, v));
r.insert(r.begin(), std::pair<Key const, T>(k, v));
std::pair<Key const, T> const value(k, v);
r.insert(value);
r.insert(r.end(), value);
Key k_lvalue(k);
T v_lvalue(v);
// Emplace
r.emplace(k, v);
r.emplace(k_lvalue, v_lvalue);
r.emplace(rvalue(k), rvalue(v));
@ -317,6 +356,17 @@ void unordered_map_test(X& r, Key const& k, T const& v)
r.emplace(boost::unordered::piecewise_construct, boost::make_tuple(k),
boost::make_tuple(v));
// Emplace with hint
r.emplace_hint(r.begin(), k, v);
r.emplace_hint(r.begin(), k_lvalue, v_lvalue);
r.emplace_hint(r.begin(), rvalue(k), rvalue(v));
r.emplace_hint(r.begin(), boost::unordered::piecewise_construct,
boost::make_tuple(k), boost::make_tuple(v));
// Extract
test::check_return_type<node_type>::equals(r.extract(r.begin()));
r.emplace(k, v);
@ -327,8 +377,16 @@ void unordered_map_test(X& r, Key const& k, T const& v)
test::check_return_type<key_type>::equals_ref(n1.key());
test::check_return_type<T>::equals_ref(n1.mapped());
r.insert(boost::move(n1));
node_type n2 = boost::move(n1);
r.insert(boost::move(n2));
r.insert(r.extract(r.begin()));
n2 = r.extract(r.begin());
r.insert(r.begin(), boost::move(n2));
r.insert(r.end(), r.extract(r.begin()));
node_type n = r.extract(r.begin());
test::check_return_type<node_key_type>::equals_ref(n.key());
test::check_return_type<node_mapped_type>::equals_ref(n.mapped());
}
template <class X> void equality_test(X& r)
@ -385,6 +443,7 @@ void unordered_map_functions(X&, Key const& k, T const& v)
X a;
test::check_return_type<mapped_type>::equals_ref(a[k]);
test::check_return_type<mapped_type>::equals_ref(a[rvalue(k)]);
test::check_return_type<mapped_type>::equals_ref(a.at(k));
test::check_return_type<std::pair<iterator, bool> >::equals(
a.try_emplace(k, v));
@ -517,6 +576,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
const_iterator q1 = a.cbegin(), q2 = a.cend();
test::check_return_type<iterator>::equals(a.erase(q1, q2));
TEST_NOEXCEPT_EXPR(a.clear());
a.clear();
X const b;
@ -627,6 +687,13 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
sink(X(b, m));
X a9a(b, m);
X b1;
b1.insert(t);
X a9b(b1);
sink(a9b);
X a9c(b1, m);
sink(a9c);
const_iterator q = a.cbegin();
test::check_return_type<iterator>::equals(a.insert(q, t));
@ -638,7 +705,9 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
a.insert(list);
a.insert({t, t, t});
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) && \
(!defined(__clang__) || __clang_major__ >= 4 || \
(__clang_major__ == 3 && __clang_minor__ >= 4))
a.insert({});
a.insert({t});
a.insert({t, t});

View File

@ -28,7 +28,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
BOOST_DEDUCED_TYPENAME T::key_equal eq;
BOOST_DEDUCED_TYPENAME T::allocator_type al;
std::cerr << "Construct 1\n";
UNORDERED_SUB_TEST("Construct 1")
{
test::check_instances check_;
@ -40,7 +40,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 2\n";
UNORDERED_SUB_TEST("Construct 2")
{
test::check_instances check_;
@ -53,7 +53,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 3\n";
UNORDERED_SUB_TEST("Construct 3")
{
test::check_instances check_;
@ -66,7 +66,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 4\n";
UNORDERED_SUB_TEST("Construct 4")
{
test::check_instances check_;
@ -78,7 +78,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 5\n";
UNORDERED_SUB_TEST("Construct 5")
{
test::check_instances check_;
@ -92,7 +92,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 6\n";
UNORDERED_SUB_TEST("Construct 6")
{
test::check_instances check_;
@ -106,7 +106,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 7\n";
UNORDERED_SUB_TEST("Construct 7")
{
test::check_instances check_;
@ -120,7 +120,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 8\n";
UNORDERED_SUB_TEST("Construct 8")
{
test::check_instances check_;
@ -133,7 +133,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 9\n";
UNORDERED_SUB_TEST("Construct 9")
{
test::check_instances check_;
@ -145,7 +145,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 10\n";
UNORDERED_SUB_TEST("Construct 10")
{
test::check_instances check_;
@ -159,7 +159,7 @@ template <class T> void constructor_tests1(T*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 11\n";
UNORDERED_SUB_TEST("Construct 11")
{
test::check_instances check_;
@ -185,7 +185,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
std::cerr << "Construct 1\n";
UNORDERED_SUB_TEST("Construct 1")
{
test::check_instances check_;
T x(10000, hf1, eq1);
@ -196,7 +196,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 2\n";
UNORDERED_SUB_TEST("Construct 2")
{
test::check_instances check_;
T x(100, hf1);
@ -208,7 +208,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 3\n";
UNORDERED_SUB_TEST("Construct 3")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@ -220,7 +220,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 4\n";
UNORDERED_SUB_TEST("Construct 4")
{
test::check_instances check_;
test::random_values<T> v(5, generator);
@ -233,7 +233,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(x);
}
std::cerr << "Construct 5\n";
UNORDERED_SUB_TEST("Construct 5")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@ -245,7 +245,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 6\n";
UNORDERED_SUB_TEST("Construct 6")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@ -257,7 +257,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 7\n";
UNORDERED_SUB_TEST("Construct 7")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@ -269,7 +269,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 8 - from input iterator\n";
UNORDERED_SUB_TEST("Construct 8 - from input iterator")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@ -288,7 +288,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 8.5 - from copy iterator\n";
UNORDERED_SUB_TEST("Construct 8.5 - from copy iterator")
{
test::check_instances check_;
test::random_values<T> v(100, generator);
@ -302,7 +302,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
test::check_equivalent_keys(y);
}
std::cerr << "Construct 9\n";
UNORDERED_SUB_TEST("Construct 9")
{
test::check_instances check_;
@ -320,7 +320,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
std::initializer_list<BOOST_DEDUCED_TYPENAME T::value_type> list;
std::cerr << "Initializer list construct 1\n";
UNORDERED_SUB_TEST("Initializer list construct 1")
{
test::check_instances check_;
@ -331,7 +331,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
std::cerr << "Initializer list construct 2\n";
UNORDERED_SUB_TEST("Initializer list construct 2")
{
test::check_instances check_;
@ -343,7 +343,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
std::cerr << "Initializer list construct 3\n";
UNORDERED_SUB_TEST("Initializer list construct 3")
{
test::check_instances check_;
@ -355,7 +355,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
std::cerr << "Initializer list construct 4\n";
UNORDERED_SUB_TEST("Initializer list construct 4")
{
test::check_instances check_;
@ -367,7 +367,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
BOOST_TEST(test::equivalent(x.get_allocator(), al));
}
std::cerr << "Initializer list construct 5\n";
UNORDERED_SUB_TEST("Initializer list construct 5")
{
test::check_instances check_;
@ -384,8 +384,6 @@ void constructor_tests2(T*, test::random_generator const& generator)
template <class T>
void map_constructor_test(T*, test::random_generator const& generator)
{
std::cerr << "map_constructor_test\n";
typedef test::list<std::pair<BOOST_DEDUCED_TYPENAME T::key_type,
BOOST_DEDUCED_TYPENAME T::mapped_type> >
list;
@ -429,7 +427,6 @@ UNORDERED_TEST(map_constructor_test,
UNORDERED_AUTO_TEST(test_default_initializer_list)
{
std::cerr << "Initializer List Tests\n";
std::initializer_list<int> init;
boost::unordered_set<int> x1 = init;
BOOST_TEST(x1.empty());
@ -441,7 +438,6 @@ UNORDERED_AUTO_TEST(test_default_initializer_list)
UNORDERED_AUTO_TEST(test_initializer_list)
{
std::cerr << "Initializer List Tests\n";
boost::unordered_set<int> x1 = {2, 10, 45, -5};
BOOST_TEST(x1.find(10) != x1.end());
BOOST_TEST(x1.find(46) == x1.end());
@ -450,4 +446,4 @@ UNORDERED_AUTO_TEST(test_initializer_list)
#endif
}
RUN_TESTS()
RUN_TESTS_QUIET()

View File

@ -0,0 +1,102 @@
// Copyright 2017 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// clang-format off
#include "../helpers/prefix.hpp"
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "../helpers/postfix.hpp"
// clang-format on
#include "../helpers/test.hpp"
#include <map>
// Pretty inefficient, but the test is fast enough.
// Might be too slow if we had larger primes?
bool is_prime(std::size_t x)
{
if (x == 2) {
return true;
} else if (x == 1 || x % 2 == 0) {
return false;
} else {
// y*y <= x had rounding errors, so instead use y <= (x/y).
for (std::size_t y = 3; y <= (x / y); y += 2) {
if (x % y == 0) {
return false;
break;
}
}
return true;
}
}
void test_next_prime(std::size_t value)
{
std::size_t x = boost::unordered::detail::next_prime(value);
BOOST_TEST(is_prime(x));
BOOST_TEST(x >= value);
}
void test_prev_prime(std::size_t value)
{
std::size_t x = boost::unordered::detail::prev_prime(value);
BOOST_TEST(is_prime(x));
BOOST_TEST(x <= value);
if (x > value) {
BOOST_LIGHTWEIGHT_TEST_OSTREAM << x << "," << value << std::endl;
}
}
UNORDERED_AUTO_TEST(next_prime_test)
{
BOOST_TEST(!is_prime(0));
BOOST_TEST(!is_prime(1));
BOOST_TEST(is_prime(2));
BOOST_TEST(is_prime(3));
BOOST_TEST(is_prime(13));
BOOST_TEST(!is_prime(4));
BOOST_TEST(!is_prime(100));
BOOST_TEST(boost::unordered::detail::next_prime(0) > 0);
// test_prev_prime doesn't work for values less than 17.
// Which should be okay, unless an allocator has a really tiny
// max_size?
const std::size_t min_prime = 17;
// test_next_prime doesn't work for values greater than this,
// which might be a problem if you've got terrabytes of memory?
// I seriously doubt the container would work well at such sizes
// regardless.
const std::size_t max_prime = 4294967291ul;
std::size_t i;
BOOST_TEST(is_prime(min_prime));
BOOST_TEST(is_prime(max_prime));
for (i = 0; i < 10000; ++i) {
if (i < min_prime) {
BOOST_TEST(boost::unordered::detail::prev_prime(i) == min_prime);
} else {
test_prev_prime(i);
}
test_next_prime(i);
}
std::size_t last = i - 1;
for (; i > last; last = i, i += i / 5) {
if (i > max_prime) {
BOOST_TEST(boost::unordered::detail::next_prime(i) == max_prime);
} else {
test_next_prime(i);
}
test_prev_prime(i);
}
}
RUN_TESTS()

View File

@ -17,8 +17,6 @@
#include "../helpers/tracker.hpp"
#include "../helpers/invariants.hpp"
#include <iostream>
template <class Container, class Iterator>
void test_equal_insertion(Iterator begin, Iterator end)
{

View File

@ -17,7 +17,6 @@
#include "../helpers/invariants.hpp"
#include "../helpers/helpers.hpp"
#include <set>
#include <iostream>
#include <iterator>
#include "../objects/test.hpp"
@ -31,14 +30,15 @@ struct write_pair_type
template <class X1, class X2>
void operator()(std::pair<X1, X2> const& x) const
{
std::cout << "(" << x.first << "," << x.second << ")";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "(" << x.first << "," << x.second
<< ")";
}
} write_pair;
template <class Container> void write_container(Container const& x)
{
std::for_each(x.begin(), x.end(), write_pair);
std::cout << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
// Make everything collide - for testing erase in a single bucket.
@ -165,8 +165,8 @@ template <class Container> void erase_subrange_tests(Container const& x)
collide_list init(y.begin(), y.end());
if (!general_erase_range_test(y, position, position + length)) {
BOOST_ERROR("general_erase_range_test failed.");
std::cout << "Erase: [" << position << "," << position + length
<< ")\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase: [" << position << ","
<< position + length << ")\n";
write_container(init);
write_container(y);
}
@ -185,7 +185,8 @@ void x_by_y_erase_range_tests(Container*, int values, int duplicates)
}
}
std::cout << "Values: " << values << ", Duplicates: " << duplicates << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Values: " << values
<< ", Duplicates: " << duplicates << "\n";
erase_subrange_tests(y);
}
@ -201,24 +202,24 @@ void exhaustive_erase_tests(Container* x, int num_values, int num_duplicated)
UNORDERED_AUTO_TEST(exhaustive_collide_tests)
{
std::cout << "exhaustive_collide_tests:\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide_tests:\n";
collide_map m;
exhaustive_erase_tests((collide_map*)0, 4, 4);
std::cout << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
UNORDERED_AUTO_TEST(exhaustive_collide2_tests)
{
std::cout << "exhaustive_collide2_tests:\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide2_tests:\n";
exhaustive_erase_tests((collide_map2*)0, 8, 4);
std::cout << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
UNORDERED_AUTO_TEST(exhaustive_collide3_tests)
{
std::cout << "exhaustive_collide3_tests:\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide3_tests:\n";
exhaustive_erase_tests((collide_map3*)0, 8, 4);
std::cout << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
RUN_TESTS()

View File

@ -18,7 +18,6 @@
#include "../helpers/helpers.hpp"
#include "../helpers/invariants.hpp"
#include <vector>
#include <iostream>
#include <cstdlib>
namespace erase_tests {
@ -31,7 +30,7 @@ void erase_tests1(Container*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME Container::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME Container::const_iterator c_iterator;
std::cerr << "Erase by key.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase by key.\n";
{
test::check_instances check_;
@ -52,7 +51,7 @@ void erase_tests1(Container*, test::random_generator generator)
}
}
std::cerr << "erase(begin()).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(begin()).\n";
{
test::check_instances check_;
@ -75,7 +74,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "erase(random position).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random position).\n";
{
test::check_instances check_;
@ -104,7 +103,8 @@ void erase_tests1(Container*, test::random_generator generator)
index == 0 ? next == x.begin() : next == test::next(prev));
BOOST_TEST(x.count(key) == count - 1);
if (x.count(key) != count - 1) {
std::cerr << count << " => " << x.count(key) << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => "
<< x.count(key) << std::endl;
}
BOOST_TEST(x.size() == size);
if (++iterations % 20 == 0)
@ -113,7 +113,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "erase(ranges).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(ranges).\n";
{
test::check_instances check_;
@ -140,7 +140,7 @@ void erase_tests1(Container*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "erase(random ranges).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random ranges).\n";
{
test::check_instances check_;
Container x;
@ -179,7 +179,7 @@ void erase_tests1(Container*, test::random_generator generator)
}
}
std::cerr << "quick_erase(begin()).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(begin()).\n";
{
test::check_instances check_;
@ -201,7 +201,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "quick_erase(random position).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(random position).\n";
{
test::check_instances check_;
@ -230,7 +230,8 @@ void erase_tests1(Container*, test::random_generator generator)
index == 0 ? next == x.begin() : next == test::next(prev));
BOOST_TEST(x.count(key) == count - 1);
if (x.count(key) != count - 1) {
std::cerr << count << " => " << x.count(key) << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => "
<< x.count(key) << std::endl;
}
BOOST_TEST(x.size() == size);
if (++iterations % 20 == 0)
@ -239,7 +240,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "clear().\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "clear().\n";
{
test::check_instances check_;
@ -250,7 +251,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.begin() == x.end());
}
std::cerr << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
boost::unordered_set<test::object, test::hash, test::equal_to,

View File

@ -19,8 +19,6 @@
#include "../objects/test.hpp"
#include <boost/next_prior.hpp>
#include <iostream>
namespace extract_tests {
test::seed_t initialize_seed(85638);
@ -28,7 +26,7 @@ test::seed_t initialize_seed(85638);
template <class Container>
void extract_tests1(Container*, test::random_generator generator)
{
std::cerr << "Extract by key.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Extract by key.\n";
{
test::check_instances check_;
@ -58,7 +56,7 @@ void extract_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "extract(begin()).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(begin()).\n";
{
test::check_instances check_;
@ -81,7 +79,7 @@ void extract_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "extract(random position).\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(random position).\n";
{
test::check_instances check_;
@ -117,7 +115,7 @@ void extract_tests1(Container*, test::random_generator generator)
BOOST_TEST(x.empty());
}
std::cerr << "\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
}
boost::unordered_set<test::object, test::hash, test::equal_to,

View File

@ -65,6 +65,11 @@ template <typename T> struct allocator : std::allocator<T>
allocator(const allocator<T2>& other) : std::allocator<T>(other)
{
}
template <typename T2>
allocator(const std::allocator<T2>& other) : std::allocator<T>(other)
{
}
};
// Declare some members of a structs.

View File

@ -15,7 +15,6 @@
#include <map>
#include <set>
#include <iostream>
namespace insert_hint {
UNORDERED_AUTO_TEST(insert_hint_empty)

View File

@ -12,8 +12,6 @@
#include "../helpers/test.hpp"
#include <iostream>
namespace insert_stable {
struct member
{
@ -47,9 +45,9 @@ std::size_t hash_value(insert_stable::member const& x)
}
}
// This is now only supported when using grouped nodes. I can't see any
// efficient way to do it otherwise.
#if !BOOST_UNORDERED_INTEROPERABLE_NODES
// This is no longer supported, as there's no longer an efficient way to get to
// the end of a group of equivalent nodes.
#if 0
UNORDERED_AUTO_TEST(stable_insert_test1)
{

View File

@ -3,6 +3,8 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(PIECEWISE_TEST_NAME)
// clang-format off
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
@ -19,8 +21,6 @@
#include "../helpers/input_iterator.hpp"
#include "../helpers/helpers.hpp"
#include <iostream>
namespace insert_tests {
test::seed_t initialize_seed(243432);
@ -33,66 +33,138 @@ void unique_insert_tests1(X*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef test::ordered<X> ordered;
std::cerr << "insert(value) tests for containers with unique keys.\n";
UNORDERED_SUB_TEST("insert(value) tests for containers with unique keys")
{
X x;
test::ordered<X> tracker = test::create_ordered(x);
X x;
test::ordered<X> tracker = test::create_ordered(x);
test::random_values<X> v(1000, generator);
test::random_values<X> v(1000, generator);
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it =
v.begin();
it != v.end(); ++it) {
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it) {
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count =
x.bucket_count();
float b = x.max_load_factor();
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
std::pair<iterator, bool> r1 = x.insert(*it);
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool> r2 =
tracker.insert(*it);
std::pair<iterator, bool> r1 = x.insert(*it);
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool> r2 =
tracker.insert(*it);
BOOST_TEST(r1.second == r2.second);
BOOST_TEST(*r1.first == *r2.first);
BOOST_TEST(r1.second == r2.second);
BOOST_TEST(*r1.first == *r2.first);
tracker.compare_key(x, *it);
tracker.compare_key(x, *it);
if (static_cast<double>(x.size()) <=
b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
if (static_cast<double>(x.size()) <=
b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
test::check_equivalent_keys(x);
}
test::check_equivalent_keys(x);
UNORDERED_SUB_TEST("insert(rvalue) tests for containers with unique keys")
{
X x;
test::ordered<X> tracker = test::create_ordered(x);
test::random_values<X> v(1000, generator);
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it =
v.begin();
it != v.end(); ++it) {
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count =
x.bucket_count();
float b = x.max_load_factor();
typename X::value_type value = *it;
std::pair<iterator, bool> r1 = x.insert(boost::move(value));
std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool> r2 =
tracker.insert(*it);
BOOST_TEST(r1.second == r2.second);
BOOST_TEST(*r1.first == *r2.first);
tracker.compare_key(x, *it);
if (static_cast<double>(x.size()) <=
b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
}
template <class X>
void equivalent_insert_tests1(X*, test::random_generator generator)
{
std::cerr << "insert(value) tests for containers with equivalent keys.\n";
test::check_instances check_;
X x;
test::ordered<X> tracker = test::create_ordered(x);
UNORDERED_SUB_TEST(
"insert(value) tests for containers with equivalent keys")
{
X x;
test::ordered<X> tracker = test::create_ordered(x);
test::random_values<X> v(1000, generator);
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it) {
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
test::random_values<X> v(1000, generator);
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it =
v.begin();
it != v.end(); ++it) {
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count =
x.bucket_count();
float b = x.max_load_factor();
BOOST_DEDUCED_TYPENAME X::iterator r1 = x.insert(*it);
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2 =
tracker.insert(*it);
BOOST_DEDUCED_TYPENAME X::iterator r1 = x.insert(*it);
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2 =
tracker.insert(*it);
BOOST_TEST(*r1 == *r2);
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
tracker.compare_key(x, *it);
if (static_cast<double>(x.size()) <=
b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
if (static_cast<double>(x.size()) <=
b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
test::check_equivalent_keys(x);
UNORDERED_SUB_TEST(
"insert(rvalue) tests for containers with equivalent keys")
{
X x;
test::ordered<X> tracker = test::create_ordered(x);
test::random_values<X> v(1000, generator);
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it =
v.begin();
it != v.end(); ++it) {
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count =
x.bucket_count();
float b = x.max_load_factor();
typename X::value_type value = *it;
BOOST_DEDUCED_TYPENAME X::iterator r1 =
x.insert(boost::move(value));
BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2 =
tracker.insert(*it);
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if (static_cast<double>(x.size()) <=
b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
}
template <class X> void insert_tests2(X*, test::random_generator generator)
@ -102,8 +174,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME tracker_type::iterator tracker_iterator;
std::cerr << "insert(begin(), value) tests.\n";
UNORDERED_SUB_TEST("insert(begin(), value) tests")
{
test::check_instances check_;
@ -132,8 +203,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert(end(), value) tests.\n";
UNORDERED_SUB_TEST("insert(end(), value) tests")
{
test::check_instances check_;
@ -163,8 +233,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert(pos, value) tests.\n";
UNORDERED_SUB_TEST("insert(pos, value) tests")
{
test::check_instances check_;
@ -194,8 +263,38 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert single item range tests.\n";
UNORDERED_SUB_TEST("insert(pos, rvalue) tests")
{
test::check_instances check_;
X x;
const_iterator pos = x.begin();
tracker_type tracker = test::create_ordered(x);
test::random_values<X> v(1000, generator);
for (BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it =
v.begin();
it != v.end(); ++it) {
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count =
x.bucket_count();
float b = x.max_load_factor();
typename X::value_type value = *it;
pos = x.insert(pos, boost::move(value));
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
BOOST_TEST(*pos == *r2);
tracker.compare_key(x, *it);
if (static_cast<double>(x.size()) <=
b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
tracker.compare(x);
test::check_equivalent_keys(x);
}
UNORDERED_SUB_TEST("insert single item range tests")
{
test::check_instances check_;
@ -223,8 +322,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert range tests.\n";
UNORDERED_SUB_TEST("insert range tests")
{
test::check_instances check_;
@ -237,8 +335,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert range with rehash tests.\n";
UNORDERED_SUB_TEST("insert range with rehash tests")
{
test::check_instances check_;
@ -255,8 +352,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert input iterator range tests.\n";
UNORDERED_SUB_TEST("insert input iterator range tests")
{
test::check_instances check_;
@ -272,8 +368,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert copy iterator range tests.\n";
UNORDERED_SUB_TEST("insert copy iterator range tests")
{
test::check_instances check_;
@ -286,8 +381,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert copy iterator range test 2.\n";
UNORDERED_SUB_TEST("insert copy iterator range test 2")
{
test::check_instances check_;
@ -303,8 +397,7 @@ template <class X> void insert_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert various ranges.\n";
UNORDERED_SUB_TEST("insert various ranges")
{
for (int i = 0; i < 100; ++i) {
X x;
@ -350,8 +443,6 @@ void unique_emplace_tests1(X*, test::random_generator generator)
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
typedef test::ordered<X> ordered;
std::cerr << "emplace(value) tests for containers with unique keys.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
@ -384,8 +475,6 @@ void unique_emplace_tests1(X*, test::random_generator generator)
template <class X>
void equivalent_emplace_tests1(X*, test::random_generator generator)
{
std::cerr << "emplace(value) tests for containers with equivalent keys.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
@ -414,9 +503,6 @@ void equivalent_emplace_tests1(X*, test::random_generator generator)
template <class X> void move_emplace_tests(X*, test::random_generator generator)
{
std::cerr
<< "emplace(move(value)) tests for containers with unique keys.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
@ -444,8 +530,7 @@ template <class X> void move_emplace_tests(X*, test::random_generator generator)
template <class X> void default_emplace_tests(X*, test::random_generator)
{
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
std::cerr << "emplace() tests.\n";
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
bool is_unique = test::has_unique_keys<X>::value;
X x;
@ -480,8 +565,6 @@ template <class X> void default_emplace_tests(X*, test::random_generator)
template <class X> void map_tests(X*, test::random_generator generator)
{
std::cerr << "map tests.\n";
X x;
test::ordered<X> tracker = test::create_ordered(x);
@ -508,8 +591,8 @@ template <class X> void map_tests(X*, test::random_generator generator)
template <class X> void map_tests2(X*, test::random_generator generator)
{
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
std::cerr << "insert_or_assign\n";
UNORDERED_SUB_TEST("insert_or_assign")
{
test::check_instances check_;
@ -540,8 +623,7 @@ template <class X> void map_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert_or_assign(begin)\n";
UNORDERED_SUB_TEST("insert_or_assign(begin)")
{
test::check_instances check_;
@ -571,8 +653,7 @@ template <class X> void map_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert_or_assign(end)\n";
UNORDERED_SUB_TEST("insert_or_assign(end)")
{
test::check_instances check_;
@ -602,8 +683,7 @@ template <class X> void map_tests2(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "insert_or_assign(last)\n";
UNORDERED_SUB_TEST("insert_or_assign(last)")
{
test::check_instances check_;
@ -639,10 +719,9 @@ template <class X> void map_tests2(X*, test::random_generator generator)
template <class X> void try_emplace_tests(X*, test::random_generator generator)
{
std::cerr << "try_emplace(key, value)\n";
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
UNORDERED_SUB_TEST("try_emplace(key, value)")
{
test::check_instances check_;
@ -682,10 +761,9 @@ template <class X> void try_emplace_tests(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "try_emplace(begin(), key, value)\n";
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
UNORDERED_SUB_TEST("try_emplace(begin(), key, value)")
{
test::check_instances check_;
@ -722,10 +800,9 @@ template <class X> void try_emplace_tests(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "try_emplace(end(), key, value)\n";
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
UNORDERED_SUB_TEST("try_emplace(end(), key, value)")
{
test::check_instances check_;
@ -762,10 +839,9 @@ template <class X> void try_emplace_tests(X*, test::random_generator generator)
test::check_equivalent_keys(x);
}
std::cerr << "try_emplace(pos, key, value)\n";
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
UNORDERED_SUB_TEST("try_emplace(pos, key, value)")
{
test::check_instances check_;
@ -808,8 +884,6 @@ template <class X> void try_emplace_tests(X*, test::random_generator generator)
template <class X>
void map_insert_range_test1(X*, test::random_generator generator)
{
std::cerr << "map_insert_range_test1\n";
test::check_instances check_;
typedef test::list<std::pair<BOOST_DEDUCED_TYPENAME X::key_type,
@ -827,8 +901,6 @@ void map_insert_range_test1(X*, test::random_generator generator)
template <class X>
void map_insert_range_test2(X*, test::random_generator generator)
{
std::cerr << "map_insert_range_test2\n";
test::check_instances check_;
typedef test::list<std::pair<BOOST_DEDUCED_TYPENAME X::key_type const,
@ -1030,21 +1102,43 @@ struct overloaded_constructor
UNORDERED_AUTO_TEST(map_emplace_test)
{
boost::unordered_map<int, overloaded_constructor> x;
{
boost::unordered_map<int, overloaded_constructor, test::hash,
test::equal_to,
test::allocator1<std::pair<int const, overloaded_constructor> > >
x;
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
x.emplace();
BOOST_TEST(
x.find(0) != x.end() && x.find(0)->second == overloaded_constructor());
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
x.emplace();
BOOST_TEST(x.find(0) != x.end() &&
x.find(0)->second == overloaded_constructor());
#endif
x.emplace(2, 3);
BOOST_TEST(
x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3));
x.emplace(2, 3);
BOOST_TEST(x.find(2) != x.end() &&
x.find(2)->second == overloaded_constructor(3));
x.try_emplace(5);
BOOST_TEST(
x.find(5) != x.end() && x.find(5)->second == overloaded_constructor());
x.try_emplace(5);
BOOST_TEST(x.find(5) != x.end() &&
x.find(5)->second == overloaded_constructor());
}
{
boost::unordered_multimap<int, overloaded_constructor, test::hash,
test::equal_to,
test::allocator1<std::pair<int const, overloaded_constructor> > >
x;
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
x.emplace();
BOOST_TEST(x.find(0) != x.end() &&
x.find(0)->second == overloaded_constructor());
#endif
x.emplace(2, 3);
BOOST_TEST(x.find(2) != x.end() &&
x.find(2)->second == overloaded_constructor(3));
}
}
UNORDERED_AUTO_TEST(set_emplace_test)
@ -1052,7 +1146,7 @@ UNORDERED_AUTO_TEST(set_emplace_test)
boost::unordered_set<overloaded_constructor> x;
overloaded_constructor check;
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
x.emplace();
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
#endif
@ -1098,48 +1192,109 @@ struct convertible_to_piecewise
UNORDERED_AUTO_TEST(map_emplace_test2)
{
boost::unordered_map<overloaded_constructor, overloaded_constructor> x;
// Emulating piecewise construction with boost::tuple bypasses the
// allocator's construct method, but still uses test destroy method.
test::detail::disable_construction_tracking _scoped;
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(),
boost::make_tuple());
BOOST_TEST(
x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second == overloaded_constructor());
{
boost::unordered_map<overloaded_constructor, overloaded_constructor,
boost::hash<overloaded_constructor>,
std::equal_to<overloaded_constructor>,
test::allocator1<std::pair<overloaded_constructor const,
overloaded_constructor> > >
x;
x.emplace(
convertible_to_piecewise(), boost::make_tuple(1), boost::make_tuple());
BOOST_TEST(
x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second == overloaded_constructor());
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(),
boost::make_tuple());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3),
boost::make_tuple(4, 5, 6));
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
x.find(overloaded_constructor(2, 3))->second ==
overloaded_constructor(4, 5, 6));
x.emplace(convertible_to_piecewise(), boost::make_tuple(1),
boost::make_tuple());
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
derived_from_piecewise_construct_t d;
x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10));
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
x.find(overloaded_constructor(9, 3, 1))->second ==
overloaded_constructor(10));
x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3),
boost::make_tuple(4, 5, 6));
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
x.find(overloaded_constructor(2, 3))->second ==
overloaded_constructor(4, 5, 6));
x.clear();
derived_from_piecewise_construct_t d;
x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10));
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
x.find(overloaded_constructor(9, 3, 1))->second ==
overloaded_constructor(10));
x.try_emplace(overloaded_constructor());
BOOST_TEST(
x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second == overloaded_constructor());
x.clear();
x.try_emplace(1);
BOOST_TEST(
x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second == overloaded_constructor());
x.try_emplace(overloaded_constructor());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6);
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
x.find(overloaded_constructor(2, 3))->second ==
overloaded_constructor(4, 5, 6));
x.try_emplace(1);
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6);
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
x.find(overloaded_constructor(2, 3))->second ==
overloaded_constructor(4, 5, 6));
x.clear();
x.try_emplace(x.begin(), overloaded_constructor());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.try_emplace(x.end(), 1);
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.try_emplace(x.begin(), overloaded_constructor(2, 3), 4, 5, 6);
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
x.find(overloaded_constructor(2, 3))->second ==
overloaded_constructor(4, 5, 6));
}
{
boost::unordered_multimap<overloaded_constructor,
overloaded_constructor, boost::hash<overloaded_constructor>,
std::equal_to<overloaded_constructor>,
test::allocator1<std::pair<overloaded_constructor const,
overloaded_constructor> > >
x;
x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(),
boost::make_tuple());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.emplace(convertible_to_piecewise(), boost::make_tuple(1),
boost::make_tuple());
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3),
boost::make_tuple(4, 5, 6));
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
x.find(overloaded_constructor(2, 3))->second ==
overloaded_constructor(4, 5, 6));
derived_from_piecewise_construct_t d;
x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10));
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
x.find(overloaded_constructor(9, 3, 1))->second ==
overloaded_constructor(10));
}
}
UNORDERED_AUTO_TEST(set_emplace_test2)
@ -1158,9 +1313,171 @@ UNORDERED_AUTO_TEST(set_emplace_test2)
boost::make_tuple(2, 3));
check =
std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3));
;
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
}
// Use the preprocessor to generate tests using different combinations of
// boost/std piecewise_construct_t/tuple.
#define PIECEWISE_TEST_NAME boost_tuple_piecewise_tests
#define PIECEWISE_NAMESPACE boost::unordered
#define TUPLE_NAMESPACE boost
#define EMULATING_PIECEWISE_CONSTRUCTION 1
#include "./insert_tests.cpp"
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
#define PIECEWISE_TEST_NAME boost_tuple_std_piecewise_tests
#define PIECEWISE_NAMESPACE std
#define TUPLE_NAMESPACE boost
#define EMULATING_PIECEWISE_CONSTRUCTION 1
#include "./insert_tests.cpp"
#endif
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
#define PIECEWISE_TEST_NAME std_tuple_boost_piecewise_tests
#define PIECEWISE_NAMESPACE boost::unordered
#define TUPLE_NAMESPACE std
#define EMULATING_PIECEWISE_CONSTRUCTION 0
#include "./insert_tests.cpp"
#endif
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && \
BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
#define PIECEWISE_TEST_NAME std_piecewise_tests
#define PIECEWISE_NAMESPACE std
#define TUPLE_NAMESPACE std
#define EMULATING_PIECEWISE_CONSTRUCTION 0
#include "./insert_tests.cpp"
#endif
}
RUN_TESTS()
RUN_TESTS_QUIET()
#else // PIECEWISE_TEST_NAME
UNORDERED_AUTO_TEST(PIECEWISE_TEST_NAME)
{
#if EMULATING_PIECEWISE_CONSTRUCTION
test::detail::disable_construction_tracking _scoped;
#endif
{
boost::unordered_map<overloaded_constructor, overloaded_constructor,
boost::hash<overloaded_constructor>,
std::equal_to<overloaded_constructor>,
test::allocator1<std::pair<overloaded_constructor const,
overloaded_constructor> > >
x;
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1),
TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3),
TUPLE_NAMESPACE::make_tuple(4, 5, 6));
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
x.find(overloaded_constructor(2, 3))->second ==
overloaded_constructor(4, 5, 6));
derived_from_piecewise_construct_t d;
x.emplace(d, TUPLE_NAMESPACE::make_tuple(9, 3, 1),
TUPLE_NAMESPACE::make_tuple(10));
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
x.find(overloaded_constructor(9, 3, 1))->second ==
overloaded_constructor(10));
x.clear();
x.try_emplace(overloaded_constructor());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.try_emplace(1);
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6);
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
x.find(overloaded_constructor(2, 3))->second ==
overloaded_constructor(4, 5, 6));
}
{
boost::unordered_multimap<overloaded_constructor,
overloaded_constructor, boost::hash<overloaded_constructor>,
std::equal_to<overloaded_constructor>,
test::allocator1<std::pair<overloaded_constructor const,
overloaded_constructor> > >
x;
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(overloaded_constructor()) != x.end() &&
x.find(overloaded_constructor())->second ==
overloaded_constructor());
x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1),
TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() &&
x.find(overloaded_constructor(1))->second ==
overloaded_constructor());
x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3),
TUPLE_NAMESPACE::make_tuple(4, 5, 6));
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
x.find(overloaded_constructor(2, 3))->second ==
overloaded_constructor(4, 5, 6));
derived_from_piecewise_construct_t d;
x.emplace(d, TUPLE_NAMESPACE::make_tuple(9, 3, 1),
TUPLE_NAMESPACE::make_tuple(10));
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
x.find(overloaded_constructor(9, 3, 1))->second ==
overloaded_constructor(10));
}
}
UNORDERED_AUTO_TEST(BOOST_PP_CAT(PIECEWISE_TEST_NAME, 2))
{
#if EMULATING_PIECEWISE_CONSTRUCTION
test::detail::disable_construction_tracking _scoped;
#endif
boost::unordered_set<
std::pair<overloaded_constructor, overloaded_constructor> >
x;
std::pair<overloaded_constructor, overloaded_constructor> check;
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
x.clear();
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
TUPLE_NAMESPACE::make_tuple(1), TUPLE_NAMESPACE::make_tuple(2, 3));
check =
std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3));
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
}
#undef PIECEWISE_TEST_NAME
#undef PIECEWISE_NAMESPACE
#undef TUPLE_NAMESPACE
#undef EMULATING_PIECEWISE_CONSTRUCTION
#endif

View File

@ -99,7 +99,6 @@ UNORDERED_AUTO_TEST(merge_multiset)
test::check_equivalent_keys(y);
}
#if BOOST_UNORDERED_INTEROPERABLE_NODES
UNORDERED_AUTO_TEST(merge_set_and_multiset)
{
boost::unordered_set<int> x;
@ -139,14 +138,15 @@ UNORDERED_AUTO_TEST(merge_set_and_multiset)
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
}
#endif
template <class X> void merge_empty_test(X*, test::random_generator generator)
template <class X1, class X2>
void merge_empty_test(X1*, X2*, test::random_generator generator)
{
test::check_instances check_;
test::random_values<X> v(1000, generator);
X x1(v.begin(), v.end()), x2;
test::random_values<X1> v(1000, generator);
X1 x1(v.begin(), v.end());
X2 x2;
x1.merge(x2);
test::check_container(x1, v);
BOOST_TEST(x2.empty());
@ -160,7 +160,8 @@ void merge_into_empty_test(X*, test::random_generator generator)
test::check_instances check_;
test::random_values<X> v(1000, generator);
X x1, x2(v.begin(), v.end());
X x1;
X x2(v.begin(), v.end());
x1.merge(x2);
test::check_container(x1, v);
BOOST_TEST(x2.empty());
@ -168,89 +169,173 @@ void merge_into_empty_test(X*, test::random_generator generator)
test::check_equivalent_keys(x2);
}
template <class X> void unique_merge_test(X*, test::random_generator generator)
template <class X1, class X2>
void merge_into_unique_keys_test(X1*, X2*, int hash_equal1, int hash_equal2,
test::random_generator generator)
{
test::check_instances check_;
test::random_values<X> v1(1000, generator);
test::random_values<X> v2(1000, generator);
test::random_values<X1> v1(1000, generator);
test::random_values<X2> v2(1000, generator);
v1.insert(v2.begin(), boost::next(v2.begin(), 100));
v2.insert(v1.begin(), boost::next(v1.begin(), 100));
X x1(v1.begin(), v1.end()), x2(v2.begin(), v2.end());
x1.merge(x2);
X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1),
test::equal_to(hash_equal1));
X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2),
test::equal_to(hash_equal2));
test::ordered<X> tracker1 = test::create_ordered(x1);
test::ordered<X> tracker2 = test::create_ordered(x2);
test::ordered<X> tracker_tmp = test::create_ordered(x2);
test::ordered<X1> tracker1 = test::create_ordered(x1);
test::ordered<X2> tracker2 = test::create_ordered(x2);
tracker1.insert(v1.begin(), v1.end());
tracker_tmp.insert(v2.begin(), v2.end());
for (BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator it =
tracker_tmp.begin();
it != tracker_tmp.end(); ++it) {
for (typename X2::iterator it = x2.begin(); it != x2.end(); ++it) {
if (!tracker1.insert(*it).second) {
tracker2.insert(*it);
}
}
x1.merge(x2);
tracker1.compare(x1);
tracker2.compare(x2);
test::check_equivalent_keys(x1);
test::check_equivalent_keys(x2);
}
template <class X> void equiv_merge_test(X*, test::random_generator generator)
template <class X1, class X2>
void merge_into_equiv_keys_test(X1*, X2*, int hash_equal1, int hash_equal2,
test::random_generator generator)
{
test::check_instances check_;
test::random_values<X> v1(1000, generator);
test::random_values<X> v2(1000, generator);
test::random_values<X1> v1(1000, generator);
test::random_values<X2> v2(1000, generator);
v1.insert(v2.begin(), boost::next(v2.begin(), 100));
v2.insert(v1.begin(), boost::next(v1.begin(), 100));
X x1(v1.begin(), v1.end()), x2(v2.begin(), v2.end());
X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1),
test::equal_to(hash_equal1));
X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2),
test::equal_to(hash_equal2));
x1.merge(x2);
test::ordered<X> tracker1 = test::create_ordered(x1);
test::ordered<X1> tracker1 = test::create_ordered(x1);
test::ordered<X2> tracker2 = test::create_ordered(x2);
tracker1.insert(v1.begin(), v1.end());
tracker1.insert(v2.begin(), v2.end());
tracker2.insert(v2.begin(), v2.end());
tracker1.insert(tracker2.begin(), tracker2.end());
tracker2.clear();
tracker1.compare(x1);
BOOST_TEST(x2.empty());
tracker2.compare(x2);
test::check_equivalent_keys(x1);
test::check_equivalent_keys(x2);
}
boost::unordered_set<test::movable, test::hash, test::equal_to,
std::allocator<test::movable> >* test_set_std_alloc;
boost::unordered_multiset<test::movable, test::hash, test::equal_to,
std::allocator<test::movable> >* test_multiset_std_alloc;
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
std::allocator<test::object> >* test_map_std_alloc;
boost::unordered_multimap<test::object, test::object, test::hash,
test::equal_to, std::allocator<test::object> >* test_multimap_std_alloc;
boost::unordered_set<test::object, test::hash, test::equal_to,
test::allocator1<test::object> >* test_set;
boost::unordered_multiset<test::movable, test::hash, test::equal_to,
test::allocator2<test::movable> >* test_multiset;
boost::unordered_multiset<test::object, test::hash, test::equal_to,
test::allocator1<test::object> >* test_multiset;
boost::unordered_map<test::movable, test::movable, test::hash, test::equal_to,
test::allocator2<test::movable> >* test_map;
boost::unordered_multimap<test::object, test::object, test::hash,
test::equal_to, test::allocator1<test::object> >* test_multimap;
boost::unordered_multimap<test::movable, test::movable, test::hash,
test::equal_to, test::allocator2<test::movable> >* test_multimap;
using test::default_generator;
using test::generate_collisions;
// clang-format off
UNORDERED_TEST(merge_empty_test,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_multiset)(
test_map)(test_multimap))((default_generator)(generate_collisions)))
((test_set_std_alloc)(test_multiset_std_alloc))
((test_set_std_alloc)(test_multiset_std_alloc))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_empty_test,
((test_map_std_alloc)(test_multimap_std_alloc))
((test_map_std_alloc)(test_multimap_std_alloc))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_empty_test,
((test_set)(test_multiset))
((test_set)(test_multiset))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_empty_test,
((test_map)(test_multimap))
((test_map)(test_multimap))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_empty_test,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_multiset)(
test_map)(test_multimap))((default_generator)(generate_collisions)))
((test_set_std_alloc)(test_multiset_std_alloc))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_empty_test,
((test_map_std_alloc)(test_multimap_std_alloc))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_empty_test,
((test_set)(test_multiset))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_empty_test,
((test_map)(test_multimap))
((default_generator)(generate_collisions)))
UNORDERED_TEST(unique_merge_test,
((test_set_std_alloc)(test_set)(test_map))((default_generator)))
UNORDERED_TEST(merge_into_unique_keys_test,
((test_set_std_alloc))
((test_set_std_alloc)(test_multiset_std_alloc))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_unique_keys_test,
((test_map_std_alloc))
((test_map_std_alloc)(test_multimap_std_alloc))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_unique_keys_test,
((test_set))
((test_set)(test_multiset))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_unique_keys_test,
((test_map))
((test_map)(test_multimap))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(equiv_merge_test, ((test_multimap_std_alloc)(test_multiset)(
test_multimap))((default_generator)))
UNORDERED_TEST(merge_into_equiv_keys_test,
((test_multiset_std_alloc))
((test_set_std_alloc)(test_multiset_std_alloc))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_equiv_keys_test,
((test_multimap_std_alloc))
((test_map_std_alloc)(test_multimap_std_alloc))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_equiv_keys_test,
((test_multiset))
((test_set)(test_multiset))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
UNORDERED_TEST(merge_into_equiv_keys_test,
((test_multimap))
((test_map)(test_multimap))
((0)(1)(2))
((0)(1)(2))
((default_generator)(generate_collisions)))
// clang-format on
}
RUN_TESTS()

View File

@ -36,7 +36,8 @@ bool throwing_test_exception = false;
void test_throw(char const* name)
{
if (throwing_test_exception) {
std::cerr << "Throw exception in: " << name << std::endl;
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Throw exception in: " << name
<< std::endl;
throw test_exception();
}
}

View File

@ -93,7 +93,7 @@ UNORDERED_AUTO_TEST(simple_tests)
using namespace std;
srand(14878);
std::cout << "Test unordered_set.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
boost::unordered_set<int> set;
simple_test(set);
@ -102,7 +102,7 @@ UNORDERED_AUTO_TEST(simple_tests)
set.insert(1456);
simple_test(set);
std::cout << "Test unordered_multiset.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
boost::unordered_multiset<int> multiset;
simple_test(multiset);
@ -113,7 +113,7 @@ UNORDERED_AUTO_TEST(simple_tests)
}
simple_test(multiset);
std::cout << "Test unordered_map.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
boost::unordered_map<int, int> map;
for (int i2 = 0; i2 < 1000; ++i2) {
@ -121,7 +121,7 @@ UNORDERED_AUTO_TEST(simple_tests)
}
simple_test(map);
std::cout << "Test unordered_multimap.\n";
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
boost::unordered_multimap<int, int> multimap;
for (int i3 = 0; i3 < 1000; ++i3) {

View File

@ -10,7 +10,6 @@
#include "../helpers/postfix.hpp"
// clang-format on
#include <iostream>
#include "../helpers/test.hpp"
namespace unnecessary_copy_tests {
@ -138,32 +137,36 @@ std::size_t hash_value(unnecessary_copy_tests::count_copies const& x)
#define COPY_COUNT(n) \
if (::unnecessary_copy_tests::count_copies::copies != n) { \
BOOST_ERROR("Wrong number of copies."); \
std::cerr << "Number of copies: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: " << n << std::endl; \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Number of copies: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: " << n << std::endl; \
}
#define MOVE_COUNT(n) \
if (::unnecessary_copy_tests::count_copies::moves != n) { \
BOOST_ERROR("Wrong number of moves."); \
std::cerr << "Number of moves: " \
<< ::unnecessary_copy_tests::count_copies::moves \
<< " expecting: " << n << std::endl; \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Number of moves: " \
<< ::unnecessary_copy_tests::count_copies::moves \
<< " expecting: " << n << std::endl; \
}
#define COPY_COUNT_RANGE(a, b) \
if (::unnecessary_copy_tests::count_copies::copies < a || \
::unnecessary_copy_tests::count_copies::copies > b) { \
BOOST_ERROR("Wrong number of copies."); \
std::cerr << "Number of copies: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Number of copies: " \
<< ::unnecessary_copy_tests::count_copies::copies \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
}
#define MOVE_COUNT_RANGE(a, b) \
if (::unnecessary_copy_tests::count_copies::moves < a || \
::unnecessary_copy_tests::count_copies::moves > b) { \
BOOST_ERROR("Wrong number of moves."); \
std::cerr << "Number of moves: " \
<< ::unnecessary_copy_tests::count_copies::moves \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
<< "Number of moves: " \
<< ::unnecessary_copy_tests::count_copies::moves \
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
}
#define COPY_COUNT_EXTRA(a, b) COPY_COUNT_RANGE(a, a + b * EXTRA_CONSTRUCT_COST)
#define MOVE_COUNT_EXTRA(a, b) MOVE_COUNT_RANGE(a, a + b * EXTRA_CONSTRUCT_COST)
@ -180,6 +183,53 @@ template <class T> void unnecessary_copy_insert_test(T*)
reset();
x.insert(a);
COPY_COUNT(1);
MOVE_COUNT(0);
}
template <class T> void unnecessary_copy_insert_rvalue_set_test(T*)
{
T x;
BOOST_DEDUCED_TYPENAME T::value_type a;
reset();
x.insert(boost::move(a));
COPY_COUNT(0);
MOVE_COUNT(1);
BOOST_DEDUCED_TYPENAME T::value_type a2;
reset();
x.insert(boost::move(a));
COPY_COUNT(0);
MOVE_COUNT((x.size() == 2 ? 1 : 0));
}
template <class T> void unnecessary_copy_insert_rvalue_map_test(T*)
{
// Doesn't currently try to emulate std::pair move construction,
// so std::pair's require a copy. Could try emulating it in
// construct_from_args.
T x;
BOOST_DEDUCED_TYPENAME T::value_type a;
reset();
x.insert(boost::move(a));
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(1);
MOVE_COUNT(0);
#else
COPY_COUNT(0);
MOVE_COUNT(1);
#endif
BOOST_DEDUCED_TYPENAME T::value_type a2;
reset();
x.insert(boost::move(a));
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT((x.size() == 2 ? 1 : 0));
MOVE_COUNT(0);
#else
COPY_COUNT(0);
MOVE_COUNT((x.size() == 2 ? 1 : 0));
#endif
}
boost::unordered_set<count_copies>* set;
@ -188,6 +238,8 @@ boost::unordered_map<int, count_copies>* map;
boost::unordered_multimap<int, count_copies>* multimap;
UNORDERED_TEST(unnecessary_copy_insert_test, ((set)(multiset)(map)(multimap)))
UNORDERED_TEST(unnecessary_copy_insert_rvalue_set_test, ((set)(multiset)))
UNORDERED_TEST(unnecessary_copy_insert_rvalue_map_test, ((map)(multimap)))
template <class T> void unnecessary_copy_emplace_test(T*)
{
@ -310,20 +362,15 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
// 0 arguments
//
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
// The container will have to create a copy in order to compare with
// the existing element.
reset();
x.emplace();
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
// source_cost doesn't make much sense here, but it seems to fit.
COPY_COUNT(1);
MOVE_COUNT(source_cost);
#else
COPY_COUNT(1);
MOVE_COUNT(1 + source_cost);
#endif
#endif
//
@ -347,13 +394,8 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
// No move should take place.
reset();
x.emplace(boost::move(a));
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
COPY_COUNT(0);
MOVE_COUNT(0);
#else
COPY_COUNT(0);
MOVE_COUNT(1);
#endif
// Use a new value for cases where a did get moved...
count_copies b;
@ -409,7 +451,7 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test)
// 0 arguments
//
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
// COPY_COUNT(1) would be okay here.
reset();
x.emplace();
@ -501,7 +543,7 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test)
COPY_COUNT(0);
MOVE_COUNT(0);
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE)
#if BOOST_UNORDERED_TUPLE_ARGS
reset();
x.emplace(boost::unordered::piecewise_construct,