Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r74067 - in trunk: boost/unordered/detail libs/unordered/test/helpers libs/unordered/test/objects libs/unordered/test/unordered
From: dnljms_at_[hidden]
Date: 2011-08-26 04:11:48


Author: danieljames
Date: 2011-08-26 04:11:46 EDT (Fri, 26 Aug 2011)
New Revision: 74067
URL: http://svn.boost.org/trac/boost/changeset/74067

Log:
Unordered: More portable allocator_traits.
Added:
   trunk/libs/unordered/test/unordered/allocator_traits.cpp (contents, props changed)
Text files modified:
   trunk/boost/unordered/detail/allocator_helpers.hpp | 121 ++++++++++++++++++++++-----------------
   trunk/libs/unordered/test/helpers/memory.hpp | 9 ++
   trunk/libs/unordered/test/objects/cxx11_allocator.hpp | 17 +++-
   trunk/libs/unordered/test/objects/test.hpp | 4
   trunk/libs/unordered/test/unordered/Jamfile.v2 | 1
   5 files changed, 91 insertions(+), 61 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-26 04:11:46 EDT (Fri, 26 Aug 2011)
@@ -5,8 +5,8 @@
 // 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)
 //
-// Written by Daniel James using some code from Pablo Halpern's
-// allocator traits implementation.
+// Allocator traits written by Daniel James based on Pablo Halpern's
+// implementation.
 
 #ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
 #define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
@@ -18,6 +18,7 @@
 #include <boost/config.hpp>
 #include <boost/detail/select_type.hpp>
 #include <boost/utility/enable_if.hpp>
+#include <boost/preprocessor/cat.hpp>
 
 #if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
     && !defined(__BORLANDC__)
@@ -81,38 +82,39 @@
     };
 # endif
 
- struct convertible_from_anything
- {
- template<typename T> convertible_from_anything(T const&);
- };
+ template <typename T> T& make();
+ struct choice9 { typedef char (&type)[9]; };
+ struct choice8 : choice9 { typedef char (&type)[8]; };
+ struct choice7 : choice8 { typedef char (&type)[7]; };
+ struct choice6 : choice7 { typedef char (&type)[6]; };
+ struct choice5 : choice6 { typedef char (&type)[5]; };
+ struct choice4 : choice5 { typedef char (&type)[4]; };
+ struct choice3 : choice4 { typedef char (&type)[3]; };
+ struct choice2 : choice3 { typedef char (&type)[2]; };
+ struct choice1 : choice2 { typedef char (&type)[1]; };
+ choice1 choose();
 
- typedef char (&no_type)[1];
- typedef char (&yes_type)[2];
-
- template <typename T> struct sfinae {
- typedef yes_type type;
- };
-
- // Infrastructure for providing a default type for Tp::tname if absent.
     #define BOOST_DEFAULT_TYPE_TMPLT(tname) \
         template <typename Tp, typename Default> \
         struct default_type_ ## tname { \
- template <typename T> \
- static BOOST_DEDUCED_TYPENAME sfinae< \
- BOOST_DEDUCED_TYPENAME T::tname>::type test(int); \
- template <typename T> \
- static no_type test(long); \
                                                                             \
- enum { value = sizeof(test<Tp>(0)) == sizeof(yes_type) }; \
+ template <typename X> \
+ static choice1::type test(choice1, \
+ BOOST_DEDUCED_TYPENAME X::tname* = 0); \
+ \
+ template <typename X> \
+ static choice2::type test(choice2, void* = 0); \
                                                                             \
             struct DefaultWrap { typedef Default tname; }; \
                                                                             \
+ enum { value = (1 == sizeof(test<Tp>(choose()))) }; \
+ \
             typedef BOOST_DEDUCED_TYPENAME \
                 boost::detail::if_true<value>:: \
                 BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \
                 ::type::tname type; \
         }
-
+
     #define BOOST_DEFAULT_TYPE(T,tname, arg) \
         BOOST_DEDUCED_TYPENAME default_type_ ## tname<T, arg>::type
 
@@ -127,47 +129,62 @@
     BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
 
 #if !defined(BOOST_NO_SFINAE_EXPR) || BOOST_WORKAROUND(BOOST_MSVC, >= 1500)
- // 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, unsigned int> struct expr_test;
+ template <typename T> struct expr_test<T, sizeof(char)> : T {};
+ template <typename U> static char for_expr_test(U const&);
+
+#define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \
+ template <typename U> \
+ static typename expr_test< \
+ BOOST_PP_CAT(choice, result), \
+ sizeof(for_expr_test(((expression), 0)))>::type test( \
+ BOOST_PP_CAT(choice, count))
+
+#define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \
+ template <typename U> \
+ static BOOST_PP_CAT(choice, result)::type test( \
+ BOOST_PP_CAT(choice, count));
+
     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*);
+ BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, make<U const>().select_on_container_copy_construction());
+ BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2);
         
- enum { value = sizeof(check((T*) 0)) == sizeof(yes_type) };
+ enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };
     };
+
 #else
+
+ template <typename T> struct identity { typedef T type; };
+
+#define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \
+ \
+ typedef typename identity<member>::type BOOST_PP_CAT(check, count); \
+ \
+ template <BOOST_PP_CAT(check, count) e> \
+ struct BOOST_PP_CAT(test, count) { \
+ typedef void* type; \
+ }; \
+ \
+ template <class U> static BOOST_PP_CAT(choice, result)::type \
+ test(BOOST_PP_CAT(choice, count), \
+ typename BOOST_PP_CAT(test, count)< \
+ &U::name>::type = 0)
+
+#define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \
+ template <class U> static BOOST_PP_CAT(choice, result)::type \
+ test(BOOST_PP_CAT(choice, count), void* = 0)
+
+
     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(...);
+ BOOST_UNORDERED_CHECK_MEMBER(1, 1, select_on_container_copy_construction, T (T::*)() const);
+ BOOST_UNORDERED_DEFAULT_MEMBER(2, 2);
  
- enum { value = sizeof(test<T>(1)) == sizeof(yes_type) };
+ enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };
     };
 
 #endif

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-26 04:11:46 EDT (Fri, 26 Aug 2011)
@@ -194,8 +194,13 @@
         enum { value = false };
     };
 
- template <typename Alloc>
- int selected_count(Alloc const&)
+ struct convert_from_anything
+ {
+ template <typename T>
+ convert_from_anything(T const&) {}
+ };
+
+ int selected_count(convert_from_anything)
     {
         return 0;
     }

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-26 04:11:46 EDT (Fri, 26 Aug 2011)
@@ -186,9 +186,14 @@
     };
 
     template <typename T, typename Flags = propagate_swap,
- bool SelectCopy = Flags::is_select_on_copy ? true : false>
- struct cxx11_allocator :
- public cxx11_allocator_base<T>,
+ typename Enable = void>
+ struct cxx11_allocator;
+
+ template <typename T, typename Flags>
+ struct cxx11_allocator<
+ T, Flags,
+ typename boost::disable_if_c<Flags::is_select_on_copy>::type
+ > : public cxx11_allocator_base<T>,
         public swap_allocator_base<Flags>,
         public assign_allocator_base<Flags>,
         public move_allocator_base<Flags>,
@@ -228,8 +233,10 @@
     };
 
     template <typename T, typename Flags>
- struct cxx11_allocator<T, Flags, true> :
- public cxx11_allocator_base<T>,
+ struct cxx11_allocator<
+ T, Flags,
+ typename boost::enable_if_c<Flags::is_select_on_copy>::type
+ > : public cxx11_allocator_base<T>,
         public swap_allocator_base<Flags>,
         public assign_allocator_base<Flags>,
         public move_allocator_base<Flags>,

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-26 04:11:46 EDT (Fri, 26 Aug 2011)
@@ -26,7 +26,7 @@
     object generate(object const*);
     implicitly_convertible generate(implicitly_convertible const*);
     
- class object : globally_counted_object
+ class object : private globally_counted_object
     {
         friend class hash;
         friend class equal_to;
@@ -64,7 +64,7 @@
         }
     };
 
- class implicitly_convertible : globally_counted_object
+ class implicitly_convertible : private globally_counted_object
     {
         int tag1_, tag2_;
     public:

Modified: trunk/libs/unordered/test/unordered/Jamfile.v2
==============================================================================
--- trunk/libs/unordered/test/unordered/Jamfile.v2 (original)
+++ trunk/libs/unordered/test/unordered/Jamfile.v2 2011-08-26 04:11:46 EDT (Fri, 26 Aug 2011)
@@ -22,6 +22,7 @@
     :
         [ run fwd_set_test.cpp ]
         [ run fwd_map_test.cpp ]
+ [ run allocator_traits.cpp ]
         [ run compile_set.cpp ]
         [ run compile_map.cpp ]
         [ run link_test_1.cpp link_test_2.cpp ]

Added: trunk/libs/unordered/test/unordered/allocator_traits.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/unordered/test/unordered/allocator_traits.cpp 2011-08-26 04:11:46 EDT (Fri, 26 Aug 2011)
@@ -0,0 +1,226 @@
+
+// Copyright 2011 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 <boost/unordered/detail/allocator_helpers.hpp>
+#include <boost/detail/lightweight_test.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/mpl/assert.hpp>
+
+// Boilerplate
+
+#define ALLOCATOR_METHODS(name) \
+ template <typename U> struct rebind { \
+ typedef name<U> other; \
+ }; \
+ \
+ name() {} \
+ template <typename Y> name(name<Y> const&) {} \
+ T* address(T& r) { return &r;} \
+ T const* address(T const& r) { return &r; } \
+ T* allocate(std::size_t n) \
+ { return static_cast<T*>(::operator new(n * sizeof(T))); } \
+ T* allocate(std::size_t n, void const* u) \
+ { return static_cast<T*>(::operator new(n * sizeof(T))); } \
+ void deallocate(T* p, std::size_t n) { ::operator delete((void*) p); } \
+ void construct(T* p, T const& t) { new(p) T(t); } \
+ void destroy(T* p) { p->~T(); } \
+ std::size_t max_size() const \
+ { return (std::numeric_limits<std::size_t>::max)(); } \
+ bool operator==(name<T> const&) { return true; } \
+ bool operator!=(name<T> const&) { return false; } \
+/**/
+
+#define ALLOCATOR_METHODS_TYPEDEFS(name) \
+ template <typename U> struct rebind { \
+ typedef name<U> other; \
+ }; \
+ \
+ name() {} \
+ template <typename Y> name(name<Y> const&) {} \
+ pointer address(T& r) { return &r;} \
+ const_pointer address(T const& r) { return &r; } \
+ pointer allocate(std::size_t n) \
+ { return pointer(::operator new(n * sizeof(T))); } \
+ pointer allocate(std::size_t n, void const* u) \
+ { return pointer(::operator new(n * sizeof(T))); } \
+ void deallocate(pointer p, std::size_t n) \
+ { ::operator delete((void*) p); } \
+ void construct(T* p, T const& t) { new(p) T(t); } \
+ void destroy(T* p) { p->~T(); } \
+ size_type max_size() const \
+ { return (std::numeric_limits<size_type>::max)(); } \
+ bool operator==(name<T> const&) { return true; } \
+ bool operator!=(name<T> const&) { return false; } \
+/**/
+
+struct yes_type { enum { value = true }; };
+struct no_type { enum { value = false }; };
+
+// For tracking calls...
+
+static int selected;
+void reset() {
+ selected = 0;
+}
+
+template <typename Allocator>
+int call_select()
+{
+ typedef boost::unordered::detail::allocator_traits<Allocator> traits;
+ Allocator a;
+
+ reset();
+ BOOST_TEST(traits::select_on_container_copy_construction(a) == a);
+ return selected;
+}
+
+// Empty allocator test
+
+template <typename T>
+struct empty_allocator
+{
+ typedef T value_type;
+ ALLOCATOR_METHODS(empty_allocator)
+};
+
+void test_empty_allocator()
+{
+ typedef empty_allocator<int> allocator;
+ typedef boost::unordered::detail::allocator_traits<allocator> traits;
+ BOOST_MPL_ASSERT((boost::is_same<traits::size_type, std::size_t>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::pointer, int*>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::const_pointer, int const*>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::value_type, int>));
+ BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
+ BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
+ BOOST_TEST(!traits::propagate_on_container_swap::value);
+ BOOST_TEST(call_select<allocator>() == 0);
+}
+
+// allocator 1
+
+template <typename T>
+struct allocator1
+{
+ typedef T value_type;
+ ALLOCATOR_METHODS(allocator1)
+
+ typedef yes_type propagate_on_container_copy_assignment;
+ typedef yes_type propagate_on_container_move_assignment;
+ typedef yes_type propagate_on_container_swap;
+
+ allocator1<T> select_on_container_copy_construction() const {
+ ++selected;
+ return allocator1<T>();
+ }
+};
+
+void test_allocator1()
+{
+ typedef allocator1<int> allocator;
+ typedef boost::unordered::detail::allocator_traits<allocator> traits;
+ BOOST_MPL_ASSERT((boost::is_same<traits::size_type, std::size_t>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::pointer, int*>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::const_pointer, int const*>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::value_type, int>));
+ BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
+ BOOST_TEST(traits::propagate_on_container_move_assignment::value);
+ BOOST_TEST(traits::propagate_on_container_swap::value);
+ BOOST_TEST(call_select<allocator>() == 1);
+}
+
+// allocator 2
+
+template <typename T>
+struct allocator2
+{
+ typedef T value_type;
+ typedef T* pointer;
+ typedef T const* const_pointer;
+ typedef std::size_t size_type;
+
+ ALLOCATOR_METHODS(allocator2)
+
+ typedef no_type propagate_on_container_copy_assignment;
+ typedef no_type propagate_on_container_move_assignment;
+ typedef no_type propagate_on_container_swap;
+
+ // Note: Not const - so it shouldn't be called.
+ allocator2<T> select_on_container_copy_construction() {
+ ++selected;
+ return allocator2<T>();
+ }
+};
+
+void test_allocator2()
+{
+ typedef allocator2<int> allocator;
+ typedef boost::unordered::detail::allocator_traits<allocator> traits;
+ BOOST_MPL_ASSERT((boost::is_same<traits::size_type, std::size_t>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::pointer, int*>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::const_pointer, int const*>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::value_type, int>));
+ BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
+ BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
+ BOOST_TEST(!traits::propagate_on_container_swap::value);
+ BOOST_TEST(call_select<allocator>() == 0);
+}
+
+// allocator 3
+
+template <typename T>
+struct ptr
+{
+ T* value_;
+
+ ptr(void* v) : value_((T*) v) {}
+ T& operator*() const { return *value_; }
+};
+
+template <typename T>
+struct allocator3
+{
+ typedef T value_type;
+ typedef ptr<T> pointer;
+ typedef ptr<T const> const_pointer;
+ typedef unsigned short size_type;
+
+ ALLOCATOR_METHODS_TYPEDEFS(allocator3)
+
+ typedef yes_type propagate_on_container_copy_assignment;
+ typedef no_type propagate_on_container_move_assignment;
+
+ allocator3<T> select_on_container_copy_construction() const {
+ ++selected;
+ return allocator3<T>();
+ }
+};
+
+void test_allocator3()
+{
+ typedef allocator3<int> allocator;
+ typedef boost::unordered::detail::allocator_traits<allocator> traits;
+ BOOST_MPL_ASSERT((boost::is_same<traits::size_type, unsigned short>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>));
+ BOOST_MPL_ASSERT((boost::is_same<traits::pointer, ptr<int> >));
+ BOOST_MPL_ASSERT((boost::is_same<traits::const_pointer, ptr<int const> >));
+ BOOST_MPL_ASSERT((boost::is_same<traits::value_type, int>));
+ BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
+ BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
+ BOOST_TEST(!traits::propagate_on_container_swap::value);
+ BOOST_TEST(call_select<allocator>() == 1);
+}
+
+int main()
+{
+ test_empty_allocator();
+ test_allocator1();
+ test_allocator2();
+ test_allocator3();
+ return boost::report_errors();
+}


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