$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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()