From e58370b4fff4f4c920450dfb65daa81a93d1b20e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 17 Aug 2016 12:08:15 +0100 Subject: [PATCH 01/46] Move emplace before emplace_impl in equivalent.hpp --- include/boost/unordered/detail/equivalent.hpp | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 691d3154..f3ddc47f 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -375,25 +375,6 @@ namespace boost { namespace unordered { namespace detail { return iterator(n); } - 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); - } - - 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) iterator emplace(boost::unordered::detail::emplace_args1< @@ -420,6 +401,25 @@ namespace boost { namespace unordered { namespace detail { 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); + } + + 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 From cae72eec2f4fde469742b203bc08618e8c5bd8ea Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 17 Aug 2016 12:08:15 +0100 Subject: [PATCH 02/46] Insert/emplace with hint. --- doc/changes.qbk | 1 + include/boost/unordered/detail/equivalent.hpp | 63 +++++++++- include/boost/unordered/detail/unique.hpp | 73 ++++++++++- include/boost/unordered/unordered_map.hpp | 48 +++---- include/boost/unordered/unordered_set.hpp | 48 +++---- test/Jamfile.v2 | 1 + test/unordered/insert_hint_tests.cpp | 118 ++++++++++++++++++ test/unordered/insert_stable_tests.cpp | 11 +- 8 files changed, 307 insertions(+), 56 deletions(-) create mode 100644 test/unordered/insert_hint_tests.cpp diff --git a/doc/changes.qbk b/doc/changes.qbk index 54002878..7444c69b 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -278,5 +278,6 @@ C++11 support has resulted in some breaking changes: for `unordered_multiset` and `unordered_multimap`. Might be a little slower. * Stop using return value SFINAE which some older compilers have issues with. +* Check hint iterator in `insert`/`emplace_hint`. [endsect] diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index f3ddc47f..45cd026d 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,6 +378,24 @@ namespace boost { namespace unordered { namespace detail { return iterator(n); } + inline iterator add_using_hint( + node_pointer n, + node_pointer hint) + { + 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); + } + + #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) # if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) iterator emplace(boost::unordered::detail::emplace_args1< @@ -383,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&) @@ -390,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 @@ -401,6 +436,14 @@ 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()); @@ -411,6 +454,22 @@ namespace boost { namespace unordered { namespace detail { 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()); 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/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 6f844095..cef0f17e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -37,6 +37,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 ] diff --git a/test/unordered/insert_hint_tests.cpp b/test/unordered/insert_hint_tests.cpp new file mode 100644 index 00000000..3a07c7b8 --- /dev/null +++ b/test/unordered/insert_hint_tests.cpp @@ -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 +#include +#include "../helpers/postfix.hpp" + +#include "../helpers/test.hpp" +#include "../helpers/invariants.hpp" + +#include +#include +#include + +namespace insert_hint +{ +UNORDERED_AUTO_TEST(insert_hint_empty) { + typedef boost::unordered_multiset container; + container x; + x.insert(x.cbegin(), 10); + BOOST_TEST_EQ(x.size(), 1); + BOOST_TEST_EQ(x.count(10), 1); + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_empty2) { + typedef boost::unordered_multimap container; + container x; + x.emplace_hint(x.cbegin(), "hello", 50); + BOOST_TEST_EQ(x.size(), 1); + BOOST_TEST_EQ(x.count("hello"), 1); + BOOST_TEST_EQ(x.find("hello")->second, 50); + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_single) { + typedef boost::unordered_multiset container; + container x; + x.insert("equal"); + x.insert(x.cbegin(), "equal"); + BOOST_TEST_EQ(x.size(), 2); + BOOST_TEST_EQ(x.count("equal"), 2); + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_single2) { + typedef boost::unordered_multimap container; + container x; + x.emplace(10, "one"); + x.emplace_hint(x.cbegin(), 10, "two"); + BOOST_TEST_EQ(x.size(), 2); + BOOST_TEST_EQ(x.count(10), 2); + + container::iterator it = x.find(10); + std::string v0 = (it++)->second; + std::string v1 = (it++)->second; + + BOOST_TEST(v0 == "one" || v0 == "two"); + BOOST_TEST(v1 == "one" || v1 == "two"); + BOOST_TEST(v0 != v1); + + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_multiple) { + for (unsigned int size = 0; size < 10; ++size) { + for (unsigned int offset = 0; offset <= size; ++offset) { + typedef boost::unordered_multiset container; + container x; + + for (unsigned int i = 0; i < size; ++i) { x.insert("multiple"); } + + BOOST_TEST_EQ(x.size(), size); + + container::const_iterator position = x.cbegin(); + for (unsigned int i = 0; i < offset; ++i) { ++position; } + + x.insert(position, "multiple"); + + BOOST_TEST_EQ(x.size(), size + 1); + BOOST_TEST_EQ(x.count("multiple"), size + 1); + test::check_equivalent_keys(x); + } + } +} + +UNORDERED_AUTO_TEST(insert_hint_unique) { + typedef boost::unordered_set container; + container x; + x.insert(x.cbegin(), 10); + BOOST_TEST_EQ(x.size(), 1); + BOOST_TEST_EQ(x.count(10), 1); + test::check_equivalent_keys(x); +} + +UNORDERED_AUTO_TEST(insert_hint_unique_single) { + typedef boost::unordered_set container; + container x; + x.insert(10); + + x.insert(x.cbegin(), 10); + BOOST_TEST_EQ(x.size(), 1); + BOOST_TEST(x.count(10) == 1); + test::check_equivalent_keys(x); + + x.insert(x.cbegin(), 20); + BOOST_TEST(x.size() == 2); + BOOST_TEST(x.count(10) == 1); + BOOST_TEST(x.count(20) == 1); + test::check_equivalent_keys(x); +} + +} + +RUN_TESTS() diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index f750e50f..b4482764 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -49,6 +49,8 @@ UNORDERED_AUTO_TEST(stable_insert_test1) { x.insert(insert_stable::member(1,2)); x.insert(insert_stable::member(1,3)); + BOOST_TEST(x.count(insert_stable::member(1,4)) == 3); + boost::unordered_multiset::const_iterator it = x.begin(), end = x.end(); BOOST_TEST(it != end); @@ -66,10 +68,11 @@ UNORDERED_AUTO_TEST(stable_insert_test2) { boost::unordered_multimap::const_iterator iterator; - iterator it - = x.insert(x.end(), std::make_pair(insert_stable::member(1,1), 1)); - it = x.insert(it, std::make_pair(insert_stable::member(1,2), 2)); - it = x.insert(it, std::make_pair(insert_stable::member(1,3), 3)); + iterator it = x.emplace(insert_stable::member(1,1), 1); + it = x.emplace(insert_stable::member(1,2), 2); + it = x.emplace(insert_stable::member(1,3), 3); + + BOOST_TEST(x.count(insert_stable::member(1,4)) == 3); it = x.begin(); iterator end = x.end(); From 9debeadee7c430c02a0f39946114af59eab350e8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 17 Aug 2016 12:08:16 +0100 Subject: [PATCH 03/46] Fix some test warnings. And turn on warnings as errors in Travis. --- .travis.yml | 8 ++++---- test/Jamfile.v2 | 1 + test/exception/rehash_exception_tests.cpp | 4 ++-- test/exception/swap_exception_tests.cpp | 4 ++-- test/objects/cxx11_allocator.hpp | 2 +- test/objects/exception.hpp | 4 ++-- test/objects/minimal.hpp | 4 ++-- test/objects/test.hpp | 4 ++-- test/unordered/allocator_traits.cpp | 8 ++++---- test/unordered/at_tests.cpp | 1 - test/unordered/minimal_allocator.cpp | 2 +- 11 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6f98b329..e6c0c766 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,10 +27,10 @@ matrix: before_script: - | - echo "using gcc : : g++-4.8 --std=c++03 -fsanitize=address ;" > ~/user-config.jam - echo "using gcc : std11 : g++-4.8 --std=c++11 -fsanitize=address ;" >> ~/user-config.jam - echo "using clang : : clang++ --std=c++03 -fsanitize=address ;" >> ~/user-config.jam - echo "using clang : std11 : clang++ --std=c++11 -fsanitize=address ;" >> ~/user-config.jam + 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 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 - cat ~/user-config.jam - touch Jamroot.jam diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index cef0f17e..b6a362dc 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -13,6 +13,7 @@ project unordered-test/unordered # Boost.Preprocessor on trunk. gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow -Wno-long-long" darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow" + clang:"-pedantic -Wextra -Wno-long-long" ; #alias framework : /boost/test//boost_unit_test_framework ; diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index ad5c6193..0163bfec 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -18,8 +18,8 @@ struct rehash_test_base : public test::exception_base { test::random_values values; unsigned int n; - rehash_test_base(unsigned int count = 100, unsigned int n = 0) - : values(count), n(n) + rehash_test_base(unsigned int count = 100, unsigned int n_ = 0) + : values(count), n(n_) {} typedef T data_type; diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 623a0fce..5e1cd084 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -66,8 +66,8 @@ struct swap_base : public test::exception_base {} struct data_type { - data_type(T const& x, T const& y) - : x(x), y(y) {} + data_type(T const& x_, T const& y_) + : x(x_), y(y_) {} T x, y; }; diff --git a/test/objects/cxx11_allocator.hpp b/test/objects/cxx11_allocator.hpp index 8b4e8db9..11f67808 100644 --- a/test/objects/cxx11_allocator.hpp +++ b/test/objects/cxx11_allocator.hpp @@ -148,7 +148,7 @@ namespace test return ptr; } - pointer allocate(size_type n, void const* u) + pointer allocate(size_type n, void const*) { pointer ptr(static_cast(::operator new(n * sizeof(T)))); detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_); diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index 28d4d5b4..034f31b2 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -314,7 +314,7 @@ namespace exception //return pointer(static_cast(::operator new(n * sizeof(T)))); } - pointer allocate(size_type n, void const* u) + pointer allocate(size_type n, void const*) { T* ptr = 0; UNORDERED_SCOPE(allocator::allocate(size_type, const_pointer)) { @@ -494,7 +494,7 @@ namespace exception //return pointer(static_cast(::operator new(n * sizeof(T)))); } - pointer allocate(size_type n, void const* u) + pointer allocate(size_type n, void const*) { T* ptr = 0; UNORDERED_SCOPE(allocator2::allocate(size_type, const_pointer)) { diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index 85132aa3..b876aa20 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -386,7 +386,7 @@ namespace minimal } template - pointer allocate(size_type n, const_ptr u) + pointer allocate(size_type n, const_ptr) { return pointer(static_cast(::operator new(n * sizeof(T)))); } @@ -462,7 +462,7 @@ namespace minimal } template - T* allocate(std::size_t n, const_ptr u) { + T* allocate(std::size_t n, const_ptr) { return static_cast(::operator new(n * sizeof(T))); } diff --git a/test/objects/test.hpp b/test/objects/test.hpp index 1c2a24ab..f6b03db7 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -347,7 +347,7 @@ namespace test return ptr; } - T* allocate(std::size_t n, void const* u) + T* allocate(std::size_t n, void const*) { T* ptr(static_cast(::operator new(n * sizeof(T)))); detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_); @@ -573,7 +573,7 @@ namespace test return p; } - pointer allocate(size_type n, void const* u) + pointer allocate(size_type n, void const*) { pointer ptr(static_cast(::operator new(n * sizeof(T)))); detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_); diff --git a/test/unordered/allocator_traits.cpp b/test/unordered/allocator_traits.cpp index 264c70d0..4f4fe797 100644 --- a/test/unordered/allocator_traits.cpp +++ b/test/unordered/allocator_traits.cpp @@ -22,9 +22,9 @@ T const* address(T const& r) { return &r; } \ T* allocate(std::size_t n) \ { return static_cast(::operator new(n * sizeof(T))); } \ - T* allocate(std::size_t n, void const* u) \ + T* allocate(std::size_t n, void const*) \ { return static_cast(::operator new(n * sizeof(T))); } \ - void deallocate(T* p, std::size_t n) { ::operator delete((void*) p); } \ + void deallocate(T* p, std::size_t) { ::operator delete((void*) p); } \ void construct(T* p, T const& t) { new(p) T(t); } \ void destroy(T* p) { p->~T(); } \ std::size_t max_size() const \ @@ -44,9 +44,9 @@ const_pointer address(T const& r) { return &r; } \ pointer allocate(std::size_t n) \ { return pointer(::operator new(n * sizeof(T))); } \ - pointer allocate(std::size_t n, void const* u) \ + pointer allocate(std::size_t n, void const*) \ { return pointer(::operator new(n * sizeof(T))); } \ - void deallocate(pointer p, std::size_t n) \ + void deallocate(pointer p, std::size_t) \ { ::operator delete((void*) p); } \ void construct(T* p, T const& t) { new(p) T(t); } \ void destroy(T* p) { p->~T(); } \ diff --git a/test/unordered/at_tests.cpp b/test/unordered/at_tests.cpp index cd272679..8899efcb 100644 --- a/test/unordered/at_tests.cpp +++ b/test/unordered/at_tests.cpp @@ -16,7 +16,6 @@ UNORDERED_AUTO_TEST(at_tests) { BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl; boost::unordered_map x; - typedef boost::unordered_map::iterator iterator; BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Add elements" << std::endl; diff --git a/test/unordered/minimal_allocator.cpp b/test/unordered/minimal_allocator.cpp index 26d1323a..85e99e61 100644 --- a/test/unordered/minimal_allocator.cpp +++ b/test/unordered/minimal_allocator.cpp @@ -18,7 +18,7 @@ struct SimpleAllocator { } - template SimpleAllocator(const SimpleAllocator& other) + template SimpleAllocator(const SimpleAllocator&) { } From 7434e116a7783ffbdeea86e6ef82a0cc664142a3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 29 Aug 2016 23:03:06 +0100 Subject: [PATCH 04/46] Try using boost::long_long_type to avoid warning. --- include/boost/unordered/detail/buckets.hpp | 4 ++-- test/Jamfile.v2 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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/test/Jamfile.v2 b/test/Jamfile.v2 index b6a362dc..e31f1534 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 -Wextra" ; #alias framework : /boost/test//boost_unit_test_framework ; From da7a5bf269be30a9ce7408e51dc0ba4f6f77e291 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 4 Sep 2016 08:07:51 +0100 Subject: [PATCH 05/46] Fix insert from range documentation. Was the same for containers with unique and equivalent keys. --- doc/ref.php | 6 +++++- doc/ref.xml | 14 ++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/doc/ref.php b/doc/ref.php index 0a474807..b516a4f2 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -640,7 +640,11 @@ 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 diff --git a/doc/ref.xml b/doc/ref.xml index f16e6028..406790b5 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -537,7 +537,9 @@ 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 @@ -1569,7 +1571,8 @@ 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 @@ -2618,7 +2621,9 @@ 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 @@ -3697,7 +3702,8 @@ 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 From 8bb94734435b21cbda0e73a9d4d3050900f66704 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 4 Sep 2016 08:07:51 +0100 Subject: [PATCH 06/46] Document assignment from initializer list. --- doc/ref.php | 15 ++++++++++++++ doc/ref.xml | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/doc/ref.php b/doc/ref.php index b516a4f2..0f66d789 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 diff --git a/doc/ref.xml b/doc/ref.xml index 406790b5..b0f45726 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 @@ -1336,6 +1351,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 @@ -2383,6 +2413,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 @@ -3467,6 +3512,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 From 4b0054813800d42b340cdf179f0b738865b4102d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 4 Sep 2016 08:07:51 +0100 Subject: [PATCH 07/46] Test+document insertion from initializer lists. --- doc/ref.php | 24 +++++++++ doc/ref.xml | 86 ++++++++++++++++++++++++++++++++ test/unordered/compile_tests.hpp | 3 ++ 3 files changed, 113 insertions(+) diff --git a/doc/ref.php b/doc/ref.php index 0f66d789..1530bd87 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -673,6 +673,30 @@ EOL; 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 + 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. + + const_iterator diff --git a/doc/ref.xml b/doc/ref.xml index b0f45726..11e3d8a0 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -568,6 +568,28 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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 + 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. + + const_iterator @@ -1616,6 +1638,27 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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 + 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. + + const_iterator @@ -2682,6 +2725,28 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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 + 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. + + const_iterator @@ -3777,6 +3842,27 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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 + 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. + + const_iterator diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index c83ae41f..e944bf0e 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -476,6 +476,9 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) test::check_return_type::equals(a.emplace_hint(q, t)); a.insert(i, j); +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + a.insert({t}); +#endif X a10; a10.insert(t); From 6c81de37f5acbd0e667edaf2bf02819093a94b50 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 4 Sep 2016 10:37:15 +0100 Subject: [PATCH 08/46] Fix closing tag. --- doc/ref.php | 2 +- doc/ref.xml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ref.php b/doc/ref.php index 1530bd87..d2fb2b42 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -368,7 +368,7 @@ EOL; - value_type is CopyInsertable into the container and + value_type is CopyInsertable into the container and CopyAssignable. diff --git a/doc/ref.xml b/doc/ref.xml index 11e3d8a0..d03e8dd3 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -309,7 +309,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - value_type is CopyInsertable into the container and + value_type is CopyInsertable into the container and CopyAssignable. @@ -1383,7 +1383,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - value_type is CopyInsertable into the container and + value_type is CopyInsertable into the container and CopyAssignable. @@ -2466,7 +2466,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - value_type is CopyInsertable into the container and + value_type is CopyInsertable into the container and CopyAssignable. @@ -3587,7 +3587,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - value_type is CopyInsertable into the container and + value_type is CopyInsertable into the container and CopyAssignable. From 7f380028ccc233571cd792782e0f4d1a180ef549 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 19 Aug 2016 12:37:57 +0100 Subject: [PATCH 09/46] Hint iterator support was too late for 1.62.0 --- doc/changes.qbk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index 7444c69b..1e1c77af 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -278,6 +278,9 @@ C++11 support has resulted in some breaking changes: for `unordered_multiset` and `unordered_multimap`. Might be a little slower. * Stop using return value SFINAE which some older compilers have issues with. + +[h2 Boost 1.63.0] + * Check hint iterator in `insert`/`emplace_hint`. [endsect] From 2d1d6ccd758f888de2aacbb4c4334122f236c2f7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 17 Aug 2016 16:37:39 +0100 Subject: [PATCH 10/46] Try using boost 1.61.0 in travis --- .travis.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index e6c0c766..53f034e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ language: c++ addons: apt: packages: - - libboost-dev - libboost-tools-dev matrix: @@ -26,13 +25,19 @@ matrix: env: BJAM_TOOLSET=clang-std11 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 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 - cat ~/user-config.jam - - touch Jamroot.jam + - wget -O boost_1_61_0.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.61.0/boost_1_61_0.tar.bz2/download + - tar -xjf boost_1_61_0.tar.bz2 + - rm -r boost_1_61_0/boost/unordered script: - - cd test && bjam ${BJAM_TOOLSET} include=${TRAVIS_BUILD_DIR}/include + - cd ${TRAVIS_BUILD_DIR}/test + - bjam ${BJAM_TOOLSET} include=${HOME}/boost_1_61_0 include=${TRAVIS_BUILD_DIR}/include From d08dcb7465ddcaf59950ed31180341b8e3edef36 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 4 Sep 2016 10:45:30 +0100 Subject: [PATCH 11/46] Run xmllint over reference docs in travis. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 53f034e2..dfccb0d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ addons: apt: packages: - libboost-tools-dev + - libxml2-utils matrix: include: @@ -41,3 +42,4 @@ before_script: script: - cd ${TRAVIS_BUILD_DIR}/test - bjam ${BJAM_TOOLSET} include=${HOME}/boost_1_61_0 include=${TRAVIS_BUILD_DIR}/include + - xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml From 7c2f11f8e145a278289d73fa25f98c515e666023 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 18 Aug 2016 12:33:31 +0100 Subject: [PATCH 12/46] Fix signed/unsigned comparisons. --- test/unordered/insert_hint_tests.cpp | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/test/unordered/insert_hint_tests.cpp b/test/unordered/insert_hint_tests.cpp index 3a07c7b8..add39024 100644 --- a/test/unordered/insert_hint_tests.cpp +++ b/test/unordered/insert_hint_tests.cpp @@ -21,8 +21,8 @@ UNORDERED_AUTO_TEST(insert_hint_empty) { typedef boost::unordered_multiset container; container x; x.insert(x.cbegin(), 10); - BOOST_TEST_EQ(x.size(), 1); - BOOST_TEST_EQ(x.count(10), 1); + BOOST_TEST_EQ(x.size(), 1u); + BOOST_TEST_EQ(x.count(10), 1u); test::check_equivalent_keys(x); } @@ -30,8 +30,8 @@ UNORDERED_AUTO_TEST(insert_hint_empty2) { typedef boost::unordered_multimap container; container x; x.emplace_hint(x.cbegin(), "hello", 50); - BOOST_TEST_EQ(x.size(), 1); - BOOST_TEST_EQ(x.count("hello"), 1); + 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); } @@ -41,8 +41,8 @@ UNORDERED_AUTO_TEST(insert_hint_single) { container x; x.insert("equal"); x.insert(x.cbegin(), "equal"); - BOOST_TEST_EQ(x.size(), 2); - BOOST_TEST_EQ(x.count("equal"), 2); + BOOST_TEST_EQ(x.size(), 2u); + BOOST_TEST_EQ(x.count("equal"), 2u); test::check_equivalent_keys(x); } @@ -51,8 +51,8 @@ UNORDERED_AUTO_TEST(insert_hint_single2) { container x; x.emplace(10, "one"); x.emplace_hint(x.cbegin(), 10, "two"); - BOOST_TEST_EQ(x.size(), 2); - BOOST_TEST_EQ(x.count(10), 2); + BOOST_TEST_EQ(x.size(), 2u); + BOOST_TEST_EQ(x.count(10), 2u); container::iterator it = x.find(10); std::string v0 = (it++)->second; @@ -80,8 +80,8 @@ UNORDERED_AUTO_TEST(insert_hint_multiple) { x.insert(position, "multiple"); - BOOST_TEST_EQ(x.size(), size + 1); - BOOST_TEST_EQ(x.count("multiple"), size + 1); + BOOST_TEST_EQ(x.size(), size + 1u); + BOOST_TEST_EQ(x.count("multiple"), size + 1u); test::check_equivalent_keys(x); } } @@ -91,8 +91,8 @@ UNORDERED_AUTO_TEST(insert_hint_unique) { typedef boost::unordered_set container; container x; x.insert(x.cbegin(), 10); - BOOST_TEST_EQ(x.size(), 1); - BOOST_TEST_EQ(x.count(10), 1); + BOOST_TEST_EQ(x.size(), 1u); + BOOST_TEST_EQ(x.count(10), 1u); test::check_equivalent_keys(x); } @@ -102,14 +102,14 @@ UNORDERED_AUTO_TEST(insert_hint_unique_single) { x.insert(10); x.insert(x.cbegin(), 10); - BOOST_TEST_EQ(x.size(), 1); - BOOST_TEST(x.count(10) == 1); + 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(x.size() == 2); - BOOST_TEST(x.count(10) == 1); - BOOST_TEST(x.count(20) == 1); + 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); } From cc32bfb96fb8b4dc160d6c6be687ba298e95ff48 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 18 Aug 2016 14:09:00 +0100 Subject: [PATCH 13/46] Pointless change to extract_key. --- include/boost/unordered/detail/extract_key.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; } From 95e477902e722c351cf5675f6aa58273351a69d2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 18 Sep 2016 10:28:21 +0100 Subject: [PATCH 14/46] Special case for Visual C++ 12 test failure. Plus some extra tests while I'm at it. --- test/unordered/compile_tests.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index e944bf0e..516304cb 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -477,7 +477,15 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) a.insert(i, j); #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + std::initializer_list list = {t}; + a.insert(list); + a.insert({t,t,t}); + +#if !defined(BOOST_MSVC) || BOOST_MSVC >= 1800 + a.insert({}); a.insert({t}); + a.insert({t,t}); +#endif #endif X a10; From 0d6e58d9fd0d2e8d79190106feb576efae43a932 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 18 Sep 2016 12:22:48 +0100 Subject: [PATCH 15/46] Write out some compiler info before test results. --- test/helpers/test.hpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) 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 From 1c606980ecbd8936f1a43ff9469d85183cb03a80 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 18 Sep 2016 12:22:48 +0100 Subject: [PATCH 16/46] Update tests for standard changes involving bucket count. It seems my defect report was accepted at some point, and they tweaked the requirements involving bucket counts. This also makes it possible to have a bucket count of 0, which I think wasn't allowed in the past. I don't think I'll change this implementation to do so, but I'd like to be able to run these tests against standard implementations, so I'm starting to take that into account. I believe these changes were made after the C++14 standard, but I've always been tracking the draft standards, so that doesn't really matter. --- test/exception/insert_exception_tests.cpp | 1 + test/helpers/invariants.hpp | 2 +- test/unordered/bucket_tests.cpp | 8 +++++--- test/unordered/insert_tests.cpp | 20 ++++++++++---------- test/unordered/load_factor_tests.cpp | 2 +- test/unordered/rehash_tests.cpp | 5 +---- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index aed566dc..428dbb04 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -130,6 +130,7 @@ 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); 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/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index 58d9be30..7c6ff2d3 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -34,8 +34,10 @@ void tests(X*, test::random_generator generator) X x(v.begin(), v.end()); - BOOST_TEST(x.bucket_count() < x.max_bucket_count()); - std::cerr<::const_iterator it = v.begin(), end = v.end(); it != end; ++it) @@ -43,7 +45,7 @@ void tests(X*, test::random_generator generator) size_type bucket = x.bucket(test::get_key(*it)); BOOST_TEST(bucket < x.bucket_count()); - if(bucket < x.max_bucket_count()) { + if(bucket < x.bucket_count()) { // lit? lend?? I need a new naming scheme. const_local_iterator lit = x.begin(bucket), lend = x.end(bucket); while(lit != lend diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 019d2ac3..8ebdd337 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -55,7 +55,7 @@ void unique_insert_tests1(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -88,7 +88,7 @@ void equivalent_insert_tests1(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -124,7 +124,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -153,7 +153,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -182,7 +182,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(*pos == *r2); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -209,7 +209,7 @@ void insert_tests2(X*, test::random_generator generator) tracker.insert(*it); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -323,7 +323,7 @@ void unique_emplace_tests1(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -353,7 +353,7 @@ void equivalent_emplace_tests1(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -382,7 +382,7 @@ void move_emplace_tests(X*, test::random_generator generator) tracker.insert(*it); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -445,7 +445,7 @@ void map_tests(X*, test::random_generator generator) tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(old_bucket_count)) + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 6dbd7967..2553c7fe 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -51,7 +51,7 @@ void insert_test(X*, float mlf, test::random_generator generator) BOOST_DEDUCED_TYPENAME X::size_type old_size = x.size(), old_bucket_count = x.bucket_count(); x.insert(*it); - if(static_cast(old_size + 1) < b * static_cast(old_bucket_count)) + if(static_cast(old_size + 1) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } } diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 3746bed3..551b79fa 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -22,7 +22,7 @@ test::seed_t initialize_seed(2974); template bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n) { - return static_cast(x.bucket_count()) > + return static_cast(x.bucket_count()) >= static_cast(x.size()) / x.max_load_factor() && x.bucket_count() >= n; } @@ -149,9 +149,6 @@ void reserve_test1(X*, test::random_generator generator) X x; x.max_load_factor(random_mlf ? static_cast(std::rand() % 1000) / 500.0f + 0.5f : 1.0f); - // For the current standard this should reserve i+1, I've - // submitted a defect report and will assume it's a defect - // for now. x.reserve(test::has_unique_keys::value ? i : v.size()); // Insert an element before the range insert, otherwise there are From b881bcfee3b2f39225c3a768efc3297981a1cfdc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 18 Sep 2016 12:22:48 +0100 Subject: [PATCH 17/46] More insert and erase tests --- test/unordered/erase_tests.cpp | 49 ++++++++++++++++++++++++++++++--- test/unordered/insert_tests.cpp | 45 +++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 9c737bd8..d098c3df 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -16,7 +16,7 @@ #include "../helpers/equivalent.hpp" #include "../helpers/helpers.hpp" #include "../helpers/invariants.hpp" - +#include #include namespace erase_tests @@ -27,6 +27,9 @@ test::seed_t initialize_seed(85638); template void erase_tests1(Container*, test::random_generator generator) { + typedef BOOST_DEDUCED_TYPENAME Container::iterator iterator; + typedef BOOST_DEDUCED_TYPENAME Container::const_iterator c_iterator; + std::cerr<<"Erase by key.\n"; { test::check_instances check_; @@ -60,8 +63,7 @@ void erase_tests1(Container*, test::random_generator generator) BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*x.begin()); std::size_t count = x.count(key); - BOOST_DEDUCED_TYPENAME Container::iterator - pos = x.erase(x.begin()); + iterator pos = x.erase(x.begin()); --size; BOOST_TEST(pos == x.begin()); BOOST_TEST(x.count(key) == count - 1); @@ -83,7 +85,7 @@ void erase_tests1(Container*, test::random_generator generator) { using namespace std; int index = rand() % (int) x.size(); - BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next; + c_iterator prev, pos, next; if(index == 0) { prev = pos = x.begin(); } @@ -138,6 +140,45 @@ void erase_tests1(Container*, test::random_generator generator) test::check_equivalent_keys(x); } + std::cerr<<"erase(random ranges).\n"; + { + test::check_instances check_; + Container x; + + for (int i = 0; i < 100; ++i) { + test::random_values v(1000, generator); + x.insert(v.begin(), v.end()); + + // Note that erase only invalidates the erased iterators. + std::vector iterators; + for(c_iterator it = x.cbegin(); it != x.cend(); ++it) { + iterators.push_back(it); + } + iterators.push_back(x.cend()); + + while(iterators.size() > 1) { + int start = rand() % (int) iterators.size(); + int length = rand() % (int) (iterators.size() - start); + x.erase(iterators[start], iterators[start + length]); + iterators.erase( + boost::next(iterators.begin(), start), + boost::next(iterators.begin(), start + length)); + + BOOST_TEST(x.size() == iterators.size() - 1); + BOOST_DEDUCED_TYPENAME std::vector::const_iterator + i2 = iterators.begin(); + for(c_iterator i1 = x.cbegin(); i1 != x.cend(); ++i1) { + BOOST_TEST(i1 == *i2); + ++i2; + } + BOOST_TEST(x.cend() == *i2); + + test::check_equivalent_keys(x); + } + BOOST_TEST(x.empty()); + } + } + std::cerr<<"quick_erase(begin()).\n"; { test::check_instances check_; diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 8ebdd337..36c5c9dc 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -128,6 +128,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -157,6 +158,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -186,6 +188,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -213,6 +216,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -292,6 +296,42 @@ void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } + + std::cerr<<"insert various ranges.\n"; + + { + for (int i = 0; i < 100; ++i) { + X x; + test::ordered tracker = test::create_ordered(x); + + test::random_values v(1000, generator); + + for(BOOST_DEDUCED_TYPENAME test::random_values::iterator + it = v.begin(); it != v.end();) + { + BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + BOOST_DEDUCED_TYPENAME test::random_values::iterator + next = it; + for (int j = rand() % 20; j > 0; ++j) { + ++next; + if (next == v.end()) { break; } + } + + x.insert(it, next); + tracker.insert(it, next); + it = next; + + tracker.compare(x); // Slow, but I can't see any other way. + + if(static_cast(x.size()) <= b * static_cast(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + } } template @@ -327,6 +367,7 @@ void unique_emplace_tests1(X*, test::random_generator generator) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -357,6 +398,7 @@ void equivalent_emplace_tests1(X*, test::random_generator generator) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } @@ -386,8 +428,8 @@ void move_emplace_tests(X*, test::random_generator generator) BOOST_TEST(x.bucket_count() == old_bucket_count); } - test::check_equivalent_keys(x); tracker.compare(x); + test::check_equivalent_keys(x); } template @@ -449,6 +491,7 @@ void map_tests(X*, test::random_generator generator) BOOST_TEST(x.bucket_count() == old_bucket_count); } + tracker.compare(x); test::check_equivalent_keys(x); } From 8fda9113b8f568c32790f49559268c00509350fd Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 18 Sep 2016 12:22:48 +0100 Subject: [PATCH 18/46] Make 'has_unique_keys' container independent. --- test/helpers/metafunctions.hpp | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) 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)) + )); }; } From 13ff69efbf5b0627ba5ce872c92d13f96652fa00 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 18 Sep 2016 12:22:48 +0100 Subject: [PATCH 19/46] Make 'ordered' container independent. --- test/helpers/tracker.hpp | 43 +++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/test/helpers/tracker.hpp b/test/helpers/tracker.hpp index 52d9fa45..ab2470c0 100644 --- a/test/helpers/tracker.hpp +++ b/test/helpers/tracker.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include "../objects/fwd.hpp" #include "./metafunctions.hpp" #include "./helpers.hpp" @@ -60,38 +59,46 @@ namespace test values2.begin(), test::equivalent)); } - template + template ::value, + bool has_unique_keys = test::has_unique_keys::value> struct ordered_base; - template - struct ordered_base > + template + struct ordered_base { - typedef std::set::type> + typedef std::set< + BOOST_DEDUCED_TYPENAME X::value_type, + BOOST_DEDUCED_TYPENAME equals_to_compare::type> type; }; - template - struct ordered_base > + template + struct ordered_base { - typedef std::multiset::type> + typedef std::multiset< + BOOST_DEDUCED_TYPENAME X::value_type, + BOOST_DEDUCED_TYPENAME equals_to_compare::type> type; }; - template - struct ordered_base > + template + struct ordered_base { - typedef std::map::type> + typedef std::map< + BOOST_DEDUCED_TYPENAME X::key_type, + BOOST_DEDUCED_TYPENAME X::mapped_type, + BOOST_DEDUCED_TYPENAME equals_to_compare::type> type; }; - template - struct ordered_base > + template + struct ordered_base { - typedef std::multimap::type> + typedef std::multimap< + BOOST_DEDUCED_TYPENAME X::key_type, + BOOST_DEDUCED_TYPENAME X::mapped_type, + BOOST_DEDUCED_TYPENAME equals_to_compare::type> type; }; From 021817f2b45f740d128afed59df9b9ee655ef031 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 18 Sep 2016 22:56:23 +0100 Subject: [PATCH 20/46] Fix Visual C++ version number + use BOOST_WORKAROUND. --- test/unordered/compile_tests.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 516304cb..12c72c9e 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -481,7 +481,7 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) a.insert(list); a.insert({t,t,t}); -#if !defined(BOOST_MSVC) || BOOST_MSVC >= 1800 +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) a.insert({}); a.insert({t}); a.insert({t,t}); From 9decbe0cbd1936644dc2b1b4bebd96631ee22aea Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 30 Sep 2016 00:32:19 +0100 Subject: [PATCH 21/46] Manually write out emplace_args for small numbers. Still need some macros to handle rvalue reference support. --- include/boost/unordered/detail/allocate.hpp | 125 +++++++++++++++----- 1 file changed, 94 insertions(+), 31 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index a83edad2..4a6a2ae3 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -96,20 +96,109 @@ 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); + +#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 + +template +struct emplace_args1 +{ + BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) + + emplace_args1(Arg0 b0) : + BOOST_UNORDERED_EARGS_INIT(1, 0, _) + {} +}; + +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) : + BOOST_UNORDERED_EARGS_INIT(1, 0, _), + BOOST_UNORDERED_EARGS_INIT(1, 1, _) + {} +}; + +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) : + BOOST_UNORDERED_EARGS_INIT(1, 0, _), + BOOST_UNORDERED_EARGS_INIT(1, 1, _), + BOOST_UNORDERED_EARGS_INIT(1, 2, _) + {} +}; + +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) @@ -141,33 +230,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 From e174af228695e8b4f1fa6152b29c107bb694e00f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 30 Sep 2016 00:32:19 +0100 Subject: [PATCH 22/46] Try not using boost::forward in emplace_args constructor. AFAICT it's not needed since the construct arguments and the members are the same reference type. Maybe it was for older compilers? And it appears to be causing issues with string literals in older versions of Visual C++. --- include/boost/unordered/detail/allocate.hpp | 25 +++++---------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 4a6a2ae3..319c9cd5 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -120,10 +120,6 @@ namespace boost { namespace unordered { namespace detail { 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, _) \ @@ -131,9 +127,6 @@ namespace boost { namespace unordered { namespace detail { 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 template @@ -141,9 +134,7 @@ struct emplace_args1 { BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) - emplace_args1(Arg0 b0) : - BOOST_UNORDERED_EARGS_INIT(1, 0, _) - {} + emplace_args1(Arg0 b0) : a0(b0) {} }; template @@ -160,10 +151,7 @@ struct emplace_args2 BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) - emplace_args2(Arg0 b0, Arg1 b1) : - BOOST_UNORDERED_EARGS_INIT(1, 0, _), - BOOST_UNORDERED_EARGS_INIT(1, 1, _) - {} + emplace_args2(Arg0 b0, Arg1 b1) : a0(b0), a1(b1) {} }; template @@ -182,11 +170,7 @@ struct emplace_args3 BOOST_UNORDERED_EARGS_MEMBER(1, 1, _) BOOST_UNORDERED_EARGS_MEMBER(1, 2, _) - emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : - BOOST_UNORDERED_EARGS_INIT(1, 0, _), - BOOST_UNORDERED_EARGS_INIT(1, 1, _), - BOOST_UNORDERED_EARGS_INIT(1, 2, _) - {} + emplace_args3(Arg0 b0, Arg1 b1, Arg2 b2) : a0(b0), a1(b1), a2(b2) {} }; template @@ -205,6 +189,9 @@ inline emplace_args3 create_emplace_args( #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) \ From a93331dd964e5646ad6967c1da142424ed0ce81a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 1 Oct 2016 13:51:25 +0100 Subject: [PATCH 23/46] Fix new emplace tests. --- test/unordered/insert_tests.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 36c5c9dc..f3d7be92 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -443,17 +443,17 @@ void default_emplace_tests(X*, test::random_generator) x.emplace(); BOOST_TEST(x.size() == 1); x.emplace(); - BOOST_TEST(x.size() == is_unique ? 1: 2); + BOOST_TEST(x.size() == (is_unique ? 1: 2)); x.emplace(); - BOOST_TEST(x.size() == is_unique ? 1: 3); + BOOST_TEST(x.size() == (is_unique ? 1: 3)); typename X::value_type y; - BOOST_TEST(x.count(test::get_key(y)) == is_unique ? 1: 3); + BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1: 3)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); x.emplace(y); - BOOST_TEST(x.size() == is_unique ? 1: 4); - BOOST_TEST(x.count(test::get_key(y)) == is_unique ? 1: 4); + BOOST_TEST(x.size() == (is_unique ? 1: 4)); + BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1: 4)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); x.clear(); @@ -461,9 +461,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 ? 1: 2)); - BOOST_TEST(x.count(test::get_key(y)) == is_unique ? 1: 2); + BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1: 2)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); } From 98462fbcc3ba8da4e6ceb457843f719af3f083d6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 1 Oct 2016 13:53:05 +0100 Subject: [PATCH 24/46] Avoid conversion warning. --- test/exception/insert_exception_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 428dbb04..654072f7 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -133,7 +133,7 @@ struct insert_test_rehash1 : public insert_test_base // 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)); @@ -202,7 +202,7 @@ 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; From 588ad6e69f22dfb174dd0e2998eb9e8f8f6d908a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 30 Sep 2016 15:34:51 +0100 Subject: [PATCH 25/46] Travis tests in 32 and 64 bit. --- .travis.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dfccb0d1..d45b1f5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ addons: packages: - libboost-tools-dev - libxml2-utils + - g++-multilib matrix: include: @@ -20,10 +21,18 @@ 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} @@ -32,8 +41,13 @@ before_script: - | echo "using gcc : : g++-4.8 -Werror --std=c++03 -fsanitize=address ;" > ~/user-config.jam echo "using gcc : std11 : g++-4.8 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam + echo "using gcc : m32 : g++-4.8 -m32 -Werror -fsanitize=address ;" >> ~/user-config.jam + echo "using gcc : std11m32 : g++-4.8 -m32 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam echo "using clang : : clang++ -Werror --std=c++03 -fsanitize=address ;" >> ~/user-config.jam echo "using clang : std11 : clang++ -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam + # sanitized=address not available for 32-bit clang on travis. + echo "using clang : m32 : clang++ -m32 -Werror --std=c++03 ;" >> ~/user-config.jam + echo "using clang : std11m32 : clang++ -m32 -Werror --std=c++11 ;" >> ~/user-config.jam - cat ~/user-config.jam - wget -O boost_1_61_0.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.61.0/boost_1_61_0.tar.bz2/download - tar -xjf boost_1_61_0.tar.bz2 From e7b20d28770859d2f8e36003941db98c94de2bda Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 2 Oct 2016 13:04:25 +0100 Subject: [PATCH 26/46] Fix exception bug in asssignment. The hash and key equality functions were assigned before allocating new buckets. If that allocation failed, then the existing elements would be left in place - so if accessed after the exception they could be in the wrong buckets or equivalent elements could be incorrectly grouped together. --- include/boost/unordered/detail/table.hpp | 9 +- test/Jamfile.v2 | 1 + test/exception/assign_exception_tests.cpp | 8 +- .../exception/move_assign_exception_tests.cpp | 131 ++++++++++++++++++ test/helpers/exception_test.hpp | 16 ++- 5 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 test/exception/move_assign_exception_tests.cpp 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/test/Jamfile.v2 b/test/Jamfile.v2 index e31f1534..307dfe1a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -72,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..486bd03c 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -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/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/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; + } } }; From d0acb81f2ed58a325b30b3d47d6b9932c4a20244 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 2 Oct 2016 13:04:25 +0100 Subject: [PATCH 27/46] Release notes for latest changes. --- doc/changes.qbk | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index 1e1c77af..03fe1987 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -282,5 +282,16 @@ C++11 support has resulted in some breaking changes: [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] From 573e10665cd7c9576be36a33e9817c8a785d7942 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 2 Oct 2016 13:04:25 +0100 Subject: [PATCH 28/46] Use standard boost move style in noexcept_tests. --- test/unordered/noexcept_tests.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/unordered/noexcept_tests.cpp b/test/unordered/noexcept_tests.cpp index 0f066f87..740602d6 100644 --- a/test/unordered/noexcept_tests.cpp +++ b/test/unordered/noexcept_tests.cpp @@ -70,8 +70,10 @@ namespace noexcept_tests hash_nothrow_move() { test_throw("Constructor"); } hash_nothrow_move(hash_nothrow_move const&) { test_throw("Copy"); } - hash_nothrow_move& operator=(hash_nothrow_move const&) + hash_nothrow_move& operator=(BOOST_COPY_ASSIGN_REF(hash_nothrow_move)) { test_throw("Assign"); return *this; } + hash_nothrow_move& operator=(BOOST_RV_REF(hash_nothrow_move)) + { test_throw("Move Assign"); return *this; } std::size_t operator()(int x) const { test_throw("Operator"); return static_cast(*this)(x); } }; @@ -87,8 +89,10 @@ namespace noexcept_tests equal_to_nothrow_move() { test_throw("Constructor"); } equal_to_nothrow_move(equal_to_nothrow_move const&) { test_throw("Copy"); } - equal_to_nothrow_move& operator=(equal_to_nothrow_move const&) + equal_to_nothrow_move& operator=(BOOST_COPY_ASSIGN_REF(equal_to_nothrow_move)) { test_throw("Assign"); return *this; } + equal_to_nothrow_move& operator=(BOOST_RV_REF(equal_to_nothrow_move)) + { test_throw("Move Assign"); return *this; } std::size_t operator()(int x, int y) const { test_throw("Operator"); return static_cast(*this)(x, y); } }; From 50c4cbe06c6a86ad693b686f9b8f969cc8894206 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 2 Oct 2016 13:04:25 +0100 Subject: [PATCH 29/46] Try to fix the failures in noxcept_tests --- test/unordered/noexcept_tests.cpp | 65 +++++++++++++++++++------------ 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/test/unordered/noexcept_tests.cpp b/test/unordered/noexcept_tests.cpp index 740602d6..ba31b6e3 100644 --- a/test/unordered/noexcept_tests.cpp +++ b/test/unordered/noexcept_tests.cpp @@ -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 >::value)); - BOOST_TEST((boost::is_nothrow_move_constructible< - boost::unordered_multiset >::value)); - BOOST_TEST((boost::is_nothrow_move_constructible< - boost::unordered_map >::value)); - BOOST_TEST((boost::is_nothrow_move_constructible< - boost::unordered_multimap >::value)); -#endif - - BOOST_TEST((!boost::is_nothrow_move_constructible< - boost::unordered_set - >::value)); - BOOST_TEST((!boost::is_nothrow_move_constructible< - boost::unordered_multiset, - equal_to_possible_exception> - >::value)); - } - // Test that the move constructor does actually move without throwing // an exception when it claims to. @@ -97,20 +75,59 @@ namespace noexcept_tests { test_throw("Operator"); return static_cast(*this)(x, y); } }; + bool have_is_nothrow_move = false; + + UNORDERED_AUTO_TEST(check_is_nothrow_move) + { + BOOST_TEST(!boost::is_nothrow_move_constructible::value); + have_is_nothrow_move = boost::is_nothrow_move_constructible::value; + + // Copied from boost::is_nothrow_move_constructible implementation + // to make sure this does actually detect it when expected. +#ifdef BOOST_IS_NOTHROW_MOVE_CONSTRUCT + BOOST_TEST(have_is_nothrow_move); +#elif !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + BOOST_TEST(have_is_nothrow_move); +#endif + } + + UNORDERED_AUTO_TEST(test_noexcept) + { + if (have_is_nothrow_move) { + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_set >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_multiset >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_map >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_multimap >::value)); + } + + BOOST_TEST((!boost::is_nothrow_move_constructible< + boost::unordered_set + >::value)); + BOOST_TEST((!boost::is_nothrow_move_constructible< + boost::unordered_multiset, + equal_to_possible_exception> + >::value)); + } + UNORDERED_AUTO_TEST(test_no_throw_when_noexcept) { typedef boost::unordered_set throwing_set; - if (boost::is_nothrow_move_constructible::value) + if (have_is_nothrow_move) { + BOOST_TEST(boost::is_nothrow_move_constructible::value); + throwing_test_exception = false; throwing_set x1; x1.insert(10); x1.insert(50); - try { throwing_test_exception = true; From b00bc15c3e6954ac010ff3f6823fc3bb80743208 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 2 Oct 2016 17:56:01 +0100 Subject: [PATCH 30/46] Allocator aware constructors. --- doc/changes.qbk | 1 + doc/ref.php | 169 +++++- doc/ref.xml | 676 +++++++++++++++++++++- include/boost/unordered/unordered_map.hpp | 154 ++++- include/boost/unordered/unordered_set.hpp | 142 +++++ test/unordered/compile_tests.hpp | 32 +- 6 files changed, 1164 insertions(+), 10 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 03fe1987..45267739 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -281,6 +281,7 @@ C++11 support has resulted in some breaking changes: [h2 Boost 1.63.0] +* Implement missing allocator aware constructors. * Check hint iterator in `insert`/`emplace_hint`. * Fix some warnings, mostly in the tests. * Manually write out `emplace_args` for small numbers of arguments - diff --git a/doc/ref.php b/doc/ref.php index d2fb2b42..8ca01919 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -246,7 +246,12 @@ EOL; allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -310,6 +315,168 @@ EOL; Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated diff --git a/doc/ref.xml b/doc/ref.xml index d03e8dd3..cb77d263 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -187,7 +187,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -251,6 +256,168 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + unordered_set && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated @@ -1261,7 +1428,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -1325,6 +1497,168 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + unordered_multiset && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated @@ -2344,7 +2678,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -2408,6 +2747,168 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + unordered_map && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated @@ -3465,7 +3966,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -3529,6 +4035,168 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + unordered_multimap && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index fc6fbe0e..75b39d0f 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -108,6 +108,19 @@ namespace unordered const key_equal&, const allocator_type&); + template + unordered_map( + InputIt, InputIt, + size_type, + const hasher&, + const allocator_type&); + + template + unordered_map( + InputIt, InputIt, + size_type, + const allocator_type&); + // copy/move constructors unordered_map(unordered_map const&); @@ -139,6 +152,15 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); + unordered_map( + std::initializer_list, + size_type, + const hasher&, + const allocator_type&); + unordered_map( + std::initializer_list, + size_type, + const allocator_type&); #endif // Destructor @@ -570,6 +592,13 @@ namespace unordered const hasher& = hasher(), const key_equal& = key_equal(), const allocator_type& = allocator_type()); + explicit unordered_multimap( + size_type, + const allocator_type&); + explicit unordered_multimap( + size_type, + const hasher&, + const allocator_type&); explicit unordered_multimap(allocator_type const&); @@ -591,11 +620,25 @@ namespace unordered const key_equal&, const allocator_type&); + template + unordered_multimap( + InputIt, InputIt, + size_type, + const hasher&, + const allocator_type&); + + template + unordered_multimap( + InputIt, InputIt, + size_type, + const allocator_type&); + // copy/move constructors unordered_multimap(unordered_multimap const&); unordered_multimap(unordered_multimap const&, allocator_type const&); + unordered_multimap(BOOST_RV_REF(unordered_multimap), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multimap(BOOST_RV_REF(unordered_multimap) other) @@ -611,10 +654,6 @@ namespace unordered } #endif -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_multimap(unordered_multimap&&, allocator_type const&); -#endif - #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_multimap( std::initializer_list, @@ -622,6 +661,15 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); + unordered_multimap( + std::initializer_list, + size_type, + const hasher&, + const allocator_type&); + unordered_multimap( + std::initializer_list, + size_type, + const allocator_type&); #endif // Destructor @@ -1059,6 +1107,31 @@ namespace unordered table_.insert_range(f, l); } + template + template + unordered_map::unordered_map( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hf, key_equal(), a) + { + table_.insert_range(f, l); + } + + template + template + unordered_map::unordered_map( + InputIt f, InputIt l, + size_type n, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hasher(), key_equal(), a) + { + table_.insert_range(f, l); + } + template unordered_map::~unordered_map() BOOST_NOEXCEPT {} @@ -1094,6 +1167,30 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } + template + unordered_map::unordered_map( + std::initializer_list list, size_type n, + const hasher &hf, const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_map::unordered_map( + std::initializer_list list, size_type n, + const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hasher(), key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + template unordered_map& unordered_map::operator=( std::initializer_list list) @@ -1392,6 +1489,31 @@ namespace unordered table_.insert_range(f, l); } + template + template + unordered_multimap::unordered_multimap( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hf, key_equal(), a) + { + table_.insert_range(f, l); + } + + template + template + unordered_multimap::unordered_multimap( + InputIt f, InputIt l, + size_type n, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hasher(), key_equal(), a) + { + table_.insert_range(f, l); + } + template unordered_multimap::~unordered_multimap() BOOST_NOEXCEPT {} @@ -1427,6 +1549,30 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } + template + unordered_multimap::unordered_multimap( + std::initializer_list list, size_type n, + const hasher &hf, const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_multimap::unordered_multimap( + std::initializer_list list, size_type n, + const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hasher(), key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + template unordered_multimap& unordered_multimap::operator=( std::initializer_list list) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index aa9911bc..044cf1ac 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -105,6 +105,19 @@ namespace unordered const key_equal&, const allocator_type&); + template + unordered_set( + InputIt, InputIt, + size_type, + const hasher&, + const allocator_type&); + + template + unordered_set( + InputIt, InputIt, + size_type, + const allocator_type&); + // copy/move constructors unordered_set(unordered_set const&); @@ -136,6 +149,15 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); + unordered_set( + std::initializer_list, + size_type, + const hasher&, + const allocator_type&); + unordered_set( + std::initializer_list, + size_type, + const allocator_type&); #endif // Destructor @@ -574,6 +596,19 @@ namespace unordered const key_equal&, const allocator_type&); + template + unordered_multiset( + InputIt, InputIt, + size_type, + const hasher&, + const allocator_type&); + + template + unordered_multiset( + InputIt, InputIt, + size_type, + const allocator_type&); + // copy/move constructors unordered_multiset(unordered_multiset const&); @@ -605,6 +640,15 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); + unordered_multiset( + std::initializer_list, + size_type, + const hasher&, + const allocator_type&); + unordered_multiset( + std::initializer_list, + size_type, + const allocator_type&); #endif // Destructor @@ -1033,6 +1077,31 @@ namespace unordered table_.insert_range(f, l); } + template + template + unordered_set::unordered_set( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hf, key_equal(), a) + { + table_.insert_range(f, l); + } + + template + template + unordered_set::unordered_set( + InputIt f, InputIt l, + size_type n, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hasher(), key_equal(), a) + { + table_.insert_range(f, l); + } + template unordered_set::~unordered_set() BOOST_NOEXCEPT {} @@ -1068,6 +1137,30 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } + template + unordered_set::unordered_set( + std::initializer_list list, size_type n, + const hasher &hf, const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_set::unordered_set( + std::initializer_list list, size_type n, + const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hasher(), key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + template unordered_set& unordered_set::operator=( std::initializer_list list) @@ -1317,6 +1410,31 @@ namespace unordered table_.insert_range(f, l); } + template + template + unordered_multiset::unordered_multiset( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hf, key_equal(), a) + { + table_.insert_range(f, l); + } + + template + template + unordered_multiset::unordered_multiset( + InputIt f, InputIt l, + size_type n, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hasher(), key_equal(), a) + { + table_.insert_range(f, l); + } + template unordered_multiset::~unordered_multiset() BOOST_NOEXCEPT {} @@ -1352,6 +1470,30 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } + template + unordered_multiset::unordered_multiset( + std::initializer_list list, size_type n, + const hasher &hf, const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_multiset::unordered_multiset( + std::initializer_list list, size_type n, + const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hasher(), key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + template unordered_multiset& unordered_multiset::operator=( std::initializer_list list) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 12c72c9e..fb9a864d 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -111,6 +111,7 @@ void container_test(X& r, T const&) sink(X(a)); X u2(a); X u3 = a; + X u4(rvalue(a_const)); a.swap(b); boost::swap(a, b); @@ -120,12 +121,24 @@ void container_test(X& r, T const&) typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; test::check_return_type::equals(a_const.get_allocator()); + + allocator_type m = a.get_allocator(); + sink(X(m)); + X c(m); + sink(X(a_const, m)); + X c2(a_const, m); + sink(X(rvalue(a_const), m)); + X c3(rvalue(a_const), m); // Avoid unused variable warnings: sink(u); sink(u2); sink(u3); + sink(u4); + sink(c); + sink(c2); + sink(c3); } template @@ -449,14 +462,15 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator; + typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; X a; + allocator_type m = a.get_allocator(); BOOST_DEDUCED_TYPENAME X::value_type* i = 0; BOOST_DEDUCED_TYPENAME X::value_type* j = 0; X(i, j, 10, hf, eq); - X a5(i, j, 10, hf, eq); X(i, j, 10, hf); X a6(i, j, 10, hf); @@ -465,6 +479,22 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) X(i, j); X a8(i, j); + X(i, j, 10, hf, m); + X(i, j, 10, m); + //X(i, j, m); + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + std::size_t min_buckets = 10; + X({t}); + X({t}, min_buckets); + X({t}, min_buckets, hf); + X({t}, min_buckets, hf, eq); + //X({t}, m); + X({t}, min_buckets, m); + X({t}, min_buckets, hf, m); + X({t}, min_buckets, hf, eq, m); +#endif + X const b; sink(X(b)); X a9(b); From ff0228e7523c81e7e8b52ea18e4e05b1d1eb9b3f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 2 Oct 2016 17:56:01 +0100 Subject: [PATCH 31/46] Support for std::piecewise_construct. --- include/boost/unordered/detail/fwd.hpp | 36 +++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) 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 } } From 21d6d7bc210eeac4b467b69f41838fe54b30f7ad Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 3 Oct 2016 10:48:02 +0100 Subject: [PATCH 32/46] Fix detection of is_nothrow_move_constructible support. I should possibly also check how it handles `throw()`? --- test/unordered/noexcept_tests.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/unordered/noexcept_tests.cpp b/test/unordered/noexcept_tests.cpp index ba31b6e3..9ccc846c 100644 --- a/test/unordered/noexcept_tests.cpp +++ b/test/unordered/noexcept_tests.cpp @@ -84,9 +84,11 @@ namespace noexcept_tests // Copied from boost::is_nothrow_move_constructible implementation // to make sure this does actually detect it when expected. -#ifdef BOOST_IS_NOTHROW_MOVE_CONSTRUCT - BOOST_TEST(have_is_nothrow_move); -#elif !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_SFINAE_EXPR) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + // + // 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 } From d14c1dec5963045b9a5bca5defaa542a5d345ed4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 3 Oct 2016 20:58:15 +0100 Subject: [PATCH 33/46] Revert "Allocator aware constructors." This reverts commit b00bc15c3e6954ac010ff3f6823fc3bb80743208. I messed that up a bit, will get back to it later. --- doc/changes.qbk | 1 - doc/ref.php | 169 +----- doc/ref.xml | 676 +--------------------- include/boost/unordered/unordered_map.hpp | 154 +---- include/boost/unordered/unordered_set.hpp | 142 ----- test/unordered/compile_tests.hpp | 32 +- 6 files changed, 10 insertions(+), 1164 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 45267739..03fe1987 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -281,7 +281,6 @@ C++11 support has resulted in some breaking changes: [h2 Boost 1.63.0] -* Implement missing allocator aware constructors. * Check hint iterator in `insert`/`emplace_hint`. * Fix some warnings, mostly in the tests. * Manually write out `emplace_args` for small numbers of arguments - diff --git a/doc/ref.php b/doc/ref.php index 8ca01919..d2fb2b42 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -246,12 +246,7 @@ EOL; allocator_type() - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. If the defaults are used, hasher, key_equal and @@ -315,168 +310,6 @@ EOL; Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. - - - && - - - Allocator const& - - - Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. - - - This is implemented using Boost.Move. - - - - value_type is move insertable. - - - - - - initializer_list<value_type> - - - size_type - implementation-defined - - - hasher const& - hasher() - - - key_equal const& - key_equal() - - - allocator_type const& - allocator_type() - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from il into it. - - - - If the defaults are used, hasher, key_equal and - allocator_type need to be DefaultConstructible. - - - - - - size_type - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default hash function and key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - hasher and key_equal need to be DefaultConstructible. - - - - - - size_type - - - hasher const& - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - key_equal needs to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using a as the allocator, with the - default hash function and key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - hasher, key_equal need to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - hasher const& - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - a as the allocator, with the - default key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - key_equal needs to be DefaultConstructible. - - - The destructor is applied to every element, and all memory is deallocated diff --git a/doc/ref.xml b/doc/ref.xml index cb77d263..d03e8dd3 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -187,12 +187,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. If the defaults are used, hasher, key_equal and @@ -256,168 +251,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. - - - unordered_set && - - - Allocator const& - - - Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. - - - This is implemented using Boost.Move. - - - - value_type is move insertable. - - - - - - initializer_list<value_type> - - - size_type - implementation-defined - - - hasher const& - hasher() - - - key_equal const& - key_equal() - - - allocator_type const& - allocator_type() - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from il into it. - - - - If the defaults are used, hasher, key_equal and - allocator_type need to be DefaultConstructible. - - - - - - size_type - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default hash function and key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - hasher and key_equal need to be DefaultConstructible. - - - - - - size_type - - - hasher const& - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - key_equal needs to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using a as the allocator, with the - default hash function and key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - hasher, key_equal need to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - hasher const& - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - a as the allocator, with the - default key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - key_equal needs to be DefaultConstructible. - - - The destructor is applied to every element, and all memory is deallocated @@ -1428,12 +1261,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. If the defaults are used, hasher, key_equal and @@ -1497,168 +1325,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. - - - unordered_multiset && - - - Allocator const& - - - Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. - - - This is implemented using Boost.Move. - - - - value_type is move insertable. - - - - - - initializer_list<value_type> - - - size_type - implementation-defined - - - hasher const& - hasher() - - - key_equal const& - key_equal() - - - allocator_type const& - allocator_type() - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from il into it. - - - - If the defaults are used, hasher, key_equal and - allocator_type need to be DefaultConstructible. - - - - - - size_type - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default hash function and key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - hasher and key_equal need to be DefaultConstructible. - - - - - - size_type - - - hasher const& - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - key_equal needs to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using a as the allocator, with the - default hash function and key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - hasher, key_equal need to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - hasher const& - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - a as the allocator, with the - default key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - key_equal needs to be DefaultConstructible. - - - The destructor is applied to every element, and all memory is deallocated @@ -2678,12 +2344,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. If the defaults are used, hasher, key_equal and @@ -2747,168 +2408,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. - - - unordered_map && - - - Allocator const& - - - Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. - - - This is implemented using Boost.Move. - - - - value_type is move insertable. - - - - - - initializer_list<value_type> - - - size_type - implementation-defined - - - hasher const& - hasher() - - - key_equal const& - key_equal() - - - allocator_type const& - allocator_type() - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from il into it. - - - - If the defaults are used, hasher, key_equal and - allocator_type need to be DefaultConstructible. - - - - - - size_type - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default hash function and key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - hasher and key_equal need to be DefaultConstructible. - - - - - - size_type - - - hasher const& - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - key_equal needs to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using a as the allocator, with the - default hash function and key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - hasher, key_equal need to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - hasher const& - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - a as the allocator, with the - default key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - key_equal needs to be DefaultConstructible. - - - The destructor is applied to every element, and all memory is deallocated @@ -3966,12 +3465,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. If the defaults are used, hasher, key_equal and @@ -4035,168 +3529,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. - - - unordered_multimap && - - - Allocator const& - - - Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. - - - This is implemented using Boost.Move. - - - - value_type is move insertable. - - - - - - initializer_list<value_type> - - - size_type - implementation-defined - - - hasher const& - hasher() - - - key_equal const& - key_equal() - - - allocator_type const& - allocator_type() - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - eq as the key equality predicate, - a as the allocator and a maximum load factor of 1.0 - and inserts the elements from il into it. - - - - If the defaults are used, hasher, key_equal and - allocator_type need to be DefaultConstructible. - - - - - - size_type - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default hash function and key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - hasher and key_equal need to be DefaultConstructible. - - - - - - size_type - - - hasher const& - - - allocator_type const& - - - size() == 0 - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - the default key equality predicate, - a as the allocator and a maximum load factor of 1.0. - - - key_equal needs to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using a as the allocator, with the - default hash function and key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - hasher, key_equal need to be DefaultConstructible. - - - - - - - InputIterator - - - InputIterator - - - size_type - - - hasher const& - - - allocator_type const& - - - Constructs an empty container with at least n buckets, - using hf as the hash function, - a as the allocator, with the - default key equality predicate - and a maximum load factor of 1.0 - and inserts the elements from [f, l) into it. - - - - key_equal needs to be DefaultConstructible. - - - The destructor is applied to every element, and all memory is deallocated diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 75b39d0f..fc6fbe0e 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -108,19 +108,6 @@ namespace unordered const key_equal&, const allocator_type&); - template - unordered_map( - InputIt, InputIt, - size_type, - const hasher&, - const allocator_type&); - - template - unordered_map( - InputIt, InputIt, - size_type, - const allocator_type&); - // copy/move constructors unordered_map(unordered_map const&); @@ -152,15 +139,6 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); - unordered_map( - std::initializer_list, - size_type, - const hasher&, - const allocator_type&); - unordered_map( - std::initializer_list, - size_type, - const allocator_type&); #endif // Destructor @@ -592,13 +570,6 @@ namespace unordered const hasher& = hasher(), const key_equal& = key_equal(), const allocator_type& = allocator_type()); - explicit unordered_multimap( - size_type, - const allocator_type&); - explicit unordered_multimap( - size_type, - const hasher&, - const allocator_type&); explicit unordered_multimap(allocator_type const&); @@ -620,25 +591,11 @@ namespace unordered const key_equal&, const allocator_type&); - template - unordered_multimap( - InputIt, InputIt, - size_type, - const hasher&, - const allocator_type&); - - template - unordered_multimap( - InputIt, InputIt, - size_type, - const allocator_type&); - // copy/move constructors unordered_multimap(unordered_multimap const&); unordered_multimap(unordered_multimap const&, allocator_type const&); - unordered_multimap(BOOST_RV_REF(unordered_multimap), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multimap(BOOST_RV_REF(unordered_multimap) other) @@ -654,6 +611,10 @@ namespace unordered } #endif +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + unordered_multimap(unordered_multimap&&, allocator_type const&); +#endif + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_multimap( std::initializer_list, @@ -661,15 +622,6 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); - unordered_multimap( - std::initializer_list, - size_type, - const hasher&, - const allocator_type&); - unordered_multimap( - std::initializer_list, - size_type, - const allocator_type&); #endif // Destructor @@ -1107,31 +1059,6 @@ namespace unordered table_.insert_range(f, l); } - template - template - unordered_map::unordered_map( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, key_equal(), a) - { - table_.insert_range(f, l); - } - - template - template - unordered_map::unordered_map( - InputIt f, InputIt l, - size_type n, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hasher(), key_equal(), a) - { - table_.insert_range(f, l); - } - template unordered_map::~unordered_map() BOOST_NOEXCEPT {} @@ -1167,30 +1094,6 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } - template - unordered_map::unordered_map( - std::initializer_list list, size_type n, - const hasher &hf, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } - - template - unordered_map::unordered_map( - std::initializer_list list, size_type n, - const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hasher(), key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } - template unordered_map& unordered_map::operator=( std::initializer_list list) @@ -1489,31 +1392,6 @@ namespace unordered table_.insert_range(f, l); } - template - template - unordered_multimap::unordered_multimap( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, key_equal(), a) - { - table_.insert_range(f, l); - } - - template - template - unordered_multimap::unordered_multimap( - InputIt f, InputIt l, - size_type n, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hasher(), key_equal(), a) - { - table_.insert_range(f, l); - } - template unordered_multimap::~unordered_multimap() BOOST_NOEXCEPT {} @@ -1549,30 +1427,6 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } - template - unordered_multimap::unordered_multimap( - std::initializer_list list, size_type n, - const hasher &hf, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } - - template - unordered_multimap::unordered_multimap( - std::initializer_list list, size_type n, - const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hasher(), key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } - template unordered_multimap& unordered_multimap::operator=( std::initializer_list list) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 044cf1ac..aa9911bc 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -105,19 +105,6 @@ namespace unordered const key_equal&, const allocator_type&); - template - unordered_set( - InputIt, InputIt, - size_type, - const hasher&, - const allocator_type&); - - template - unordered_set( - InputIt, InputIt, - size_type, - const allocator_type&); - // copy/move constructors unordered_set(unordered_set const&); @@ -149,15 +136,6 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); - unordered_set( - std::initializer_list, - size_type, - const hasher&, - const allocator_type&); - unordered_set( - std::initializer_list, - size_type, - const allocator_type&); #endif // Destructor @@ -596,19 +574,6 @@ namespace unordered const key_equal&, const allocator_type&); - template - unordered_multiset( - InputIt, InputIt, - size_type, - const hasher&, - const allocator_type&); - - template - unordered_multiset( - InputIt, InputIt, - size_type, - const allocator_type&); - // copy/move constructors unordered_multiset(unordered_multiset const&); @@ -640,15 +605,6 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); - unordered_multiset( - std::initializer_list, - size_type, - const hasher&, - const allocator_type&); - unordered_multiset( - std::initializer_list, - size_type, - const allocator_type&); #endif // Destructor @@ -1077,31 +1033,6 @@ namespace unordered table_.insert_range(f, l); } - template - template - unordered_set::unordered_set( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, key_equal(), a) - { - table_.insert_range(f, l); - } - - template - template - unordered_set::unordered_set( - InputIt f, InputIt l, - size_type n, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hasher(), key_equal(), a) - { - table_.insert_range(f, l); - } - template unordered_set::~unordered_set() BOOST_NOEXCEPT {} @@ -1137,30 +1068,6 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } - template - unordered_set::unordered_set( - std::initializer_list list, size_type n, - const hasher &hf, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } - - template - unordered_set::unordered_set( - std::initializer_list list, size_type n, - const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hasher(), key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } - template unordered_set& unordered_set::operator=( std::initializer_list list) @@ -1410,31 +1317,6 @@ namespace unordered table_.insert_range(f, l); } - template - template - unordered_multiset::unordered_multiset( - InputIt f, InputIt l, - size_type n, - const hasher &hf, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hf, key_equal(), a) - { - table_.insert_range(f, l); - } - - template - template - unordered_multiset::unordered_multiset( - InputIt f, InputIt l, - size_type n, - const allocator_type &a) - : table_(boost::unordered::detail::initial_size(f, l, n), - hasher(), key_equal(), a) - { - table_.insert_range(f, l); - } - template unordered_multiset::~unordered_multiset() BOOST_NOEXCEPT {} @@ -1470,30 +1352,6 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } - template - unordered_multiset::unordered_multiset( - std::initializer_list list, size_type n, - const hasher &hf, const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hf, key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } - - template - unordered_multiset::unordered_multiset( - std::initializer_list list, size_type n, - const allocator_type &a) - : table_( - boost::unordered::detail::initial_size( - list.begin(), list.end(), n), - hasher(), key_equal(), a) - { - table_.insert_range(list.begin(), list.end()); - } - template unordered_multiset& unordered_multiset::operator=( std::initializer_list list) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index fb9a864d..12c72c9e 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -111,7 +111,6 @@ void container_test(X& r, T const&) sink(X(a)); X u2(a); X u3 = a; - X u4(rvalue(a_const)); a.swap(b); boost::swap(a, b); @@ -121,24 +120,12 @@ void container_test(X& r, T const&) typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; test::check_return_type::equals(a_const.get_allocator()); - - allocator_type m = a.get_allocator(); - sink(X(m)); - X c(m); - sink(X(a_const, m)); - X c2(a_const, m); - sink(X(rvalue(a_const), m)); - X c3(rvalue(a_const), m); // Avoid unused variable warnings: sink(u); sink(u2); sink(u3); - sink(u4); - sink(c); - sink(c2); - sink(c3); } template @@ -462,15 +449,14 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator; - typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; X a; - allocator_type m = a.get_allocator(); BOOST_DEDUCED_TYPENAME X::value_type* i = 0; BOOST_DEDUCED_TYPENAME X::value_type* j = 0; X(i, j, 10, hf, eq); + X a5(i, j, 10, hf, eq); X(i, j, 10, hf); X a6(i, j, 10, hf); @@ -479,22 +465,6 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) X(i, j); X a8(i, j); - X(i, j, 10, hf, m); - X(i, j, 10, m); - //X(i, j, m); - -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - std::size_t min_buckets = 10; - X({t}); - X({t}, min_buckets); - X({t}, min_buckets, hf); - X({t}, min_buckets, hf, eq); - //X({t}, m); - X({t}, min_buckets, m); - X({t}, min_buckets, hf, m); - X({t}, min_buckets, hf, eq, m); -#endif - X const b; sink(X(b)); X a9(b); From dadb4486eedab6dd50cf7081bfbf230f171afc67 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 4 Oct 2016 15:51:07 +0100 Subject: [PATCH 34/46] Fix calls to std::rand in tests --- test/unordered/erase_tests.cpp | 16 ++++++++++------ test/unordered/insert_tests.cpp | 7 ++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index d098c3df..4acec4c3 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -18,12 +18,18 @@ #include "../helpers/invariants.hpp" #include #include +#include namespace erase_tests { test::seed_t initialize_seed(85638); +int random_value(int max) { + using namespace std; + return rand() % max; +} + template void erase_tests1(Container*, test::random_generator generator) { @@ -83,8 +89,7 @@ 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(); + int index = random_value((int) x.size()); c_iterator prev, pos, next; if(index == 0) { prev = pos = x.begin(); @@ -157,8 +162,8 @@ void erase_tests1(Container*, test::random_generator generator) iterators.push_back(x.cend()); while(iterators.size() > 1) { - int start = rand() % (int) iterators.size(); - int length = rand() % (int) (iterators.size() - start); + int start = random_value((int) iterators.size()); + int length = random_value((int) (iterators.size() - start)); x.erase(iterators[start], iterators[start + length]); iterators.erase( boost::next(iterators.begin(), start), @@ -211,8 +216,7 @@ 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(); + int index = random_value((int) x.size()); BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next; if(index == 0) { prev = pos = x.begin(); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index f3d7be92..83ec15f9 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -24,6 +24,11 @@ namespace insert_tests { test::seed_t initialize_seed(243432); +int random_value(int max) { + using namespace std; + return rand() % max; +} + template void unique_insert_tests1(X*, test::random_generator generator) { @@ -314,7 +319,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_DEDUCED_TYPENAME test::random_values::iterator next = it; - for (int j = rand() % 20; j > 0; ++j) { + for (int j = random_value(20); j > 0; ++j) { ++next; if (next == v.end()) { break; } } From 982685d3a06affc1f5bf717d821e2ab84f32f1a2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 5 Oct 2016 00:57:58 +0100 Subject: [PATCH 35/46] Adjust order of variables to see if intel failure changes. So currently on one intel tester find_tests is failing the 'pos != x.end()' test, but not the 'const_pos != x_const.end()' test for unordered_set (and possibly others, the test results are truncated). I'm a bit stumped as to why this should be, as for unordered_set the const and non-const versions are basically the exact same code. See if changing the order makes any difference to what fails. --- test/unordered/find_tests.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index 45151e99..5bb1b7c0 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -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(*it1); - iterator pos = x.find(key); BOOST_DEDUCED_TYPENAME X::const_iterator const_pos = x_const.find(key); - BOOST_TEST(pos != x.end()); - BOOST_TEST(pos != x.end() && - x.key_eq()(key, test::get_key(*pos))); + iterator pos = x.find(key); BOOST_TEST(const_pos != x_const.end()); BOOST_TEST(const_pos != x_const.end() && x_const.key_eq()(key, test::get_key(*const_pos))); + BOOST_TEST(pos != x.end()); + BOOST_TEST(pos != x.end() && + x.key_eq()(key, test::get_key(*pos))); BOOST_TEST(x.count(key) == tracker.count(key)); From a0dc86ecbc77ac29394e9c4839f9b6468af6b27d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 5 Oct 2016 09:35:46 +0100 Subject: [PATCH 36/46] Use the boost snapshot for travis testing. --- .travis.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d45b1f5b..01420b5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,11 +49,12 @@ before_script: echo "using clang : m32 : clang++ -m32 -Werror --std=c++03 ;" >> ~/user-config.jam echo "using clang : std11m32 : clang++ -m32 -Werror --std=c++11 ;" >> ~/user-config.jam - cat ~/user-config.jam - - wget -O boost_1_61_0.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.61.0/boost_1_61_0.tar.bz2/download - - tar -xjf boost_1_61_0.tar.bz2 - - rm -r boost_1_61_0/boost/unordered + - wget -O boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/snapshots/master/boost_1_62_0.tar.bz2/download + - tar -xjf boost.tar.bz2 + - mv boost_1_62_0 boost + - rm -r boost/boost/unordered script: - cd ${TRAVIS_BUILD_DIR}/test - - bjam ${BJAM_TOOLSET} include=${HOME}/boost_1_61_0 include=${TRAVIS_BUILD_DIR}/include + - bjam ${BJAM_TOOLSET} include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include - xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml From 71d19820acf2d7f459cb0967fe7d9e0d4dd4ed2a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 5 Oct 2016 09:45:53 +0100 Subject: [PATCH 37/46] Fix signed conversion warnings. --- include/boost/unordered/detail/equivalent.hpp | 2 +- include/boost/unordered/detail/util.hpp | 2 +- test/Jamfile.v2 | 6 ++--- test/exception/assign_exception_tests.cpp | 2 +- test/exception/swap_exception_tests.cpp | 2 +- test/helpers/random_values.hpp | 4 +-- test/objects/exception.hpp | 8 +++--- test/objects/test.hpp | 27 ++++++++++++++----- test/unordered/compile_tests.hpp | 5 ++-- test/unordered/equality_tests.cpp | 6 +++-- test/unordered/erase_equiv_tests.cpp | 6 ++--- test/unordered/erase_tests.cpp | 19 +++++++------ test/unordered/insert_tests.cpp | 6 ++--- test/unordered/rehash_tests.cpp | 4 +-- test/unordered/unnecessary_copy_tests.cpp | 2 +- 15 files changed, 61 insertions(+), 40 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 45cd026d..5835884a 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -490,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/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/test/Jamfile.v2 b/test/Jamfile.v2 index 307dfe1a..065cdefa 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" - darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow" - clang:"-pedantic -Wextra" + gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow" + darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow" + 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 ; diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index 486bd03c..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()); } 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/random_values.hpp b/test/helpers/random_values.hpp index b65a29b2..e22eb36c 100644 --- a/test/helpers/random_values.hpp +++ b/test/helpers/random_values.hpp @@ -105,13 +105,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/objects/exception.hpp b/test/objects/exception.hpp index 034f31b2..b3c4bacb 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -146,14 +146,16 @@ namespace exception UNORDERED_EPOINT("Mock hash function."); } + int result; switch(tag_) { case 1: - return x.tag1_; + result = x.tag1_; case 2: - return x.tag2_; + result = x.tag2_; default: - return x.tag1_ + x.tag2_; + result = x.tag1_ + x.tag2_; } + return static_cast(result); } friend bool operator==(hash const& x1, hash const& x2) { diff --git a/test/objects/test.hpp b/test/objects/test.hpp index f6b03db7..ae6e90a7 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -182,29 +182,42 @@ 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_; case 2: - return x.tag2_; + result = x.tag2_; default: - return x.tag1_ + x.tag2_; + result = x.tag1_ + x.tag2_; } + return static_cast(result); } std::size_t operator()(movable const& x) const { + int result; switch(type_) { case 1: - return x.tag1_; + result = x.tag1_; case 2: - return x.tag2_; + result = x.tag2_; default: - return x.tag1_ + x.tag2_; + result = x.tag1_ + x.tag2_; } + return static_cast(result); } std::size_t operator()(int x) const { - return x; + int result; + switch(type_) { + case 1: + result = x; + case 2: + result = x * 7; + default: + result = x * 256; + } + return static_cast(result); } friend bool operator==(hash const& x1, hash const& x2) { diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 12c72c9e..7e475432 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -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::max)()); - difference_type converted_diff(max_diff); + size_type max_diff = static_cast( + (std::numeric_limits::max)()); + difference_type converted_diff(static_cast(max_diff)); BOOST_TEST((std::numeric_limits::max)() == converted_diff); diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index b6d146c6..4dc6bb1e 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -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(x % 250) : + static_cast((x + 5) % 250); } }; diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index c81a9ad9..26da1455 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -43,19 +43,19 @@ void write_container(Container const& x) // Make everything collide - for testing erase in a single bucket. struct collision_hash { - int operator()(int) const { return 0; } + std::size_t operator()(int) const { return 0; } }; // For testing erase in 2 buckets. struct collision2_hash { - int operator()(int x) const { return x & 1; } + std::size_t operator()(int x) const { return static_cast(x & 1); } }; // For testing erase in lots of buckets. struct collision3_hash { - int operator()(int x) const { return x; } + std::size_t operator()(int x) const { return static_cast(x); } }; typedef boost::unordered_multimap(rand()) % max; } template @@ -35,6 +35,7 @@ void erase_tests1(Container*, test::random_generator generator) { typedef BOOST_DEDUCED_TYPENAME Container::iterator iterator; typedef BOOST_DEDUCED_TYPENAME Container::const_iterator c_iterator; + typedef BOOST_DEDUCED_TYPENAME Container::difference_type difference_type; std::cerr<<"Erase by key.\n"; { @@ -89,7 +90,7 @@ void erase_tests1(Container*, test::random_generator generator) int iterations = 0; while(size > 0 && !x.empty()) { - int index = random_value((int) x.size()); + std::size_t index = random_value(x.size()); c_iterator prev, pos, next; if(index == 0) { prev = pos = x.begin(); @@ -162,12 +163,14 @@ void erase_tests1(Container*, test::random_generator generator) iterators.push_back(x.cend()); while(iterators.size() > 1) { - int start = random_value((int) iterators.size()); - int length = random_value((int) (iterators.size() - start)); + std::size_t start = random_value(iterators.size()); + std::size_t length = random_value(iterators.size() - start); x.erase(iterators[start], iterators[start + length]); iterators.erase( - boost::next(iterators.begin(), start), - boost::next(iterators.begin(), start + length)); + boost::next(iterators.begin(), + static_cast(start)), + boost::next(iterators.begin(), + static_cast(start + length))); BOOST_TEST(x.size() == iterators.size() - 1); BOOST_DEDUCED_TYPENAME std::vector::const_iterator @@ -216,7 +219,7 @@ void erase_tests1(Container*, test::random_generator generator) int iterations = 0; while(size > 0 && !x.empty()) { - int index = random_value((int) x.size()); + std::size_t index = random_value(x.size()); BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next; if(index == 0) { prev = pos = x.begin(); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 83ec15f9..8d1a189b 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -24,9 +24,9 @@ namespace insert_tests { test::seed_t initialize_seed(243432); -int random_value(int max) { +std::size_t random_value(std::size_t max) { using namespace std; - return rand() % max; + return static_cast(rand()) % max; } template @@ -319,7 +319,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_DEDUCED_TYPENAME test::random_values::iterator next = it; - for (int j = random_value(20); j > 0; ++j) { + for (std::size_t j = random_value(20); j > 0; ++j) { ++next; if (next == v.end()) { break; } } diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 551b79fa..122815d3 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -139,7 +139,7 @@ void reserve_test1(X*, test::random_generator generator) { for (int random_mlf = 0; random_mlf < 2; ++random_mlf) { - for (int i = 1; i < 2000; i += i < 50 ? 1 : 13) + for (std::size_t i = 1; i < 2000; i += i < 50 ? 1 : 13) { test::random_values v(i, generator); @@ -171,7 +171,7 @@ void reserve_test2(X*, test::random_generator generator) { for (int random_mlf = 0; random_mlf < 2; ++random_mlf) { - for (int i = 0; i < 2000; i += i < 50 ? 1 : 13) + for (std::size_t i = 0; i < 2000; i += i < 50 ? 1 : 13) { test::random_values v(i, generator); diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index f2b5e892..cb1346ba 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -115,7 +115,7 @@ namespace unnecessary_copy_tests #endif { std::size_t hash_value(unnecessary_copy_tests::count_copies const& x) { - return x.tag_; + return static_cast(x.tag_); } } From 094fa38360b12216ede3b92145b54f6724e19567 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 5 Oct 2016 13:34:26 +0100 Subject: [PATCH 38/46] Remove -Wsign-conversion, old gcc doesn't support it. --- test/Jamfile.v2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 065cdefa..f2207f89 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -11,8 +11,8 @@ 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 -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow" - darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow" + 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 -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow" ; From b1588929cc752ce78b58a08867b9b07249e092ec Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 5 Oct 2016 13:52:33 +0100 Subject: [PATCH 39/46] Fix another sign conversion warning. --- test/unordered/insert_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 8d1a189b..baea83f6 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -627,7 +627,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(x.a + x.b); } bool operator==(initialize_from_two_ints const& x) const From 65aaf2738073c5aee46576b81eaa112125621416 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 6 Oct 2016 10:53:10 +0100 Subject: [PATCH 40/46] Fix accidental fallthrough in switch cases. This was causing the hash function to be different to the equality function. For some reason this resulted in a lot of windows test failures, but none on linux or os x. I'm a bit confused and worried about that. --- test/objects/test.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/objects/test.hpp b/test/objects/test.hpp index ae6e90a7..a8c81263 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -186,8 +186,10 @@ namespace test switch(type_) { case 1: result = x.tag1_; + break; case 2: result = x.tag2_; + break; default: result = x.tag1_ + x.tag2_; } @@ -199,8 +201,10 @@ namespace test switch(type_) { case 1: result = x.tag1_; + break; case 2: result = x.tag2_; + break; default: result = x.tag1_ + x.tag2_; } @@ -212,8 +216,10 @@ namespace test switch(type_) { case 1: result = x; + break; case 2: result = x * 7; + break; default: result = x * 256; } From 147885fec4ef0223be4f64ae8ec6085a08af0d66 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 6 Oct 2016 17:06:32 +0100 Subject: [PATCH 41/46] Add another random generation style. This time for a more limited range of values so that equal values turn up more often. This is a bit shoddy, but seems like the best way to improve the existing tests without too much effort. --- test/helpers/fwd.hpp | 16 +++++++---- test/helpers/generators.hpp | 42 ++++++++++++++++++++-------- test/helpers/random_values.hpp | 25 ++++++----------- test/objects/exception.hpp | 11 ++++---- test/objects/test.hpp | 18 ++++++------ test/unordered/assign_tests.cpp | 5 ++-- test/unordered/bucket_tests.cpp | 3 +- test/unordered/constructor_tests.cpp | 7 +++-- test/unordered/copy_tests.cpp | 5 ++-- test/unordered/erase_tests.cpp | 16 ++++------- test/unordered/find_tests.cpp | 5 ++-- test/unordered/insert_tests.cpp | 28 ++++++++----------- test/unordered/load_factor_tests.cpp | 3 +- test/unordered/move_tests.cpp | 9 +++--- test/unordered/rehash_tests.cpp | 11 ++++---- test/unordered/swap_tests.cpp | 5 ++-- 16 files changed, 115 insertions(+), 94 deletions(-) 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/random_values.hpp b/test/helpers/random_values.hpp index e22eb36c..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_))); } } } diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index b3c4bacb..7ffe8f4c 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -23,7 +23,7 @@ namespace exception class hash; class equal_to; template class allocator; - object generate(object const*); + object generate(object const*, random_generator); struct true_type { @@ -101,9 +101,9 @@ namespace exception (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); } - friend object generate(object const*) { + friend object generate(object const*, random_generator g) { int* x = 0; - return object(::test::generate(x), ::test::generate(x)); + return object(::test::generate(x, g), ::test::generate(x, g)); } friend std::ostream& operator<<(std::ostream& out, object const& o) @@ -590,8 +590,9 @@ namespace exception #if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) namespace test { - test::exception::object generate(test::exception::object const* x) { - return test::exception::generate(x); + test::exception::object generate(test::exception::object const* x, + random_generator g) { + return test::exception::generate(x, g); } } #endif diff --git a/test/objects/test.hpp b/test/objects/test.hpp index a8c81263..2fe4b1f3 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -25,9 +25,9 @@ namespace test class equal_to; template class allocator1; template class allocator2; - object generate(object const*); - movable generate(movable const*); - implicitly_convertible generate(implicitly_convertible const*); + object generate(object const*, random_generator); + movable generate(movable const*, random_generator); + implicitly_convertible generate(implicitly_convertible const*, random_generator); inline void ignore_variable(void const*) {} @@ -58,9 +58,9 @@ namespace test (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); } - friend object generate(object const*) { + friend object generate(object const*, random_generator g) { int* x = 0; - return object(generate(x), generate(x)); + return object(generate(x, g), generate(x, g)); } friend std::ostream& operator<<(std::ostream& out, object const& o) @@ -133,9 +133,9 @@ namespace test (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); } - friend movable generate(movable const*) { + friend movable generate(movable const*, random_generator g) { int* x = 0; - return movable(generate(x), generate(x)); + return movable(generate(x, g), generate(x, g)); } friend std::ostream& operator<<(std::ostream& out, movable const& o) @@ -163,9 +163,9 @@ namespace test return movable(tag1_, tag2_); } - friend implicitly_convertible generate(implicitly_convertible const*) { + friend implicitly_convertible generate(implicitly_convertible const*, random_generator g) { int* x = 0; - return implicitly_convertible(generate(x), generate(x)); + return implicitly_convertible(generate(x, g), generate(x, g)); } friend std::ostream& operator<<(std::ostream& out, implicitly_convertible const& o) diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index e66967c6..aa0f579f 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -236,6 +236,7 @@ boost::unordered_multimap bool is_propagate(T*) @@ -256,7 +257,7 @@ UNORDERED_TEST(assign_tests1, ( (test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign) (test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign) ) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) UNORDERED_TEST(assign_tests2, ( @@ -264,7 +265,7 @@ UNORDERED_TEST(assign_tests2, ( (test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign) (test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign) ) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index 7c6ff2d3..4417f2d5 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -89,10 +89,11 @@ boost::unordered_multimap(rand()) % max; -} - template void erase_tests1(Container*, test::random_generator generator) { @@ -90,7 +85,7 @@ void erase_tests1(Container*, test::random_generator generator) int iterations = 0; while(size > 0 && !x.empty()) { - std::size_t index = random_value(x.size()); + std::size_t index = test::random_value(x.size()); c_iterator prev, pos, next; if(index == 0) { prev = pos = x.begin(); @@ -163,8 +158,8 @@ void erase_tests1(Container*, test::random_generator generator) iterators.push_back(x.cend()); while(iterators.size() > 1) { - std::size_t start = random_value(iterators.size()); - std::size_t length = random_value(iterators.size() - start); + 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( boost::next(iterators.begin(), @@ -219,7 +214,7 @@ void erase_tests1(Container*, test::random_generator generator) int iterations = 0; while(size > 0 && !x.empty()) { - std::size_t index = random_value(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(); @@ -278,10 +273,11 @@ boost::unordered_multimap(rand()) % max; -} - template void unique_insert_tests1(X*, test::random_generator generator) { @@ -319,7 +314,7 @@ void insert_tests2(X*, test::random_generator generator) BOOST_DEDUCED_TYPENAME test::random_values::iterator next = it; - for (std::size_t j = random_value(20); j > 0; ++j) { + for (std::size_t j = test::random_value(20); j > 0; ++j) { ++next; if (next == v.end()) { break; } } @@ -566,57 +561,58 @@ boost::unordered_multimap* int_multimap_ptr; using test::default_generator; using test::generate_collisions; +using test::limited_range; UNORDERED_TEST(set_load_factor_tests, ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr)) @@ -85,7 +86,7 @@ UNORDERED_TEST(set_load_factor_tests, UNORDERED_TEST(load_factor_insert_tests, ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr)) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) } diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 8c7e8702..b04f33b0 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -369,6 +369,7 @@ boost::unordered_multimap* 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)) @@ -232,11 +233,11 @@ UNORDERED_TEST(reserve_empty_test2, ) UNORDERED_TEST(reserve_test1, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) UNORDERED_TEST(reserve_test2, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) } diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index d967af03..7814a26a 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -206,6 +206,7 @@ bool is_propagate(T*) using test::default_generator; using test::generate_collisions; +using test::limited_range; UNORDERED_AUTO_TEST(check_traits) { @@ -220,7 +221,7 @@ UNORDERED_TEST(swap_tests1, ( (test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap) (test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap) ) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) UNORDERED_TEST(swap_tests2, ( @@ -228,7 +229,7 @@ UNORDERED_TEST(swap_tests2, ( (test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap) (test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap) ) - ((default_generator)(generate_collisions)) + ((default_generator)(generate_collisions)(limited_range)) ) } From ade302f0a03a4b9add0dac347237139328d78c92 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Fri, 7 Oct 2016 23:07:37 -0500 Subject: [PATCH 42/46] Add, and update, documentation build targets. --- doc/Jamfile.v2 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 156d8d7c..6a5b7012 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -57,3 +57,12 @@ boostbook standalone : unordered : pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/libs/unordered/doc/html ; +############################################################################### +alias boostdoc + : unordered + : + : + : ; +explicit boostdoc ; +alias boostrelease ; +explicit boostrelease ; From a316d3fa461d52f3db854cd5e2ee8a965cf475d8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 11 Oct 2016 10:07:07 +0100 Subject: [PATCH 43/46] Fix more warnings --- test/exception/insert_exception_tests.cpp | 16 +++++++--------- test/objects/exception.hpp | 2 ++ test/unordered/erase_equiv_tests.cpp | 8 ++++++-- test/unordered/erase_tests.cpp | 6 ++++-- test/unordered/insert_tests.cpp | 14 +++++++------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 654072f7..c2e2999a 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -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; @@ -136,7 +136,7 @@ struct insert_test_rehash1 : public insert_test_base 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)); + this->values.begin() + initial_elements); BOOST_TEST(bucket_count == x.bucket_count()); return x; } @@ -147,8 +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()), - end = this->values.end(); + it = this->values.begin() + x.size(), end = this->values.end(); it != end && count < 10; ++it, ++count) { strong.store(x, test::detail::tracker.count_allocations); @@ -171,7 +170,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 = this->values.begin(), x.size()), end = this->values.end(); it != end && count < 10; ++it, ++count) { @@ -208,8 +207,7 @@ struct insert_test_rehash3 : public insert_test_base 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)); + x.insert(this->values.begin(), this->values.begin() + initial_elements); BOOST_TEST(original_bucket_count == x.bucket_count()); return x; } @@ -217,8 +215,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(this->values.begin() + x.size(), + 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/objects/exception.hpp b/test/objects/exception.hpp index 7ffe8f4c..0e0aa869 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -150,8 +150,10 @@ namespace exception switch(tag_) { case 1: result = x.tag1_; + break; case 2: result = x.tag2_; + break; default: result = x.tag1_ + x.tag2_; } diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index 26da1455..98da1e6d 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -143,9 +143,13 @@ bool compare(Range1 const& x, Range2 const& y) template bool general_erase_range_test(Container& x, std::size_t start, std::size_t end) { + typedef BOOST_DEDUCED_TYPENAME Container::difference_type difference_type; + difference_type start2 = start, end2 = 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(boost::next(l.begin(), start2), boost::next(l.begin(), end2)); + x.erase(boost::next(x.begin(), start2), boost::next(x.begin(), end2)); test::check_equivalent_keys(x); return compare(l, x); diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 2204e4b3..5d986a7f 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -91,7 +91,8 @@ void erase_tests1(Container*, test::random_generator generator) prev = pos = x.begin(); } else { - prev = boost::next(x.begin(), index - 1); + prev = boost::next(x.begin(), + static_cast(index - 1)); pos = boost::next(prev); } next = boost::next(pos); @@ -220,7 +221,8 @@ void erase_tests1(Container*, test::random_generator generator) prev = pos = x.begin(); } else { - prev = boost::next(x.begin(), index - 1); + prev = boost::next(x.begin(), + static_cast(index - 1)); pos = boost::next(prev); } next = boost::next(pos); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index db34ec4a..07b30932 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -443,17 +443,17 @@ void default_emplace_tests(X*, test::random_generator) x.emplace(); BOOST_TEST(x.size() == 1); x.emplace(); - BOOST_TEST(x.size() == (is_unique ? 1: 2)); + BOOST_TEST(x.size() == (is_unique ? 1u : 2u)); x.emplace(); - BOOST_TEST(x.size() == (is_unique ? 1: 3)); + BOOST_TEST(x.size() == (is_unique ? 1u : 3u)); typename X::value_type y; - BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1: 3)); + BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 3u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); x.emplace(y); - BOOST_TEST(x.size() == (is_unique ? 1: 4)); - BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1: 4)); + BOOST_TEST(x.size() == (is_unique ? 1u : 4u)); + BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 4u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); x.clear(); @@ -461,9 +461,9 @@ void default_emplace_tests(X*, test::random_generator) x.emplace(y); BOOST_TEST(x.size() == 1); x.emplace(y); - BOOST_TEST(x.size() == (is_unique ? 1: 2)); + BOOST_TEST(x.size() == (is_unique ? 1u : 2u)); - BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1: 2)); + BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 2u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); } From 74abdd6973367255e7eccf2804705d840ddbda02 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 11 Oct 2016 13:36:41 +0100 Subject: [PATCH 44/46] Replace boost::next with a simpler version Less optimized, but hopefully it won't cause any warnings. --- test/exception/insert_exception_tests.cpp | 18 +++++++++------- test/helpers/helpers.hpp | 20 +++++++++++++++++ test/unordered/erase_equiv_tests.cpp | 15 ++++++------- test/unordered/erase_tests.cpp | 26 +++++++++-------------- test/unordered/insert_tests.cpp | 3 +-- 5 files changed, 47 insertions(+), 35 deletions(-) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index c2e2999a..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); @@ -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)); } } }; @@ -136,7 +136,7 @@ struct insert_test_rehash1 : public insert_test_base ceil((double) bucket_count * (double) x.max_load_factor()) - 1); BOOST_TEST(initial_elements < this->values.size()); x.insert(this->values.begin(), - this->values.begin() + initial_elements); + test::next(this->values.begin(), initial_elements)); BOOST_TEST(bucket_count == x.bucket_count()); return x; } @@ -147,7 +147,8 @@ 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 = this->values.begin() + x.size(), end = this->values.end(); + it = test::next(this->values.begin(), x.size()), + end = this->values.end(); it != end && count < 10; ++it, ++count) { strong.store(x, test::detail::tracker.count_allocations); @@ -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 = this->values.begin(), x.size()), + it = test::next(this->values.begin(), x.size()), end = this->values.end(); it != end && count < 10; ++it, ++count) { @@ -207,7 +208,8 @@ struct insert_test_rehash3 : public insert_test_base rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1; BOOST_TEST(initial_elements < this->values.size()); - x.insert(this->values.begin(), this->values.begin() + initial_elements); + x.insert(this->values.begin(), + test::next(this->values.begin(), initial_elements)); BOOST_TEST(original_bucket_count == x.bucket_count()); return x; } @@ -215,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(this->values.begin() + x.size(), - 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/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/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index 98da1e6d..b55bc202 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -13,10 +13,10 @@ #include "../helpers/test.hpp" #include "../helpers/list.hpp" #include "../helpers/invariants.hpp" +#include "../helpers/helpers.hpp" #include #include #include -#include #include "../objects/test.hpp" #if BOOST_WORKAROUND(BOOST_MSVC, < 1400) @@ -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); @@ -143,13 +143,10 @@ bool compare(Range1 const& x, Range2 const& y) template bool general_erase_range_test(Container& x, std::size_t start, std::size_t end) { - typedef BOOST_DEDUCED_TYPENAME Container::difference_type difference_type; - difference_type start2 = start, end2 = end; - collide_list l(x.begin(), x.end()); - l.erase(boost::next(l.begin(), start2), boost::next(l.begin(), end2)); - x.erase(boost::next(x.begin(), start2), boost::next(x.begin(), end2)); + l.erase(test::next(l.begin(), start), test::next(l.begin(), end)); + x.erase(test::next(x.begin(), start), test::next(x.begin(), end)); test::check_equivalent_keys(x); return compare(l, x); diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 5d986a7f..34d7ec9e 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -9,7 +9,6 @@ #include "../helpers/postfix.hpp" #include "../helpers/test.hpp" -#include #include "../objects/test.hpp" #include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" @@ -30,7 +29,6 @@ void erase_tests1(Container*, test::random_generator generator) { typedef BOOST_DEDUCED_TYPENAME Container::iterator iterator; typedef BOOST_DEDUCED_TYPENAME Container::const_iterator c_iterator; - typedef BOOST_DEDUCED_TYPENAME Container::difference_type difference_type; std::cerr<<"Erase by key.\n"; { @@ -91,11 +89,10 @@ void erase_tests1(Container*, test::random_generator generator) prev = pos = x.begin(); } else { - prev = boost::next(x.begin(), - static_cast(index - 1)); - pos = boost::next(prev); + prev = test::next(x.begin(), index - 1); + pos = test::next(prev); } - next = boost::next(pos); + next = test::next(pos); BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*pos); std::size_t count = x.count(key); @@ -104,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; @@ -163,10 +160,8 @@ void erase_tests1(Container*, test::random_generator generator) std::size_t length = test::random_value(iterators.size() - start); x.erase(iterators[start], iterators[start + length]); iterators.erase( - boost::next(iterators.begin(), - static_cast(start)), - boost::next(iterators.begin(), - static_cast(start + length))); + test::next(iterators.begin(), start), + test::next(iterators.begin(), start + length)); BOOST_TEST(x.size() == iterators.size() - 1); BOOST_DEDUCED_TYPENAME std::vector::const_iterator @@ -221,11 +216,10 @@ void erase_tests1(Container*, test::random_generator generator) prev = pos = x.begin(); } else { - prev = boost::next(x.begin(), - static_cast(index - 1)); - pos = boost::next(prev); + prev = test::next(x.begin(), index - 1); + pos = test::next(prev); } - next = boost::next(pos); + next = test::next(pos); BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*pos); std::size_t count = x.count(key); @@ -234,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; diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 07b30932..3f13ea0f 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -9,7 +9,6 @@ #include "../helpers/postfix.hpp" #include "../helpers/test.hpp" -#include #include "../objects/test.hpp" #include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" @@ -208,7 +207,7 @@ 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); From ece41163299a95d02103de422ff7aabde38d5aa2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 13 Oct 2016 10:00:20 +0100 Subject: [PATCH 45/46] Try to fix another warning --- test/helpers/equivalent.hpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/helpers/equivalent.hpp b/test/helpers/equivalent.hpp index f452c807..127a394b 100644 --- a/test/helpers/equivalent.hpp +++ b/test/helpers/equivalent.hpp @@ -43,19 +43,15 @@ namespace test struct 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 + // This should'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 From 04607dc9f377c0676e0a7df97039a12e699eccea Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 13 Oct 2016 17:03:31 +0100 Subject: [PATCH 46/46] Fix for clang. --- test/helpers/equivalent.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/helpers/equivalent.hpp b/test/helpers/equivalent.hpp index 127a394b..61b91538 100644 --- a/test/helpers/equivalent.hpp +++ b/test/helpers/equivalent.hpp @@ -42,15 +42,14 @@ namespace test } struct equivalent_type { + equivalent_type() {} + template bool operator()(T1 const& x, T2 const& y) const { return equivalent_impl(x, y, derived); } }; - // This should'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). const equivalent_type equivalent; template