From 995ef1efdb2410a1909269abef246b0741f4f0e6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 6 May 2012 12:29:24 +0000 Subject: [PATCH] Unordered: Use std::allocator_trait's variadic construct. [SVN r78349] --- .../unordered/detail/allocator_helpers.hpp | 225 +++++++++++++----- include/boost/unordered/detail/buckets.hpp | 94 ++++---- .../boost/unordered/detail/emplace_args.hpp | 36 +++ include/boost/unordered/detail/equivalent.hpp | 42 +++- include/boost/unordered/detail/unique.hpp | 40 +++- 5 files changed, 332 insertions(+), 105 deletions(-) diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index c4da2e68..dd92373a 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -15,14 +15,7 @@ # pragma once #endif -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include @@ -31,23 +24,29 @@ # if defined(__GXX_EXPERIMENTAL_CXX0X__) && \ (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) # define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 -# elif BOOST_MSVC >= 1700 && defined(_CPPLIB_VER) -# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 +# elif defined(BOOST_MSVC) +# if BOOST_MSVC < 1400 + // Use container's allocator_traits for older versions of Visual + // C++ as I don't test with them. +# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2 +# elif BOOST_MSVC >= 1700 +# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 +# endif # endif - -// Use container's allocator_traits for older versions of Visual C++ as I don't -// test with them. -# if defined(BOOST_MSVC) && BOOST_MSVC < 1400 -# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2 -# endif - #endif #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) # define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 #endif -#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 +# include +# include +# include +# if defined(BOOST_NO_SFINAE_EXPR) +# include +# endif +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 # include #elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 # include @@ -57,6 +56,7 @@ # include #endif + namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// @@ -98,43 +98,10 @@ namespace boost { namespace unordered { namespace detail { #endif //////////////////////////////////////////////////////////////////////////// - // Bits and pieces for implementing traits - // - // Some of these are also used elsewhere - - template typename boost::add_lvalue_reference::type 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 choice1::type yes_type; - typedef choice2::type no_type; - - struct private_type - { - private_type const &operator,(int) const; - }; - - template - no_type is_private_type(T const&); - yes_type is_private_type(private_type const&); - - struct convert_from_anything { - template - convert_from_anything(T const&); - }; + // Expression test mechanism #if !defined(BOOST_NO_SFINAE_EXPR) -# define BOOST_UNORDERED_HAVE_CALL_DETECTION 1 - template struct expr_test; template struct expr_test : T {}; template static char for_expr_test(U const&); @@ -165,8 +132,6 @@ namespace boost { namespace unordered { namespace detail { #else -# define BOOST_UNORDERED_HAVE_CALL_DETECTION 0 - template struct identity { typedef T type; }; #define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \ @@ -209,12 +174,11 @@ namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// // Allocator traits - // - // Uses the standard versions if available. - // (although untested as I don't have access to a standard version yet) #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 +#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 + template struct allocator_traits : std::allocator_traits {}; @@ -227,6 +191,8 @@ namespace boost { namespace unordered { namespace detail { #elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 +#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 + template struct allocator_traits : boost::container::allocator_traits {}; @@ -239,6 +205,13 @@ namespace boost { namespace unordered { namespace detail { #else +#if defined(BOOST_UNORDERED_VARIADIC_MOVE) +# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 +#else +# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 +#endif + + // TODO: Does this match std::allocator_traits::rebind_alloc? template struct rebind_wrap @@ -309,7 +282,7 @@ namespace boost { namespace unordered { namespace detail { BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment); BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap); -#if BOOST_UNORDERED_HAVE_CALL_DETECTION +#if !defined(BOOST_NO_SFINAE_EXPR) template BOOST_UNORDERED_HAS_FUNCTION( select_on_container_copy_construction, U const, (), 0 @@ -320,12 +293,21 @@ namespace boost { namespace unordered { namespace detail { max_size, U const, (), 0 ); +# if defined(BOOST_UNORDERED_VARIADIC_MOVE) + template + BOOST_UNORDERED_HAS_FUNCTION( + construct, U, ( + boost::unordered::detail::make(), + boost::unordered::detail::make()...), 2 + ); +# else template BOOST_UNORDERED_HAS_FUNCTION( construct, U, ( boost::unordered::detail::make(), boost::unordered::detail::make()), 2 ); +# endif template BOOST_UNORDERED_HAS_FUNCTION( @@ -425,7 +407,27 @@ namespace boost { namespace unordered { namespace detail { public: - // Only supporting the basic copy constructor for now. +#if defined(BOOST_UNORDERED_VARIADIC_MOVE) + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_construct + ::value>::type + construct(Alloc& a, T* p, Args&&... x) + { + a.construct(p, boost::forward(x)...); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_construct + ::value>::type + construct(Alloc&, T* p, Args&&... x) + { + new ((void*) p) T(boost::forward(x)...); + } + +#elif !defined(BOOST_NO_SFINAE_EXPR) template static typename boost::enable_if_c< @@ -443,6 +445,34 @@ namespace boost { namespace unordered { namespace detail { new ((void*) p) T(x); } +#else + + // If we don't have SFINAE expressions, only construct the type + // that matches the allocator. + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_construct::value && + boost::is_same::value + >::type + construct(Alloc& a, T* p, T const& x) + { + a.construct(p, x); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_construct::value && + boost::is_same::value + >::type + construct(Alloc&, T* p, T const& x) + { + new ((void*) p) T(x); + } + +#endif + +#if defined(BOOST_UNORDERED_VARIADIC_MOVE) template static typename boost::enable_if_c< boost::unordered::detail::has_destroy::value>::type @@ -459,6 +489,48 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::destroy(p); } +#elif !defined(BOOST_NO_SFINAE_EXPR) + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_destroy::value>::type + destroy(Alloc& a, T* p) + { + a.destroy(p); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_destroy::value>::type + destroy(Alloc&, T* p) + { + boost::unordered::detail::destroy(p); + } + +#else + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_destroy::value && + boost::is_same::value + >::type + destroy(Alloc& a, T* p) + { + a.destroy(p); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_destroy::value && + boost::is_same::value + >::type + destroy(Alloc&, T* p) + { + boost::unordered::detail::destroy(p); + } + +#endif + static size_type max_size(const Alloc& a) { return boost::unordered::detail::call_max_size(a); @@ -488,6 +560,41 @@ namespace boost { namespace unordered { namespace detail { #undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT #undef BOOST_UNORDERED_DEFAULT_TYPE +#endif + +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + template + inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS) + { + boost::unordered::detail::allocator_traits::construct( + a, p, BOOST_UNORDERED_EMPLACE_FORWARD); + } + + template + inline void destroy_node(Alloc& a, T* p) + { + boost::unordered::detail::allocator_traits::destroy(a, p); + } +#else + template + inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS) + { + boost::unordered::detail::allocator_traits::construct(a, p, T()); + try { + boost::unordered::detail::construct_impl( + p->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); + } catch(...) { + boost::unordered::detail::allocator_traits::destroy(a, p); + throw; + } + } + + template + inline void destroy_node(Alloc& a, T* p) + { + boost::unordered::detail::destroy(p->value_ptr()); + boost::unordered::detail::allocator_traits::destroy(a, p); + } #endif // array_constructor diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 9ee1343c..5132ec3e 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -54,16 +53,14 @@ namespace boost { namespace unordered { namespace detail { node_allocator& alloc_; node_pointer node_; - bool node_constructed_; - bool value_constructed_; + bool constructed_; public: node_constructor(node_allocator& n) : alloc_(n), node_(), - node_constructed_(false), - value_constructed_(false) + constructed_(false) { } @@ -74,26 +71,40 @@ namespace boost { namespace unordered { namespace detail { template void construct_value(BOOST_UNORDERED_EMPLACE_ARGS) { - BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); - boost::unordered::detail::construct_impl( - node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); - value_constructed_ = true; + BOOST_ASSERT(node_ && !constructed_); + boost::unordered::detail::construct_node(alloc_, + boost::addressof(*node_), BOOST_UNORDERED_EMPLACE_FORWARD); + node_->init(static_cast(node_)); + constructed_ = true; } template void construct_value2(BOOST_FWD_REF(A0) a0) { - BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); - boost::unordered::detail::construct_impl2( - node_->value_ptr(), boost::forward(a0)); - value_constructed_ = true; + BOOST_ASSERT(node_ && !constructed_); +# if defined(BOOST_UNORDERED_VARIADIC_MOVE) + boost::unordered::detail::construct_node(alloc_, + boost::addressof(*node_), boost::forward(a0)); +# else + boost::unordered::detail::construct_node(alloc_, + boost::addressof(*node_), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))); +# endif + constructed_ = true; + node_->init(static_cast(node_)); } value_type const& value() const { - BOOST_ASSERT(node_ && node_constructed_ && value_constructed_); + BOOST_ASSERT(node_ && constructed_); return node_->value(); } + node_pointer get() + { + return node_; + } + // no throw node_pointer release() { @@ -111,12 +122,8 @@ namespace boost { namespace unordered { namespace detail { node_constructor::~node_constructor() { if (node_) { - if (value_constructed_) { - boost::unordered::detail::destroy(node_->value_ptr()); - } - - if (node_constructed_) { - node_allocator_traits::destroy(alloc_, + if (constructed_) { + boost::unordered::detail::destroy_node(alloc_, boost::addressof(*node_)); } @@ -128,24 +135,13 @@ namespace boost { namespace unordered { namespace detail { void node_constructor::construct_node() { if(!node_) { - node_constructed_ = false; - value_constructed_ = false; - + constructed_ = false; node_ = node_allocator_traits::allocate(alloc_, 1); - - node_allocator_traits::construct(alloc_, - boost::addressof(*node_), node()); - node_->init(static_cast(node_)); - node_constructed_ = true; } - else { - BOOST_ASSERT(node_constructed_); - - if (value_constructed_) - { - boost::unordered::detail::destroy(node_->value_ptr()); - value_constructed_ = false; - } + else if (constructed_) { + boost::unordered::detail::destroy_node(alloc_, + boost::addressof(*node_)); + constructed_ = false; } } @@ -183,6 +179,16 @@ namespace boost { namespace unordered { namespace detail { enum { extra_node = false }; }; + + template + struct node_base + { + typedef LinkPointer link_pointer; + link_pointer next_; + + node_base() : next_() {} + }; + }}} namespace boost { namespace unordered { namespace iterator_detail { @@ -718,6 +724,14 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(this->node_alloc()); a.construct_node(); + // Since this node is just to mark the beginning it doesn't + // contain a value, so just construct node::node_base + // which containers the pointer to the next element. + node_allocator_traits::construct(node_alloc(), + static_cast( + boost::addressof(*a.get())), + typename node::node_base()); + (constructor.get() + static_cast(this->bucket_count_))->next_ = a.release(); @@ -762,9 +776,8 @@ namespace boost { namespace unordered { namespace detail { inline void delete_node(c_iterator n) { - boost::unordered::detail::destroy(n.node_->value_ptr()); - node_allocator_traits::destroy(node_alloc(), - boost::addressof(*n.node_)); + boost::unordered::detail::destroy_node( + node_alloc(), boost::addressof(*n.node_)); node_allocator_traits::deallocate(node_alloc(), n.node_, 1); --size_; } @@ -786,7 +799,8 @@ namespace boost { namespace unordered { namespace detail { inline void delete_extra_node(bucket_pointer) {} inline void delete_extra_node(node_pointer n) { - node_allocator_traits::destroy(node_alloc(), boost::addressof(*n)); + node_allocator_traits::destroy(node_alloc(), + static_cast(boost::addressof(*n))); node_allocator_traits::deallocate(node_alloc(), n, 1); } diff --git a/include/boost/unordered/detail/emplace_args.hpp b/include/boost/unordered/detail/emplace_args.hpp index be2339fe..493130d5 100644 --- a/include/boost/unordered/detail/emplace_args.hpp +++ b/include/boost/unordered/detail/emplace_args.hpp @@ -12,6 +12,7 @@ # pragma once #endif +#include #include #include #include @@ -21,7 +22,10 @@ #include #include #include +#include #include +#include +#include #include #if !defined(BOOST_NO_0X_HDR_TUPLE) @@ -45,6 +49,38 @@ namespace boost { namespace unordered { namespace detail { + //////////////////////////////////////////////////////////////////////////// + // Bits and pieces for implementing traits + + template typename boost::add_lvalue_reference::type 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 choice1::type yes_type; + typedef choice2::type no_type; + + struct private_type + { + private_type const &operator,(int) const; + }; + + template + no_type is_private_type(T const&); + yes_type is_private_type(private_type const&); + + struct convert_from_anything { + template + convert_from_anything(T const&); + }; + //////////////////////////////////////////////////////////////////////////// // emplace_args // diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index ba58c8a2..6dc23eaf 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -12,7 +12,6 @@ #endif #include -#include #include namespace boost { namespace unordered { namespace detail { @@ -23,20 +22,40 @@ namespace boost { namespace unordered { namespace detail { template struct grouped_node : + boost::unordered::detail::node_base< + typename ::boost::unordered::detail::rebind_wrap< + A, grouped_node >::type::pointer + >, boost::unordered::detail::value_base { typedef typename ::boost::unordered::detail::rebind_wrap< A, grouped_node >::type::pointer link_pointer; + typedef boost::unordered::detail::node_base node_base; - link_pointer next_; link_pointer group_prev_; std::size_t hash_; +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + template + grouped_node(BOOST_UNORDERED_EMPLACE_ARGS) : + node_base(), + group_prev_(), + hash_(0) + { + boost::unordered::detail::construct_impl( + this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); + } + + ~grouped_node() { + boost::unordered::detail::destroy(this->value_ptr()); + } +#else grouped_node() : - next_(), + node_base(), group_prev_(), hash_(0) {} +#endif void init(link_pointer self) { @@ -50,16 +69,33 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::ptr_bucket { typedef boost::unordered::detail::ptr_bucket bucket_base; + typedef bucket_base node_base; typedef ptr_bucket* link_pointer; link_pointer group_prev_; std::size_t hash_; +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + template + grouped_ptr_node(BOOST_UNORDERED_EMPLACE_ARGS) : + bucket_base(), + group_prev_(0), + hash_(0) + { + boost::unordered::detail::construct_impl( + this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); + } + + ~grouped_ptr_node() { + boost::unordered::detail::destroy(this->value_ptr()); + } +#else grouped_ptr_node() : bucket_base(), group_prev_(0), hash_(0) {} +#endif void init(link_pointer self) { diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 84fef433..6b9db4b8 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -12,7 +12,6 @@ #endif #include -#include #include #include #include @@ -25,18 +24,37 @@ namespace boost { namespace unordered { namespace detail { template struct node : + boost::unordered::detail::node_base< + typename ::boost::unordered::detail::rebind_wrap< + A, node >::type::pointer + >, boost::unordered::detail::value_base { typedef typename ::boost::unordered::detail::rebind_wrap< A, node >::type::pointer link_pointer; + typedef boost::unordered::detail::node_base node_base; - link_pointer next_; std::size_t hash_; +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + template + node(BOOST_UNORDERED_EMPLACE_ARGS) : + node_base(), + hash_(0) + { + boost::unordered::detail::construct_impl( + this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); + } + + ~node() { + boost::unordered::detail::destroy(this->value_ptr()); + } +#else node() : - next_(), + node_base(), hash_(0) {} +#endif void init(link_pointer) { @@ -49,14 +67,30 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::ptr_bucket { typedef boost::unordered::detail::ptr_bucket bucket_base; + typedef bucket_base node_base; typedef ptr_bucket* link_pointer; std::size_t hash_; +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + template + ptr_node(BOOST_UNORDERED_EMPLACE_ARGS) : + bucket_base(), + hash_(0) + { + boost::unordered::detail::construct_impl( + this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); + } + + ~ptr_node() { + boost::unordered::detail::destroy(this->value_ptr()); + } +#else ptr_node() : bucket_base(), hash_(0) {} +#endif void init(link_pointer) {