Boost logo

Boost-Commit :

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))
 )
 


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