From cc2b1a1ef17a5cac157ed2084d3caacd774b8320 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 May 2016 09:23:01 +0100 Subject: [PATCH 1/6] Stop using deprecated boost::iterator. --- doc/changes.qbk | 4 ++++ include/boost/unordered/detail/buckets.hpp | 10 +++++----- test/helpers/input_iterator.hpp | 6 +++--- test/helpers/list.hpp | 6 +++--- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index af8cf0a5..ecabe158 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -269,4 +269,8 @@ C++11 support has resulted in some breaking changes: * Fix potential overflow when calculating number of buckets to allocate ([@https://github.com/boostorg/unordered/pull/4 GitHub #4]). +[h2 Boost 1.62.0] + +* Remove use of deprecated `boost::iterator`. + [endsect] diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 8a67345c..ac5bd6d8 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include namespace boost { namespace unordered { namespace detail { @@ -56,7 +56,7 @@ namespace boost { namespace unordered { namespace iterator_detail { template struct l_iterator - : public boost::iterator< + : public std::iterator< std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, @@ -116,7 +116,7 @@ namespace boost { namespace unordered { namespace iterator_detail { template struct cl_iterator - : public boost::iterator< + : public std::iterator< std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, @@ -184,7 +184,7 @@ namespace boost { namespace unordered { namespace iterator_detail { template struct iterator - : public boost::iterator< + : public std::iterator< std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, @@ -248,7 +248,7 @@ namespace boost { namespace unordered { namespace iterator_detail { template struct c_iterator - : public boost::iterator< + : public std::iterator< std::forward_iterator_tag, typename Node::value_type, std::ptrdiff_t, diff --git a/test/helpers/input_iterator.hpp b/test/helpers/input_iterator.hpp index 1671e0c0..d3c91afb 100644 --- a/test/helpers/input_iterator.hpp +++ b/test/helpers/input_iterator.hpp @@ -7,8 +7,8 @@ #define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER #include -#include #include +#include namespace test { @@ -28,7 +28,7 @@ namespace test template struct input_iterator_adaptor - : public boost::iterator< + : public std::iterator< std::input_iterator_tag, BOOST_DEDUCED_TYPENAME boost::iterator_value::type, std::ptrdiff_t, @@ -72,7 +72,7 @@ namespace test template struct copy_iterator_adaptor - : public boost::iterator< + : public std::iterator< BOOST_DEDUCED_TYPENAME boost::iterator_category::type, BOOST_DEDUCED_TYPENAME boost::iterator_value::type, BOOST_DEDUCED_TYPENAME boost::iterator_difference::type, diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp index 5d02c2df..0c92928d 100644 --- a/test/helpers/list.hpp +++ b/test/helpers/list.hpp @@ -11,8 +11,8 @@ #if !defined(UNORDERED_TEST_LIST_HEADER) #define UNORDERED_TEST_LIST_HEADER -#include #include +#include #include namespace test @@ -83,7 +83,7 @@ namespace test template class list_iterator - : public boost::iterator< + : public std::iterator< std::forward_iterator_tag, T, int, T*, T&> { @@ -109,7 +109,7 @@ namespace test template class list_const_iterator - : public boost::iterator< + : public std::iterator< std::forward_iterator_tag, T, int, T const*, T const&> { From 144a0c1791abad25b74fecafbf14f411a6743777 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 May 2016 09:23:01 +0100 Subject: [PATCH 2/6] Remove BOOST_NO_STD_DISTANCE workaround. --- doc/changes.qbk | 1 + include/boost/unordered/detail/equivalent.hpp | 2 +- include/boost/unordered/detail/util.hpp | 15 --------------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index ecabe158..a884b2bc 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -272,5 +272,6 @@ C++11 support has resulted in some breaking changes: [h2 Boost 1.62.0] * Remove use of deprecated `boost::iterator`. +* Remove `BOOST_NO_STD_DISTANCE` workaround. [endsect] diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 58478f99..a62a3571 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -482,7 +482,7 @@ namespace boost { namespace unordered { namespace detail { { if(i == j) return; - std::size_t distance = boost::unordered::detail::distance(i, j); + std::size_t distance = std::distance(i, j); if(distance == 1) { node_constructor a(this->node_alloc()); a.construct_with_value2(*i); diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 3428ed7a..14dcfd84 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -124,21 +124,6 @@ namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// // insert_size/initial_size -#if !defined(BOOST_NO_STD_DISTANCE) - - using ::std::distance; - -#else - - template - inline std::size_t distance(ForwardIterator i, ForwardIterator j) { - std::size_t x; - std::distance(i, j, x); - return x; - } - -#endif - template inline typename boost::unordered::detail::enable_if_forward::type From 3f42a56bae7030b190c97e22ec75a8b60f0b28e9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 May 2016 09:23:01 +0100 Subject: [PATCH 3/6] Remove old deprecated warning. --- doc/changes.qbk | 1 + include/boost/unordered/detail/table.hpp | 12 ------------ 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index a884b2bc..fdaf3f89 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -273,5 +273,6 @@ C++11 support has resulted in some breaking changes: * Remove use of deprecated `boost::iterator`. * Remove `BOOST_NO_STD_DISTANCE` workaround. +* Remove `BOOST_UNORDERED_DEPRECATED_EQUALITY` warning. [endsect] diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index b356ca22..f0b9a8b0 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -23,18 +23,6 @@ #pragma warning(disable:4127) // conditional expression is constant #endif -#if defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) - -#if defined(__EDG__) -#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__) -#pragma message("Warning: BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported.") -#elif defined(__GNUC__) || defined(__HP_aCC) || \ - defined(__SUNPRO_CC) || defined(__IBMCPP__) -#warning "BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported." -#endif - -#endif - namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// From c26acdba1549068678b30d265c9d36c6818e8b05 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 May 2016 22:31:43 +0100 Subject: [PATCH 4/6] Travis --- .travis.yml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..a005cd16 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,38 @@ +# Copyright (C) 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) + +# Use Trusty to get a reasonably recent version of Boost. +sudo: required +dist: trusty + +language: c++ + +addons: + apt: + packages: + - libboost-dev + - libboost-tools-dev + +matrix: + include: + - compiler: gcc + env: BJAM_TOOLSET=gcc + - compiler: gcc + env: BJAM_TOOLSET=gcc-std11 + - compiler: clang + env: BJAM_TOOLSET=clang + - compiler: clang + env: BJAM_TOOLSET=clang-std11 + +before_script: + - | + echo "using gcc : : g++-4.8 ;" > ~/user-config.jam + echo "using gcc : std11 : g++-4.8 --std=c++11 ;" >> ~/user-config.jam + echo "using clang : : clang++ ;" >> ~/user-config.jam + echo "using clang : std11 : clang++ --std=c++11 ;" >> ~/user-config.jam + - cat ~/user-config.jam + - touch Jamroot.jam + +script: + - cd test && bjam -q ${BJAM_TOOLSET} include=${TRAVIS_BUILD_DIR}/include From 1d4845d6b85ac69eebd22acc2abef2628edca31c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 May 2016 22:39:47 +0100 Subject: [PATCH 5/6] Stop using predef in test. --- test/unordered/insert_tests.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 872bfc12..019d2ac3 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 #include "../objects/test.hpp" #include "../helpers/random_values.hpp" @@ -599,7 +598,7 @@ UNORDERED_AUTO_TEST(insert_initializer_list_set) boost::unordered_set set2; -#if BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4,5,0) +#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)) set2.insert({{1, 2}}); #else set2.insert({1, 2}); From b4a3c6f46076059bbf9acedb91fe5c1503a2483d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 30 May 2016 11:29:20 +0100 Subject: [PATCH 6/6] Fix exception safety in assignment for multimap/multiset. The assignment code seemed like a bit of a premature optimization, I replaced it with a slightly slower but much simpler implementation. --- doc/changes.qbk | 2 + include/boost/unordered/detail/equivalent.hpp | 28 +++---- include/boost/unordered/detail/table.hpp | 10 +-- include/boost/unordered/detail/unique.hpp | 23 +++--- test/exception/assign_exception_tests.cpp | 78 +++++++++++++------ test/helpers/random_values.hpp | 10 ++- 6 files changed, 91 insertions(+), 60 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index fdaf3f89..839b370f 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -274,5 +274,7 @@ C++11 support has resulted in some breaking changes: * Remove use of deprecated `boost::iterator`. * Remove `BOOST_NO_STD_DISTANCE` workaround. * Remove `BOOST_UNORDERED_DEPRECATED_EQUALITY` warning. +* Simpler implementation of assignment, fixes an exception safety issue + for `unordered_multiset` and `unordered_multimap`. Might be a little slower. [endsect] diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index a62a3571..407b5f79 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -385,7 +385,14 @@ namespace boost { namespace unordered { namespace detail { std::size_t key_hash, iterator pos) { - node_pointer n = a.release(); + return add_node(a.release(), key_hash, pos); + } + + inline iterator add_node( + node_pointer n, + std::size_t key_hash, + iterator pos) + { n->hash_ = key_hash; if (pos.node_) { this->add_after_node(n, pos.node_); @@ -622,30 +629,17 @@ namespace boost { namespace unordered { namespace detail { // fill_buckets template - static void fill_buckets(iterator n, table& dst, - NodeCreator& creator) + void fill_buckets(iterator n, NodeCreator& creator) { - link_pointer prev = dst.get_previous_start(); - while (n.node_) { std::size_t key_hash = n.node_->hash_; iterator group_end(n.node_->group_prev_->next_); - node_pointer first_node = creator.create(*n); - node_pointer end = first_node; - first_node->hash_ = key_hash; - prev->next_ = first_node; - ++dst.size_; - + iterator pos = this->add_node(creator.create(*n), key_hash, iterator()); for (++n; n != group_end; ++n) { - end = creator.create(*n); - end->hash_ = key_hash; - add_after_node(end, first_node); - ++dst.size_; + this->add_node(creator.create(*n), key_hash, pos); } - - prev = place_in_bucket(dst, prev, end); } } diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index f0b9a8b0..a337f45b 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -393,7 +393,7 @@ namespace boost { namespace unordered { namespace detail { if (x.size_) { create_buckets(bucket_count_); copy_nodes node_creator(node_alloc()); - table_impl::fill_buckets(x.begin(), *this, node_creator); + static_cast(this)->fill_buckets(x.begin(), node_creator); } } @@ -408,7 +408,7 @@ namespace boost { namespace unordered { namespace detail { move_nodes node_creator(node_alloc()); node_holder nodes(x); - table_impl::fill_buckets(nodes.begin(), *this, node_creator); + static_cast(this)->fill_buckets(nodes.begin(), node_creator); } } @@ -654,7 +654,7 @@ namespace boost { namespace unordered { namespace detail { // assigning to them if possible, and deleting any that are // left over. assign_nodes node_creator(*this); - table_impl::fill_buckets(x.begin(), *this, node_creator); + static_cast(this)->fill_buckets(x.begin(), node_creator); } void assign(table const& x, true_type) @@ -681,7 +681,7 @@ namespace boost { namespace unordered { namespace detail { if (x.size_) { create_buckets(bucket_count_); copy_nodes node_creator(node_alloc()); - table_impl::fill_buckets(x.begin(), *this, node_creator); + static_cast(this)->fill_buckets(x.begin(), node_creator); } } } @@ -740,7 +740,7 @@ namespace boost { namespace unordered { namespace detail { // any that are left over. move_assign_nodes
node_creator(*this); node_holder nodes(x); - table_impl::fill_buckets(nodes.begin(), *this, node_creator); + static_cast(this)->fill_buckets(nodes.begin(), node_creator); } } diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index f76ca5a6..a318d0b3 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -311,7 +311,13 @@ namespace boost { namespace unordered { namespace detail { node_constructor& a, std::size_t key_hash) { - node_pointer n = a.release(); + return add_node(a.release(), key_hash); + } + + inline iterator add_node( + node_pointer n, + std::size_t key_hash) + { n->hash_ = key_hash; bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); @@ -577,19 +583,10 @@ namespace boost { namespace unordered { namespace detail { // fill_buckets template - static void fill_buckets(iterator n, table& dst, - NodeCreator& creator) + void fill_buckets(iterator n, NodeCreator& creator) { - link_pointer prev = dst.get_previous_start(); - - while (n.node_) { - node_pointer node = creator.create(*n); - node->hash_ = n.node_->hash_; - prev->next_ = node; - ++dst.size_; - ++n; - - prev = place_in_bucket(dst, prev); + for (; n.node_; ++n) { + this->add_node(creator.create(*n), n.node_->hash_); } } diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index 75be2adb..a9f4976f 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -38,21 +38,18 @@ struct self_assign_test2 : self_assign_base template struct assign_base : public test::exception_base { - const test::random_values x_values, y_values; + 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; - assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2, - float mlf1 = 1.0, float mlf2 = 1.0) : - x_values(count1), - y_values(count2), - x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1), - allocator_type(tag1)), - y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2), - allocator_type(tag2)) + 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); @@ -66,47 +63,80 @@ struct assign_base : public test::exception_base test::check_equivalent_keys(x1); // If the container is empty at the point of the exception, the - // internal structure is hidden, this exposes it. - T& y = const_cast(x1); + // internal structure is hidden, this exposes it, at the cost of + // messing up the data. if (x_values.size()) { - y.emplace(*x_values.begin()); - test::check_equivalent_keys(y); + T& x2 = const_cast(x1); + x2.emplace(*x_values.begin()); + test::check_equivalent_keys(x2); } } }; template -struct assign_test1 : assign_base +struct assign_values : assign_base { - assign_test1() : assign_base(0, 0, 0, 0) {} + assign_values(unsigned int count1, unsigned int count2, + int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0) : + 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 assign_test2 : assign_base +struct assign_test1 : assign_values { - assign_test2() : assign_base(60, 0, 0, 0) {} + assign_test1() : assign_values(0, 0, 0, 0) {} }; template -struct assign_test3 : assign_base +struct assign_test2 : assign_values { - assign_test3() : assign_base(0, 60, 0, 0) {} + assign_test2() : assign_values(60, 0, 0, 0) {} }; template -struct assign_test4 : assign_base +struct assign_test3 : assign_values { - assign_test4() : assign_base(10, 10, 1, 2) {} + assign_test3() : assign_values(0, 60, 0, 0) {} }; template -struct assign_test5 : assign_base +struct assign_test4 : assign_values { - assign_test5() : assign_base(5, 60, 0, 0, 1.0, 0.1) {} + assign_test4() : assign_values(10, 10, 1, 2) {} +}; + +template +struct assign_test5 : assign_values +{ + assign_test5() : assign_values(5, 60, 0, 0, 1.0f, 0.1f) {} +}; + +template +struct equivalent_test1 : assign_base +{ + equivalent_test1() : + 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( (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_test5) + (equivalent_test1), CONTAINER_SEQ) RUN_TESTS() diff --git a/test/helpers/random_values.hpp b/test/helpers/random_values.hpp index f8ba252c..b65a29b2 100644 --- a/test/helpers/random_values.hpp +++ b/test/helpers/random_values.hpp @@ -103,8 +103,16 @@ namespace test struct random_values : public test::list { - random_values(int count, test::random_generator const& generator = + random_values() {} + + explicit random_values(int count, test::random_generator const& generator = test::default_generator) + { + fill(count, generator); + } + + void fill(int count, test::random_generator const& generator = + test::default_generator) { test::unordered_generator gen(generator); gen.fill(*this, count);