diff --git a/.travis.yml b/.travis.yml
index e6c0c766..01420b5e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,8 +11,9 @@ language: c++
addons:
apt:
packages:
- - libboost-dev
- libboost-tools-dev
+ - libxml2-utils
+ - g++-multilib
matrix:
include:
@@ -20,19 +21,40 @@ matrix:
env: BJAM_TOOLSET=gcc
- compiler: gcc
env: BJAM_TOOLSET=gcc-std11
- - compiler: clang
- env: BJAM_TOOLSET=clang
+ #- compiler: gcc
+ # env: BJAM_TOOLSET=gcc-m32
+ - compiler: gcc
+ env: BJAM_TOOLSET=gcc-std11m32
+ #- compiler: clang
+ # env: BJAM_TOOLSET=clang
- compiler: clang
env: BJAM_TOOLSET=clang-std11
+ - compiler: clang
+ env: BJAM_TOOLSET=clang-m32
+ #- compiler: clang
+ # env: BJAM_TOOLSET=clang-std11m32
before_script:
+ - cd ${TRAVIS_BUILD_DIR}
+ - touch Jamroot.jam
+ - cd $HOME
- |
echo "using gcc : : g++-4.8 -Werror --std=c++03 -fsanitize=address ;" > ~/user-config.jam
echo "using gcc : std11 : g++-4.8 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam
+ echo "using gcc : m32 : g++-4.8 -m32 -Werror -fsanitize=address ;" >> ~/user-config.jam
+ echo "using gcc : std11m32 : g++-4.8 -m32 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam
echo "using clang : : clang++ -Werror --std=c++03 -fsanitize=address ;" >> ~/user-config.jam
echo "using clang : std11 : clang++ -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam
+ # sanitized=address not available for 32-bit clang on travis.
+ echo "using clang : m32 : clang++ -m32 -Werror --std=c++03 ;" >> ~/user-config.jam
+ echo "using clang : std11m32 : clang++ -m32 -Werror --std=c++11 ;" >> ~/user-config.jam
- cat ~/user-config.jam
- - touch Jamroot.jam
+ - wget -O boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/snapshots/master/boost_1_62_0.tar.bz2/download
+ - tar -xjf boost.tar.bz2
+ - mv boost_1_62_0 boost
+ - rm -r boost/boost/unordered
script:
- - cd test && bjam ${BJAM_TOOLSET} include=${TRAVIS_BUILD_DIR}/include
+ - cd ${TRAVIS_BUILD_DIR}/test
+ - bjam ${BJAM_TOOLSET} include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include
+ - xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml
diff --git a/doc/changes.qbk b/doc/changes.qbk
index 54002878..03fe1987 100644
--- a/doc/changes.qbk
+++ b/doc/changes.qbk
@@ -279,4 +279,19 @@ C++11 support has resulted in some breaking changes:
* Stop using return value SFINAE which some older compilers have issues
with.
+[h2 Boost 1.63.0]
+
+* Check hint iterator in `insert`/`emplace_hint`.
+* Fix some warnings, mostly in the tests.
+* Manually write out `emplace_args` for small numbers of arguments -
+ should make template error messages a little more bearable.
+* Remove superfluous use of `boost::forward` in emplace arguments,
+ which fixes emplacing string literals in old versions of Visual C++.
+* Fix an exception safety issue in assignment. If bucket allocation
+ throws an exception, it can overwrite the hash and equality functions while
+ leaving the existing elements in place. This would mean that the function
+ objects wouldn't match the container elements, so elements might be in the
+ wrong bucket and equivalent elements would be incorrectly handled.
+* Various reference documentation improvements.
+
[endsect]
diff --git a/doc/ref.php b/doc/ref.php
index 0a474807..d2fb2b42 100644
--- a/doc/ref.php
+++ b/doc/ref.php
@@ -358,6 +358,21 @@ EOL;
+
+
+ initializer_list<value_type>
+
+ &
+
+ Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.
+
+
+
+ value_type
is CopyInsertable
into the container and
+ CopyAssignable
.
+
+
+
allocator_type
@@ -640,7 +655,35 @@ EOL;
void
- Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent .
+ Inserts a range of elements into the container.
+
+ Elements are inserted if and only if there is no element in the container with an equivalent .
+
+
+
+
+ value_type
is EmplaceConstructible
into
+ X
from *first
.
+
+
+ When inserting a single element, if an exception is thrown by an operation other than a call to hasher
the function has no effect.
+
+
+ Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.
+ Pointers and references to elements are never invalidated.
+
+
+
+
+ initializer_list<value_type>
+
+ void
+
+ Inserts a range of elements into the container.
+
+ Elements are inserted if and only if there is no element in the container with an equivalent .
+
+
value_type
is EmplaceConstructible
into
diff --git a/doc/ref.xml b/doc/ref.xml
index f16e6028..d03e8dd3 100644
--- a/doc/ref.xml
+++ b/doc/ref.xml
@@ -299,6 +299,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+ initializer_list<value_type>
+
+ unordered_set&
+
+ Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.
+
+
+
+ value_type
is CopyInsertable
into the container and
+ CopyAssignable
.
+
+
+
allocator_type
@@ -537,7 +552,31 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
void
- Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent value.
+ Inserts a range of elements into the container.
+ Elements are inserted if and only if there is no element in the container with an equivalent value.
+
+
+
+ value_type
is EmplaceConstructible
into
+ X
from *first
.
+
+
+ When inserting a single element, if an exception is thrown by an operation other than a call to hasher
the function has no effect.
+
+
+ Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.
+ Pointers and references to elements are never invalidated.
+
+
+
+
+ initializer_list<value_type>
+
+ void
+
+ Inserts a range of elements into the container.
+ Elements are inserted if and only if there is no element in the container with an equivalent value.
+
value_type
is EmplaceConstructible
into
@@ -1334,6 +1373,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+ initializer_list<value_type>
+
+ unordered_multiset&
+
+ Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.
+
+
+
+ value_type
is CopyInsertable
into the container and
+ CopyAssignable
.
+
+
+
allocator_type
@@ -1569,7 +1623,29 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
void
- Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent value.
+ Inserts a range of elements into the container.
+
+
+
+ value_type
is EmplaceConstructible
into
+ X
from *first
.
+
+
+ When inserting a single element, if an exception is thrown by an operation other than a call to hasher
the function has no effect.
+
+
+ Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.
+ Pointers and references to elements are never invalidated.
+
+
+
+
+ initializer_list<value_type>
+
+ void
+
+ Inserts a range of elements into the container.
+
value_type
is EmplaceConstructible
into
@@ -2380,6 +2456,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+ initializer_list<value_type>
+
+ unordered_map&
+
+ Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.
+
+
+
+ value_type
is CopyInsertable
into the container and
+ CopyAssignable
.
+
+
+
allocator_type
@@ -2618,7 +2709,31 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
void
- Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.
+ Inserts a range of elements into the container.
+ Elements are inserted if and only if there is no element in the container with an equivalent key.
+
+
+
+ value_type
is EmplaceConstructible
into
+ X
from *first
.
+
+
+ When inserting a single element, if an exception is thrown by an operation other than a call to hasher
the function has no effect.
+
+
+ Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.
+ Pointers and references to elements are never invalidated.
+
+
+
+
+ initializer_list<value_type>
+
+ void
+
+ Inserts a range of elements into the container.
+ Elements are inserted if and only if there is no element in the container with an equivalent key.
+
value_type
is EmplaceConstructible
into
@@ -3462,6 +3577,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+ initializer_list<value_type>
+
+ unordered_multimap&
+
+ Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.
+
+
+
+ value_type
is CopyInsertable
into the container and
+ CopyAssignable
.
+
+
+
allocator_type
@@ -3697,7 +3827,29 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
void
- Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.
+ Inserts a range of elements into the container.
+
+
+
+ value_type
is EmplaceConstructible
into
+ X
from *first
.
+
+
+ When inserting a single element, if an exception is thrown by an operation other than a call to hasher
the function has no effect.
+
+
+ Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.
+ Pointers and references to elements are never invalidated.
+
+
+
+
+ initializer_list<value_type>
+
+ void
+
+ Inserts a range of elements into the container.
+
value_type
is EmplaceConstructible
into
diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp
index a83edad2..319c9cd5 100644
--- a/include/boost/unordered/detail/allocate.hpp
+++ b/include/boost/unordered/detail/allocate.hpp
@@ -96,26 +96,102 @@ namespace boost { namespace unordered { namespace detail {
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
-#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
-#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args
-#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward(args)...
-
#define BOOST_UNORDERED_EMPLACE_ARGS1(a0) a0
#define BOOST_UNORDERED_EMPLACE_ARGS2(a0, a1) a0, a1
#define BOOST_UNORDERED_EMPLACE_ARGS3(a0, a1, a2) a0, a1, a2
+#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
+#define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args
+#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward(args)...
+
#else
+#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args
+#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args
+#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args
+
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args
#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args
#define BOOST_UNORDERED_EMPLACE_FORWARD args
+#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+
+#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
+ typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \
+ BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
+
+#else
+
+#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
+ typedef typename boost::add_lvalue_reference::type \
+ BOOST_PP_CAT(Arg, n); \
+ BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
+
+#endif
+
+template
+struct emplace_args1
+{
+ BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
+
+ emplace_args1(Arg0 b0) : a0(b0) {}
+};
+
+template
+inline emplace_args1 create_emplace_args(
+ BOOST_FWD_REF(A0) b0)
+{
+ emplace_args1 e(b0);
+ return e;
+}
+
+template
+struct emplace_args2
+{
+ BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
+ BOOST_UNORDERED_EARGS_MEMBER(1, 1, _)
+
+ emplace_args2(Arg0 b0, Arg1 b1) : a0(b0), a1(b1) {}
+};
+
+template
+inline emplace_args2 create_emplace_args(
+ BOOST_FWD_REF(A0) b0,
+ BOOST_FWD_REF(A1) b1)
+{
+ emplace_args2 e(b0, b1);
+ return e;
+}
+
+template
+struct emplace_args3
+{
+ BOOST_UNORDERED_EARGS_MEMBER(1, 0, _)
+ BOOST_UNORDERED_EARGS_MEMBER(1, 1, _)
+ BOOST_UNORDERED_EARGS_MEMBER(1, 2, _)
+
+ emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : a0(b0), a1(b1), a2(b2) {}
+};
+
+template
+inline emplace_args3 create_emplace_args(
+ BOOST_FWD_REF(A0) b0,
+ BOOST_FWD_REF(A1) b1,
+ BOOST_FWD_REF(A2) b2)
+{
+ emplace_args3 e(b0, b1, b2);
+ return e;
+}
+
#define BOOST_UNORDERED_FWD_PARAM(z, n, a) \
BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n)
#define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \
boost::forward(BOOST_PP_CAT(a,i))
+#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
+BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n))
+
#define BOOST_UNORDERED_EARGS(z, n, _) \
template \
struct BOOST_PP_CAT(emplace_args, n) \
@@ -141,33 +217,7 @@ namespace boost { namespace unordered { namespace detail {
return e; \
}
-#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args
-#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args
-#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args
-
-#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
-
-#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
- typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \
- BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
-
-#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
- BOOST_PP_CAT(a, n)( \
- boost::forward(BOOST_PP_CAT(b, n)))
-
-#else
-
-#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
- typedef typename boost::add_lvalue_reference::type \
- BOOST_PP_CAT(Arg, n); \
- BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
-
-#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
- BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n))
-
-#endif
-
-BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
+BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
_)
#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS
diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp
index 232944b0..31e1ee59 100644
--- a/include/boost/unordered/detail/buckets.hpp
+++ b/include/boost/unordered/detail/buckets.hpp
@@ -583,12 +583,12 @@ namespace boost { namespace unordered { namespace detail {
// TODO: Maybe not if std::size_t is smaller than long long.
#if !defined(BOOST_NO_LONG_LONG)
template <>
- struct pick_policy {
+ struct pick_policy {
typedef prime_policy type;
};
template <>
- struct pick_policy {
+ struct pick_policy {
typedef prime_policy type;
};
#endif
diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp
index 691d3154..5835884a 100644
--- a/include/boost/unordered/detail/equivalent.hpp
+++ b/include/boost/unordered/detail/equivalent.hpp
@@ -321,7 +321,10 @@ namespace boost { namespace unordered { namespace detail {
// Emplace/Insert
- static inline void add_after_node(
+ // Add node 'n' to the group containing 'pos'.
+ // If 'pos' is the first node in group, add to the end of the group,
+ // otherwise add before 'pos'.
+ static inline void add_to_node_group(
node_pointer n,
node_pointer pos)
{
@@ -338,7 +341,7 @@ namespace boost { namespace unordered { namespace detail {
{
n->hash_ = key_hash;
if (pos.node_) {
- this->add_after_node(n, pos.node_);
+ this->add_to_node_group(n, pos.node_);
if (n->next_) {
std::size_t next_bucket = this->hash_to_bucket(
static_cast(n->next_)->hash_);
@@ -375,24 +378,23 @@ namespace boost { namespace unordered { namespace detail {
return iterator(n);
}
- iterator emplace_impl(node_pointer n)
+ inline iterator add_using_hint(
+ node_pointer n,
+ node_pointer hint)
{
- node_tmp a(n, this->node_alloc());
- key_type const& k = this->get_key(a.node_->value());
- std::size_t key_hash = this->hash(k);
- iterator position = this->find_node(key_hash, k);
- this->reserve_for_insert(this->size_ + 1);
- return this->add_node(a.release(), key_hash, position);
+ n->hash_ = hint->hash_;
+ this->add_to_node_group(n, hint);
+ if (n->next_ != hint && n->next_) {
+ std::size_t next_bucket = this->hash_to_bucket(
+ static_cast(n->next_)->hash_);
+ if (next_bucket != this->hash_to_bucket(n->hash_)) {
+ this->get_bucket(next_bucket)->next_ = n;
+ }
+ }
+ ++this->size_;
+ return iterator(n);
}
- void emplace_impl_no_rehash(node_pointer n)
- {
- node_tmp a(n, this->node_alloc());
- key_type const& k = this->get_key(a.node_->value());
- std::size_t key_hash = this->hash(k);
- iterator position = this->find_node(key_hash, k);
- this->add_node(a.release(), key_hash, position);
- }
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
# if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
@@ -402,6 +404,13 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(false);
return iterator();
}
+
+ iterator emplace_hint(c_iterator, boost::unordered::detail::emplace_args1<
+ boost::unordered::detail::please_ignore_this_overload> const&)
+ {
+ BOOST_ASSERT(false);
+ return iterator();
+ }
# else
iterator emplace(
boost::unordered::detail::please_ignore_this_overload const&)
@@ -409,6 +418,13 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(false);
return iterator();
}
+
+ iterator emplace_hint(c_iterator,
+ boost::unordered::detail::please_ignore_this_overload const&)
+ {
+ BOOST_ASSERT(false);
+ return iterator();
+ }
# endif
#endif
@@ -420,6 +436,49 @@ namespace boost { namespace unordered { namespace detail {
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD)));
}
+ template
+ iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS)
+ {
+ return iterator(emplace_hint_impl(hint,
+ boost::unordered::detail::func::construct_value_generic(
+ this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD)));
+ }
+
+ iterator emplace_impl(node_pointer n)
+ {
+ node_tmp a(n, this->node_alloc());
+ key_type const& k = this->get_key(a.node_->value());
+ std::size_t key_hash = this->hash(k);
+ iterator position = this->find_node(key_hash, k);
+ this->reserve_for_insert(this->size_ + 1);
+ return this->add_node(a.release(), key_hash, position);
+ }
+
+ iterator emplace_hint_impl(c_iterator hint, node_pointer n)
+ {
+ node_tmp a(n, this->node_alloc());
+ key_type const& k = this->get_key(a.node_->value());
+ if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
+ this->reserve_for_insert(this->size_ + 1);
+ return this->add_using_hint(a.release(), hint.node_);
+ }
+ else {
+ std::size_t key_hash = this->hash(k);
+ iterator position = this->find_node(key_hash, k);
+ this->reserve_for_insert(this->size_ + 1);
+ return this->add_node(a.release(), key_hash, position);
+ }
+ }
+
+ void emplace_impl_no_rehash(node_pointer n)
+ {
+ node_tmp a(n, this->node_alloc());
+ key_type const& k = this->get_key(a.node_->value());
+ std::size_t key_hash = this->hash(k);
+ iterator position = this->find_node(key_hash, k);
+ this->add_node(a.release(), key_hash, position);
+ }
+
////////////////////////////////////////////////////////////////////////
// Insert range methods
@@ -431,7 +490,7 @@ namespace boost { namespace unordered { namespace detail {
{
if(i == j) return;
- std::size_t distance = std::distance(i, j);
+ std::size_t distance = static_cast(std::distance(i, j));
if(distance == 1) {
emplace_impl(
boost::unordered::detail::func::construct_value(
diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp
index d68a4a77..338e918c 100644
--- a/include/boost/unordered/detail/extract_key.hpp
+++ b/include/boost/unordered/detail/extract_key.hpp
@@ -51,7 +51,7 @@ namespace detail {
typedef ValueType value_type;
typedef ValueType key_type;
- static key_type const& extract(key_type const& v)
+ static key_type const& extract(value_type const& v)
{
return v;
}
diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp
index 87c2c23b..74419062 100644
--- a/include/boost/unordered/detail/fwd.hpp
+++ b/include/boost/unordered/detail/fwd.hpp
@@ -1,5 +1,5 @@
-// Copyright (C) 2008-2011 Daniel James.
+// Copyright (C) 2008-2016 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -11,12 +11,46 @@
#pragma once
#endif
+#if defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
+// Already defined.
+#elif defined(BOOST_LIBSTDCXX11)
+// https://github.com/gcc-mirror/gcc/blob/gcc-4_6-branch/libstdc++-v3/include/bits/stl_pair.h#L70
+# if BOOST_LIBSTDCXX_VERSION > 40600
+# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
+# endif
+#elif defined(_LIBCPP_VERSION)
+// https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206
+# if LIBCPP_VERSION >= 3000
+# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
+# endif
+#elif defined(BOOST_MSVC)
+// Apparently C++11 standard supported in Visual Studio 2012
+// https://msdn.microsoft.com/en-us/library/hh567368.aspx#stl
+// 2012 = VC+11 = BOOST_MSVC 1700 Hopefully!
+# if BOOST_MSVC >= 1700
+# define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
+# endif
+#endif
+
+#if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
+#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 0
+#endif
+
+#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
+#include
+#endif
+
namespace boost
{
namespace unordered
{
+#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
+ using std::piecewise_construct_t;
+ using std::piecewise_construct;
+#else
struct piecewise_construct_t {};
const piecewise_construct_t piecewise_construct = piecewise_construct_t();
+#endif
}
}
diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp
index ab4000b4..6ae1d73e 100644
--- a/include/boost/unordered/detail/table.hpp
+++ b/include/boost/unordered/detail/table.hpp
@@ -584,7 +584,6 @@ namespace boost { namespace unordered { namespace detail {
{
// Strong exception safety.
set_hash_functions new_func_this(*this, x);
- new_func_this.commit();
mlf_ = x.mlf_;
recalculate_max_load();
@@ -597,6 +596,7 @@ namespace boost { namespace unordered { namespace detail {
clear_buckets();
}
+ new_func_this.commit();
static_cast(this)->assign_buckets(x);
}
@@ -663,11 +663,13 @@ namespace boost { namespace unordered { namespace detail {
}
else {
set_hash_functions new_func_this(*this, x);
- new_func_this.commit();
mlf_ = x.mlf_;
recalculate_max_load();
- if (!size_ && !x.size_) return;
+ if (!size_ && !x.size_) {
+ new_func_this.commit();
+ return;
+ }
if (x.size_ >= max_load_) {
create_buckets(min_buckets_for_size(x.size_));
@@ -676,6 +678,7 @@ namespace boost { namespace unordered { namespace detail {
clear_buckets();
}
+ new_func_this.commit();
static_cast(this)->move_assign_buckets(x);
}
}
diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp
index 07923981..db397980 100644
--- a/include/boost/unordered/detail/unique.hpp
+++ b/include/boost/unordered/detail/unique.hpp
@@ -316,6 +316,14 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(false);
return emplace_return(this->begin(), false);
}
+
+ iterator emplace_hint(c_iterator,
+ boost::unordered::detail::emplace_args1<
+ boost::unordered::detail::please_ignore_this_overload> const&)
+ {
+ BOOST_ASSERT(false);
+ return this->begin();
+ }
# else
emplace_return emplace(
boost::unordered::detail::please_ignore_this_overload const&)
@@ -323,6 +331,13 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(false);
return emplace_return(this->begin(), false);
}
+
+ iterator emplace_hint(c_iterator,
+ boost::unordered::detail::please_ignore_this_overload const&)
+ {
+ BOOST_ASSERT(false);
+ return this->begin();
+ }
# endif
#endif
@@ -340,6 +355,21 @@ namespace boost { namespace unordered { namespace detail {
#endif
}
+ template
+ iterator emplace_hint(c_iterator hint,
+ BOOST_UNORDERED_EMPLACE_ARGS)
+ {
+#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+ return emplace_hint_impl(hint,
+ extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
+ BOOST_UNORDERED_EMPLACE_FORWARD);
+#else
+ return emplace_hint_impl(hint,
+ extractor::extract(args.a0, args.a1),
+ BOOST_UNORDERED_EMPLACE_FORWARD);
+#endif
+ }
+
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template
emplace_return emplace(
@@ -347,8 +377,27 @@ namespace boost { namespace unordered { namespace detail {
{
return emplace_impl(extractor::extract(args.a0), args);
}
+
+ template
+ iterator emplace_hint(c_iterator hint,
+ boost::unordered::detail::emplace_args1 const& args)
+ {
+ return emplace_hint_impl(hint, extractor::extract(args.a0), args);
+ }
#endif
+ template
+ iterator emplace_hint_impl(c_iterator hint, key_type const& k,
+ BOOST_UNORDERED_EMPLACE_ARGS)
+ {
+ if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
+ return iterator(hint.node_);
+ }
+ else {
+ return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first;
+ }
+ }
+
template
emplace_return emplace_impl(key_type const& k,
BOOST_UNORDERED_EMPLACE_ARGS)
@@ -368,11 +417,31 @@ namespace boost { namespace unordered { namespace detail {
}
}
+ template
+ iterator emplace_hint_impl(c_iterator hint, no_key,
+ BOOST_UNORDERED_EMPLACE_ARGS)
+ {
+ node_tmp b(
+ boost::unordered::detail::func::construct_value_generic(
+ this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
+ this->node_alloc());
+ key_type const& k = this->get_key(b.node_->value());
+ if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
+ return iterator(hint.node_);
+ }
+ std::size_t key_hash = this->hash(k);
+ iterator pos = this->find_node(key_hash, k);
+ if (pos.node_) {
+ return pos;
+ }
+ else {
+ return this->resize_and_add_node(b.release(), key_hash);
+ }
+ }
+
template
emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
{
- // Don't have a key, so construct the node first in order
- // to be able to lookup the position.
node_tmp b(
boost::unordered::detail::func::construct_value_generic(
this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp
index 0a406c85..cd722e44 100644
--- a/include/boost/unordered/detail/util.hpp
+++ b/include/boost/unordered/detail/util.hpp
@@ -128,7 +128,7 @@ namespace boost { namespace unordered { namespace detail {
inline std::size_t insert_size(I i, I j, typename
boost::unordered::detail::enable_if_forward::type = 0)
{
- return std::distance(i, j);
+ return static_cast(std::distance(i, j));
}
template
diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp
index 3904e56e..fc6fbe0e 100644
--- a/include/boost/unordered/unordered_map.hpp
+++ b/include/boost/unordered/unordered_map.hpp
@@ -240,9 +240,9 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
+ iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
- return table_.emplace(boost::forward(args)...).first;
+ return table_.emplace_hint(hint, boost::forward(args)...);
}
#else
@@ -281,12 +281,12 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
+ iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0))
- ).first;
+ );
}
template
@@ -302,15 +302,15 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator,
+ iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0),
boost::forward(a1))
- ).first;
+ );
}
template
@@ -328,17 +328,17 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator,
+ iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0),
boost::forward(a1),
boost::forward(a2))
- ).first;
+ );
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
@@ -360,15 +360,15 @@ namespace unordered
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
- const_iterator, \
+ const_iterator hint, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
- return table_.emplace( \
+ return table_.emplace_hint(hint, \
boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
- )).first; \
+ )); \
}
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
@@ -724,9 +724,9 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
+ iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
- return table_.emplace(boost::forward(args)...);
+ return table_.emplace_hint(hint, boost::forward(args)...);
}
#else
@@ -765,9 +765,9 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
+ iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0))
);
@@ -786,11 +786,11 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator,
+ iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0),
boost::forward(a1))
@@ -812,12 +812,12 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator,
+ iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0),
boost::forward(a1),
@@ -844,11 +844,11 @@ namespace unordered
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
- const_iterator, \
+ const_iterator hint, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
- return table_.emplace( \
+ return table_.emplace_hint(hint, \
boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp
index c8c06215..aa9911bc 100644
--- a/include/boost/unordered/unordered_set.hpp
+++ b/include/boost/unordered/unordered_set.hpp
@@ -237,9 +237,9 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
+ iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
- return table_.emplace(boost::forward(args)...).first;
+ return table_.emplace_hint(hint, boost::forward(args)...);
}
#else
@@ -278,12 +278,12 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
+ iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0))
- ).first;
+ );
}
template
@@ -299,15 +299,15 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator,
+ iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0),
boost::forward(a1))
- ).first;
+ );
}
template
@@ -325,17 +325,17 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator,
+ iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0),
boost::forward(a1),
boost::forward(a2))
- ).first;
+ );
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
@@ -357,15 +357,15 @@ namespace unordered
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
- const_iterator, \
+ const_iterator hint, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
- return table_.emplace( \
+ return table_.emplace_hint(hint, \
boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
- )).first; \
+ )); \
}
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
@@ -707,9 +707,9 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
+ iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args)
{
- return table_.emplace(boost::forward(args)...);
+ return table_.emplace_hint(hint, boost::forward(args)...);
}
#else
@@ -748,9 +748,9 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
+ iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0))
);
@@ -769,11 +769,11 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator,
+ iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0),
boost::forward(a1))
@@ -795,12 +795,12 @@ namespace unordered
}
template
- iterator emplace_hint(const_iterator,
+ iterator emplace_hint(const_iterator hint,
BOOST_FWD_REF(A0) a0,
BOOST_FWD_REF(A1) a1,
BOOST_FWD_REF(A2) a2)
{
- return table_.emplace(
+ return table_.emplace_hint(hint,
boost::unordered::detail::create_emplace_args(
boost::forward(a0),
boost::forward(a1),
@@ -827,11 +827,11 @@ namespace unordered
BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
> \
iterator emplace_hint( \
- const_iterator, \
+ const_iterator hint, \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
) \
{ \
- return table_.emplace( \
+ return table_.emplace_hint(hint, \
boost::unordered::detail::create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
a) \
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 2803eabc..f2207f89 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -11,9 +11,9 @@ project unordered-test/unordered
intel:on
# Would be nice to define -Wundef, but I'm getting warnings from
# Boost.Preprocessor on trunk.
- gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow -Wno-long-long"
+ gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
- clang:"-pedantic -Wextra -Wno-long-long"
+ clang:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow"
;
#alias framework : /boost/test//boost_unit_test_framework ;
@@ -38,6 +38,7 @@ test-suite unordered
[ run unordered/assign_tests.cpp ]
[ run unordered/insert_tests.cpp ]
[ run unordered/insert_stable_tests.cpp ]
+ [ run unordered/insert_hint_tests.cpp ]
[ run unordered/unnecessary_copy_tests.cpp ]
[ run unordered/erase_tests.cpp ]
[ run unordered/erase_equiv_tests.cpp ]
@@ -71,6 +72,7 @@ test-suite unordered-exception
[ run exception/constructor_exception_tests.cpp framework ]
[ run exception/copy_exception_tests.cpp framework ]
[ run exception/assign_exception_tests.cpp framework ]
+ [ run exception/move_assign_exception_tests.cpp framework ]
[ run exception/insert_exception_tests.cpp framework ]
[ run exception/erase_exception_tests.cpp framework ]
[ run exception/rehash_exception_tests.cpp framework ]
diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp
index a9f4976f..e8304ee9 100644
--- a/test/exception/assign_exception_tests.cpp
+++ b/test/exception/assign_exception_tests.cpp
@@ -17,7 +17,7 @@ template
struct self_assign_base : public test::exception_base
{
test::random_values values;
- self_assign_base(int count = 0) : values(count) {}
+ self_assign_base(std::size_t count = 0) : values(count) {}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
@@ -111,6 +111,12 @@ struct assign_test4 : assign_values
assign_test4() : assign_values(10, 10, 1, 2) {}
};
+template
+struct assign_test4a : assign_values
+{
+ assign_test4a() : assign_values(10, 100, 1, 2) {}
+};
+
template
struct assign_test5 : assign_values
{
@@ -136,7 +142,7 @@ struct equivalent_test1 : assign_base
EXCEPTION_TESTS(
(self_assign_test1)(self_assign_test2)
- (assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test5)
+ (assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test4a)(assign_test5)
(equivalent_test1),
CONTAINER_SEQ)
RUN_TESTS()
diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp
index aed566dc..588a6713 100644
--- a/test/exception/insert_exception_tests.cpp
+++ b/test/exception/insert_exception_tests.cpp
@@ -8,7 +8,7 @@
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/strong.hpp"
-#include
+#include "../helpers/helpers.hpp"
#include
test::seed_t initialize_seed(747373);
@@ -17,7 +17,7 @@ template
struct insert_test_base : public test::exception_base
{
test::random_values values;
- insert_test_base(unsigned int count = 5) : values(count) {}
+ insert_test_base(unsigned int count = 5) : values(count, test::limited_range) {}
typedef T data_type;
typedef test::strong strong_type;
@@ -112,7 +112,7 @@ struct insert_test4 : public insert_test_base
it != end; ++it)
{
strong.store(x, test::detail::tracker.count_allocations);
- x.insert(it, boost::next(it));
+ x.insert(it, test::next(it));
}
}
};
@@ -130,12 +130,13 @@ struct insert_test_rehash1 : public insert_test_base
T x;
x.max_load_factor(0.25);
+ // TODO: This doesn't really work is bucket_count is 0
size_type bucket_count = x.bucket_count();
size_type initial_elements = static_cast(
- ceil(bucket_count * (double) x.max_load_factor()) - 1);
+ ceil((double) bucket_count * (double) x.max_load_factor()) - 1);
BOOST_TEST(initial_elements < this->values.size());
x.insert(this->values.begin(),
- boost::next(this->values.begin(), initial_elements));
+ test::next(this->values.begin(), initial_elements));
BOOST_TEST(bucket_count == x.bucket_count());
return x;
}
@@ -146,7 +147,7 @@ struct insert_test_rehash1 : public insert_test_base
BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin();
for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator
- it = boost::next(this->values.begin(), x.size()),
+ it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count)
{
@@ -170,7 +171,7 @@ struct insert_test_rehash2 : public insert_test_rehash1
int count = 0;
for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator
- it = boost::next(this->values.begin(), x.size()),
+ it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count)
{
@@ -201,14 +202,14 @@ struct insert_test_rehash3 : public insert_test_base
original_bucket_count = x.bucket_count();
rehash_bucket_count = static_cast(
- ceil(original_bucket_count * (double) x.max_load_factor())) - 1;
+ ceil((double) original_bucket_count * (double) x.max_load_factor())) - 1;
size_type initial_elements =
rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1;
BOOST_TEST(initial_elements < this->values.size());
x.insert(this->values.begin(),
- boost::next(this->values.begin(), initial_elements));
+ test::next(this->values.begin(), initial_elements));
BOOST_TEST(original_bucket_count == x.bucket_count());
return x;
}
@@ -216,8 +217,8 @@ struct insert_test_rehash3 : public insert_test_base
void run(T& x) const {
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
- x.insert(boost::next(this->values.begin(), x.size()),
- boost::next(this->values.begin(), x.size() + 20));
+ x.insert(test::next(this->values.begin(), x.size()),
+ test::next(this->values.begin(), x.size() + 20));
// This isn't actually a failure, but it means the test isn't doing its
// job.
diff --git a/test/exception/move_assign_exception_tests.cpp b/test/exception/move_assign_exception_tests.cpp
new file mode 100644
index 00000000..d09b1b82
--- /dev/null
+++ b/test/exception/move_assign_exception_tests.cpp
@@ -0,0 +1,131 @@
+
+// Copyright 2006-2009 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include
+#include "./containers.hpp"
+#include "../helpers/random_values.hpp"
+#include "../helpers/invariants.hpp"
+
+#if defined(BOOST_MSVC)
+#pragma warning(disable:4512) // move_assignment operator could not be generated
+#endif
+
+test::seed_t initialize_seed(12847);
+
+template
+struct move_assign_base : public test::exception_base
+{
+ test::random_values x_values, y_values;
+ T x,y;
+
+ typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
+ typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
+ typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
+
+ move_assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0) :
+ x_values(),
+ y_values(),
+ x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
+ y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
+ {
+ x.max_load_factor(mlf1);
+ y.max_load_factor(mlf2);
+ }
+
+ typedef T data_type;
+ T init() const { return T(x); }
+ void run(T& x1) const {
+ test::exceptions_enable disable_exceptions(false);
+ T y1 = y;
+ disable_exceptions.release();
+ x1 = boost::move(y1);
+ }
+ void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
+ {
+ test::check_equivalent_keys(x1);
+
+ // If the container is empty at the point of the exception, the
+ // internal structure is hidden, this exposes it, at the cost of
+ // messing up the data.
+ if (x_values.size()) {
+ T& x2 = const_cast(x1);
+ x2.emplace(*x_values.begin());
+ test::check_equivalent_keys(x2);
+ }
+ }
+};
+
+template
+struct move_assign_values : move_assign_base
+{
+ move_assign_values(unsigned int count1, unsigned int count2,
+ int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0) :
+ move_assign_base(tag1, tag2, mlf1, mlf2)
+ {
+ this->x_values.fill(count1);
+ this->y_values.fill(count2);
+ this->x.insert(this->x_values.begin(), this->x_values.end());
+ this->y.insert(this->y_values.begin(), this->y_values.end());
+ }
+};
+
+template
+struct move_assign_test1 : move_assign_values
+{
+ move_assign_test1() : move_assign_values(0, 0, 0, 0) {}
+};
+
+template
+struct move_assign_test2 : move_assign_values
+{
+ move_assign_test2() : move_assign_values(60, 0, 0, 0) {}
+};
+
+template
+struct move_assign_test3 : move_assign_values
+{
+ move_assign_test3() : move_assign_values(0, 60, 0, 0) {}
+};
+
+template
+struct move_assign_test4 : move_assign_values
+{
+ move_assign_test4() : move_assign_values(10, 10, 1, 2) {}
+};
+
+template
+struct move_assign_test4a : move_assign_values
+{
+ move_assign_test4a() : move_assign_values(10, 100, 1, 2) {}
+};
+
+template
+struct move_assign_test5 : move_assign_values
+{
+ move_assign_test5() : move_assign_values(5, 60, 0, 0, 1.0f, 0.1f) {}
+};
+
+template
+struct equivalent_test1 : move_assign_base
+{
+ equivalent_test1() :
+ move_assign_base(0, 0)
+ {
+ test::random_values x_values2(10);
+ this->x_values.insert(x_values2.begin(), x_values2.end());
+ this->x_values.insert(x_values2.begin(), x_values2.end());
+ test::random_values y_values2(10);
+ this->y_values.insert(y_values2.begin(), y_values2.end());
+ this->y_values.insert(y_values2.begin(), y_values2.end());
+ this->x.insert(this->x_values.begin(), this->x_values.end());
+ this->y.insert(this->y_values.begin(), this->y_values.end());
+ }
+};
+
+EXCEPTION_TESTS(
+ (move_assign_test1)(move_assign_test2)(move_assign_test3)(move_assign_test4)(move_assign_test4a)(move_assign_test5)
+ (equivalent_test1),
+ CONTAINER_SEQ)
+RUN_TESTS()
diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp
index 5e1cd084..0873093a 100644
--- a/test/exception/swap_exception_tests.cpp
+++ b/test/exception/swap_exception_tests.cpp
@@ -17,7 +17,7 @@ template
struct self_swap_base : public test::exception_base
{
test::random_values values;
- self_swap_base(int count = 0) : values(count) {}
+ self_swap_base(std::size_t count = 0) : values(count) {}
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
diff --git a/test/helpers/equivalent.hpp b/test/helpers/equivalent.hpp
index f452c807..61b91538 100644
--- a/test/helpers/equivalent.hpp
+++ b/test/helpers/equivalent.hpp
@@ -42,20 +42,15 @@ namespace test
}
struct equivalent_type {
+ equivalent_type() {}
+
template
- bool operator()(T1 const& x, T2 const& y) {
+ bool operator()(T1 const& x, T2 const& y) const {
return equivalent_impl(x, y, derived);
}
};
- // This won't be a problem as I'm only using a single compile unit
- // in each test (this is actually require by the minimal test
- // framework).
- //
- // boostinspect:nounnamed
- namespace {
- equivalent_type equivalent;
- }
+ const equivalent_type equivalent;
template
class unordered_equivalence_tester
diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp
index 289cd1a5..c3aad5d5 100644
--- a/test/helpers/exception_test.hpp
+++ b/test/helpers/exception_test.hpp
@@ -111,16 +111,28 @@ namespace test {
exceptions_enable(exceptions_enable const&);
bool old_value_;
+ bool released_;
public:
exceptions_enable(bool enable)
- : old_value_(exceptions_enabled)
+ : old_value_(exceptions_enabled), released_(false)
{
exceptions_enabled = enable;
}
~exceptions_enable()
{
- exceptions_enabled = old_value_;
+ if (!released_) {
+ exceptions_enabled = old_value_;
+ released_ = true;
+ }
+ }
+
+ void release()
+ {
+ if (!released_) {
+ exceptions_enabled = old_value_;
+ released_ = true;
+ }
}
};
diff --git a/test/helpers/fwd.hpp b/test/helpers/fwd.hpp
index ddff09c5..14476dda 100644
--- a/test/helpers/fwd.hpp
+++ b/test/helpers/fwd.hpp
@@ -10,11 +10,17 @@
namespace test
{
- int generate(int const*);
- char generate(char const*);
- signed char generate(signed char const*);
- std::string generate(std::string*);
- float generate(float const*);
+ typedef enum {
+ default_generator,
+ generate_collisions,
+ limited_range
+ } random_generator;
+
+ int generate(int const*, random_generator);
+ char generate(char const*, random_generator);
+ signed char generate(signed char const*, random_generator);
+ std::string generate(std::string const*, random_generator);
+ float generate(float const*, random_generator);
struct base_type {} base;
struct derived_type : base_type {} derived;
diff --git a/test/helpers/generators.hpp b/test/helpers/generators.hpp
index 15441524..3265a77b 100644
--- a/test/helpers/generators.hpp
+++ b/test/helpers/generators.hpp
@@ -27,25 +27,32 @@ namespace test
}
};
- inline int generate(int const*)
- {
+ std::size_t random_value(std::size_t max) {
using namespace std;
- return rand();
+ return static_cast(rand()) % max;
}
- inline char generate(char const*)
+ inline int generate(int const*, random_generator g)
+ {
+ using namespace std;
+ int value = rand();
+ if (g == limited_range) { value = value % 100; }
+ return value;
+ }
+
+ inline char generate(char const*, random_generator)
{
using namespace std;
return static_cast((rand() >> 1) % (128-32) + 32);
}
- inline signed char generate(signed char const*)
+ inline signed char generate(signed char const*, random_generator)
{
using namespace std;
return static_cast(rand());
}
- inline std::string generate(std::string const*)
+ inline std::string generate(std::string const*, random_generator g)
{
using namespace std;
@@ -53,17 +60,30 @@ namespace test
std::string result;
- int length = rand() % 10;
- for(int i = 0; i < length; ++i)
- result += generate(char_ptr);
+ if (g == limited_range) {
+ std::size_t length = test::random_value(2) + 2;
+
+ char const* strings[] = { "'vZh(3~ms", "%m", "_Y%U", "N'Y", "4,J_J" };
+ for (std::size_t i = 0; i < length; ++i) {
+ result += strings[random_value(sizeof(strings) / sizeof(strings[0]))];
+ }
+ }
+ else {
+ std::size_t length = test::random_value(10) + 1;
+ for (std::size_t i = 0; i < length; ++i) {
+ result += generate(char_ptr, g);
+ }
+ }
return result;
}
- float generate(float const*)
+ float generate(float const*, random_generator g)
{
using namespace std;
- return (float) rand() / (float) RAND_MAX;
+ int x = 0;
+ int value = generate(&x, g);
+ return (float) value / (float) RAND_MAX;
}
}
diff --git a/test/helpers/helpers.hpp b/test/helpers/helpers.hpp
index 2293f23f..96e90cdc 100644
--- a/test/helpers/helpers.hpp
+++ b/test/helpers/helpers.hpp
@@ -38,6 +38,26 @@ namespace test
{
return get_key_impl::get_key(x);
}
+
+ // test::next
+ //
+ // Increments an iterator by 1 or a given value.
+ // Like boost::next, but simpler and slower.
+
+ template
+ Iterator next(Iterator it)
+ {
+ return ++it;
+ }
+
+ template
+ Iterator next(Iterator it, IntType x)
+ {
+ for(; x > 0; --x) {
+ ++it;
+ }
+ return it;
+ }
}
#endif
diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp
index e18ef865..5c2048b7 100644
--- a/test/helpers/invariants.hpp
+++ b/test/helpers/invariants.hpp
@@ -91,7 +91,7 @@ namespace test
// Check the load factor.
- float load_factor =
+ float load_factor = size == 0 ? 0 :
static_cast(size) / static_cast(x1.bucket_count());
using namespace std;
if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)
diff --git a/test/helpers/metafunctions.hpp b/test/helpers/metafunctions.hpp
index 139fe0a2..8e36549d 100644
--- a/test/helpers/metafunctions.hpp
+++ b/test/helpers/metafunctions.hpp
@@ -8,8 +8,6 @@
#include
#include
-#include
-#include
namespace test
{
@@ -22,19 +20,11 @@ namespace test
template
struct has_unique_keys
{
- BOOST_STATIC_CONSTANT(bool, value = false);
- };
-
- template
- struct has_unique_keys >
- {
- BOOST_STATIC_CONSTANT(bool, value = true);
- };
-
- template
- struct has_unique_keys >
- {
- BOOST_STATIC_CONSTANT(bool, value = true);
+ static char flip(BOOST_DEDUCED_TYPENAME Container::iterator const&);
+ static long flip(std::pair const&);
+ BOOST_STATIC_CONSTANT(bool, value = sizeof(long) == sizeof(
+ flip(((Container*) 0)->insert(*(BOOST_DEDUCED_TYPENAME Container::value_type*) 0))
+ ));
};
}
diff --git a/test/helpers/random_values.hpp b/test/helpers/random_values.hpp
index b65a29b2..7628514d 100644
--- a/test/helpers/random_values.hpp
+++ b/test/helpers/random_values.hpp
@@ -14,11 +14,6 @@
namespace test
{
- typedef enum {
- default_generator,
- generate_collisions
- } random_generator;
-
template
struct unordered_generator_set
{
@@ -32,16 +27,15 @@ namespace test
template
void fill(T& x, std::size_t len) {
value_type* value_ptr = 0;
- int* int_ptr = 0;
len += x.size();
for (std::size_t i = 0; i < len; ++i) {
- value_type value = generate(value_ptr);
+ value_type value = generate(value_ptr, type_);
- int count = type_ == generate_collisions ?
- 1 + (generate(int_ptr) % 5) : 1;
+ std::size_t count = type_ == generate_collisions ?
+ random_value(5) + 1 : 1;
- for(int j = 0; j < count; ++j) {
+ for(std::size_t j = 0; j < count; ++j) {
x.push_back(value);
}
}
@@ -63,17 +57,16 @@ namespace test
void fill(T& x, std::size_t len) {
key_type* key_ptr = 0;
mapped_type* mapped_ptr = 0;
- int* int_ptr = 0;
for (std::size_t i = 0; i < len; ++i) {
- key_type key = generate(key_ptr);
+ key_type key = generate(key_ptr, type_);
- int count = type_ == generate_collisions ?
- 1 + (generate(int_ptr) % 5) : 1;
+ std::size_t count = type_ == generate_collisions ?
+ random_value(5) + 1 : 1;
- for(int j = 0; j < count; ++j) {
+ for(std::size_t j = 0; j < count; ++j) {
x.push_back(std::pair(
- key, generate(mapped_ptr)));
+ key, generate(mapped_ptr, type_)));
}
}
}
@@ -105,13 +98,13 @@ namespace test
{
random_values() {}
- explicit random_values(int count, test::random_generator const& generator =
+ explicit random_values(std::size_t count, test::random_generator const& generator =
test::default_generator)
{
fill(count, generator);
}
- void fill(int count, test::random_generator const& generator =
+ void fill(std::size_t count, test::random_generator const& generator =
test::default_generator)
{
test::unordered_generator gen(generator);
diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp
index dea6e0ea..b9d4c3b5 100644
--- a/test/helpers/test.hpp
+++ b/test/helpers/test.hpp
@@ -24,7 +24,11 @@
void BOOST_PP_CAT(x, _type)::run() \
#define RUN_TESTS() int main(int, char**) \
- { ::test::test_list::run_tests(); return boost::report_errors(); } \
+ { \
+ ::test::write_compiler_info(); \
+ ::test::test_list::run_tests(); \
+ return boost::report_errors(); \
+ }
namespace test {
struct registered_test_base {
@@ -66,6 +70,21 @@ namespace test {
}
}
}
+
+ inline void write_compiler_info() {
+#if defined(BOOST_GCC_CXX11)
+ char const* cpp11 = "true";
+#else
+ char const* cpp11 = "false";
+#endif
+
+ std::cout
+ << "Compiler: " << BOOST_COMPILER << "\n"
+ << "Library: " << BOOST_STDLIB << "\n"
+ << "C++11: " << cpp11 << "\n"
+ << "\n"
+ << std::flush;
+ }
}
#include
diff --git a/test/helpers/tracker.hpp b/test/helpers/tracker.hpp
index 52d9fa45..ab2470c0 100644
--- a/test/helpers/tracker.hpp
+++ b/test/helpers/tracker.hpp
@@ -13,7 +13,6 @@
#include