$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r73772 - in trunk: boost/unordered/detail libs/unordered/test/helpers libs/unordered/test/objects libs/unordered/test/unordered
From: dnljms_at_[hidden]
Date: 2011-08-15 03:48:54
Author: danieljames
Date: 2011-08-15 03:48:53 EDT (Mon, 15 Aug 2011)
New Revision: 73772
URL: http://svn.boost.org/trac/boost/changeset/73772
Log:
Unordered: Implement select_on_container_copy_construction support.
Text files modified: 
   trunk/boost/unordered/detail/allocator_helpers.hpp    |    73 +++++++++++++++++++++-                  
   trunk/libs/unordered/test/helpers/memory.hpp          |     8 ++                                      
   trunk/libs/unordered/test/objects/cxx11_allocator.hpp |   127 +++++++++++++++++++++++++++++++-------- 
   trunk/libs/unordered/test/objects/test.hpp            |     7 --                                      
   trunk/libs/unordered/test/unordered/copy_tests.cpp    |    67 +++++++++++++++++++-                    
   5 files changed, 238 insertions(+), 44 deletions(-)
Modified: trunk/boost/unordered/detail/allocator_helpers.hpp
==============================================================================
--- trunk/boost/unordered/detail/allocator_helpers.hpp	(original)
+++ trunk/boost/unordered/detail/allocator_helpers.hpp	2011-08-15 03:48:53 EDT (Mon, 15 Aug 2011)
@@ -17,6 +17,7 @@
 
 #include <boost/config.hpp>
 #include <boost/detail/select_type.hpp>
+#include <boost/utility/enable_if.hpp>
 
 #if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
     && !defined(__BORLANDC__)
@@ -125,6 +126,69 @@
     BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment);
     BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
 
+// Disabling for Visual C++ for now as it hasn't been tested yet.
+#if !defined(BOOST_NO_SFINAE_EXPR) // || BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 
+    // Specialization is only needed for Visual C++. Without it SFINAE doesn't
+    // kick in.
+    template <unsigned int>
+    struct expr_sfinae;
+    
+    template <>
+    struct expr_sfinae<sizeof(yes_type)> {
+        typedef yes_type type;
+    };
+    
+    template <typename T>
+    struct has_select_on_container_copy_construction
+    {
+        // This needs to be a template for Visual C++.
+        template <typename T2>
+        static yes_type to_yes_type(const T2&);
+
+        template <typename T2>
+        static typename expr_sfinae<sizeof(to_yes_type(
+            ((T2 const*)0)->select_on_container_copy_construction()
+        ))>::type check(T2*);
+
+        static no_type check(void*);
+        
+        enum { value = sizeof(check((T*) 0)) == sizeof(yes_type) };
+    };
+#else
+    template <typename T>
+    struct has_select_on_container_copy_construction
+    {
+        typedef T (T::*SelectFunc)() const;
+
+        template <SelectFunc e> struct sfinae { typedef yes_type type; };
+
+        template <class U>  
+        static typename sfinae<&U::select_on_container_copy_construction>::type
+            test(int);  
+        template <class U>  
+        static no_type test(...);  
+ 
+        enum { value = sizeof(test<T>(1)) == sizeof(yes_type) };
+    };
+
+#endif
+
+    template <typename Alloc>
+    inline BOOST_DEDUCED_TYPENAME boost::enable_if<
+            has_select_on_container_copy_construction<Alloc>, Alloc
+        >::type call_select_on_container_copy_construction(const Alloc& rhs)
+    {
+        return rhs.select_on_container_copy_construction();
+    }
+
+    template <typename Alloc>
+    inline BOOST_DEDUCED_TYPENAME boost::disable_if<
+            has_select_on_container_copy_construction<Alloc>, Alloc
+        >::type call_select_on_container_copy_construction(const Alloc& rhs)
+    {
+        return rhs;
+    }
+
     template <typename Alloc>
     struct allocator_traits
     {
@@ -197,10 +261,11 @@
             { return a.max_size(); }
 
         // Allocator propagation on construction
-
-        static Alloc select_on_container_copy_construction(const Alloc& rhs) {
-            //return BOOST_DEFAULT_FUNC(select_on_container_copy_construction,Alloc)(rhs);
-            return rhs;
+        
+        static Alloc select_on_container_copy_construction(Alloc const& rhs)
+        {
+            return boost::unordered::detail::
+                call_select_on_container_copy_construction(rhs);
         }
     
         // Allocator propagation on assignment and swap.
Modified: trunk/libs/unordered/test/helpers/memory.hpp
==============================================================================
--- trunk/libs/unordered/test/helpers/memory.hpp	(original)
+++ trunk/libs/unordered/test/helpers/memory.hpp	2011-08-15 03:48:53 EDT (Mon, 15 Aug 2011)
@@ -195,11 +195,19 @@
     };
 
     template <typename Alloc>
+    struct is_select_on_copy : false_type {};
+    template <typename Alloc>
     struct is_propagate_on_swap : false_type {};
     template <typename Alloc>
     struct is_propagate_on_assign : false_type {};
     template <typename Alloc>
     struct is_propagate_on_move : false_type {};
+
+    template <typename Alloc>
+    int selected_count(Alloc const&)
+    {
+        return 0;
+    }
 }
 
 #endif
Modified: trunk/libs/unordered/test/objects/cxx11_allocator.hpp
==============================================================================
--- trunk/libs/unordered/test/objects/cxx11_allocator.hpp	(original)
+++ trunk/libs/unordered/test/objects/cxx11_allocator.hpp	2011-08-15 03:48:53 EDT (Mon, 15 Aug 2011)
@@ -10,6 +10,7 @@
 #include <boost/limits.hpp>
 #include <cstddef>
 
+#include "../helpers/fwd.hpp"
 #include "../helpers/memory.hpp"
 
 namespace test
@@ -29,15 +30,6 @@
     };
     
     template <int Flag>
-    struct copy_allocator_base
-    {
-        // select_on_copy goes here.
-    };
-
-    template <>
-    struct copy_allocator_base<allocator_false> {};
-
-    template <int Flag>
     struct swap_allocator_base
     {
         struct propagate_on_container_swap {
@@ -76,14 +68,11 @@
         { force_equal_allocator_value = old_value_; }
     };
 
-    template <typename T, allocator_flags Flags = propagate_swap>
-    struct cxx11_allocator :
-        public copy_allocator_base<Flags & select_copy>,
-        public swap_allocator_base<Flags & propagate_swap>,
-        public assign_allocator_base<Flags & propagate_assign>,
-        public move_allocator_base<Flags & propagate_move>
+    template <typename T>
+    struct cxx11_allocator_base
     {
         int tag_;
+        int selected_;
 
         typedef std::size_t size_type;
         typedef std::ptrdiff_t difference_type;
@@ -93,29 +82,26 @@
         typedef T const& const_reference;
         typedef T value_type;
 
-        template <typename U> struct rebind {
-            typedef cxx11_allocator<U, Flags> other;
-        };
-
-        explicit cxx11_allocator(int t = 0) : tag_(t)
+        explicit cxx11_allocator_base(int t)
+            : tag_(t), selected_(0)
         {
             detail::tracker.allocator_ref();
         }
         
-        template <typename Y> cxx11_allocator(
-                cxx11_allocator<Y, Flags> const& x)
-            : tag_(x.tag_)
+        template <typename Y> cxx11_allocator_base(
+                cxx11_allocator_base<Y> const& x)
+            : tag_(x.tag_), selected_(x.selected_)
         {
             detail::tracker.allocator_ref();
         }
 
-        cxx11_allocator(cxx11_allocator const& x)
-            : tag_(x.tag_)
+        cxx11_allocator_base(cxx11_allocator_base const& x)
+            : tag_(x.tag_), selected_(x.selected_)
         {
             detail::tracker.allocator_ref();
         }
 
-        ~cxx11_allocator()
+        ~cxx11_allocator_base()
         {
             detail::tracker.allocator_unref();
         }
@@ -149,7 +135,7 @@
             // Note that tags will be tested
             // properly in the normal allocator.
             detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_,
-                (Flags & propagate_swap) ? true : false);
+                 !force_equal_allocator_value);
             ::operator delete((void*) p);
         }
 
@@ -173,12 +159,88 @@
         size_type max_size() const {
             return (std::numeric_limits<size_type>::max)();
         }
+    };
+
+    template <typename T, allocator_flags Flags = propagate_swap,
+        bool SelectCopy = (Flags & select_copy) ? true : false>
+    struct cxx11_allocator :
+        public cxx11_allocator_base<T>,
+        public swap_allocator_base<Flags & propagate_swap>,
+        public assign_allocator_base<Flags & propagate_assign>,
+        public move_allocator_base<Flags & propagate_move>
+    {
+        template <typename U> struct rebind {
+            typedef cxx11_allocator<U, Flags> other;
+        };
+
+        explicit cxx11_allocator(int t = 0)
+            : cxx11_allocator_base<T>(t)
+        {
+        }
+        
+        template <typename Y> cxx11_allocator(
+                cxx11_allocator<Y, Flags> const& x)
+            : cxx11_allocator_base<T>(x)
+        {
+        }
+
+        cxx11_allocator(cxx11_allocator const& x)
+            : cxx11_allocator_base<T>(x)
+        {
+        }
 
         // When not propagating swap, allocators are always equal
         // to avoid undefined behaviour.
         bool operator==(cxx11_allocator const& x) const
         {
-            return force_equal_allocator_value || (tag_ == x.tag_);
+            return force_equal_allocator_value || (this->tag_ == x.tag_);
+        }
+
+        bool operator!=(cxx11_allocator const& x) const
+        {
+            return !(*this == x);
+        }
+    };
+
+    template <typename T, allocator_flags Flags>
+    struct cxx11_allocator<T, Flags, true> : 
+        public cxx11_allocator_base<T>,
+        public swap_allocator_base<Flags & propagate_swap>,
+        public assign_allocator_base<Flags & propagate_assign>,
+        public move_allocator_base<Flags & propagate_move>
+    {
+        cxx11_allocator select_on_container_copy_construction() const
+        {
+            cxx11_allocator tmp(*this);
+            ++tmp.selected_;
+            return tmp;
+        }
+
+        template <typename U> struct rebind {
+            typedef cxx11_allocator<U, Flags> other;
+        };
+
+        explicit cxx11_allocator(int t = 0)
+            : cxx11_allocator_base<T>(t)
+        {
+        }
+        
+        template <typename Y> cxx11_allocator(
+                cxx11_allocator<Y, Flags> const& x)
+            : cxx11_allocator_base<T>(x)
+        {
+        }
+
+        cxx11_allocator(cxx11_allocator const& x)
+            : cxx11_allocator_base<T>(x)
+        {
+        }
+
+        // When not propagating swap, allocators are always equal
+        // to avoid undefined behaviour.
+        bool operator==(cxx11_allocator const& x) const
+        {
+            return force_equal_allocator_value || (this->tag_ == x.tag_);
         }
 
         bool operator!=(cxx11_allocator const& x) const
@@ -197,6 +259,9 @@
     }
 
     template <typename T, allocator_flags Flags>
+    struct is_select_on_copy<cxx11_allocator<T, Flags> >
+        : bool_type<(Flags & select_copy) ? true : false> {};
+    template <typename T, allocator_flags Flags>
     struct is_propagate_on_swap<cxx11_allocator<T, Flags> >
         : bool_type<(Flags & propagate_swap) ? true : false> {};
     template <typename T, allocator_flags Flags>
@@ -205,6 +270,12 @@
     template <typename T, allocator_flags Flags>
     struct is_propagate_on_move<cxx11_allocator<T, Flags> >
         : bool_type<(Flags & propagate_move) ? true : false> {};
+
+    template <typename T, allocator_flags Flags>
+    int selected_count(cxx11_allocator<T, Flags> const& x)
+    {
+        return x.selected_;
+    }
 }
 
 #endif
Modified: trunk/libs/unordered/test/objects/test.hpp
==============================================================================
--- trunk/libs/unordered/test/objects/test.hpp	(original)
+++ trunk/libs/unordered/test/objects/test.hpp	2011-08-15 03:48:53 EDT (Mon, 15 Aug 2011)
@@ -286,13 +286,6 @@
         }
     };
 
-    template <typename T>
-    struct is_propagate_on_swap<allocator<T> > : false_type {};
-    template <typename T>
-    struct is_propagate_on_assign<allocator<T> > : false_type {};
-    template <typename T>
-    struct is_propagate_on_move<allocator<T> > : false_type {};
-
     template <class T>
     bool equivalent_impl(allocator<T> const& x, allocator<T> const& y,
         test::derived_type)
Modified: trunk/libs/unordered/test/unordered/copy_tests.cpp
==============================================================================
--- trunk/libs/unordered/test/unordered/copy_tests.cpp	(original)
+++ trunk/libs/unordered/test/unordered/copy_tests.cpp	2011-08-15 03:48:53 EDT (Mon, 15 Aug 2011)
@@ -9,6 +9,7 @@
 #include <boost/unordered_map.hpp>
 #include "../helpers/test.hpp"
 #include "../objects/test.hpp"
+#include "../objects/cxx11_allocator.hpp"
 #include "../helpers/random_values.hpp"
 #include "../helpers/tracker.hpp"
 #include "../helpers/equivalent.hpp"
@@ -23,9 +24,11 @@
 void copy_construct_tests1(T*,
     test::random_generator const& generator = test::default_generator)
 {
+    typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
+
     BOOST_DEDUCED_TYPENAME T::hasher hf;
     BOOST_DEDUCED_TYPENAME T::key_equal eq;
-    BOOST_DEDUCED_TYPENAME T::allocator_type al;
+    BOOST_DEDUCED_TYPENAME T::allocator_type al;    
 
     {
         test::check_instances check_;
@@ -37,6 +40,8 @@
         BOOST_TEST(test::equivalent(y.key_eq(), eq));
         BOOST_TEST(test::equivalent(y.get_allocator(), al));
         BOOST_TEST(x.max_load_factor() == y.max_load_factor());
+        BOOST_TEST(test::selected_count(y.get_allocator()) ==
+            (test::is_select_on_copy<allocator_type>::value ? 1 : 0));
         test::check_equivalent_keys(y);
     }
 
@@ -49,6 +54,8 @@
         T y(x);
         test::unordered_equivalence_tester<T> equivalent(x);
         BOOST_TEST(equivalent(y));
+        BOOST_TEST(test::selected_count(y.get_allocator()) ==
+            (test::is_select_on_copy<allocator_type>::value ? 1 : 0));
         test::check_equivalent_keys(y);
     }
 
@@ -67,6 +74,8 @@
         BOOST_TEST(equivalent(y));
         // This isn't guaranteed:
         BOOST_TEST(y.load_factor() < y.max_load_factor());
+        BOOST_TEST(test::selected_count(y.get_allocator()) ==
+            (test::is_select_on_copy<allocator_type>::value ? 1 : 0));
         test::check_equivalent_keys(y);
     }
 }
@@ -81,6 +90,8 @@
     BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
     BOOST_DEDUCED_TYPENAME T::allocator_type al(1);
     BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
+    
+    typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
 
     {
         test::check_instances check_;
@@ -92,6 +103,8 @@
         BOOST_TEST(test::equivalent(y.key_eq(), eq));
         BOOST_TEST(test::equivalent(y.get_allocator(), al));
         BOOST_TEST(x.max_load_factor() == y.max_load_factor());
+        BOOST_TEST(test::selected_count(y.get_allocator()) ==
+            (test::is_select_on_copy<allocator_type>::value ? 1 : 0));
         test::check_equivalent_keys(y);
     }
 
@@ -105,6 +118,7 @@
         BOOST_TEST(test::equivalent(y.key_eq(), eq));
         BOOST_TEST(test::equivalent(y.get_allocator(), al2));
         BOOST_TEST(x.max_load_factor() == y.max_load_factor());
+        BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
         test::check_equivalent_keys(y);
     }
 
@@ -118,6 +132,8 @@
         test::unordered_equivalence_tester<T> equivalent(x);
         BOOST_TEST(equivalent(y));
         test::check_equivalent_keys(y);
+        BOOST_TEST(test::selected_count(y.get_allocator()) ==
+            (test::is_select_on_copy<allocator_type>::value ? 1 : 0));
         BOOST_TEST(test::equivalent(y.get_allocator(), al));
     }
 
@@ -131,6 +147,7 @@
         test::unordered_equivalence_tester<T> equivalent(x);
         BOOST_TEST(equivalent(y));
         test::check_equivalent_keys(y);
+        BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
         BOOST_TEST(test::equivalent(y.get_allocator(), al2));
     }
 }
@@ -148,15 +165,55 @@
     test::hash, test::equal_to,
     test::allocator<test::object> >* test_multimap;
 
+boost::unordered_set<test::object,
+        test::hash, test::equal_to,
+        test::cxx11_allocator<test::object, test::select_copy> >*
+    test_set_select_copy;
+boost::unordered_multiset<test::object,
+        test::hash, test::equal_to,
+        test::cxx11_allocator<test::object, test::select_copy> >*
+    test_multiset_select_copy;
+boost::unordered_map<test::object, test::object,
+        test::hash, test::equal_to,
+        test::cxx11_allocator<test::object, test::select_copy> >*
+    test_map_select_copy;
+boost::unordered_multimap<test::object, test::object,
+        test::hash, test::equal_to,
+        test::cxx11_allocator<test::object, test::select_copy> >*
+    test_multimap_select_copy;
+
+boost::unordered_set<test::object,
+        test::hash, test::equal_to,
+        test::cxx11_allocator<test::object, test::no_select_copy> >*
+    test_set_no_select_copy;
+boost::unordered_multiset<test::object,
+        test::hash, test::equal_to,
+        test::cxx11_allocator<test::object, test::no_select_copy> >*
+    test_multiset_no_select_copy;
+boost::unordered_map<test::object, test::object,
+        test::hash, test::equal_to,
+        test::cxx11_allocator<test::object, test::no_select_copy> >*
+    test_map_no_select_copy;
+boost::unordered_multimap<test::object, test::object,
+        test::hash, test::equal_to,
+        test::cxx11_allocator<test::object, test::no_select_copy> >*
+    test_multimap_no_select_copy;
+
 using test::default_generator;
 using test::generate_collisions;
 
-UNORDERED_TEST(copy_construct_tests1,
-    ((test_set)(test_multiset)(test_map)(test_multimap))
+UNORDERED_TEST(copy_construct_tests1, (
+        (test_set)(test_multiset)(test_map)(test_multimap)
+        (test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
+        (test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
+    )
 )
 
-UNORDERED_TEST(copy_construct_tests2,
-    ((test_set)(test_multiset)(test_map)(test_multimap))
+UNORDERED_TEST(copy_construct_tests2, (
+        (test_set)(test_multiset)(test_map)(test_multimap)
+        (test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
+        (test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
+    )
     ((default_generator)(generate_collisions))
 )