Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r85048 - in branches/release: boost/unordered boost/unordered/detail libs/unordered libs/unordered/doc libs/unordered/test/unordered
From: dnljms_at_[hidden]
Date: 2013-07-15 17:32:45


Author: danieljames
Date: 2013-07-15 17:32:45 EDT (Mon, 15 Jul 2013)
New Revision: 85048
URL: http://svn.boost.org/trac/boost/changeset/85048

Log:
Merge unordered from trunk.

Add `BOOST_NOEXPECT` to:

- Move constructors (when appropriate)
- Destructors
- Iterators

Also, fix some misleading documentation about the containers' move support.

Added:
   branches/release/libs/unordered/test/unordered/noexcept_tests.cpp
      - copied unchanged from r84408, trunk/libs/unordered/test/unordered/noexcept_tests.cpp
Properties modified:
   branches/release/boost/unordered/ (props changed)
   branches/release/libs/unordered/ (props changed)
Text files modified:
   branches/release/boost/unordered/detail/buckets.hpp | 44 ++++++++-----
   branches/release/boost/unordered/unordered_map.hpp | 12 ++-
   branches/release/boost/unordered/unordered_set.hpp | 12 ++-
   branches/release/libs/unordered/doc/compliance.qbk | 9 +-
   branches/release/libs/unordered/test/unordered/Jamfile.v2 | 1
   branches/release/libs/unordered/test/unordered/noexcept_tests.cpp | 125 ++++++++++++++++++++++++++++++++++++++++
   6 files changed, 173 insertions(+), 30 deletions(-)

Modified: branches/release/boost/unordered/detail/buckets.hpp
==============================================================================
--- branches/release/boost/unordered/detail/buckets.hpp Mon Jul 15 17:24:43 2013 (r85047)
+++ branches/release/boost/unordered/detail/buckets.hpp 2013-07-15 17:32:45 EDT (Mon, 15 Jul 2013) (r85048)
@@ -73,9 +73,9 @@
 
         typedef typename Node::value_type value_type;
 
- l_iterator() : ptr_() {}
+ l_iterator() BOOST_NOEXCEPT : ptr_() {}
 
- l_iterator(iterator x, std::size_t b, std::size_t c)
+ l_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT
             : ptr_(x.node_), bucket_(b), bucket_count_(c) {}
 
         value_type& operator*() const {
@@ -100,11 +100,11 @@
             return tmp;
         }
 
- bool operator==(l_iterator x) const {
+ bool operator==(l_iterator x) const BOOST_NOEXCEPT {
             return ptr_ == x.ptr_;
         }
 
- bool operator!=(l_iterator x) const {
+ bool operator!=(l_iterator x) const BOOST_NOEXCEPT {
             return ptr_ != x.ptr_;
         }
     };
@@ -132,13 +132,13 @@
 
         typedef typename Node::value_type value_type;
 
- cl_iterator() : ptr_() {}
+ cl_iterator() BOOST_NOEXCEPT : ptr_() {}
 
- cl_iterator(iterator x, std::size_t b, std::size_t c) :
+ cl_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT :
             ptr_(x.node_), bucket_(b), bucket_count_(c) {}
 
         cl_iterator(boost::unordered::iterator_detail::l_iterator<
- Node, Policy> const& x) :
+ Node, Policy> const& x) BOOST_NOEXCEPT :
             ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_)
         {}
 
@@ -164,11 +164,15 @@
             return tmp;
         }
 
- friend bool operator==(cl_iterator const& x, cl_iterator const& y) {
+ friend bool operator==(cl_iterator const& x, cl_iterator const& y)
+ BOOST_NOEXCEPT
+ {
             return x.ptr_ == y.ptr_;
         }
 
- friend bool operator!=(cl_iterator const& x, cl_iterator const& y) {
+ friend bool operator!=(cl_iterator const& x, cl_iterator const& y)
+ BOOST_NOEXCEPT
+ {
             return x.ptr_ != y.ptr_;
         }
     };
@@ -204,9 +208,9 @@
 
         typedef typename Node::value_type value_type;
 
- iterator() : node_() {}
+ iterator() BOOST_NOEXCEPT : node_() {}
 
- explicit iterator(typename Node::link_pointer x) :
+ explicit iterator(typename Node::link_pointer x) BOOST_NOEXCEPT :
             node_(static_cast<node_pointer>(x)) {}
 
         value_type& operator*() const {
@@ -228,11 +232,11 @@
             return tmp;
         }
 
- bool operator==(iterator const& x) const {
+ bool operator==(iterator const& x) const BOOST_NOEXCEPT {
             return node_ == x.node_;
         }
 
- bool operator!=(iterator const& x) const {
+ bool operator!=(iterator const& x) const BOOST_NOEXCEPT {
             return node_ != x.node_;
         }
     };
@@ -266,12 +270,12 @@
 
         typedef typename Node::value_type value_type;
 
- c_iterator() : node_() {}
+ c_iterator() BOOST_NOEXCEPT : node_() {}
 
- explicit c_iterator(typename Node::link_pointer x) :
+ explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT :
             node_(static_cast<node_pointer>(x)) {}
 
- c_iterator(iterator const& x) : node_(x.node_) {}
+ c_iterator(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {}
 
         value_type const& operator*() const {
             return node_->value();
@@ -292,11 +296,15 @@
             return tmp;
         }
 
- friend bool operator==(c_iterator const& x, c_iterator const& y) {
+ friend bool operator==(c_iterator const& x, c_iterator const& y)
+ BOOST_NOEXCEPT
+ {
             return x.node_ == y.node_;
         }
 
- friend bool operator!=(c_iterator const& x, c_iterator const& y) {
+ friend bool operator!=(c_iterator const& x, c_iterator const& y)
+ BOOST_NOEXCEPT
+ {
             return x.node_ != y.node_;
         }
     };

Modified: branches/release/boost/unordered/unordered_map.hpp
==============================================================================
--- branches/release/boost/unordered/unordered_map.hpp Mon Jul 15 17:24:43 2013 (r85047)
+++ branches/release/boost/unordered/unordered_map.hpp 2013-07-15 17:32:45 EDT (Mon, 15 Jul 2013) (r85048)
@@ -117,11 +117,13 @@
 
 #if defined(BOOST_UNORDERED_USE_MOVE)
         unordered_map(BOOST_RV_REF(unordered_map) other)
+ BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
             : table_(other.table_, boost::unordered::detail::move_tag())
         {
         }
 #elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
         unordered_map(unordered_map&& other)
+ BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
             : table_(other.table_, boost::unordered::detail::move_tag())
         {
         }
@@ -142,7 +144,7 @@
 
         // Destructor
 
- ~unordered_map();
+ ~unordered_map() BOOST_NOEXCEPT;
 
         // Assign
 
@@ -598,11 +600,13 @@
 
 #if defined(BOOST_UNORDERED_USE_MOVE)
         unordered_multimap(BOOST_RV_REF(unordered_multimap) other)
+ BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
             : table_(other.table_, boost::unordered::detail::move_tag())
         {
         }
 #elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
         unordered_multimap(unordered_multimap&& other)
+ BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
             : table_(other.table_, boost::unordered::detail::move_tag())
         {
         }
@@ -623,7 +627,7 @@
 
         // Destructor
 
- ~unordered_multimap();
+ ~unordered_multimap() BOOST_NOEXCEPT;
 
         // Assign
 
@@ -1057,7 +1061,7 @@
     }
     
     template <class K, class T, class H, class P, class A>
- unordered_map<K,T,H,P,A>::~unordered_map() {}
+ unordered_map<K,T,H,P,A>::~unordered_map() BOOST_NOEXCEPT {}
 
     template <class K, class T, class H, class P, class A>
     unordered_map<K,T,H,P,A>::unordered_map(
@@ -1390,7 +1394,7 @@
     }
     
     template <class K, class T, class H, class P, class A>
- unordered_multimap<K,T,H,P,A>::~unordered_multimap() {}
+ unordered_multimap<K,T,H,P,A>::~unordered_multimap() BOOST_NOEXCEPT {}
 
     template <class K, class T, class H, class P, class A>
     unordered_multimap<K,T,H,P,A>::unordered_multimap(

Modified: branches/release/boost/unordered/unordered_set.hpp
==============================================================================
--- branches/release/boost/unordered/unordered_set.hpp Mon Jul 15 17:24:43 2013 (r85047)
+++ branches/release/boost/unordered/unordered_set.hpp 2013-07-15 17:32:45 EDT (Mon, 15 Jul 2013) (r85048)
@@ -115,11 +115,13 @@
 
 #if defined(BOOST_UNORDERED_USE_MOVE)
         unordered_set(BOOST_RV_REF(unordered_set) other)
+ BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
             : table_(other.table_, boost::unordered::detail::move_tag())
         {
         }
 #elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
         unordered_set(unordered_set&& other)
+ BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
             : table_(other.table_, boost::unordered::detail::move_tag())
         {
         }
@@ -140,7 +142,7 @@
 
         // Destructor
 
- ~unordered_set();
+ ~unordered_set() BOOST_NOEXCEPT;
 
         // Assign
 
@@ -582,11 +584,13 @@
 
 #if defined(BOOST_UNORDERED_USE_MOVE)
         unordered_multiset(BOOST_RV_REF(unordered_multiset) other)
+ BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
             : table_(other.table_, boost::unordered::detail::move_tag())
         {
         }
 #elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
         unordered_multiset(unordered_multiset&& other)
+ BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
             : table_(other.table_, boost::unordered::detail::move_tag())
         {
         }
@@ -607,7 +611,7 @@
 
         // Destructor
 
- ~unordered_multiset();
+ ~unordered_multiset() BOOST_NOEXCEPT;
 
         // Assign
 
@@ -1032,7 +1036,7 @@
     }
     
     template <class T, class H, class P, class A>
- unordered_set<T,H,P,A>::~unordered_set() {}
+ unordered_set<T,H,P,A>::~unordered_set() BOOST_NOEXCEPT {}
 
     template <class T, class H, class P, class A>
     unordered_set<T,H,P,A>::unordered_set(
@@ -1316,7 +1320,7 @@
     }
     
     template <class T, class H, class P, class A>
- unordered_multiset<T,H,P,A>::~unordered_multiset() {}
+ unordered_multiset<T,H,P,A>::~unordered_multiset() BOOST_NOEXCEPT {}
 
     template <class T, class H, class P, class A>
     unordered_multiset<T,H,P,A>::unordered_multiset(

Modified: branches/release/libs/unordered/doc/compliance.qbk
==============================================================================
--- branches/release/libs/unordered/doc/compliance.qbk Mon Jul 15 17:24:43 2013 (r85047)
+++ branches/release/libs/unordered/doc/compliance.qbk 2013-07-15 17:32:45 EDT (Mon, 15 Jul 2013) (r85048)
@@ -8,11 +8,12 @@
 
 Support for move semantics is implemented using Boost.Move. If rvalue
 references are available it will use them, but if not it uses a close,
-but imperfect emulation. On such compilers you'll need to use Boost.Move
-to take advantage of using movable container elements, also note that:
+but imperfect emulation. On such compilers:
 
-* Non-copyable objects can be stored in the containers, but without support
- for rvalue references the container will not be movable.
+* Non-copyable objects can be stored in the containers.
+ They can be constructed in place using `emplace`, or if they support
+ Boost.Move, moved into place.
+* The containers themselves are not movable.
 * Argument forwarding is not perfect.
 
 [endsect]

Modified: branches/release/libs/unordered/test/unordered/Jamfile.v2
==============================================================================
--- branches/release/libs/unordered/test/unordered/Jamfile.v2 Mon Jul 15 17:24:43 2013 (r85047)
+++ branches/release/libs/unordered/test/unordered/Jamfile.v2 2013-07-15 17:32:45 EDT (Mon, 15 Jul 2013) (r85048)
@@ -25,6 +25,7 @@
         [ run minimal_allocator.cpp ]
         [ run compile_set.cpp ]
         [ run compile_map.cpp ]
+ [ run noexcept_tests.cpp ]
         [ run link_test_1.cpp link_test_2.cpp ]
         [ run incomplete_test.cpp ]
         [ run simple_tests.cpp ]

Copied: branches/release/libs/unordered/test/unordered/noexcept_tests.cpp (from r84408, trunk/libs/unordered/test/unordered/noexcept_tests.cpp)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ branches/release/libs/unordered/test/unordered/noexcept_tests.cpp 2013-07-15 17:32:45 EDT (Mon, 15 Jul 2013) (r85048, copy of r84408, trunk/libs/unordered/test/unordered/noexcept_tests.cpp)
@@ -0,0 +1,125 @@
+
+// Copyright 2013 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include "../helpers/prefix.hpp"
+#include <boost/unordered_set.hpp>
+#include <boost/unordered_map.hpp>
+#include "../helpers/postfix.hpp"
+
+#include "../helpers/test.hpp"
+
+namespace noexcept_tests
+{
+ // Test the noexcept is set correctly for the move constructor.
+
+ struct hash_possible_exception : boost::hash<int>
+ {
+ hash_possible_exception(hash_possible_exception const&) {}
+ };
+
+ struct equal_to_possible_exception : std::equal_to<int>
+ {
+ equal_to_possible_exception(equal_to_possible_exception const&) {}
+ };
+
+ UNORDERED_AUTO_TEST(test_noexcept)
+ {
+#if !defined(BOOST_NO_CXX11_NOEXCEPT)
+ BOOST_TEST((boost::is_nothrow_move_constructible<
+ boost::unordered_set<int> >::value));
+ BOOST_TEST((boost::is_nothrow_move_constructible<
+ boost::unordered_multiset<int> >::value));
+ BOOST_TEST((boost::is_nothrow_move_constructible<
+ boost::unordered_map<int, int> >::value));
+ BOOST_TEST((boost::is_nothrow_move_constructible<
+ boost::unordered_multimap<int, int> >::value));
+#endif
+
+ BOOST_TEST((!boost::is_nothrow_move_constructible<
+ boost::unordered_set<int, hash_possible_exception>
+ >::value));
+ BOOST_TEST((!boost::is_nothrow_move_constructible<
+ boost::unordered_multiset<int, boost::hash<int>,
+ equal_to_possible_exception>
+ >::value));
+ }
+
+ // Test that the move constructor does actually move without throwing
+ // an exception when it claims to.
+
+ struct test_exception {};
+
+ bool throwing_test_exception = false;
+ void test_throw(char const* name) {
+ if (throwing_test_exception) {
+ std::cerr << "Throw exception in: " << name << std::endl;
+ throw test_exception();
+ }
+ }
+
+ class hash_nothrow_move : boost::hash<int>
+ {
+ BOOST_COPYABLE_AND_MOVABLE(hash_nothrow_move)
+
+ typedef boost::hash<int> base;
+ public:
+ hash_nothrow_move(BOOST_RV_REF(hash_nothrow_move))
+ BOOST_NOEXCEPT {}
+
+ hash_nothrow_move() { test_throw("Constructor"); }
+ hash_nothrow_move(hash_nothrow_move const& x) { test_throw("Copy"); }
+ hash_nothrow_move& operator=(hash_nothrow_move const&)
+ { test_throw("Assign"); return *this; }
+ std::size_t operator()(int x) const
+ { test_throw("Operator"); return static_cast<base const&>(*this)(x); }
+ };
+
+ class equal_to_nothrow_move : std::equal_to<int>
+ {
+ BOOST_COPYABLE_AND_MOVABLE(equal_to_nothrow_move)
+
+ typedef std::equal_to<int> base;
+ public:
+ equal_to_nothrow_move(BOOST_RV_REF(equal_to_nothrow_move))
+ BOOST_NOEXCEPT {}
+ equal_to_nothrow_move() { test_throw("Constructor"); }
+ equal_to_nothrow_move(equal_to_nothrow_move const& x)
+ { test_throw("Copy"); }
+ equal_to_nothrow_move& operator=(equal_to_nothrow_move const&)
+ { test_throw("Assign"); return *this; }
+ std::size_t operator()(int x, int y) const
+ { test_throw("Operator"); return static_cast<base const&>(*this)(x, y); }
+ };
+
+ UNORDERED_AUTO_TEST(test_no_throw_when_noexcept)
+ {
+ typedef boost::unordered_set<int,
+ hash_nothrow_move, equal_to_nothrow_move> throwing_set;
+
+ if (boost::is_nothrow_move_constructible<throwing_set>::value)
+ {
+ throwing_test_exception = false;
+
+ throwing_set x1;
+ x1.insert(10);
+ x1.insert(50);
+
+
+ try {
+ throwing_test_exception = true;
+
+ throwing_set x2 = boost::move(x1);
+ BOOST_TEST(x2.size() == 2);
+ BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
+ } catch(test_exception) {
+ BOOST_TEST(false);
+ }
+
+ throwing_test_exception = false;
+ }
+ }
+}
+
+RUN_TESTS()


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk