Merge branch 'develop'

This commit is contained in:
Daniel James
2016-10-14 09:26:19 +01:00
49 changed files with 1289 additions and 366 deletions

View File

@ -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

View File

@ -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]

View File

@ -358,6 +358,21 @@ EOL;
</para>
</requires>
</method>
<method name="operator=">
<parameter>
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type><?php echo $name; ?>&amp;</type>
<description>
<para>Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.</para>
</description>
<requires>
<para>
<code>value_type</code> is <code>CopyInsertable</code> into the container and
<code>CopyAssignable</code>.
</para>
</requires>
</method>
<method name="get_allocator" cv="const">
<type>allocator_type</type>
</method>
@ -640,7 +655,35 @@ EOL;
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.</para>
<para>Inserts a range of elements into the container.
<?php if (!$equivalent_keys): ?>
Elements are inserted if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
<?php endif; ?>
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
<code>X</code> from <code>*first</code>.</para>
</requires>
<throws>
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
</throws>
<notes>
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
<para>Pointers and references to elements are never invalidated.</para>
</notes>
</method>
<method name="insert">
<parameter name="il">
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container.
<?php if (!$equivalent_keys): ?>
Elements are inserted if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
<?php endif; ?>
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into

View File

@ -299,6 +299,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</para>
</requires>
</method>
<method name="operator=">
<parameter>
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>unordered_set&amp;</type>
<description>
<para>Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.</para>
</description>
<requires>
<para>
<code>value_type</code> is <code>CopyInsertable</code> into the container and
<code>CopyAssignable</code>.
</para>
</requires>
</method>
<method name="get_allocator" cv="const">
<type>allocator_type</type>
</method>
@ -537,7 +552,31 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent value.</para>
<para>Inserts a range of elements into the container.
Elements are inserted if and only if there is no element in the container with an equivalent value.
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
<code>X</code> from <code>*first</code>.</para>
</requires>
<throws>
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
</throws>
<notes>
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
<para>Pointers and references to elements are never invalidated.</para>
</notes>
</method>
<method name="insert">
<parameter name="il">
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container.
Elements are inserted if and only if there is no element in the container with an equivalent value.
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
@ -1334,6 +1373,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</para>
</requires>
</method>
<method name="operator=">
<parameter>
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>unordered_multiset&amp;</type>
<description>
<para>Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.</para>
</description>
<requires>
<para>
<code>value_type</code> is <code>CopyInsertable</code> into the container and
<code>CopyAssignable</code>.
</para>
</requires>
</method>
<method name="get_allocator" cv="const">
<type>allocator_type</type>
</method>
@ -1569,7 +1623,29 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent value.</para>
<para>Inserts a range of elements into the container.
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
<code>X</code> from <code>*first</code>.</para>
</requires>
<throws>
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
</throws>
<notes>
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
<para>Pointers and references to elements are never invalidated.</para>
</notes>
</method>
<method name="insert">
<parameter name="il">
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container.
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
@ -2380,6 +2456,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</para>
</requires>
</method>
<method name="operator=">
<parameter>
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>unordered_map&amp;</type>
<description>
<para>Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.</para>
</description>
<requires>
<para>
<code>value_type</code> is <code>CopyInsertable</code> into the container and
<code>CopyAssignable</code>.
</para>
</requires>
</method>
<method name="get_allocator" cv="const">
<type>allocator_type</type>
</method>
@ -2618,7 +2709,31 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.</para>
<para>Inserts a range of elements into the container.
Elements are inserted if and only if there is no element in the container with an equivalent key.
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
<code>X</code> from <code>*first</code>.</para>
</requires>
<throws>
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
</throws>
<notes>
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
<para>Pointers and references to elements are never invalidated.</para>
</notes>
</method>
<method name="insert">
<parameter name="il">
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container.
Elements are inserted if and only if there is no element in the container with an equivalent key.
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
@ -3462,6 +3577,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</para>
</requires>
</method>
<method name="operator=">
<parameter>
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>unordered_multimap&amp;</type>
<description>
<para>Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.</para>
</description>
<requires>
<para>
<code>value_type</code> is <code>CopyInsertable</code> into the container and
<code>CopyAssignable</code>.
</para>
</requires>
</method>
<method name="get_allocator" cv="const">
<type>allocator_type</type>
</method>
@ -3697,7 +3827,29 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.</para>
<para>Inserts a range of elements into the container.
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
<code>X</code> from <code>*first</code>.</para>
</requires>
<throws>
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
</throws>
<notes>
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
<para>Pointers and references to elements are never invalidated.</para>
</notes>
</method>
<method name="insert">
<parameter name="il">
<paramtype>initializer_list&lt;value_type&gt;</paramtype>
</parameter>
<type>void</type>
<description>
<para>Inserts a range of elements into the container.
</para>
</description>
<requires>
<para><code>value_type</code> is <code>EmplaceConstructible</code> into

View File

@ -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>(args)...
#define BOOST_UNORDERED_EMPLACE_ARGS1(a0) a0
#define BOOST_UNORDERED_EMPLACE_ARGS2(a0, a1) a0, a1
#define BOOST_UNORDERED_EMPLACE_ARGS3(a0, a1, a2) a0, a1, a2
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args
#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward<Args>(args)...
#else
#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args
#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args
#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args
#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args
#define BOOST_UNORDERED_EMPLACE_FORWARD args
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
#else
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \
BOOST_PP_CAT(Arg, n); \
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
#endif
template <typename A0>
struct emplace_args1
{
BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
emplace_args1(Arg0 b0) : a0(b0) {}
};
template <typename A0>
inline emplace_args1<A0> create_emplace_args(
BOOST_FWD_REF(A0) b0)
{
emplace_args1<A0> e(b0);
return e;
}
template <typename A0, typename A1>
struct emplace_args2
{
BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
BOOST_UNORDERED_EARGS_MEMBER(1, 1, _)
emplace_args2(Arg0 b0, Arg1 b1) : a0(b0), a1(b1) {}
};
template <typename A0, typename A1>
inline emplace_args2<A0, A1> create_emplace_args(
BOOST_FWD_REF(A0) b0,
BOOST_FWD_REF(A1) b1)
{
emplace_args2<A0, A1> e(b0, b1);
return e;
}
template <typename A0, typename A1, typename A2>
struct emplace_args3
{
BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
BOOST_UNORDERED_EARGS_MEMBER(1, 1, _)
BOOST_UNORDERED_EARGS_MEMBER(1, 2, _)
emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : a0(b0), a1(b1), a2(b2) {}
};
template <typename A0, typename A1, typename A2>
inline emplace_args3<A0, A1, A2> create_emplace_args(
BOOST_FWD_REF(A0) b0,
BOOST_FWD_REF(A1) b1,
BOOST_FWD_REF(A2) b2)
{
emplace_args3<A0, A1, A2> e(b0, b1, b2);
return e;
}
#define BOOST_UNORDERED_FWD_PARAM(z, n, a) \
BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n)
#define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \
boost::forward<BOOST_PP_CAT(A,i)>(BOOST_PP_CAT(a,i))
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n))
#define BOOST_UNORDERED_EARGS(z, n, _) \
template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
struct BOOST_PP_CAT(emplace_args, n) \
@ -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(A,n)>(BOOST_PP_CAT(b, n)))
#else
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \
BOOST_PP_CAT(Arg, n); \
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n))
#endif
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
_)
#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS

View File

@ -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<long long> {
struct pick_policy<boost::long_long_type> {
typedef prime_policy<std::size_t> type;
};
template <>
struct pick_policy<unsigned long long> {
struct pick_policy<boost::ulong_long_type> {
typedef prime_policy<std::size_t> type;
};
#endif

View File

@ -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<node_pointer>(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<node_pointer>(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 <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS)
{
return iterator(emplace_hint_impl(hint,
boost::unordered::detail::func::construct_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::size_t>(std::distance(i, j));
if(distance == 1) {
emplace_impl(
boost::unordered::detail::func::construct_value(

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
// Copyright (C) 2008-2011 Daniel James.
// Copyright (C) 2008-2016 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -11,12 +11,46 @@
#pragma once
#endif
#if defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
// Already defined.
#elif defined(BOOST_LIBSTDCXX11)
// https://github.com/gcc-mirror/gcc/blob/gcc-4_6-branch/libstdc++-v3/include/bits/stl_pair.h#L70
# if BOOST_LIBSTDCXX_VERSION > 40600
# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
# endif
#elif defined(_LIBCPP_VERSION)
// https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206
# if LIBCPP_VERSION >= 3000
# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
# endif
#elif defined(BOOST_MSVC)
// Apparently C++11 standard supported in Visual Studio 2012
// https://msdn.microsoft.com/en-us/library/hh567368.aspx#stl
// 2012 = VC+11 = BOOST_MSVC 1700 Hopefully!
# if BOOST_MSVC >= 1700
# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
# endif
#endif
#if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 0
#endif
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
#include <utility>
#endif
namespace boost
{
namespace unordered
{
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
using std::piecewise_construct_t;
using std::piecewise_construct;
#else
struct piecewise_construct_t {};
const piecewise_construct_t piecewise_construct = piecewise_construct_t();
#endif
}
}

View File

@ -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<table_impl*>(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<table_impl*>(this)->move_assign_buckets(x);
}
}

View File

@ -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 <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace_hint(c_iterator hint,
BOOST_UNORDERED_EMPLACE_ARGS)
{
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
return emplace_hint_impl(hint,
extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
BOOST_UNORDERED_EMPLACE_FORWARD);
#else
return emplace_hint_impl(hint,
extractor::extract(args.a0, args.a1),
BOOST_UNORDERED_EMPLACE_FORWARD);
#endif
}
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <typename A0>
emplace_return emplace(
@ -347,8 +377,27 @@ namespace boost { namespace unordered { namespace detail {
{
return emplace_impl(extractor::extract(args.a0), args);
}
template <typename A0>
iterator emplace_hint(c_iterator hint,
boost::unordered::detail::emplace_args1<A0> const& args)
{
return emplace_hint_impl(hint, extractor::extract(args.a0), args);
}
#endif
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace_hint_impl(c_iterator hint, key_type const& k,
BOOST_UNORDERED_EMPLACE_ARGS)
{
if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
return iterator(hint.node_);
}
else {
return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first;
}
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
emplace_return emplace_impl(key_type const& k,
BOOST_UNORDERED_EMPLACE_ARGS)
@ -368,11 +417,31 @@ namespace boost { namespace unordered { namespace detail {
}
}
template <BOOST_UNORDERED_EMPLACE_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 <BOOST_UNORDERED_EMPLACE_TEMPLATE>
emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
{
// Don't have a key, so construct the node first in order
// to be able to lookup the position.
node_tmp b(
boost::unordered::detail::func::construct_value_generic(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),

View File

@ -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<I, void*>::type = 0)
{
return std::distance(i, j);
return static_cast<std::size_t>(std::distance(i, j));
}
template <class I>

View File

@ -240,9 +240,9 @@ namespace unordered
}
template <class... Args>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
return table_.emplace(boost::forward<Args>(args)...).first;
return table_.emplace_hint(hint, boost::forward<Args>(args)...);
}
#else
@ -281,12 +281,12 @@ namespace unordered
}
template <typename A0>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0))
).first;
);
}
template <typename A0, typename A1>
@ -302,15 +302,15 @@ namespace unordered
}
template <typename A0, typename A1>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1))
).first;
);
}
template <typename A0, typename A1, typename A2>
@ -328,17 +328,17 @@ namespace unordered
}
template <typename A0, typename A1, typename A2>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1),
boost::forward<A2>(a2))
).first;
);
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
@ -360,15 +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 <class... Args>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
return table_.emplace(boost::forward<Args>(args)...);
return table_.emplace_hint(hint, boost::forward<Args>(args)...);
}
#else
@ -765,9 +765,9 @@ namespace unordered
}
template <typename A0>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0))
);
@ -786,11 +786,11 @@ namespace unordered
}
template <typename A0, typename A1>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1))
@ -812,12 +812,12 @@ namespace unordered
}
template <typename A0, typename A1, typename A2>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1),
@ -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) \

View File

@ -237,9 +237,9 @@ namespace unordered
}
template <class... Args>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
return table_.emplace(boost::forward<Args>(args)...).first;
return table_.emplace_hint(hint, boost::forward<Args>(args)...);
}
#else
@ -278,12 +278,12 @@ namespace unordered
}
template <typename A0>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0))
).first;
);
}
template <typename A0, typename A1>
@ -299,15 +299,15 @@ namespace unordered
}
template <typename A0, typename A1>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1))
).first;
);
}
template <typename A0, typename A1, typename A2>
@ -325,17 +325,17 @@ namespace unordered
}
template <typename A0, typename A1, typename A2>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1),
boost::forward<A2>(a2))
).first;
);
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
@ -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 <class... Args>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
return table_.emplace(boost::forward<Args>(args)...);
return table_.emplace_hint(hint, boost::forward<Args>(args)...);
}
#else
@ -748,9 +748,9 @@ namespace unordered
}
template <typename A0>
iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0))
);
@ -769,11 +769,11 @@ namespace unordered
}
template <typename A0, typename A1>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1))
@ -795,12 +795,12 @@ namespace unordered
}
template <typename A0, typename A1, typename A2>
iterator emplace_hint(const_iterator,
iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
return table_.emplace(
return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0),
boost::forward<A1>(a1),
@ -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) \

View File

@ -11,9 +11,9 @@ project unordered-test/unordered
<toolset>intel:<warnings>on
# Would be nice to define -Wundef, but I'm getting warnings from
# Boost.Preprocessor on trunk.
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow -Wno-long-long"
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
<toolset>clang:<cxxflags>"-pedantic -Wextra -Wno-long-long"
<toolset>clang:<cxxflags>"-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 ]

View File

@ -17,7 +17,7 @@ template <class T>
struct self_assign_base : public test::exception_base
{
test::random_values<T> values;
self_assign_base(int count = 0) : values(count) {}
self_assign_base(std::size_t count = 0) : values(count) {}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
@ -111,6 +111,12 @@ struct assign_test4 : assign_values<T>
assign_test4() : assign_values<T>(10, 10, 1, 2) {}
};
template <class T>
struct assign_test4a : assign_values<T>
{
assign_test4a() : assign_values<T>(10, 100, 1, 2) {}
};
template <class T>
struct assign_test5 : assign_values<T>
{
@ -136,7 +142,7 @@ struct equivalent_test1 : assign_base<T>
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()

View File

@ -8,7 +8,7 @@
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/strong.hpp"
#include <boost/utility.hpp>
#include "../helpers/helpers.hpp"
#include <cmath>
test::seed_t initialize_seed(747373);
@ -17,7 +17,7 @@ template <class T>
struct insert_test_base : public test::exception_base
{
test::random_values<T> values;
insert_test_base(unsigned int count = 5) : values(count) {}
insert_test_base(unsigned int count = 5) : values(count, test::limited_range) {}
typedef T data_type;
typedef test::strong<T> strong_type;
@ -112,7 +112,7 @@ struct insert_test4 : public insert_test_base<T>
it != end; ++it)
{
strong.store(x, test::detail::tracker.count_allocations);
x.insert(it, boost::next(it));
x.insert(it, test::next(it));
}
}
};
@ -130,12 +130,13 @@ struct insert_test_rehash1 : public insert_test_base<T>
T x;
x.max_load_factor(0.25);
// TODO: This doesn't really work is bucket_count is 0
size_type bucket_count = x.bucket_count();
size_type initial_elements = static_cast<size_type>(
ceil(bucket_count * (double) x.max_load_factor()) - 1);
ceil((double) bucket_count * (double) x.max_load_factor()) - 1);
BOOST_TEST(initial_elements < this->values.size());
x.insert(this->values.begin(),
boost::next(this->values.begin(), initial_elements));
test::next(this->values.begin(), initial_elements));
BOOST_TEST(bucket_count == x.bucket_count());
return x;
}
@ -146,7 +147,7 @@ struct insert_test_rehash1 : public insert_test_base<T>
BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin();
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = boost::next(this->values.begin(), x.size()),
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count)
{
@ -170,7 +171,7 @@ struct insert_test_rehash2 : public insert_test_rehash1<T>
int count = 0;
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = boost::next(this->values.begin(), x.size()),
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count)
{
@ -201,14 +202,14 @@ struct insert_test_rehash3 : public insert_test_base<T>
original_bucket_count = x.bucket_count();
rehash_bucket_count = static_cast<size_type>(
ceil(original_bucket_count * (double) x.max_load_factor())) - 1;
ceil((double) original_bucket_count * (double) x.max_load_factor())) - 1;
size_type initial_elements =
rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1;
BOOST_TEST(initial_elements < this->values.size());
x.insert(this->values.begin(),
boost::next(this->values.begin(), initial_elements));
test::next(this->values.begin(), initial_elements));
BOOST_TEST(original_bucket_count == x.bucket_count());
return x;
}
@ -216,8 +217,8 @@ struct insert_test_rehash3 : public insert_test_base<T>
void run(T& x) const {
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
x.insert(boost::next(this->values.begin(), x.size()),
boost::next(this->values.begin(), x.size() + 20));
x.insert(test::next(this->values.begin(), x.size()),
test::next(this->values.begin(), x.size() + 20));
// This isn't actually a failure, but it means the test isn't doing its
// job.

View File

@ -0,0 +1,131 @@
// Copyright 2006-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include "./containers.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable:4512) // move_assignment operator could not be generated
#endif
test::seed_t initialize_seed(12847);
template <class T>
struct move_assign_base : public test::exception_base
{
test::random_values<T> x_values, y_values;
T x,y;
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
move_assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0) :
x_values(),
y_values(),
x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
{
x.max_load_factor(mlf1);
y.max_load_factor(mlf2);
}
typedef T data_type;
T init() const { return T(x); }
void run(T& x1) const {
test::exceptions_enable disable_exceptions(false);
T y1 = y;
disable_exceptions.release();
x1 = boost::move(y1);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
{
test::check_equivalent_keys(x1);
// If the container is empty at the point of the exception, the
// internal structure is hidden, this exposes it, at the cost of
// messing up the data.
if (x_values.size()) {
T& x2 = const_cast<T&>(x1);
x2.emplace(*x_values.begin());
test::check_equivalent_keys(x2);
}
}
};
template <class T>
struct move_assign_values : move_assign_base<T>
{
move_assign_values(unsigned int count1, unsigned int count2,
int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0) :
move_assign_base<T>(tag1, tag2, mlf1, mlf2)
{
this->x_values.fill(count1);
this->y_values.fill(count2);
this->x.insert(this->x_values.begin(), this->x_values.end());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
};
template <class T>
struct move_assign_test1 : move_assign_values<T>
{
move_assign_test1() : move_assign_values<T>(0, 0, 0, 0) {}
};
template <class T>
struct move_assign_test2 : move_assign_values<T>
{
move_assign_test2() : move_assign_values<T>(60, 0, 0, 0) {}
};
template <class T>
struct move_assign_test3 : move_assign_values<T>
{
move_assign_test3() : move_assign_values<T>(0, 60, 0, 0) {}
};
template <class T>
struct move_assign_test4 : move_assign_values<T>
{
move_assign_test4() : move_assign_values<T>(10, 10, 1, 2) {}
};
template <class T>
struct move_assign_test4a : move_assign_values<T>
{
move_assign_test4a() : move_assign_values<T>(10, 100, 1, 2) {}
};
template <class T>
struct move_assign_test5 : move_assign_values<T>
{
move_assign_test5() : move_assign_values<T>(5, 60, 0, 0, 1.0f, 0.1f) {}
};
template <class T>
struct equivalent_test1 : move_assign_base<T>
{
equivalent_test1() :
move_assign_base<T>(0, 0)
{
test::random_values<T> x_values2(10);
this->x_values.insert(x_values2.begin(), x_values2.end());
this->x_values.insert(x_values2.begin(), x_values2.end());
test::random_values<T> y_values2(10);
this->y_values.insert(y_values2.begin(), y_values2.end());
this->y_values.insert(y_values2.begin(), y_values2.end());
this->x.insert(this->x_values.begin(), this->x_values.end());
this->y.insert(this->y_values.begin(), this->y_values.end());
}
};
EXCEPTION_TESTS(
(move_assign_test1)(move_assign_test2)(move_assign_test3)(move_assign_test4)(move_assign_test4a)(move_assign_test5)
(equivalent_test1),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -17,7 +17,7 @@ template <class T>
struct self_swap_base : public test::exception_base
{
test::random_values<T> values;
self_swap_base(int count = 0) : values(count) {}
self_swap_base(std::size_t count = 0) : values(count) {}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }

View File

@ -42,20 +42,15 @@ namespace test
}
struct equivalent_type {
equivalent_type() {}
template <class T1, class T2>
bool operator()(T1 const& x, T2 const& y) {
bool operator()(T1 const& x, T2 const& y) const {
return equivalent_impl(x, y, derived);
}
};
// This won't be a problem as I'm only using a single compile unit
// in each test (this is actually require by the minimal test
// framework).
//
// boostinspect:nounnamed
namespace {
equivalent_type equivalent;
}
const equivalent_type equivalent;
template <class Container>
class unordered_equivalence_tester

View File

@ -111,16 +111,28 @@ namespace test {
exceptions_enable(exceptions_enable const&);
bool old_value_;
bool released_;
public:
exceptions_enable(bool enable)
: old_value_(exceptions_enabled)
: old_value_(exceptions_enabled), released_(false)
{
exceptions_enabled = enable;
}
~exceptions_enable()
{
exceptions_enabled = old_value_;
if (!released_) {
exceptions_enabled = old_value_;
released_ = true;
}
}
void release()
{
if (!released_) {
exceptions_enabled = old_value_;
released_ = true;
}
}
};

View File

@ -10,11 +10,17 @@
namespace test
{
int generate(int const*);
char generate(char const*);
signed char generate(signed char const*);
std::string generate(std::string*);
float generate(float const*);
typedef enum {
default_generator,
generate_collisions,
limited_range
} random_generator;
int generate(int const*, random_generator);
char generate(char const*, random_generator);
signed char generate(signed char const*, random_generator);
std::string generate(std::string const*, random_generator);
float generate(float const*, random_generator);
struct base_type {} base;
struct derived_type : base_type {} derived;

View File

@ -27,25 +27,32 @@ namespace test
}
};
inline int generate(int const*)
{
std::size_t random_value(std::size_t max) {
using namespace std;
return rand();
return static_cast<std::size_t>(rand()) % max;
}
inline char generate(char const*)
inline int generate(int const*, random_generator g)
{
using namespace std;
int value = rand();
if (g == limited_range) { value = value % 100; }
return value;
}
inline char generate(char const*, random_generator)
{
using namespace std;
return static_cast<char>((rand() >> 1) % (128-32) + 32);
}
inline signed char generate(signed char const*)
inline signed char generate(signed char const*, random_generator)
{
using namespace std;
return static_cast<signed char>(rand());
}
inline std::string generate(std::string const*)
inline std::string generate(std::string const*, random_generator g)
{
using namespace std;
@ -53,17 +60,30 @@ namespace test
std::string result;
int length = rand() % 10;
for(int i = 0; i < length; ++i)
result += generate(char_ptr);
if (g == limited_range) {
std::size_t length = test::random_value(2) + 2;
char const* strings[] = { "'vZh(3~ms", "%m", "_Y%U", "N'Y", "4,J_J" };
for (std::size_t i = 0; i < length; ++i) {
result += strings[random_value(sizeof(strings) / sizeof(strings[0]))];
}
}
else {
std::size_t length = test::random_value(10) + 1;
for (std::size_t i = 0; i < length; ++i) {
result += generate(char_ptr, g);
}
}
return result;
}
float generate(float const*)
float generate(float const*, random_generator g)
{
using namespace std;
return (float) rand() / (float) RAND_MAX;
int x = 0;
int value = generate(&x, g);
return (float) value / (float) RAND_MAX;
}
}

View File

@ -38,6 +38,26 @@ namespace test
{
return get_key_impl<Container>::get_key(x);
}
// test::next
//
// Increments an iterator by 1 or a given value.
// Like boost::next, but simpler and slower.
template <typename Iterator>
Iterator next(Iterator it)
{
return ++it;
}
template <typename Iterator, typename IntType>
Iterator next(Iterator it, IntType x)
{
for(; x > 0; --x) {
++it;
}
return it;
}
}
#endif

View File

@ -91,7 +91,7 @@ namespace test
// Check the load factor.
float load_factor =
float load_factor = size == 0 ? 0 :
static_cast<float>(size) / static_cast<float>(x1.bucket_count());
using namespace std;
if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)

View File

@ -8,8 +8,6 @@
#include <boost/config.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
namespace test
{
@ -22,19 +20,11 @@ namespace test
template <class Container>
struct has_unique_keys
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <class V, class H, class P, class A>
struct has_unique_keys<boost::unordered_set<V, H, P, A> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <class K, class M, class H, class P, class A>
struct has_unique_keys<boost::unordered_map<K, M, H, P, A> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
static char flip(BOOST_DEDUCED_TYPENAME Container::iterator const&);
static long flip(std::pair<BOOST_DEDUCED_TYPENAME Container::iterator, bool> const&);
BOOST_STATIC_CONSTANT(bool, value = sizeof(long) == sizeof(
flip(((Container*) 0)->insert(*(BOOST_DEDUCED_TYPENAME Container::value_type*) 0))
));
};
}

View File

@ -14,11 +14,6 @@
namespace test
{
typedef enum {
default_generator,
generate_collisions
} random_generator;
template <class X>
struct unordered_generator_set
{
@ -32,16 +27,15 @@ namespace test
template <class T>
void fill(T& x, std::size_t len) {
value_type* value_ptr = 0;
int* int_ptr = 0;
len += x.size();
for (std::size_t i = 0; i < len; ++i) {
value_type value = generate(value_ptr);
value_type value = generate(value_ptr, type_);
int count = type_ == generate_collisions ?
1 + (generate(int_ptr) % 5) : 1;
std::size_t count = type_ == generate_collisions ?
random_value(5) + 1 : 1;
for(int j = 0; j < count; ++j) {
for(std::size_t j = 0; j < count; ++j) {
x.push_back(value);
}
}
@ -63,17 +57,16 @@ namespace test
void fill(T& x, std::size_t len) {
key_type* key_ptr = 0;
mapped_type* mapped_ptr = 0;
int* int_ptr = 0;
for (std::size_t i = 0; i < len; ++i) {
key_type key = generate(key_ptr);
key_type key = generate(key_ptr, type_);
int count = type_ == generate_collisions ?
1 + (generate(int_ptr) % 5) : 1;
std::size_t count = type_ == generate_collisions ?
random_value(5) + 1 : 1;
for(int j = 0; j < count; ++j) {
for(std::size_t j = 0; j < count; ++j) {
x.push_back(std::pair<key_type const, mapped_type>(
key, generate(mapped_ptr)));
key, generate(mapped_ptr, type_)));
}
}
}
@ -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<X> gen(generator);

View File

@ -24,7 +24,11 @@
void BOOST_PP_CAT(x, _type)::run() \
#define RUN_TESTS() int main(int, char**) \
{ ::test::test_list::run_tests(); return boost::report_errors(); } \
{ \
::test::write_compiler_info(); \
::test::test_list::run_tests(); \
return boost::report_errors(); \
}
namespace test {
struct registered_test_base {
@ -66,6 +70,21 @@ namespace test {
}
}
}
inline void write_compiler_info() {
#if defined(BOOST_GCC_CXX11)
char const* cpp11 = "true";
#else
char const* cpp11 = "false";
#endif
std::cout
<< "Compiler: " << BOOST_COMPILER << "\n"
<< "Library: " << BOOST_STDLIB << "\n"
<< "C++11: " << cpp11 << "\n"
<< "\n"
<< std::flush;
}
}
#include <boost/preprocessor/seq/for_each_product.hpp>

View File

@ -13,7 +13,6 @@
#include <map>
#include <iterator>
#include <algorithm>
#include <boost/type_traits/is_same.hpp>
#include "../objects/fwd.hpp"
#include "./metafunctions.hpp"
#include "./helpers.hpp"
@ -60,38 +59,46 @@ namespace test
values2.begin(), test::equivalent));
}
template <typename X>
template <typename X,
bool is_set = test::is_set<X>::value,
bool has_unique_keys = test::has_unique_keys<X>::value>
struct ordered_base;
template <class V, class H, class P, class A>
struct ordered_base<boost::unordered_set<V, H, P, A> >
template <typename X>
struct ordered_base<X, true, true>
{
typedef std::set<V,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
typedef std::set<
BOOST_DEDUCED_TYPENAME X::value_type,
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
type;
};
template <class V, class H, class P, class A>
struct ordered_base<boost::unordered_multiset<V, H, P, A> >
template <typename X>
struct ordered_base<X, true, false>
{
typedef std::multiset<V,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
typedef std::multiset<
BOOST_DEDUCED_TYPENAME X::value_type,
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
type;
};
template <class K, class M, class H, class P, class A>
struct ordered_base<boost::unordered_map<K, M, H, P, A> >
template <typename X>
struct ordered_base<X, false, true>
{
typedef std::map<K, M,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
typedef std::map<
BOOST_DEDUCED_TYPENAME X::key_type,
BOOST_DEDUCED_TYPENAME X::mapped_type,
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
type;
};
template <class K, class M, class H, class P, class A>
struct ordered_base<boost::unordered_multimap<K, M, H, P, A> >
template <typename X>
struct ordered_base<X, false, false>
{
typedef std::multimap<K, M,
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
typedef std::multimap<
BOOST_DEDUCED_TYPENAME X::key_type,
BOOST_DEDUCED_TYPENAME X::mapped_type,
BOOST_DEDUCED_TYPENAME equals_to_compare<BOOST_DEDUCED_TYPENAME X::key_equal>::type>
type;
};

View File

@ -23,7 +23,7 @@ namespace exception
class hash;
class equal_to;
template <class T> class allocator;
object generate(object const*);
object generate(object const*, random_generator);
struct true_type
{
@ -101,9 +101,9 @@ namespace exception
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
}
friend object generate(object const*) {
friend object generate(object const*, random_generator g) {
int* x = 0;
return object(::test::generate(x), ::test::generate(x));
return object(::test::generate(x, g), ::test::generate(x, g));
}
friend std::ostream& operator<<(std::ostream& out, object const& o)
@ -146,14 +146,18 @@ namespace exception
UNORDERED_EPOINT("Mock hash function.");
}
int result;
switch(tag_) {
case 1:
return x.tag1_;
result = x.tag1_;
break;
case 2:
return x.tag2_;
result = x.tag2_;
break;
default:
return x.tag1_ + x.tag2_;
result = x.tag1_ + x.tag2_;
}
return static_cast<std::size_t>(result);
}
friend bool operator==(hash const& x1, hash const& x2) {
@ -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

View File

@ -25,9 +25,9 @@ namespace test
class equal_to;
template <class T> class allocator1;
template <class T> class allocator2;
object generate(object const*);
movable generate(movable const*);
implicitly_convertible generate(implicitly_convertible const*);
object generate(object const*, random_generator);
movable generate(movable const*, random_generator);
implicitly_convertible generate(implicitly_convertible const*, random_generator);
inline void ignore_variable(void const*) {}
@ -58,9 +58,9 @@ namespace test
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
}
friend object generate(object const*) {
friend object generate(object const*, random_generator g) {
int* x = 0;
return object(generate(x), generate(x));
return object(generate(x, g), generate(x, g));
}
friend std::ostream& operator<<(std::ostream& out, object const& o)
@ -133,9 +133,9 @@ namespace test
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
}
friend movable generate(movable const*) {
friend movable generate(movable const*, random_generator g) {
int* x = 0;
return movable(generate(x), generate(x));
return movable(generate(x, g), generate(x, g));
}
friend std::ostream& operator<<(std::ostream& out, movable const& o)
@ -163,9 +163,9 @@ namespace test
return movable(tag1_, tag2_);
}
friend implicitly_convertible generate(implicitly_convertible const*) {
friend implicitly_convertible generate(implicitly_convertible const*, random_generator g) {
int* x = 0;
return implicitly_convertible(generate(x), generate(x));
return implicitly_convertible(generate(x, g), generate(x, g));
}
friend std::ostream& operator<<(std::ostream& out, implicitly_convertible const& o)
@ -182,29 +182,48 @@ namespace test
explicit hash(int t = 0) : type_(t) {}
std::size_t operator()(object const& x) const {
int result;
switch(type_) {
case 1:
return x.tag1_;
result = x.tag1_;
break;
case 2:
return x.tag2_;
result = x.tag2_;
break;
default:
return x.tag1_ + x.tag2_;
result = x.tag1_ + x.tag2_;
}
return static_cast<std::size_t>(result);
}
std::size_t operator()(movable const& x) const {
int result;
switch(type_) {
case 1:
return x.tag1_;
result = x.tag1_;
break;
case 2:
return x.tag2_;
result = x.tag2_;
break;
default:
return x.tag1_ + x.tag2_;
result = x.tag1_ + x.tag2_;
}
return static_cast<std::size_t>(result);
}
std::size_t operator()(int x) const {
return x;
int result;
switch(type_) {
case 1:
result = x;
break;
case 2:
result = x * 7;
break;
default:
result = x * 256;
}
return static_cast<std::size_t>(result);
}
friend bool operator==(hash const& x1, hash const& x2) {

View File

@ -236,6 +236,7 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
template <typename T>
bool is_propagate(T*)
@ -256,7 +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)

View File

@ -34,8 +34,10 @@ void tests(X*, test::random_generator generator)
X x(v.begin(), v.end());
BOOST_TEST(x.bucket_count() < x.max_bucket_count());
std::cerr<<x.bucket_count()<<"<"<<x.max_bucket_count()<<"\n";
BOOST_TEST(x.bucket_count() <= x.max_bucket_count());
if (!(x.bucket_count() <= x.max_bucket_count())) {
std::cerr<<x.bucket_count()<<"<="<<x.max_bucket_count()<<"\n";
}
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator
it = v.begin(), end = v.end(); it != end; ++it)
@ -43,7 +45,7 @@ void tests(X*, test::random_generator generator)
size_type bucket = x.bucket(test::get_key<X>(*it));
BOOST_TEST(bucket < x.bucket_count());
if(bucket < x.max_bucket_count()) {
if(bucket < x.bucket_count()) {
// lit? lend?? I need a new naming scheme.
const_local_iterator lit = x.begin(bucket), lend = x.end(bucket);
while(lit != lend
@ -87,10 +89,11 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(tests,
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}

View File

@ -89,8 +89,9 @@ void container_test(X& r, T const&)
// size_type can represent any non-negative value type of difference_type
// I'm not sure about either of these tests...
size_type max_diff((std::numeric_limits<difference_type>::max)());
difference_type converted_diff(max_diff);
size_type max_diff = static_cast<size_type>(
(std::numeric_limits<difference_type>::max)());
difference_type converted_diff(static_cast<difference_type>(max_diff));
BOOST_TEST((std::numeric_limits<difference_type>::max)()
== converted_diff);
@ -476,6 +477,17 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
test::check_return_type<iterator>::equals(a.emplace_hint(q, t));
a.insert(i, j);
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
std::initializer_list<T> list = {t};
a.insert(list);
a.insert({t,t,t});
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900)
a.insert({});
a.insert({t});
a.insert({t,t});
#endif
#endif
X a10;
a10.insert(t);

View File

@ -418,20 +418,21 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(constructor_tests1,
((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(constructor_tests2,
((test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(map_constructor_test,
((test_map_std_alloc)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)

View File

@ -198,13 +198,14 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(copy_construct_tests1, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(copy_construct_tests2, (
@ -212,7 +213,7 @@ UNORDERED_TEST(copy_construct_tests2, (
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}

View File

@ -25,9 +25,11 @@ namespace equality_tests
return x % 1000 == y % 1000;
}
int operator()(int x) const
std::size_t operator()(int x) const
{
return alt_hash_ ? x % 250 : (x + 5) % 250;
return alt_hash_ ?
static_cast<std::size_t>(x % 250) :
static_cast<std::size_t>((x + 5) % 250);
}
};

View File

@ -13,10 +13,10 @@
#include "../helpers/test.hpp"
#include "../helpers/list.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/helpers.hpp"
#include <set>
#include <iostream>
#include <iterator>
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
@ -43,19 +43,19 @@ void write_container(Container const& x)
// Make everything collide - for testing erase in a single bucket.
struct collision_hash
{
int operator()(int) const { return 0; }
std::size_t operator()(int) const { return 0; }
};
// For testing erase in 2 buckets.
struct collision2_hash
{
int operator()(int x) const { return x & 1; }
std::size_t operator()(int x) const { return static_cast<std::size_t>(x & 1); }
};
// For testing erase in lots of buckets.
struct collision3_hash
{
int operator()(int x) const { return x; }
std::size_t operator()(int x) const { return static_cast<std::size_t>(x); }
};
typedef boost::unordered_multimap<int, int,
@ -111,8 +111,8 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
{
collide_map x(init.begin(), init.end());
int value = boost::next(x.begin())->second;
x.erase(x.begin(), boost::next(x.begin()));
int value = test::next(x.begin())->second;
x.erase(x.begin(), test::next(x.begin()));
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
x.begin()->first == 1 && x.begin()->second == value);
test::check_equivalent_keys(x);
@ -121,7 +121,7 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
{
collide_map x(init.begin(), init.end());
int value = x.begin()->second;
x.erase(boost::next(x.begin()), x.end());
x.erase(test::next(x.begin()), x.end());
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
x.begin()->first == 1 && x.begin()->second == value);
test::check_equivalent_keys(x);
@ -144,8 +144,9 @@ template <class Container>
bool general_erase_range_test(Container& x, std::size_t start, std::size_t end)
{
collide_list l(x.begin(), x.end());
l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end));
x.erase(boost::next(x.begin(), start), boost::next(x.begin(), end));
l.erase(test::next(l.begin(), start), test::next(l.begin(), end));
x.erase(test::next(x.begin(), start), test::next(x.begin(), end));
test::check_equivalent_keys(x);
return compare(l, x);

View File

@ -9,15 +9,15 @@
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include "../helpers/helpers.hpp"
#include "../helpers/invariants.hpp"
#include <vector>
#include <iostream>
#include <cstdlib>
namespace erase_tests
{
@ -27,6 +27,9 @@ test::seed_t initialize_seed(85638);
template <class Container>
void erase_tests1(Container*, test::random_generator generator)
{
typedef BOOST_DEDUCED_TYPENAME Container::iterator iterator;
typedef BOOST_DEDUCED_TYPENAME Container::const_iterator c_iterator;
std::cerr<<"Erase by key.\n";
{
test::check_instances check_;
@ -60,8 +63,7 @@ void erase_tests1(Container*, test::random_generator generator)
BOOST_DEDUCED_TYPENAME Container::key_type
key = test::get_key<Container>(*x.begin());
std::size_t count = x.count(key);
BOOST_DEDUCED_TYPENAME Container::iterator
pos = x.erase(x.begin());
iterator pos = x.erase(x.begin());
--size;
BOOST_TEST(pos == x.begin());
BOOST_TEST(x.count(key) == count - 1);
@ -81,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<Container>(*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<Container> v(1000, generator);
x.insert(v.begin(), v.end());
// Note that erase only invalidates the erased iterators.
std::vector<c_iterator> iterators;
for(c_iterator it = x.cbegin(); it != x.cend(); ++it) {
iterators.push_back(it);
}
iterators.push_back(x.cend());
while(iterators.size() > 1) {
std::size_t start = test::random_value(iterators.size());
std::size_t length = test::random_value(iterators.size() - start);
x.erase(iterators[start], iterators[start + length]);
iterators.erase(
test::next(iterators.begin(), start),
test::next(iterators.begin(), start + length));
BOOST_TEST(x.size() == iterators.size() - 1);
BOOST_DEDUCED_TYPENAME std::vector<c_iterator>::const_iterator
i2 = iterators.begin();
for(c_iterator i1 = x.cbegin(); i1 != x.cend(); ++i1) {
BOOST_TEST(i1 == *i2);
++i2;
}
BOOST_TEST(x.cend() == *i2);
test::check_equivalent_keys(x);
}
BOOST_TEST(x.empty());
}
}
std::cerr<<"quick_erase(begin()).\n";
{
test::check_instances check_;
@ -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<Container>(*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<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(erase_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}

View File

@ -37,15 +37,15 @@ void find_tests1(X*, test::random_generator generator)
tracker.begin(); it1 != tracker.end(); ++it1)
{
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it1);
iterator pos = x.find(key);
BOOST_DEDUCED_TYPENAME X::const_iterator
const_pos = x_const.find(key);
BOOST_TEST(pos != x.end());
BOOST_TEST(pos != x.end() &&
x.key_eq()(key, test::get_key<X>(*pos)));
iterator pos = x.find(key);
BOOST_TEST(const_pos != x_const.end());
BOOST_TEST(const_pos != x_const.end() &&
x_const.key_eq()(key, test::get_key<X>(*const_pos)));
BOOST_TEST(pos != x.end());
BOOST_TEST(pos != x.end() &&
x.key_eq()(key, test::get_key<X>(*pos)));
BOOST_TEST(x.count(key) == tracker.count(key));
@ -155,14 +155,15 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(find_tests1,
((test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(find_compatible_keys_test,
((test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}

View File

@ -0,0 +1,118 @@
// Copyright 2016 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../helpers/invariants.hpp"
#include <map>
#include <set>
#include <iostream>
namespace insert_hint
{
UNORDERED_AUTO_TEST(insert_hint_empty) {
typedef boost::unordered_multiset<int> container;
container x;
x.insert(x.cbegin(), 10);
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST_EQ(x.count(10), 1u);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_empty2) {
typedef boost::unordered_multimap<std::string, int> container;
container x;
x.emplace_hint(x.cbegin(), "hello", 50);
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST_EQ(x.count("hello"), 1u);
BOOST_TEST_EQ(x.find("hello")->second, 50);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_single) {
typedef boost::unordered_multiset<std::string> container;
container x;
x.insert("equal");
x.insert(x.cbegin(), "equal");
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST_EQ(x.count("equal"), 2u);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_single2) {
typedef boost::unordered_multimap<int, std::string> container;
container x;
x.emplace(10, "one");
x.emplace_hint(x.cbegin(), 10, "two");
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST_EQ(x.count(10), 2u);
container::iterator it = x.find(10);
std::string v0 = (it++)->second;
std::string v1 = (it++)->second;
BOOST_TEST(v0 == "one" || v0 == "two");
BOOST_TEST(v1 == "one" || v1 == "two");
BOOST_TEST(v0 != v1);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_multiple) {
for (unsigned int size = 0; size < 10; ++size) {
for (unsigned int offset = 0; offset <= size; ++offset) {
typedef boost::unordered_multiset<std::string> container;
container x;
for (unsigned int i = 0; i < size; ++i) { x.insert("multiple"); }
BOOST_TEST_EQ(x.size(), size);
container::const_iterator position = x.cbegin();
for (unsigned int i = 0; i < offset; ++i) { ++position; }
x.insert(position, "multiple");
BOOST_TEST_EQ(x.size(), size + 1u);
BOOST_TEST_EQ(x.count("multiple"), size + 1u);
test::check_equivalent_keys(x);
}
}
}
UNORDERED_AUTO_TEST(insert_hint_unique) {
typedef boost::unordered_set<int> container;
container x;
x.insert(x.cbegin(), 10);
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST_EQ(x.count(10), 1u);
test::check_equivalent_keys(x);
}
UNORDERED_AUTO_TEST(insert_hint_unique_single) {
typedef boost::unordered_set<int> container;
container x;
x.insert(10);
x.insert(x.cbegin(), 10);
BOOST_TEST_EQ(x.size(), 1u);
BOOST_TEST_EQ(x.count(10), 1u);
test::check_equivalent_keys(x);
x.insert(x.cbegin(), 20);
BOOST_TEST_EQ(x.size(), 2u);
BOOST_TEST_EQ(x.count(10), 1u);
BOOST_TEST_EQ(x.count(20), 1u);
test::check_equivalent_keys(x);
}
}
RUN_TESTS()

View File

@ -49,6 +49,8 @@ UNORDERED_AUTO_TEST(stable_insert_test1) {
x.insert(insert_stable::member(1,2));
x.insert(insert_stable::member(1,3));
BOOST_TEST(x.count(insert_stable::member(1,4)) == 3);
boost::unordered_multiset<insert_stable::member>::const_iterator
it = x.begin(), end = x.end();
BOOST_TEST(it != end);
@ -66,10 +68,11 @@ UNORDERED_AUTO_TEST(stable_insert_test2) {
boost::unordered_multimap<insert_stable::member, int>::const_iterator
iterator;
iterator it
= x.insert(x.end(), std::make_pair(insert_stable::member(1,1), 1));
it = x.insert(it, std::make_pair(insert_stable::member(1,2), 2));
it = x.insert(it, std::make_pair(insert_stable::member(1,3), 3));
iterator it = x.emplace(insert_stable::member(1,1), 1);
it = x.emplace(insert_stable::member(1,2), 2);
it = x.emplace(insert_stable::member(1,3), 3);
BOOST_TEST(x.count(insert_stable::member(1,4)) == 3);
it = x.begin();
iterator end = x.end();

View File

@ -9,7 +9,6 @@
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
@ -55,7 +54,7 @@ void unique_insert_tests1(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -88,7 +87,7 @@ void equivalent_insert_tests1(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@ -124,10 +123,11 @@ void insert_tests2(X*, test::random_generator generator)
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
tracker.compare(x);
test::check_equivalent_keys(x);
}
@ -153,10 +153,11 @@ void insert_tests2(X*, test::random_generator generator)
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
tracker.compare(x);
test::check_equivalent_keys(x);
}
@ -182,10 +183,11 @@ void insert_tests2(X*, test::random_generator generator)
BOOST_TEST(*pos == *r2);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
tracker.compare(x);
test::check_equivalent_keys(x);
}
@ -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<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
tracker.compare(x);
test::check_equivalent_keys(x);
}
@ -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<X> tracker = test::create_ordered(x);
test::random_values<X> v(1000, generator);
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
it = v.begin(); it != v.end();)
{
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
float b = x.max_load_factor();
BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
next = it;
for (std::size_t j = test::random_value(20); j > 0; ++j) {
++next;
if (next == v.end()) { break; }
}
x.insert(it, next);
tracker.insert(it, next);
it = next;
tracker.compare(x); // Slow, but I can't see any other way.
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
}
}
}
template <class X>
@ -323,10 +362,11 @@ void unique_emplace_tests1(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
tracker.compare(x);
test::check_equivalent_keys(x);
}
@ -353,10 +393,11 @@ void equivalent_emplace_tests1(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
tracker.compare(x);
test::check_equivalent_keys(x);
}
@ -382,12 +423,12 @@ void move_emplace_tests(X*, test::random_generator generator)
tracker.insert(*it);
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
test::check_equivalent_keys(x);
tracker.compare(x);
test::check_equivalent_keys(x);
}
template <class X>
@ -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<X>(y)) == is_unique ? 1: 3);
BOOST_TEST(x.count(test::get_key<X>(y)) == (is_unique ? 1u : 3u));
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
x.emplace(y);
BOOST_TEST(x.size() == is_unique ? 1: 4);
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 4);
BOOST_TEST(x.size() == (is_unique ? 1u : 4u));
BOOST_TEST(x.count(test::get_key<X>(y)) == (is_unique ? 1u : 4u));
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
x.clear();
@ -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<X>(y)) == is_unique ? 1: 2);
BOOST_TEST(x.count(test::get_key<X>(y)) == (is_unique ? 1u : 2u));
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
}
@ -445,10 +486,11 @@ void map_tests(X*, test::random_generator generator)
tracker.compare_key(x, *it);
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(x.size()) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
tracker.compare(x);
test::check_equivalent_keys(x);
}
@ -518,57 +560,58 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(unique_insert_tests1,
((test_set_std_alloc)(test_set)(test_map))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(equivalent_insert_tests1,
((test_multimap_std_alloc)(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(insert_tests2,
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(unique_emplace_tests1,
((test_set_std_alloc)(test_set)(test_map))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(equivalent_emplace_tests1,
((test_multimap_std_alloc)(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(move_emplace_tests,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(default_emplace_tests,
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
(test_multiset)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(map_tests,
((test_map))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(map_insert_range_test1,
((test_multimap_std_alloc)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(map_insert_range_test2,
((test_multimap_std_alloc)(test_map)(test_multimap))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
@ -579,7 +622,7 @@ struct initialize_from_two_ints
friend std::size_t hash_value(initialize_from_two_ints const& x)
{
return x.a + x.b;
return static_cast<std::size_t>(x.a + x.b);
}
bool operator==(initialize_from_two_ints const& x) const

View File

@ -51,7 +51,7 @@ void insert_test(X*, float mlf, test::random_generator generator)
BOOST_DEDUCED_TYPENAME X::size_type old_size = x.size(),
old_bucket_count = x.bucket_count();
x.insert(*it);
if(static_cast<double>(old_size + 1) < b * static_cast<double>(old_bucket_count))
if(static_cast<double>(old_size + 1) <= b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
}
@ -78,6 +78,7 @@ boost::unordered_multimap<int, int>* int_multimap_ptr;
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(set_load_factor_tests,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
@ -85,7 +86,7 @@ UNORDERED_TEST(set_load_factor_tests,
UNORDERED_TEST(load_factor_insert_tests,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}

View File

@ -369,6 +369,7 @@ boost::unordered_multimap<test::object, test::object,
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(move_construct_tests1, (
(test_map_std_alloc)
@ -376,7 +377,7 @@ boost::unordered_multimap<test::object, test::object,
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(move_assign_tests1, (
(test_map_std_alloc)
@ -384,21 +385,21 @@ boost::unordered_multimap<test::object, test::object,
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(move_construct_tests2, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(move_assign_tests2, (
(test_set)(test_multiset)(test_map)(test_multimap)
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}

View File

@ -24,28 +24,6 @@ namespace noexcept_tests
equal_to_possible_exception(equal_to_possible_exception const&) {}
};
UNORDERED_AUTO_TEST(test_noexcept)
{
#if !defined(BOOST_NO_CXX11_NOEXCEPT)
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_set<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multiset<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_map<int, int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multimap<int, int> >::value));
#endif
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_set<int, hash_possible_exception>
>::value));
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_multiset<int, boost::hash<int>,
equal_to_possible_exception>
>::value));
}
// Test that the move constructor does actually move without throwing
// an exception when it claims to.
@ -70,8 +48,10 @@ namespace noexcept_tests
hash_nothrow_move() { test_throw("Constructor"); }
hash_nothrow_move(hash_nothrow_move const&) { test_throw("Copy"); }
hash_nothrow_move& operator=(hash_nothrow_move const&)
hash_nothrow_move& operator=(BOOST_COPY_ASSIGN_REF(hash_nothrow_move))
{ test_throw("Assign"); return *this; }
hash_nothrow_move& operator=(BOOST_RV_REF(hash_nothrow_move))
{ test_throw("Move Assign"); return *this; }
std::size_t operator()(int x) const
{ test_throw("Operator"); return static_cast<base const&>(*this)(x); }
};
@ -87,26 +67,69 @@ namespace noexcept_tests
equal_to_nothrow_move() { test_throw("Constructor"); }
equal_to_nothrow_move(equal_to_nothrow_move const&)
{ test_throw("Copy"); }
equal_to_nothrow_move& operator=(equal_to_nothrow_move const&)
equal_to_nothrow_move& operator=(BOOST_COPY_ASSIGN_REF(equal_to_nothrow_move))
{ test_throw("Assign"); return *this; }
equal_to_nothrow_move& operator=(BOOST_RV_REF(equal_to_nothrow_move))
{ test_throw("Move Assign"); return *this; }
std::size_t operator()(int x, int y) const
{ test_throw("Operator"); return static_cast<base const&>(*this)(x, y); }
};
bool have_is_nothrow_move = false;
UNORDERED_AUTO_TEST(check_is_nothrow_move)
{
BOOST_TEST(!boost::is_nothrow_move_constructible<hash_possible_exception>::value);
have_is_nothrow_move = boost::is_nothrow_move_constructible<hash_nothrow_move>::value;
// Copied from boost::is_nothrow_move_constructible implementation
// to make sure this does actually detect it when expected.
//
// The type trait is also available when BOOST_IS_NOTHROW_MOVE_CONSTRUCT
// is defined (for some versions of Visual C++?) but detects 'throw()',
// not noexcept.
#if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
BOOST_TEST(have_is_nothrow_move);
#endif
}
UNORDERED_AUTO_TEST(test_noexcept)
{
if (have_is_nothrow_move) {
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_set<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multiset<int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_map<int, int> >::value));
BOOST_TEST((boost::is_nothrow_move_constructible<
boost::unordered_multimap<int, int> >::value));
}
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_set<int, hash_possible_exception>
>::value));
BOOST_TEST((!boost::is_nothrow_move_constructible<
boost::unordered_multiset<int, boost::hash<int>,
equal_to_possible_exception>
>::value));
}
UNORDERED_AUTO_TEST(test_no_throw_when_noexcept)
{
typedef boost::unordered_set<int,
hash_nothrow_move, equal_to_nothrow_move> throwing_set;
if (boost::is_nothrow_move_constructible<throwing_set>::value)
if (have_is_nothrow_move)
{
BOOST_TEST(boost::is_nothrow_move_constructible<throwing_set>::value);
throwing_test_exception = false;
throwing_set x1;
x1.insert(10);
x1.insert(50);
try {
throwing_test_exception = true;

View File

@ -22,7 +22,7 @@ test::seed_t initialize_seed(2974);
template <class X>
bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n)
{
return static_cast<double>(x.bucket_count()) >
return static_cast<double>(x.bucket_count()) >=
static_cast<double>(x.size()) / x.max_load_factor() &&
x.bucket_count() >= n;
}
@ -139,7 +139,7 @@ void reserve_test1(X*, test::random_generator generator)
{
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
{
for (int i = 1; i < 2000; i += i < 50 ? 1 : 13)
for (std::size_t i = 1; i < 2000; i += i < 50 ? 1 : 13)
{
test::random_values<X> v(i, generator);
@ -149,9 +149,6 @@ void reserve_test1(X*, test::random_generator generator)
X x;
x.max_load_factor(random_mlf ?
static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f : 1.0f);
// For the current standard this should reserve i+1, I've
// submitted a defect report and will assume it's a defect
// for now.
x.reserve(test::has_unique_keys<X>::value ? i : v.size());
// Insert an element before the range insert, otherwise there are
@ -174,7 +171,7 @@ void reserve_test2(X*, test::random_generator generator)
{
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
{
for (int i = 0; i < 2000; i += i < 50 ? 1 : 13)
for (std::size_t i = 0; i < 2000; i += i < 50 ? 1 : 13)
{
test::random_values<X> v(i, generator);
@ -211,21 +208,22 @@ boost::unordered_multimap<int, int>* int_multimap_ptr;
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_TEST(rehash_empty_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
)
UNORDERED_TEST(rehash_empty_test2,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(rehash_empty_test3,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(rehash_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(reserve_empty_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
@ -235,11 +233,11 @@ UNORDERED_TEST(reserve_empty_test2,
)
UNORDERED_TEST(reserve_test1,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(reserve_test2,
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}

View File

@ -206,6 +206,7 @@ bool is_propagate(T*)
using test::default_generator;
using test::generate_collisions;
using test::limited_range;
UNORDERED_AUTO_TEST(check_traits)
{
@ -220,7 +221,7 @@ UNORDERED_TEST(swap_tests1, (
(test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
(test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
UNORDERED_TEST(swap_tests2, (
@ -228,7 +229,7 @@ UNORDERED_TEST(swap_tests2, (
(test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
(test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
)
((default_generator)(generate_collisions))
((default_generator)(generate_collisions)(limited_range))
)
}

View File

@ -115,7 +115,7 @@ namespace unnecessary_copy_tests
#endif
{
std::size_t hash_value(unnecessary_copy_tests::count_copies const& x) {
return x.tag_;
return static_cast<std::size_t>(x.tag_);
}
}