$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r84373 - in trunk: boost/unordered libs/unordered/test/unordered
From: dnljms_at_[hidden]
Date: 2013-05-19 10:30:13
Author: danieljames
Date: 2013-05-19 10:30:12 EDT (Sun, 19 May 2013)
New Revision: 84373
URL: http://svn.boost.org/trac/boost/changeset/84373
Log:
Add conditional `noexcept` for move constructors.
Also added `noexcept` for destructors because of a gcc bug, see:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56191
Found via:
http://stackoverflow.com/questions/15721544/destructors-and-noexcept
Added:
   trunk/libs/unordered/test/unordered/noexcept_tests.cpp   (contents, props changed)
Text files modified: 
   trunk/boost/unordered/unordered_map.hpp        |    12 ++++++++----                            
   trunk/boost/unordered/unordered_set.hpp        |    12 ++++++++----                            
   trunk/libs/unordered/test/unordered/Jamfile.v2 |     1 +                                       
   3 files changed, 17 insertions(+), 8 deletions(-)
Modified: trunk/boost/unordered/unordered_map.hpp
==============================================================================
--- trunk/boost/unordered/unordered_map.hpp	(original)
+++ trunk/boost/unordered/unordered_map.hpp	2013-05-19 10:30:12 EDT (Sun, 19 May 2013)
@@ -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: trunk/boost/unordered/unordered_set.hpp
==============================================================================
--- trunk/boost/unordered/unordered_set.hpp	(original)
+++ trunk/boost/unordered/unordered_set.hpp	2013-05-19 10:30:12 EDT (Sun, 19 May 2013)
@@ -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: trunk/libs/unordered/test/unordered/Jamfile.v2
==============================================================================
--- trunk/libs/unordered/test/unordered/Jamfile.v2	(original)
+++ trunk/libs/unordered/test/unordered/Jamfile.v2	2013-05-19 10:30:12 EDT (Sun, 19 May 2013)
@@ -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 ]
Added: trunk/libs/unordered/test/unordered/noexcept_tests.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/unordered/test/unordered/noexcept_tests.cpp	2013-05-19 10:30:12 EDT (Sun, 19 May 2013)
@@ -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)
+#define private public
+#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()