diff --git a/.travis.yml b/.travis.yml index e6c0c766..01420b5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,9 @@ language: c++ addons: apt: packages: - - libboost-dev - libboost-tools-dev + - libxml2-utils + - g++-multilib matrix: include: @@ -20,19 +21,40 @@ matrix: env: BJAM_TOOLSET=gcc - compiler: gcc env: BJAM_TOOLSET=gcc-std11 - - compiler: clang - env: BJAM_TOOLSET=clang + #- compiler: gcc + # env: BJAM_TOOLSET=gcc-m32 + - compiler: gcc + env: BJAM_TOOLSET=gcc-std11m32 + #- compiler: clang + # env: BJAM_TOOLSET=clang - compiler: clang env: BJAM_TOOLSET=clang-std11 + - compiler: clang + env: BJAM_TOOLSET=clang-m32 + #- compiler: clang + # env: BJAM_TOOLSET=clang-std11m32 before_script: + - cd ${TRAVIS_BUILD_DIR} + - touch Jamroot.jam + - cd $HOME - | echo "using gcc : : g++-4.8 -Werror --std=c++03 -fsanitize=address ;" > ~/user-config.jam echo "using gcc : std11 : g++-4.8 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam + echo "using gcc : m32 : g++-4.8 -m32 -Werror -fsanitize=address ;" >> ~/user-config.jam + echo "using gcc : std11m32 : g++-4.8 -m32 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam echo "using clang : : clang++ -Werror --std=c++03 -fsanitize=address ;" >> ~/user-config.jam echo "using clang : std11 : clang++ -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam + # sanitized=address not available for 32-bit clang on travis. + echo "using clang : m32 : clang++ -m32 -Werror --std=c++03 ;" >> ~/user-config.jam + echo "using clang : std11m32 : clang++ -m32 -Werror --std=c++11 ;" >> ~/user-config.jam - cat ~/user-config.jam - - touch Jamroot.jam + - wget -O boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/snapshots/master/boost_1_62_0.tar.bz2/download + - tar -xjf boost.tar.bz2 + - mv boost_1_62_0 boost + - rm -r boost/boost/unordered script: - - cd test && bjam ${BJAM_TOOLSET} include=${TRAVIS_BUILD_DIR}/include + - cd ${TRAVIS_BUILD_DIR}/test + - bjam ${BJAM_TOOLSET} include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include + - xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml diff --git a/doc/changes.qbk b/doc/changes.qbk index 54002878..03fe1987 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -279,4 +279,19 @@ C++11 support has resulted in some breaking changes: * Stop using return value SFINAE which some older compilers have issues with. +[h2 Boost 1.63.0] + +* Check hint iterator in `insert`/`emplace_hint`. +* Fix some warnings, mostly in the tests. +* Manually write out `emplace_args` for small numbers of arguments - + should make template error messages a little more bearable. +* Remove superfluous use of `boost::forward` in emplace arguments, + which fixes emplacing string literals in old versions of Visual C++. +* Fix an exception safety issue in assignment. If bucket allocation + throws an exception, it can overwrite the hash and equality functions while + leaving the existing elements in place. This would mean that the function + objects wouldn't match the container elements, so elements might be in the + wrong bucket and equivalent elements would be incorrectly handled. +* Various reference documentation improvements. + [endsect] diff --git a/doc/ref.php b/doc/ref.php index 0a474807..d2fb2b42 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -358,6 +358,21 @@ EOL; + + + initializer_list<value_type> + + & + + Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed. + + + + value_type is CopyInsertable into the container and + CopyAssignable. + + + allocator_type @@ -640,7 +655,35 @@ EOL; void - Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent . + Inserts a range of elements into the container. + + Elements are inserted if and only if there is no element in the container with an equivalent . + + + + + value_type is EmplaceConstructible into + X from *first. + + + When inserting a single element, if an exception is thrown by an operation other than a call to hasher the function has no effect. + + + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + + + + + initializer_list<value_type> + + void + + Inserts a range of elements into the container. + + Elements are inserted if and only if there is no element in the container with an equivalent . + + value_type is EmplaceConstructible into diff --git a/doc/ref.xml b/doc/ref.xml index f16e6028..d03e8dd3 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -299,6 +299,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + + initializer_list<value_type> + + unordered_set& + + Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed. + + + + value_type is CopyInsertable into the container and + CopyAssignable. + + + allocator_type @@ -537,7 +552,31 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent value. + Inserts a range of elements into the container. + Elements are inserted if and only if there is no element in the container with an equivalent value. + + + + value_type is EmplaceConstructible into + X from *first. + + + When inserting a single element, if an exception is thrown by an operation other than a call to hasher the function has no effect. + + + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + + + + + initializer_list<value_type> + + void + + Inserts a range of elements into the container. + Elements are inserted if and only if there is no element in the container with an equivalent value. + value_type is EmplaceConstructible into @@ -1334,6 +1373,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + + initializer_list<value_type> + + unordered_multiset& + + Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed. + + + + value_type is CopyInsertable into the container and + CopyAssignable. + + + allocator_type @@ -1569,7 +1623,29 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent value. + Inserts a range of elements into the container. + + + + value_type is EmplaceConstructible into + X from *first. + + + When inserting a single element, if an exception is thrown by an operation other than a call to hasher the function has no effect. + + + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + + + + + initializer_list<value_type> + + void + + Inserts a range of elements into the container. + value_type is EmplaceConstructible into @@ -2380,6 +2456,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + + initializer_list<value_type> + + unordered_map& + + Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed. + + + + value_type is CopyInsertable into the container and + CopyAssignable. + + + allocator_type @@ -2618,7 +2709,31 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + Inserts a range of elements into the container. + Elements are inserted if and only if there is no element in the container with an equivalent key. + + + + value_type is EmplaceConstructible into + X from *first. + + + When inserting a single element, if an exception is thrown by an operation other than a call to hasher the function has no effect. + + + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + + + + + initializer_list<value_type> + + void + + Inserts a range of elements into the container. + Elements are inserted if and only if there is no element in the container with an equivalent key. + value_type is EmplaceConstructible into @@ -3462,6 +3577,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + + initializer_list<value_type> + + unordered_multimap& + + Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed. + + + + value_type is CopyInsertable into the container and + CopyAssignable. + + + allocator_type @@ -3697,7 +3827,29 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + Inserts a range of elements into the container. + + + + value_type is EmplaceConstructible into + X from *first. + + + When inserting a single element, if an exception is thrown by an operation other than a call to hasher the function has no effect. + + + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + + + + + initializer_list<value_type> + + void + + Inserts a range of elements into the container. + value_type is EmplaceConstructible into diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index a83edad2..319c9cd5 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -96,26 +96,102 @@ namespace boost { namespace unordered { namespace detail { #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) -#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args -#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args -#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward(args)... - #define BOOST_UNORDERED_EMPLACE_ARGS1(a0) a0 #define BOOST_UNORDERED_EMPLACE_ARGS2(a0, a1) a0, a1 #define BOOST_UNORDERED_EMPLACE_ARGS3(a0, a1, a2) a0, a1, a2 +#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args +#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args +#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward(args)... + #else +#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args +#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args +#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args + #define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args #define BOOST_UNORDERED_EMPLACE_ARGS Args const& args #define BOOST_UNORDERED_EMPLACE_FORWARD args +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ + typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \ + BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); + +#else + +#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ + typedef typename boost::add_lvalue_reference::type \ + BOOST_PP_CAT(Arg, n); \ + BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); + +#endif + +template +struct emplace_args1 +{ + BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) + + emplace_args1(Arg0 b0) : a0(b0) {} +}; + +template +inline emplace_args1 create_emplace_args( + BOOST_FWD_REF(A0) b0) +{ + emplace_args1 e(b0); + return e; +} + +template +struct emplace_args2 +{ + BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) + BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) + + emplace_args2(Arg0 b0, Arg1 b1) : a0(b0), a1(b1) {} +}; + +template +inline emplace_args2 create_emplace_args( + BOOST_FWD_REF(A0) b0, + BOOST_FWD_REF(A1) b1) +{ + emplace_args2 e(b0, b1); + return e; +} + +template +struct emplace_args3 +{ + BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) + BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) + BOOST_UNORDERED_EARGS_MEMBER(1, 2, _) + + emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : a0(b0), a1(b1), a2(b2) {} +}; + +template +inline emplace_args3 create_emplace_args( + BOOST_FWD_REF(A0) b0, + BOOST_FWD_REF(A1) b1, + BOOST_FWD_REF(A2) b2) +{ + emplace_args3 e(b0, b1, b2); + return e; +} + #define BOOST_UNORDERED_FWD_PARAM(z, n, a) \ BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n) #define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \ boost::forward(BOOST_PP_CAT(a,i)) +#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ +BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n)) + #define BOOST_UNORDERED_EARGS(z, n, _) \ template \ struct BOOST_PP_CAT(emplace_args, n) \ @@ -141,33 +217,7 @@ namespace boost { namespace unordered { namespace detail { return e; \ } -#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args -#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args -#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args - -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - -#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ - typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \ - BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); - -#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ - BOOST_PP_CAT(a, n)( \ - boost::forward(BOOST_PP_CAT(b, n))) - -#else - -#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \ - typedef typename boost::add_lvalue_reference::type \ - BOOST_PP_CAT(Arg, n); \ - BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); - -#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ - BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n)) - -#endif - -BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, +BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, _) #undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 232944b0..31e1ee59 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -583,12 +583,12 @@ namespace boost { namespace unordered { namespace detail { // TODO: Maybe not if std::size_t is smaller than long long. #if !defined(BOOST_NO_LONG_LONG) template <> - struct pick_policy { + struct pick_policy { typedef prime_policy type; }; template <> - struct pick_policy { + struct pick_policy { typedef prime_policy type; }; #endif diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 691d3154..5835884a 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -321,7 +321,10 @@ namespace boost { namespace unordered { namespace detail { // Emplace/Insert - static inline void add_after_node( + // Add node 'n' to the group containing 'pos'. + // If 'pos' is the first node in group, add to the end of the group, + // otherwise add before 'pos'. + static inline void add_to_node_group( node_pointer n, node_pointer pos) { @@ -338,7 +341,7 @@ namespace boost { namespace unordered { namespace detail { { n->hash_ = key_hash; if (pos.node_) { - this->add_after_node(n, pos.node_); + this->add_to_node_group(n, pos.node_); if (n->next_) { std::size_t next_bucket = this->hash_to_bucket( static_cast(n->next_)->hash_); @@ -375,24 +378,23 @@ namespace boost { namespace unordered { namespace detail { return iterator(n); } - iterator emplace_impl(node_pointer n) + inline iterator add_using_hint( + node_pointer n, + node_pointer hint) { - node_tmp a(n, this->node_alloc()); - key_type const& k = this->get_key(a.node_->value()); - std::size_t key_hash = this->hash(k); - iterator position = this->find_node(key_hash, k); - this->reserve_for_insert(this->size_ + 1); - return this->add_node(a.release(), key_hash, position); + n->hash_ = hint->hash_; + this->add_to_node_group(n, hint); + if (n->next_ != hint && n->next_) { + std::size_t next_bucket = this->hash_to_bucket( + static_cast(n->next_)->hash_); + if (next_bucket != this->hash_to_bucket(n->hash_)) { + this->get_bucket(next_bucket)->next_ = n; + } + } + ++this->size_; + return iterator(n); } - void emplace_impl_no_rehash(node_pointer n) - { - node_tmp a(n, this->node_alloc()); - key_type const& k = this->get_key(a.node_->value()); - std::size_t key_hash = this->hash(k); - iterator position = this->find_node(key_hash, k); - this->add_node(a.release(), key_hash, position); - } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) # if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -402,6 +404,13 @@ namespace boost { namespace unordered { namespace detail { BOOST_ASSERT(false); return iterator(); } + + iterator emplace_hint(c_iterator, boost::unordered::detail::emplace_args1< + boost::unordered::detail::please_ignore_this_overload> const&) + { + BOOST_ASSERT(false); + return iterator(); + } # else iterator emplace( boost::unordered::detail::please_ignore_this_overload const&) @@ -409,6 +418,13 @@ namespace boost { namespace unordered { namespace detail { BOOST_ASSERT(false); return iterator(); } + + iterator emplace_hint(c_iterator, + boost::unordered::detail::please_ignore_this_overload const&) + { + BOOST_ASSERT(false); + return iterator(); + } # endif #endif @@ -420,6 +436,49 @@ namespace boost { namespace unordered { namespace detail { this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); } + template + iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS) + { + return iterator(emplace_hint_impl(hint, + boost::unordered::detail::func::construct_value_generic( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); + } + + iterator emplace_impl(node_pointer n) + { + node_tmp a(n, this->node_alloc()); + key_type const& k = this->get_key(a.node_->value()); + std::size_t key_hash = this->hash(k); + iterator position = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + return this->add_node(a.release(), key_hash, position); + } + + iterator emplace_hint_impl(c_iterator hint, node_pointer n) + { + node_tmp a(n, this->node_alloc()); + key_type const& k = this->get_key(a.node_->value()); + if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + this->reserve_for_insert(this->size_ + 1); + return this->add_using_hint(a.release(), hint.node_); + } + else { + std::size_t key_hash = this->hash(k); + iterator position = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + return this->add_node(a.release(), key_hash, position); + } + } + + void emplace_impl_no_rehash(node_pointer n) + { + node_tmp a(n, this->node_alloc()); + key_type const& k = this->get_key(a.node_->value()); + std::size_t key_hash = this->hash(k); + iterator position = this->find_node(key_hash, k); + this->add_node(a.release(), key_hash, position); + } + //////////////////////////////////////////////////////////////////////// // Insert range methods @@ -431,7 +490,7 @@ namespace boost { namespace unordered { namespace detail { { if(i == j) return; - std::size_t distance = std::distance(i, j); + std::size_t distance = static_cast(std::distance(i, j)); if(distance == 1) { emplace_impl( boost::unordered::detail::func::construct_value( diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index d68a4a77..338e918c 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -51,7 +51,7 @@ namespace detail { typedef ValueType value_type; typedef ValueType key_type; - static key_type const& extract(key_type const& v) + static key_type const& extract(value_type const& v) { return v; } diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 87c2c23b..74419062 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -1,5 +1,5 @@ -// Copyright (C) 2008-2011 Daniel James. +// Copyright (C) 2008-2016 Daniel James. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -11,12 +11,46 @@ #pragma once #endif +#if defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT) +// Already defined. +#elif defined(BOOST_LIBSTDCXX11) +// https://github.com/gcc-mirror/gcc/blob/gcc-4_6-branch/libstdc++-v3/include/bits/stl_pair.h#L70 +# if BOOST_LIBSTDCXX_VERSION > 40600 +# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 +# endif +#elif defined(_LIBCPP_VERSION) +// https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206 +# if LIBCPP_VERSION >= 3000 +# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 +# endif +#elif defined(BOOST_MSVC) +// Apparently C++11 standard supported in Visual Studio 2012 +// https://msdn.microsoft.com/en-us/library/hh567368.aspx#stl +// 2012 = VC+11 = BOOST_MSVC 1700 Hopefully! +# if BOOST_MSVC >= 1700 +# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 +# endif +#endif + +#if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT) +#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 0 +#endif + +#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT +#include +#endif + namespace boost { namespace unordered { +#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT + using std::piecewise_construct_t; + using std::piecewise_construct; +#else struct piecewise_construct_t {}; const piecewise_construct_t piecewise_construct = piecewise_construct_t(); +#endif } } diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index ab4000b4..6ae1d73e 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -584,7 +584,6 @@ namespace boost { namespace unordered { namespace detail { { // Strong exception safety. set_hash_functions new_func_this(*this, x); - new_func_this.commit(); mlf_ = x.mlf_; recalculate_max_load(); @@ -597,6 +596,7 @@ namespace boost { namespace unordered { namespace detail { clear_buckets(); } + new_func_this.commit(); static_cast(this)->assign_buckets(x); } @@ -663,11 +663,13 @@ namespace boost { namespace unordered { namespace detail { } else { set_hash_functions new_func_this(*this, x); - new_func_this.commit(); mlf_ = x.mlf_; recalculate_max_load(); - if (!size_ && !x.size_) return; + if (!size_ && !x.size_) { + new_func_this.commit(); + return; + } if (x.size_ >= max_load_) { create_buckets(min_buckets_for_size(x.size_)); @@ -676,6 +678,7 @@ namespace boost { namespace unordered { namespace detail { clear_buckets(); } + new_func_this.commit(); static_cast(this)->move_assign_buckets(x); } } diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 07923981..db397980 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -316,6 +316,14 @@ namespace boost { namespace unordered { namespace detail { BOOST_ASSERT(false); return emplace_return(this->begin(), false); } + + iterator emplace_hint(c_iterator, + boost::unordered::detail::emplace_args1< + boost::unordered::detail::please_ignore_this_overload> const&) + { + BOOST_ASSERT(false); + return this->begin(); + } # else emplace_return emplace( boost::unordered::detail::please_ignore_this_overload const&) @@ -323,6 +331,13 @@ namespace boost { namespace unordered { namespace detail { BOOST_ASSERT(false); return emplace_return(this->begin(), false); } + + iterator emplace_hint(c_iterator, + boost::unordered::detail::please_ignore_this_overload const&) + { + BOOST_ASSERT(false); + return this->begin(); + } # endif #endif @@ -340,6 +355,21 @@ namespace boost { namespace unordered { namespace detail { #endif } + template + iterator emplace_hint(c_iterator hint, + BOOST_UNORDERED_EMPLACE_ARGS) + { +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + return emplace_hint_impl(hint, + extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD), + BOOST_UNORDERED_EMPLACE_FORWARD); +#else + return emplace_hint_impl(hint, + extractor::extract(args.a0, args.a1), + BOOST_UNORDERED_EMPLACE_FORWARD); +#endif + } + #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template emplace_return emplace( @@ -347,8 +377,27 @@ namespace boost { namespace unordered { namespace detail { { return emplace_impl(extractor::extract(args.a0), args); } + + template + iterator emplace_hint(c_iterator hint, + boost::unordered::detail::emplace_args1 const& args) + { + return emplace_hint_impl(hint, extractor::extract(args.a0), args); + } #endif + template + iterator emplace_hint_impl(c_iterator hint, key_type const& k, + BOOST_UNORDERED_EMPLACE_ARGS) + { + if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + return iterator(hint.node_); + } + else { + return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; + } + } + template emplace_return emplace_impl(key_type const& k, BOOST_UNORDERED_EMPLACE_ARGS) @@ -368,11 +417,31 @@ namespace boost { namespace unordered { namespace detail { } } + template + iterator emplace_hint_impl(c_iterator hint, no_key, + BOOST_UNORDERED_EMPLACE_ARGS) + { + node_tmp b( + boost::unordered::detail::func::construct_value_generic( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + this->node_alloc()); + key_type const& k = this->get_key(b.node_->value()); + if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + return iterator(hint.node_); + } + std::size_t key_hash = this->hash(k); + iterator pos = this->find_node(key_hash, k); + if (pos.node_) { + return pos; + } + else { + return this->resize_and_add_node(b.release(), key_hash); + } + } + template emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS) { - // Don't have a key, so construct the node first in order - // to be able to lookup the position. node_tmp b( boost::unordered::detail::func::construct_value_generic( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 0a406c85..cd722e44 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -128,7 +128,7 @@ namespace boost { namespace unordered { namespace detail { inline std::size_t insert_size(I i, I j, typename boost::unordered::detail::enable_if_forward::type = 0) { - return std::distance(i, j); + return static_cast(std::distance(i, j)); } template diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 3904e56e..fc6fbe0e 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -240,9 +240,9 @@ namespace unordered } template - iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args) + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace(boost::forward(args)...).first; + return table_.emplace_hint(hint, boost::forward(args)...); } #else @@ -281,12 +281,12 @@ namespace unordered } template - iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0) + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0)) - ).first; + ); } template @@ -302,15 +302,15 @@ namespace unordered } template - iterator emplace_hint(const_iterator, + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1)) - ).first; + ); } template @@ -328,17 +328,17 @@ namespace unordered } template - iterator emplace_hint(const_iterator, + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), boost::forward(a2)) - ).first; + ); } #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -360,15 +360,15 @@ namespace unordered BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ > \ iterator emplace_hint( \ - const_iterator, \ + const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ ) \ { \ - return table_.emplace( \ + return table_.emplace_hint(hint, \ boost::unordered::detail::create_emplace_args( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ a) \ - )).first; \ + )); \ } BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -724,9 +724,9 @@ namespace unordered } template - iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args) + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace(boost::forward(args)...); + return table_.emplace_hint(hint, boost::forward(args)...); } #else @@ -765,9 +765,9 @@ namespace unordered } template - iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0) + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0)) ); @@ -786,11 +786,11 @@ namespace unordered } template - iterator emplace_hint(const_iterator, + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1)) @@ -812,12 +812,12 @@ namespace unordered } template - iterator emplace_hint(const_iterator, + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), @@ -844,11 +844,11 @@ namespace unordered BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ > \ iterator emplace_hint( \ - const_iterator, \ + const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ ) \ { \ - return table_.emplace( \ + return table_.emplace_hint(hint, \ boost::unordered::detail::create_emplace_args( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ a) \ diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index c8c06215..aa9911bc 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -237,9 +237,9 @@ namespace unordered } template - iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args) + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace(boost::forward(args)...).first; + return table_.emplace_hint(hint, boost::forward(args)...); } #else @@ -278,12 +278,12 @@ namespace unordered } template - iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0) + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0)) - ).first; + ); } template @@ -299,15 +299,15 @@ namespace unordered } template - iterator emplace_hint(const_iterator, + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1)) - ).first; + ); } template @@ -325,17 +325,17 @@ namespace unordered } template - iterator emplace_hint(const_iterator, + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), boost::forward(a2)) - ).first; + ); } #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -357,15 +357,15 @@ namespace unordered BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ > \ iterator emplace_hint( \ - const_iterator, \ + const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ ) \ { \ - return table_.emplace( \ + return table_.emplace_hint(hint, \ boost::unordered::detail::create_emplace_args( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ a) \ - )).first; \ + )); \ } BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -707,9 +707,9 @@ namespace unordered } template - iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args) + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace(boost::forward(args)...); + return table_.emplace_hint(hint, boost::forward(args)...); } #else @@ -748,9 +748,9 @@ namespace unordered } template - iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0) + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0)) ); @@ -769,11 +769,11 @@ namespace unordered } template - iterator emplace_hint(const_iterator, + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1)) @@ -795,12 +795,12 @@ namespace unordered } template - iterator emplace_hint(const_iterator, + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace( + return table_.emplace_hint(hint, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), @@ -827,11 +827,11 @@ namespace unordered BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \ > \ iterator emplace_hint( \ - const_iterator, \ + const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ ) \ { \ - return table_.emplace( \ + return table_.emplace_hint(hint, \ boost::unordered::detail::create_emplace_args( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \ a) \ diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2803eabc..f2207f89 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -11,9 +11,9 @@ project unordered-test/unordered intel:on # Would be nice to define -Wundef, but I'm getting warnings from # Boost.Preprocessor on trunk. - gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow -Wno-long-long" + gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow" darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow" - clang:"-pedantic -Wextra -Wno-long-long" + clang:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow" ; #alias framework : /boost/test//boost_unit_test_framework ; @@ -38,6 +38,7 @@ test-suite unordered [ run unordered/assign_tests.cpp ] [ run unordered/insert_tests.cpp ] [ run unordered/insert_stable_tests.cpp ] + [ run unordered/insert_hint_tests.cpp ] [ run unordered/unnecessary_copy_tests.cpp ] [ run unordered/erase_tests.cpp ] [ run unordered/erase_equiv_tests.cpp ] @@ -71,6 +72,7 @@ test-suite unordered-exception [ run exception/constructor_exception_tests.cpp framework ] [ run exception/copy_exception_tests.cpp framework ] [ run exception/assign_exception_tests.cpp framework ] + [ run exception/move_assign_exception_tests.cpp framework ] [ run exception/insert_exception_tests.cpp framework ] [ run exception/erase_exception_tests.cpp framework ] [ run exception/rehash_exception_tests.cpp framework ] diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index a9f4976f..e8304ee9 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -17,7 +17,7 @@ template struct self_assign_base : public test::exception_base { test::random_values values; - self_assign_base(int count = 0) : values(count) {} + self_assign_base(std::size_t count = 0) : values(count) {} typedef T data_type; T init() const { return T(values.begin(), values.end()); } @@ -111,6 +111,12 @@ struct assign_test4 : assign_values assign_test4() : assign_values(10, 10, 1, 2) {} }; +template +struct assign_test4a : assign_values +{ + assign_test4a() : assign_values(10, 100, 1, 2) {} +}; + template struct assign_test5 : assign_values { @@ -136,7 +142,7 @@ struct equivalent_test1 : assign_base EXCEPTION_TESTS( (self_assign_test1)(self_assign_test2) - (assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test5) + (assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test4a)(assign_test5) (equivalent_test1), CONTAINER_SEQ) RUN_TESTS() diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index aed566dc..588a6713 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -8,7 +8,7 @@ #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" #include "../helpers/strong.hpp" -#include +#include "../helpers/helpers.hpp" #include test::seed_t initialize_seed(747373); @@ -17,7 +17,7 @@ template struct insert_test_base : public test::exception_base { test::random_values values; - insert_test_base(unsigned int count = 5) : values(count) {} + insert_test_base(unsigned int count = 5) : values(count, test::limited_range) {} typedef T data_type; typedef test::strong strong_type; @@ -112,7 +112,7 @@ struct insert_test4 : public insert_test_base it != end; ++it) { strong.store(x, test::detail::tracker.count_allocations); - x.insert(it, boost::next(it)); + x.insert(it, test::next(it)); } } }; @@ -130,12 +130,13 @@ struct insert_test_rehash1 : public insert_test_base T 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( - ceil(bucket_count * (double) x.max_load_factor()) - 1); + ceil((double) bucket_count * (double) x.max_load_factor()) - 1); BOOST_TEST(initial_elements < this->values.size()); x.insert(this->values.begin(), - boost::next(this->values.begin(), initial_elements)); + test::next(this->values.begin(), initial_elements)); BOOST_TEST(bucket_count == x.bucket_count()); return x; } @@ -146,7 +147,7 @@ struct insert_test_rehash1 : public insert_test_base BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin(); for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = boost::next(this->values.begin(), x.size()), + it = test::next(this->values.begin(), x.size()), end = this->values.end(); it != end && count < 10; ++it, ++count) { @@ -170,7 +171,7 @@ struct insert_test_rehash2 : public insert_test_rehash1 int count = 0; for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = boost::next(this->values.begin(), x.size()), + it = test::next(this->values.begin(), x.size()), end = this->values.end(); it != end && count < 10; ++it, ++count) { @@ -201,14 +202,14 @@ struct insert_test_rehash3 : public insert_test_base original_bucket_count = x.bucket_count(); rehash_bucket_count = static_cast( - ceil(original_bucket_count * (double) x.max_load_factor())) - 1; + ceil((double) original_bucket_count * (double) x.max_load_factor())) - 1; size_type initial_elements = rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1; BOOST_TEST(initial_elements < this->values.size()); x.insert(this->values.begin(), - boost::next(this->values.begin(), initial_elements)); + test::next(this->values.begin(), initial_elements)); BOOST_TEST(original_bucket_count == x.bucket_count()); return x; } @@ -216,8 +217,8 @@ struct insert_test_rehash3 : public insert_test_base void run(T& x) const { BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count(); - x.insert(boost::next(this->values.begin(), x.size()), - boost::next(this->values.begin(), x.size() + 20)); + x.insert(test::next(this->values.begin(), x.size()), + test::next(this->values.begin(), x.size() + 20)); // This isn't actually a failure, but it means the test isn't doing its // job. diff --git a/test/exception/move_assign_exception_tests.cpp b/test/exception/move_assign_exception_tests.cpp new file mode 100644 index 00000000..d09b1b82 --- /dev/null +++ b/test/exception/move_assign_exception_tests.cpp @@ -0,0 +1,131 @@ + +// Copyright 2006-2009 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include "./containers.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/invariants.hpp" + +#if defined(BOOST_MSVC) +#pragma warning(disable:4512) // move_assignment operator could not be generated +#endif + +test::seed_t initialize_seed(12847); + +template +struct move_assign_base : public test::exception_base +{ + test::random_values x_values, y_values; + T x,y; + + typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; + typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; + typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type; + + move_assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0) : + x_values(), + y_values(), + x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)), + y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2)) + { + x.max_load_factor(mlf1); + y.max_load_factor(mlf2); + } + + typedef T data_type; + T init() const { return T(x); } + void run(T& x1) const { + test::exceptions_enable disable_exceptions(false); + T y1 = y; + disable_exceptions.release(); + x1 = boost::move(y1); + } + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const + { + test::check_equivalent_keys(x1); + + // If the container is empty at the point of the exception, the + // internal structure is hidden, this exposes it, at the cost of + // messing up the data. + if (x_values.size()) { + T& x2 = const_cast(x1); + x2.emplace(*x_values.begin()); + test::check_equivalent_keys(x2); + } + } +}; + +template +struct move_assign_values : move_assign_base +{ + move_assign_values(unsigned int count1, unsigned int count2, + int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0) : + move_assign_base(tag1, tag2, mlf1, mlf2) + { + this->x_values.fill(count1); + this->y_values.fill(count2); + this->x.insert(this->x_values.begin(), this->x_values.end()); + this->y.insert(this->y_values.begin(), this->y_values.end()); + } +}; + +template +struct move_assign_test1 : move_assign_values +{ + move_assign_test1() : move_assign_values(0, 0, 0, 0) {} +}; + +template +struct move_assign_test2 : move_assign_values +{ + move_assign_test2() : move_assign_values(60, 0, 0, 0) {} +}; + +template +struct move_assign_test3 : move_assign_values +{ + move_assign_test3() : move_assign_values(0, 60, 0, 0) {} +}; + +template +struct move_assign_test4 : move_assign_values +{ + move_assign_test4() : move_assign_values(10, 10, 1, 2) {} +}; + +template +struct move_assign_test4a : move_assign_values +{ + move_assign_test4a() : move_assign_values(10, 100, 1, 2) {} +}; + +template +struct move_assign_test5 : move_assign_values +{ + move_assign_test5() : move_assign_values(5, 60, 0, 0, 1.0f, 0.1f) {} +}; + +template +struct equivalent_test1 : move_assign_base +{ + equivalent_test1() : + move_assign_base(0, 0) + { + test::random_values x_values2(10); + this->x_values.insert(x_values2.begin(), x_values2.end()); + this->x_values.insert(x_values2.begin(), x_values2.end()); + test::random_values y_values2(10); + this->y_values.insert(y_values2.begin(), y_values2.end()); + this->y_values.insert(y_values2.begin(), y_values2.end()); + this->x.insert(this->x_values.begin(), this->x_values.end()); + this->y.insert(this->y_values.begin(), this->y_values.end()); + } +}; + +EXCEPTION_TESTS( + (move_assign_test1)(move_assign_test2)(move_assign_test3)(move_assign_test4)(move_assign_test4a)(move_assign_test5) + (equivalent_test1), + CONTAINER_SEQ) +RUN_TESTS() diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 5e1cd084..0873093a 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -17,7 +17,7 @@ template struct self_swap_base : public test::exception_base { test::random_values values; - self_swap_base(int count = 0) : values(count) {} + self_swap_base(std::size_t count = 0) : values(count) {} typedef T data_type; T init() const { return T(values.begin(), values.end()); } diff --git a/test/helpers/equivalent.hpp b/test/helpers/equivalent.hpp index f452c807..61b91538 100644 --- a/test/helpers/equivalent.hpp +++ b/test/helpers/equivalent.hpp @@ -42,20 +42,15 @@ namespace test } struct equivalent_type { + equivalent_type() {} + template - bool operator()(T1 const& x, T2 const& y) { + bool operator()(T1 const& x, T2 const& y) const { return equivalent_impl(x, y, derived); } }; - // This won't be a problem as I'm only using a single compile unit - // in each test (this is actually require by the minimal test - // framework). - // - // boostinspect:nounnamed - namespace { - equivalent_type equivalent; - } + const equivalent_type equivalent; template class unordered_equivalence_tester diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index 289cd1a5..c3aad5d5 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -111,16 +111,28 @@ namespace test { exceptions_enable(exceptions_enable const&); bool old_value_; + bool released_; public: exceptions_enable(bool enable) - : old_value_(exceptions_enabled) + : old_value_(exceptions_enabled), released_(false) { exceptions_enabled = enable; } ~exceptions_enable() { - exceptions_enabled = old_value_; + if (!released_) { + exceptions_enabled = old_value_; + released_ = true; + } + } + + void release() + { + if (!released_) { + exceptions_enabled = old_value_; + released_ = true; + } } }; diff --git a/test/helpers/fwd.hpp b/test/helpers/fwd.hpp index ddff09c5..14476dda 100644 --- a/test/helpers/fwd.hpp +++ b/test/helpers/fwd.hpp @@ -10,11 +10,17 @@ namespace test { - int generate(int const*); - char generate(char const*); - signed char generate(signed char const*); - std::string generate(std::string*); - float generate(float const*); + typedef enum { + default_generator, + generate_collisions, + limited_range + } random_generator; + + int generate(int const*, random_generator); + char generate(char const*, random_generator); + signed char generate(signed char const*, random_generator); + std::string generate(std::string const*, random_generator); + float generate(float const*, random_generator); struct base_type {} base; struct derived_type : base_type {} derived; diff --git a/test/helpers/generators.hpp b/test/helpers/generators.hpp index 15441524..3265a77b 100644 --- a/test/helpers/generators.hpp +++ b/test/helpers/generators.hpp @@ -27,25 +27,32 @@ namespace test } }; - inline int generate(int const*) - { + std::size_t random_value(std::size_t max) { using namespace std; - return rand(); + return static_cast(rand()) % max; } - inline char generate(char const*) + inline int generate(int const*, random_generator g) + { + using namespace std; + int value = rand(); + if (g == limited_range) { value = value % 100; } + return value; + } + + inline char generate(char const*, random_generator) { using namespace std; return static_cast((rand() >> 1) % (128-32) + 32); } - inline signed char generate(signed char const*) + inline signed char generate(signed char const*, random_generator) { using namespace std; return static_cast(rand()); } - inline std::string generate(std::string const*) + inline std::string generate(std::string const*, random_generator g) { using namespace std; @@ -53,17 +60,30 @@ namespace test std::string result; - int length = rand() % 10; - for(int i = 0; i < length; ++i) - result += generate(char_ptr); + if (g == limited_range) { + std::size_t length = test::random_value(2) + 2; + + char const* strings[] = { "'vZh(3~ms", "%m", "_Y%U", "N'Y", "4,J_J" }; + for (std::size_t i = 0; i < length; ++i) { + result += strings[random_value(sizeof(strings) / sizeof(strings[0]))]; + } + } + else { + std::size_t length = test::random_value(10) + 1; + for (std::size_t i = 0; i < length; ++i) { + result += generate(char_ptr, g); + } + } return result; } - float generate(float const*) + float generate(float const*, random_generator g) { using namespace std; - return (float) rand() / (float) RAND_MAX; + int x = 0; + int value = generate(&x, g); + return (float) value / (float) RAND_MAX; } } diff --git a/test/helpers/helpers.hpp b/test/helpers/helpers.hpp index 2293f23f..96e90cdc 100644 --- a/test/helpers/helpers.hpp +++ b/test/helpers/helpers.hpp @@ -38,6 +38,26 @@ namespace test { return get_key_impl::get_key(x); } + + // test::next + // + // Increments an iterator by 1 or a given value. + // Like boost::next, but simpler and slower. + + template + Iterator next(Iterator it) + { + return ++it; + } + + template + Iterator next(Iterator it, IntType x) + { + for(; x > 0; --x) { + ++it; + } + return it; + } } #endif diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index e18ef865..5c2048b7 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -91,7 +91,7 @@ namespace test // Check the load factor. - float load_factor = + float load_factor = size == 0 ? 0 : static_cast(size) / static_cast(x1.bucket_count()); using namespace std; if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64) diff --git a/test/helpers/metafunctions.hpp b/test/helpers/metafunctions.hpp index 139fe0a2..8e36549d 100644 --- a/test/helpers/metafunctions.hpp +++ b/test/helpers/metafunctions.hpp @@ -8,8 +8,6 @@ #include #include -#include -#include namespace test { @@ -22,19 +20,11 @@ namespace test template struct has_unique_keys { - BOOST_STATIC_CONSTANT(bool, value = false); - }; - - template - struct has_unique_keys > - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template - struct has_unique_keys > - { - BOOST_STATIC_CONSTANT(bool, value = true); + static char flip(BOOST_DEDUCED_TYPENAME Container::iterator const&); + static long flip(std::pair const&); + BOOST_STATIC_CONSTANT(bool, value = sizeof(long) == sizeof( + flip(((Container*) 0)->insert(*(BOOST_DEDUCED_TYPENAME Container::value_type*) 0)) + )); }; } diff --git a/test/helpers/random_values.hpp b/test/helpers/random_values.hpp index b65a29b2..7628514d 100644 --- a/test/helpers/random_values.hpp +++ b/test/helpers/random_values.hpp @@ -14,11 +14,6 @@ namespace test { - typedef enum { - default_generator, - generate_collisions - } random_generator; - template struct unordered_generator_set { @@ -32,16 +27,15 @@ namespace test template void fill(T& x, std::size_t len) { value_type* value_ptr = 0; - int* int_ptr = 0; len += x.size(); for (std::size_t i = 0; i < len; ++i) { - value_type value = generate(value_ptr); + value_type value = generate(value_ptr, type_); - int count = type_ == generate_collisions ? - 1 + (generate(int_ptr) % 5) : 1; + std::size_t count = type_ == generate_collisions ? + random_value(5) + 1 : 1; - for(int j = 0; j < count; ++j) { + for(std::size_t j = 0; j < count; ++j) { x.push_back(value); } } @@ -63,17 +57,16 @@ namespace test void fill(T& x, std::size_t len) { key_type* key_ptr = 0; mapped_type* mapped_ptr = 0; - int* int_ptr = 0; for (std::size_t i = 0; i < len; ++i) { - key_type key = generate(key_ptr); + key_type key = generate(key_ptr, type_); - int count = type_ == generate_collisions ? - 1 + (generate(int_ptr) % 5) : 1; + std::size_t count = type_ == generate_collisions ? + random_value(5) + 1 : 1; - for(int j = 0; j < count; ++j) { + for(std::size_t j = 0; j < count; ++j) { x.push_back(std::pair( - key, generate(mapped_ptr))); + key, generate(mapped_ptr, type_))); } } } @@ -105,13 +98,13 @@ namespace test { random_values() {} - explicit random_values(int count, test::random_generator const& generator = + explicit random_values(std::size_t count, test::random_generator const& generator = test::default_generator) { fill(count, generator); } - void fill(int count, test::random_generator const& generator = + void fill(std::size_t count, test::random_generator const& generator = test::default_generator) { test::unordered_generator gen(generator); diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index dea6e0ea..b9d4c3b5 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -24,7 +24,11 @@ void BOOST_PP_CAT(x, _type)::run() \ #define RUN_TESTS() int main(int, char**) \ - { ::test::test_list::run_tests(); return boost::report_errors(); } \ + { \ + ::test::write_compiler_info(); \ + ::test::test_list::run_tests(); \ + return boost::report_errors(); \ + } namespace test { struct registered_test_base { @@ -66,6 +70,21 @@ namespace test { } } } + + inline void write_compiler_info() { +#if defined(BOOST_GCC_CXX11) + char const* cpp11 = "true"; +#else + char const* cpp11 = "false"; +#endif + + std::cout + << "Compiler: " << BOOST_COMPILER << "\n" + << "Library: " << BOOST_STDLIB << "\n" + << "C++11: " << cpp11 << "\n" + << "\n" + << std::flush; + } } #include diff --git a/test/helpers/tracker.hpp b/test/helpers/tracker.hpp index 52d9fa45..ab2470c0 100644 --- a/test/helpers/tracker.hpp +++ b/test/helpers/tracker.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include "../objects/fwd.hpp" #include "./metafunctions.hpp" #include "./helpers.hpp" @@ -60,38 +59,46 @@ namespace test values2.begin(), test::equivalent)); } - template + template ::value, + bool has_unique_keys = test::has_unique_keys::value> struct ordered_base; - template - struct ordered_base > + template + struct ordered_base { - typedef std::set::type> + typedef std::set< + BOOST_DEDUCED_TYPENAME X::value_type, + BOOST_DEDUCED_TYPENAME equals_to_compare::type> type; }; - template - struct ordered_base > + template + struct ordered_base { - typedef std::multiset::type> + typedef std::multiset< + BOOST_DEDUCED_TYPENAME X::value_type, + BOOST_DEDUCED_TYPENAME equals_to_compare::type> type; }; - template - struct ordered_base > + template + struct ordered_base { - typedef std::map::type> + typedef std::map< + BOOST_DEDUCED_TYPENAME X::key_type, + BOOST_DEDUCED_TYPENAME X::mapped_type, + BOOST_DEDUCED_TYPENAME equals_to_compare::type> type; }; - template - struct ordered_base > + template + struct ordered_base { - typedef std::multimap::type> + typedef std::multimap< + BOOST_DEDUCED_TYPENAME X::key_type, + BOOST_DEDUCED_TYPENAME X::mapped_type, + BOOST_DEDUCED_TYPENAME equals_to_compare::type> type; }; diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index 034f31b2..0e0aa869 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -23,7 +23,7 @@ namespace exception class hash; class equal_to; template class allocator; - object generate(object const*); + object generate(object const*, random_generator); struct true_type { @@ -101,9 +101,9 @@ namespace exception (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); } - friend object generate(object const*) { + friend object generate(object const*, random_generator g) { int* x = 0; - return object(::test::generate(x), ::test::generate(x)); + return object(::test::generate(x, g), ::test::generate(x, g)); } friend std::ostream& operator<<(std::ostream& out, object const& o) @@ -146,14 +146,18 @@ namespace exception UNORDERED_EPOINT("Mock hash function."); } + int result; switch(tag_) { case 1: - return x.tag1_; + result = x.tag1_; + break; case 2: - return x.tag2_; + result = x.tag2_; + break; default: - return x.tag1_ + x.tag2_; + result = x.tag1_ + x.tag2_; } + return static_cast(result); } friend bool operator==(hash const& x1, hash const& x2) { @@ -588,8 +592,9 @@ namespace exception #if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) namespace test { - test::exception::object generate(test::exception::object const* x) { - return test::exception::generate(x); + test::exception::object generate(test::exception::object const* x, + random_generator g) { + return test::exception::generate(x, g); } } #endif diff --git a/test/objects/test.hpp b/test/objects/test.hpp index f6b03db7..2fe4b1f3 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -25,9 +25,9 @@ namespace test class equal_to; template class allocator1; template class allocator2; - object generate(object const*); - movable generate(movable const*); - implicitly_convertible generate(implicitly_convertible const*); + object generate(object const*, random_generator); + movable generate(movable const*, random_generator); + implicitly_convertible generate(implicitly_convertible const*, random_generator); inline void ignore_variable(void const*) {} @@ -58,9 +58,9 @@ namespace test (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); } - friend object generate(object const*) { + friend object generate(object const*, random_generator g) { int* x = 0; - return object(generate(x), generate(x)); + return object(generate(x, g), generate(x, g)); } friend std::ostream& operator<<(std::ostream& out, object const& o) @@ -133,9 +133,9 @@ namespace test (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); } - friend movable generate(movable const*) { + friend movable generate(movable const*, random_generator g) { int* x = 0; - return movable(generate(x), generate(x)); + return movable(generate(x, g), generate(x, g)); } friend std::ostream& operator<<(std::ostream& out, movable const& o) @@ -163,9 +163,9 @@ namespace test return movable(tag1_, tag2_); } - friend implicitly_convertible generate(implicitly_convertible const*) { + friend implicitly_convertible generate(implicitly_convertible const*, random_generator g) { int* x = 0; - return implicitly_convertible(generate(x), generate(x)); + return implicitly_convertible(generate(x, g), generate(x, g)); } friend std::ostream& operator<<(std::ostream& out, implicitly_convertible const& o) @@ -182,29 +182,48 @@ namespace test explicit hash(int t = 0) : type_(t) {} std::size_t operator()(object const& x) const { + int result; switch(type_) { case 1: - return x.tag1_; + result = x.tag1_; + break; case 2: - return x.tag2_; + result = x.tag2_; + break; default: - return x.tag1_ + x.tag2_; + result = x.tag1_ + x.tag2_; } + return static_cast(result); } std::size_t operator()(movable const& x) const { + int result; switch(type_) { case 1: - return x.tag1_; + result = x.tag1_; + break; case 2: - return x.tag2_; + result = x.tag2_; + break; default: - return x.tag1_ + x.tag2_; + result = x.tag1_ + x.tag2_; } + return static_cast(result); } std::size_t operator()(int x) const { - return x; + int result; + switch(type_) { + case 1: + result = x; + break; + case 2: + result = x * 7; + break; + default: + result = x * 256; + } + return static_cast(result); } friend bool operator==(hash const& x1, hash const& x2) { diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index e66967c6..aa0f579f 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -236,6 +236,7 @@ boost::unordered_multimap bool is_propagate(T*) @@ -256,7 +257,7 @@ UNORDERED_TEST(assign_tests1, ( (test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign) (test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign) ) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) UNORDERED_TEST(assign_tests2, ( @@ -264,7 +265,7 @@ UNORDERED_TEST(assign_tests2, ( (test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign) (test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign) ) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index 58d9be30..4417f2d5 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -34,8 +34,10 @@ void tests(X*, test::random_generator generator) X x(v.begin(), v.end()); - BOOST_TEST(x.bucket_count() < x.max_bucket_count()); - std::cerr<::const_iterator it = v.begin(), end = v.end(); it != end; ++it) @@ -43,7 +45,7 @@ void tests(X*, test::random_generator generator) size_type bucket = x.bucket(test::get_key(*it)); BOOST_TEST(bucket < x.bucket_count()); - if(bucket < x.max_bucket_count()) { + if(bucket < x.bucket_count()) { // lit? lend?? I need a new naming scheme. const_local_iterator lit = x.begin(bucket), lend = x.end(bucket); while(lit != lend @@ -87,10 +89,11 @@ boost::unordered_multimap::max)()); - difference_type converted_diff(max_diff); + size_type max_diff = static_cast( + (std::numeric_limits::max)()); + difference_type converted_diff(static_cast(max_diff)); BOOST_TEST((std::numeric_limits::max)() == converted_diff); @@ -476,6 +477,17 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) test::check_return_type::equals(a.emplace_hint(q, t)); a.insert(i, j); +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + std::initializer_list list = {t}; + a.insert(list); + a.insert({t,t,t}); + +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) + a.insert({}); + a.insert({t}); + a.insert({t,t}); +#endif +#endif X a10; a10.insert(t); diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index ba065bf1..84c63742 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -418,20 +418,21 @@ boost::unordered_multimap(x % 250) : + static_cast((x + 5) % 250); } }; diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index c81a9ad9..b55bc202 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -13,10 +13,10 @@ #include "../helpers/test.hpp" #include "../helpers/list.hpp" #include "../helpers/invariants.hpp" +#include "../helpers/helpers.hpp" #include #include #include -#include #include "../objects/test.hpp" #if BOOST_WORKAROUND(BOOST_MSVC, < 1400) @@ -43,19 +43,19 @@ void write_container(Container const& x) // Make everything collide - for testing erase in a single bucket. struct collision_hash { - int operator()(int) const { return 0; } + std::size_t operator()(int) const { return 0; } }; // For testing erase in 2 buckets. struct collision2_hash { - int operator()(int x) const { return x & 1; } + std::size_t operator()(int x) const { return static_cast(x & 1); } }; // For testing erase in lots of buckets. struct collision3_hash { - int operator()(int x) const { return x; } + std::size_t operator()(int x) const { return static_cast(x); } }; typedef boost::unordered_multimapsecond; - x.erase(x.begin(), boost::next(x.begin())); + int value = test::next(x.begin())->second; + x.erase(x.begin(), test::next(x.begin())); BOOST_TEST(x.count(1) == 1 && x.size() == 1 && x.begin()->first == 1 && x.begin()->second == value); test::check_equivalent_keys(x); @@ -121,7 +121,7 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests) { collide_map x(init.begin(), init.end()); int value = x.begin()->second; - x.erase(boost::next(x.begin()), x.end()); + x.erase(test::next(x.begin()), x.end()); BOOST_TEST(x.count(1) == 1 && x.size() == 1 && x.begin()->first == 1 && x.begin()->second == value); test::check_equivalent_keys(x); @@ -144,8 +144,9 @@ template bool general_erase_range_test(Container& x, std::size_t start, std::size_t end) { collide_list l(x.begin(), x.end()); - l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end)); - x.erase(boost::next(x.begin(), start), boost::next(x.begin(), end)); + + l.erase(test::next(l.begin(), start), test::next(l.begin(), end)); + x.erase(test::next(x.begin(), start), test::next(x.begin(), end)); test::check_equivalent_keys(x); return compare(l, x); diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 9c737bd8..34d7ec9e 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -9,15 +9,15 @@ #include "../helpers/postfix.hpp" #include "../helpers/test.hpp" -#include #include "../objects/test.hpp" #include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" #include "../helpers/equivalent.hpp" #include "../helpers/helpers.hpp" #include "../helpers/invariants.hpp" - +#include #include +#include namespace erase_tests { @@ -27,6 +27,9 @@ test::seed_t initialize_seed(85638); template void erase_tests1(Container*, test::random_generator generator) { + typedef BOOST_DEDUCED_TYPENAME Container::iterator iterator; + typedef BOOST_DEDUCED_TYPENAME Container::const_iterator c_iterator; + std::cerr<<"Erase by key.\n"; { test::check_instances check_; @@ -60,8 +63,7 @@ void erase_tests1(Container*, test::random_generator generator) BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*x.begin()); std::size_t count = x.count(key); - BOOST_DEDUCED_TYPENAME Container::iterator - pos = x.erase(x.begin()); + iterator pos = x.erase(x.begin()); --size; BOOST_TEST(pos == x.begin()); BOOST_TEST(x.count(key) == count - 1); @@ -81,17 +83,16 @@ void erase_tests1(Container*, test::random_generator generator) int iterations = 0; while(size > 0 && !x.empty()) { - using namespace std; - int index = rand() % (int) x.size(); - BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next; + std::size_t index = test::random_value(x.size()); + c_iterator prev, pos, next; if(index == 0) { prev = pos = x.begin(); } else { - prev = boost::next(x.begin(), index - 1); - pos = boost::next(prev); + prev = test::next(x.begin(), index - 1); + pos = test::next(prev); } - next = boost::next(pos); + next = test::next(pos); BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*pos); std::size_t count = x.count(key); @@ -100,7 +101,7 @@ void erase_tests1(Container*, test::random_generator generator) --size; if(size > 0) BOOST_TEST(index == 0 ? next == x.begin() : - next == boost::next(prev)); + next == test::next(prev)); BOOST_TEST(x.count(key) == count - 1); if (x.count(key) != count - 1) { std::cerr << count << " => " << x.count(key) << std::endl; @@ -138,6 +139,45 @@ void erase_tests1(Container*, test::random_generator generator) test::check_equivalent_keys(x); } + std::cerr<<"erase(random ranges).\n"; + { + test::check_instances check_; + Container x; + + for (int i = 0; i < 100; ++i) { + test::random_values v(1000, generator); + x.insert(v.begin(), v.end()); + + // Note that erase only invalidates the erased iterators. + std::vector iterators; + for(c_iterator it = x.cbegin(); it != x.cend(); ++it) { + iterators.push_back(it); + } + iterators.push_back(x.cend()); + + while(iterators.size() > 1) { + std::size_t start = test::random_value(iterators.size()); + std::size_t length = test::random_value(iterators.size() - start); + x.erase(iterators[start], iterators[start + length]); + iterators.erase( + test::next(iterators.begin(), start), + test::next(iterators.begin(), start + length)); + + BOOST_TEST(x.size() == iterators.size() - 1); + BOOST_DEDUCED_TYPENAME std::vector::const_iterator + i2 = iterators.begin(); + for(c_iterator i1 = x.cbegin(); i1 != x.cend(); ++i1) { + BOOST_TEST(i1 == *i2); + ++i2; + } + BOOST_TEST(x.cend() == *i2); + + test::check_equivalent_keys(x); + } + BOOST_TEST(x.empty()); + } + } + std::cerr<<"quick_erase(begin()).\n"; { test::check_instances check_; @@ -170,17 +210,16 @@ void erase_tests1(Container*, test::random_generator generator) int iterations = 0; while(size > 0 && !x.empty()) { - using namespace std; - int index = rand() % (int) x.size(); + std::size_t index = test::random_value(x.size()); BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next; if(index == 0) { prev = pos = x.begin(); } else { - prev = boost::next(x.begin(), index - 1); - pos = boost::next(prev); + prev = test::next(x.begin(), index - 1); + pos = test::next(prev); } - next = boost::next(pos); + next = test::next(pos); BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*pos); std::size_t count = x.count(key); @@ -189,7 +228,7 @@ void erase_tests1(Container*, test::random_generator generator) --size; if(size > 0) BOOST_TEST(index == 0 ? next == x.begin() : - next == boost::next(prev)); + next == test::next(prev)); BOOST_TEST(x.count(key) == count - 1); if (x.count(key) != count - 1) { std::cerr << count << " => " << x.count(key) << std::endl; @@ -230,10 +269,11 @@ boost::unordered_multimap(*it1); - iterator pos = x.find(key); BOOST_DEDUCED_TYPENAME X::const_iterator const_pos = x_const.find(key); - BOOST_TEST(pos != x.end()); - BOOST_TEST(pos != x.end() && - x.key_eq()(key, test::get_key(*pos))); + iterator pos = x.find(key); BOOST_TEST(const_pos != x_const.end()); BOOST_TEST(const_pos != x_const.end() && x_const.key_eq()(key, test::get_key(*const_pos))); + BOOST_TEST(pos != x.end()); + BOOST_TEST(pos != x.end() && + x.key_eq()(key, test::get_key(*pos))); BOOST_TEST(x.count(key) == tracker.count(key)); @@ -155,14 +155,15 @@ boost::unordered_multimap +#include +#include "../helpers/postfix.hpp" + +#include "../helpers/test.hpp" +#include "../helpers/invariants.hpp" + +#include +#include +#include + +namespace insert_hint +{ +UNORDERED_AUTO_TEST(insert_hint_empty) { + typedef boost::unordered_multiset container; + container x; + x.insert(x.cbegin(), 10); + BOOST_TEST_EQ(x.size(), 1u); + BOOST_TEST_EQ(x.count(10), 1u); + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_empty2) { + typedef boost::unordered_multimap container; + container x; + x.emplace_hint(x.cbegin(), "hello", 50); + BOOST_TEST_EQ(x.size(), 1u); + BOOST_TEST_EQ(x.count("hello"), 1u); + BOOST_TEST_EQ(x.find("hello")->second, 50); + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_single) { + typedef boost::unordered_multiset container; + container x; + x.insert("equal"); + x.insert(x.cbegin(), "equal"); + BOOST_TEST_EQ(x.size(), 2u); + BOOST_TEST_EQ(x.count("equal"), 2u); + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_single2) { + typedef boost::unordered_multimap container; + container x; + x.emplace(10, "one"); + x.emplace_hint(x.cbegin(), 10, "two"); + BOOST_TEST_EQ(x.size(), 2u); + BOOST_TEST_EQ(x.count(10), 2u); + + container::iterator it = x.find(10); + std::string v0 = (it++)->second; + std::string v1 = (it++)->second; + + BOOST_TEST(v0 == "one" || v0 == "two"); + BOOST_TEST(v1 == "one" || v1 == "two"); + BOOST_TEST(v0 != v1); + + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_multiple) { + for (unsigned int size = 0; size < 10; ++size) { + for (unsigned int offset = 0; offset <= size; ++offset) { + typedef boost::unordered_multiset container; + container x; + + for (unsigned int i = 0; i < size; ++i) { x.insert("multiple"); } + + BOOST_TEST_EQ(x.size(), size); + + container::const_iterator position = x.cbegin(); + for (unsigned int i = 0; i < offset; ++i) { ++position; } + + x.insert(position, "multiple"); + + BOOST_TEST_EQ(x.size(), size + 1u); + BOOST_TEST_EQ(x.count("multiple"), size + 1u); + test::check_equivalent_keys(x); + } + } +} + +UNORDERED_AUTO_TEST(insert_hint_unique) { + typedef boost::unordered_set container; + container x; + x.insert(x.cbegin(), 10); + BOOST_TEST_EQ(x.size(), 1u); + BOOST_TEST_EQ(x.count(10), 1u); + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_unique_single) { + typedef boost::unordered_set container; + container x; + x.insert(10); + + x.insert(x.cbegin(), 10); + BOOST_TEST_EQ(x.size(), 1u); + BOOST_TEST_EQ(x.count(10), 1u); + test::check_equivalent_keys(x); + + x.insert(x.cbegin(), 20); + BOOST_TEST_EQ(x.size(), 2u); + BOOST_TEST_EQ(x.count(10), 1u); + BOOST_TEST_EQ(x.count(20), 1u); + test::check_equivalent_keys(x); +} + +} + +RUN_TESTS() diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index f750e50f..b4482764 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -49,6 +49,8 @@ UNORDERED_AUTO_TEST(stable_insert_test1) { x.insert(insert_stable::member(1,2)); x.insert(insert_stable::member(1,3)); + BOOST_TEST(x.count(insert_stable::member(1,4)) == 3); + boost::unordered_multiset::const_iterator it = x.begin(), end = x.end(); BOOST_TEST(it != end); @@ -66,10 +68,11 @@ UNORDERED_AUTO_TEST(stable_insert_test2) { boost::unordered_multimap::const_iterator iterator; - iterator it - = x.insert(x.end(), std::make_pair(insert_stable::member(1,1), 1)); - it = x.insert(it, std::make_pair(insert_stable::member(1,2), 2)); - it = x.insert(it, std::make_pair(insert_stable::member(1,3), 3)); + iterator it = x.emplace(insert_stable::member(1,1), 1); + it = x.emplace(insert_stable::member(1,2), 2); + it = x.emplace(insert_stable::member(1,3), 3); + + BOOST_TEST(x.count(insert_stable::member(1,4)) == 3); it = x.begin(); iterator end = x.end(); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 019d2ac3..3f13ea0f 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -9,7 +9,6 @@ #include "../helpers/postfix.hpp" #include "../helpers/test.hpp" -#include #include "../objects/test.hpp" #include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" @@ -55,7 +54,7 @@ void unique_insert_tests1(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -88,7 +87,7 @@ void equivalent_insert_tests1(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -124,10 +123,11 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -153,10 +153,11 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -182,10 +183,11 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(*pos == *r2); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -205,14 +207,15 @@ void insert_tests2(X*, test::random_generator generator) old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); - x.insert(it, boost::next(it)); + x.insert(it, test::next(it)); tracker.insert(*it); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -292,6 +295,42 @@ void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } + + std::cerr<<"insert various ranges.\n"; + + { + for (int i = 0; i < 100; ++i) { + X x; + test::ordered tracker = test::create_ordered(x); + + test::random_values v(1000, generator); + + for(BOOST_DEDUCED_TYPENAME test::random_values::iterator + it = v.begin(); it != v.end();) + { + BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + BOOST_DEDUCED_TYPENAME test::random_values::iterator + next = it; + for (std::size_t j = test::random_value(20); j > 0; ++j) { + ++next; + if (next == v.end()) { break; } + } + + x.insert(it, next); + tracker.insert(it, next); + it = next; + + tracker.compare(x); // Slow, but I can't see any other way. + + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + } } template @@ -323,10 +362,11 @@ void unique_emplace_tests1(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -353,10 +393,11 @@ void equivalent_emplace_tests1(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -382,12 +423,12 @@ void move_emplace_tests(X*, test::random_generator generator) tracker.insert(*it); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } - test::check_equivalent_keys(x); tracker.compare(x); + test::check_equivalent_keys(x); } template @@ -401,17 +442,17 @@ void default_emplace_tests(X*, test::random_generator) x.emplace(); BOOST_TEST(x.size() == 1); x.emplace(); - BOOST_TEST(x.size() == is_unique ? 1: 2); + BOOST_TEST(x.size() == (is_unique ? 1u : 2u)); x.emplace(); - BOOST_TEST(x.size() == is_unique ? 1: 3); + BOOST_TEST(x.size() == (is_unique ? 1u : 3u)); typename X::value_type y; - BOOST_TEST(x.count(test::get_key(y)) == is_unique ? 1: 3); + BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 3u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); x.emplace(y); - BOOST_TEST(x.size() == is_unique ? 1: 4); - BOOST_TEST(x.count(test::get_key(y)) == is_unique ? 1: 4); + BOOST_TEST(x.size() == (is_unique ? 1u : 4u)); + BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 4u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); x.clear(); @@ -419,9 +460,9 @@ void default_emplace_tests(X*, test::random_generator) x.emplace(y); BOOST_TEST(x.size() == 1); x.emplace(y); - BOOST_TEST(x.size() == is_unique ? 1: 2); + BOOST_TEST(x.size() == (is_unique ? 1u : 2u)); - BOOST_TEST(x.count(test::get_key(y)) == is_unique ? 1: 2); + BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 2u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); } @@ -445,10 +486,11 @@ void map_tests(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -518,57 +560,58 @@ boost::unordered_multimap(x.a + x.b); } bool operator==(initialize_from_two_ints const& x) const diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 6dbd7967..655cc883 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -51,7 +51,7 @@ void insert_test(X*, float mlf, test::random_generator generator) BOOST_DEDUCED_TYPENAME X::size_type old_size = x.size(), old_bucket_count = x.bucket_count(); x.insert(*it); - if(static_cast(old_size + 1) < b * static_cast(old_bucket_count)) + if(static_cast(old_size + 1) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } } @@ -78,6 +78,7 @@ boost::unordered_multimap* int_multimap_ptr; using test::default_generator; using test::generate_collisions; +using test::limited_range; UNORDERED_TEST(set_load_factor_tests, ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr)) @@ -85,7 +86,7 @@ UNORDERED_TEST(set_load_factor_tests, UNORDERED_TEST(load_factor_insert_tests, ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr)) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) } diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 8c7e8702..b04f33b0 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -369,6 +369,7 @@ boost::unordered_multimap >::value)); - BOOST_TEST((boost::is_nothrow_move_constructible< - boost::unordered_multiset >::value)); - BOOST_TEST((boost::is_nothrow_move_constructible< - boost::unordered_map >::value)); - BOOST_TEST((boost::is_nothrow_move_constructible< - boost::unordered_multimap >::value)); -#endif - - BOOST_TEST((!boost::is_nothrow_move_constructible< - boost::unordered_set - >::value)); - BOOST_TEST((!boost::is_nothrow_move_constructible< - boost::unordered_multiset, - equal_to_possible_exception> - >::value)); - } - // Test that the move constructor does actually move without throwing // an exception when it claims to. @@ -70,8 +48,10 @@ namespace noexcept_tests hash_nothrow_move() { test_throw("Constructor"); } hash_nothrow_move(hash_nothrow_move const&) { test_throw("Copy"); } - hash_nothrow_move& operator=(hash_nothrow_move const&) + hash_nothrow_move& operator=(BOOST_COPY_ASSIGN_REF(hash_nothrow_move)) { test_throw("Assign"); return *this; } + hash_nothrow_move& operator=(BOOST_RV_REF(hash_nothrow_move)) + { test_throw("Move Assign"); return *this; } std::size_t operator()(int x) const { test_throw("Operator"); return static_cast(*this)(x); } }; @@ -87,26 +67,69 @@ namespace noexcept_tests equal_to_nothrow_move() { test_throw("Constructor"); } equal_to_nothrow_move(equal_to_nothrow_move const&) { test_throw("Copy"); } - equal_to_nothrow_move& operator=(equal_to_nothrow_move const&) + equal_to_nothrow_move& operator=(BOOST_COPY_ASSIGN_REF(equal_to_nothrow_move)) { test_throw("Assign"); return *this; } + equal_to_nothrow_move& operator=(BOOST_RV_REF(equal_to_nothrow_move)) + { test_throw("Move Assign"); return *this; } std::size_t operator()(int x, int y) const { test_throw("Operator"); return static_cast(*this)(x, y); } }; + bool have_is_nothrow_move = false; + + UNORDERED_AUTO_TEST(check_is_nothrow_move) + { + BOOST_TEST(!boost::is_nothrow_move_constructible::value); + have_is_nothrow_move = boost::is_nothrow_move_constructible::value; + + // Copied from boost::is_nothrow_move_constructible implementation + // to make sure this does actually detect it when expected. + // + // The type trait is also available when BOOST_IS_NOTHROW_MOVE_CONSTRUCT + // is defined (for some versions of Visual C++?) but detects 'throw()', + // not noexcept. +#if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + BOOST_TEST(have_is_nothrow_move); +#endif + } + + UNORDERED_AUTO_TEST(test_noexcept) + { + if (have_is_nothrow_move) { + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_set >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_multiset >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_map >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_multimap >::value)); + } + + BOOST_TEST((!boost::is_nothrow_move_constructible< + boost::unordered_set + >::value)); + BOOST_TEST((!boost::is_nothrow_move_constructible< + boost::unordered_multiset, + equal_to_possible_exception> + >::value)); + } + UNORDERED_AUTO_TEST(test_no_throw_when_noexcept) { typedef boost::unordered_set throwing_set; - if (boost::is_nothrow_move_constructible::value) + if (have_is_nothrow_move) { + BOOST_TEST(boost::is_nothrow_move_constructible::value); + throwing_test_exception = false; throwing_set x1; x1.insert(10); x1.insert(50); - try { throwing_test_exception = true; diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 3746bed3..01009b6d 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -22,7 +22,7 @@ test::seed_t initialize_seed(2974); template bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n) { - return static_cast(x.bucket_count()) > + return static_cast(x.bucket_count()) >= static_cast(x.size()) / x.max_load_factor() && x.bucket_count() >= n; } @@ -139,7 +139,7 @@ void reserve_test1(X*, test::random_generator generator) { for (int random_mlf = 0; random_mlf < 2; ++random_mlf) { - for (int i = 1; i < 2000; i += i < 50 ? 1 : 13) + for (std::size_t i = 1; i < 2000; i += i < 50 ? 1 : 13) { test::random_values v(i, generator); @@ -149,9 +149,6 @@ void reserve_test1(X*, test::random_generator generator) X x; x.max_load_factor(random_mlf ? static_cast(std::rand() % 1000) / 500.0f + 0.5f : 1.0f); - // For the current standard this should reserve i+1, I've - // submitted a defect report and will assume it's a defect - // for now. x.reserve(test::has_unique_keys::value ? i : v.size()); // Insert an element before the range insert, otherwise there are @@ -174,7 +171,7 @@ void reserve_test2(X*, test::random_generator generator) { for (int random_mlf = 0; random_mlf < 2; ++random_mlf) { - for (int i = 0; i < 2000; i += i < 50 ? 1 : 13) + for (std::size_t i = 0; i < 2000; i += i < 50 ? 1 : 13) { test::random_values v(i, generator); @@ -211,21 +208,22 @@ boost::unordered_multimap* int_multimap_ptr; using test::default_generator; using test::generate_collisions; +using test::limited_range; UNORDERED_TEST(rehash_empty_test1, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)) ) UNORDERED_TEST(rehash_empty_test2, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) UNORDERED_TEST(rehash_empty_test3, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) UNORDERED_TEST(rehash_test1, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) UNORDERED_TEST(reserve_empty_test1, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)) @@ -235,11 +233,11 @@ UNORDERED_TEST(reserve_empty_test2, ) UNORDERED_TEST(reserve_test1, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) UNORDERED_TEST(reserve_test2, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) } diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index d967af03..7814a26a 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -206,6 +206,7 @@ bool is_propagate(T*) using test::default_generator; using test::generate_collisions; +using test::limited_range; UNORDERED_AUTO_TEST(check_traits) { @@ -220,7 +221,7 @@ UNORDERED_TEST(swap_tests1, ( (test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap) (test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap) ) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) UNORDERED_TEST(swap_tests2, ( @@ -228,7 +229,7 @@ UNORDERED_TEST(swap_tests2, ( (test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap) (test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap) ) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) } diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index f2b5e892..cb1346ba 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -115,7 +115,7 @@ namespace unnecessary_copy_tests #endif { std::size_t hash_value(unnecessary_copy_tests::count_copies const& x) { - return x.tag_; + return static_cast(x.tag_); } }