From eced4266c217a7a8c915d2e456038975efd0c914 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 3 Aug 2011 08:34:33 +0000 Subject: [PATCH] Unordered: Copy and assign using Boost.Move. [SVN r73503] --- doc/changes.qbk | 4 + include/boost/unordered/detail/buckets.hpp | 44 +++- include/boost/unordered/detail/move.hpp | 245 --------------------- include/boost/unordered/detail/table.hpp | 17 +- include/boost/unordered/detail/util.hpp | 1 + include/boost/unordered/unordered_map.hpp | 159 +++++-------- include/boost/unordered/unordered_set.hpp | 158 +++++-------- 7 files changed, 159 insertions(+), 469 deletions(-) delete mode 100644 include/boost/unordered/detail/move.hpp diff --git a/doc/changes.qbk b/doc/changes.qbk index 7fb950a6..9ae2f989 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -134,4 +134,8 @@ First official release. * Fix a bug when inserting into an `unordered_map` or `unordered_set` using iterators which returns `value_type` by copy. +[h2 Boost 1.48.0] + +* Use Boost.Move + [endsect] diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 7c41397d..d44a9e98 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -307,6 +307,7 @@ namespace boost { namespace unordered { namespace detail { } void copy_buckets_to(buckets&) const; + void move_buckets_to(buckets&) const; }; // Assigning and swapping the equality and hash function objects @@ -598,7 +599,7 @@ namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// // copy_buckets_to // - // basic excpetion safety. If an exception is thrown this will + // basic exception safety. If an exception is thrown this will // leave dst partially filled and the buckets unset. template @@ -635,6 +636,47 @@ namespace boost { namespace unordered { namespace detail { } } } + + //////////////////////////////////////////////////////////////////////////// + // move_buckets_to + // + // Basic exception safety. The source nodes are left in an unusable state + // if an exception throws. + + template + void buckets::move_buckets_to(buckets& dst) const + { + BOOST_ASSERT(!dst.buckets_); + + dst.create_buckets(); + bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_); + + { + node_constructor a(dst); + + node_ptr n = this->buckets_[this->bucket_count_].next_; + node_ptr prev = dst_start; + + while(n) { + std::size_t hash = node::get_hash(n); + node_ptr group_end = node::next_group(n); + + a.construct(boost::move(node::get_value(n))); + node_ptr first_node = a.release(); + node::set_hash(first_node, hash); + node_ptr end = prev->next_ = first_node; + + for(n = n->next_; n != group_end; n = n->next_) { + a.construct(boost::move(node::get_value(n))); + end = a.release(); + node::set_hash(end, hash); + node::add_after_node(end, first_node); + } + + prev = dst.place_in_bucket(prev, end); + } + } + } }}} #endif diff --git a/include/boost/unordered/detail/move.hpp b/include/boost/unordered/detail/move.hpp deleted file mode 100644 index 49fb2a92..00000000 --- a/include/boost/unordered/detail/move.hpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - Use, modification and distribution are subject to 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). -*/ - -/*************************************************************************************************/ - -#ifndef BOOST_UNORDERED_DETAIL_MOVE_HEADER -#define BOOST_UNORDERED_DETAIL_MOVE_HEADER - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/*************************************************************************************************/ - -#if defined(BOOST_NO_SFINAE) -# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN -#elif defined(__GNUC__) && \ - (__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3) -# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN -#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \ - BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \ - BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593)) -# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN -#endif - -/*************************************************************************************************/ - -namespace boost { -namespace unordered { -namespace detail { - -/*************************************************************************************************/ - -namespace move_detail { - -/*************************************************************************************************/ - -#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN) - -/*************************************************************************************************/ - -template -struct class_has_move_assign { - class type { - typedef T& (T::*E)(T t); - typedef char (&no_type)[1]; - typedef char (&yes_type)[2]; - template struct sfinae { typedef yes_type type; }; - template - static typename sfinae<&U::operator=>::type test(int); - template - static no_type test(...); - public: - enum {value = sizeof(test(1)) == sizeof(yes_type)}; - }; - }; - -/*************************************************************************************************/ - -template -struct has_move_assign : ::boost::mpl::and_, class_has_move_assign > {}; - -/*************************************************************************************************/ - -class test_can_convert_anything { }; - -/*************************************************************************************************/ - -#endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN - -/*************************************************************************************************/ - -/* - REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where - ::boost::is_convertible fails to compile. -*/ - -template -struct is_convertible : ::boost::mpl::or_< - ::boost::is_same, - ::boost::is_convertible -> { }; - -/*************************************************************************************************/ - -} //namespace move_detail - - -/*************************************************************************************************/ - -/*! -\ingroup move_related -\brief move_from is used for move_ctors. -*/ - -template -struct move_from -{ - explicit move_from(T& x) : source(x) { } - T& source; -private: - move_from& operator=(move_from const&); -}; - -/*************************************************************************************************/ - -#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN) - -/*************************************************************************************************/ - -/*! -\ingroup move_related -\brief The is_movable trait can be used to identify movable types. -*/ -template -struct is_movable : ::boost::mpl::and_< - ::boost::is_convertible, T>, - move_detail::has_move_assign, - ::boost::mpl::not_ > - > { }; - -/*************************************************************************************************/ - -#else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN - -// On compilers which don't have adequate SFINAE support, treat most types as unmovable, -// unless the trait is specialized. - -template -struct is_movable : ::boost::mpl::false_ { }; - -#endif - -/*************************************************************************************************/ - -#if !defined(BOOST_NO_SFINAE) - -/*************************************************************************************************/ - -/*! -\ingroup move_related -\brief copy_sink and move_sink are used to select between overloaded operations according to - whether type T is movable and convertible to type U. -\sa move -*/ - -template -struct copy_sink : ::boost::enable_if< - ::boost::mpl::and_< - ::boost::unordered::detail::move_detail::is_convertible, - ::boost::mpl::not_ > - >, - R - > -{ }; - -/*************************************************************************************************/ - -/*! -\ingroup move_related -\brief move_sink and copy_sink are used to select between overloaded operations according to - whether type T is movable and convertible to type U. - \sa move -*/ - -template -struct move_sink : ::boost::enable_if< - ::boost::mpl::and_< - ::boost::unordered::detail::move_detail::is_convertible, - is_movable - >, - R - > -{ }; - -/*************************************************************************************************/ - -/*! -\ingroup move_related -\brief This version of move is selected when T is_movable . It in turn calls the move -constructor. This call, with the help of the return value optimization, will cause x to be moved -instead of copied to its destination. See adobe/test/move/main.cpp for examples. - -*/ -template -T move(T& x, typename move_sink::type = 0) { return T(move_from(x)); } - -/*************************************************************************************************/ - -/*! -\ingroup move_related -\brief This version of move is selected when T is not movable . The net result will be that -x gets copied. -*/ -template -T& move(T& x, typename copy_sink::type = 0) { return x; } - -/*************************************************************************************************/ - -#else // BOOST_NO_SFINAE - -// On compilers without SFINAE, define copy_sink to always use the copy function. - -template -struct copy_sink -{ - typedef R type; -}; - -// Always copy the element unless this is overloaded. - -template -T& move(T& x) { - return x; -} - -#endif // BOOST_NO_SFINAE - -} // namespace detail -} // namespace unordered -} // namespace boost - -/*************************************************************************************************/ - -#endif - -/*************************************************************************************************/ diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 328b8d25..db4625cc 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -212,7 +212,7 @@ namespace boost { namespace unordered { namespace detail { this->partial_swap(x); } - table(table& x, node_allocator const& a, move_tag) + table(table& x, node_allocator const& a, move_tag m) : buckets(a, x.bucket_count_), functions(x), size_(0), @@ -223,8 +223,11 @@ namespace boost { namespace unordered { namespace detail { this->partial_swap(x); } else if(x.size_) { - x.copy_buckets_to(*this); - this->size_ = x.size_; + // Use a temporary table because move_buckets_to leaves the + // source container in a complete mess. + table tmp(x, m); + tmp.move_buckets_to(*this); + this->size_ = tmp.size_; this->max_load_ = calculate_max_load(); } } @@ -335,10 +338,14 @@ namespace boost { namespace unordered { namespace detail { else { // Create new buckets in separate buckets // which will clean up if anything throws an exception. - // (all can throw, but with no effect as these are new objects). buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); - if (x.size_) x.copy_buckets_to(b); + if (x.size_) { + // Use a temporary table because move_buckets_to leaves the + // source container in a complete mess. + table tmp(x, move_tag()); + tmp.move_buckets_to(b); + } // Start updating the data here, no throw from now on. this->size_ = x.size_; diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index fa86c65b..1147965a 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -27,6 +27,7 @@ #include #include #include +#include // Template parameters: // diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 251ae239..88574013 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -19,10 +19,6 @@ #include #include -#if defined(BOOST_NO_RVALUE_REFERENCES) -#include -#endif - #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) #include #endif @@ -43,6 +39,7 @@ namespace unordered template class unordered_map { + BOOST_COPYABLE_AND_MOVABLE(unordered_map) public: typedef K key_type; typedef std::pair value_type; @@ -129,19 +126,30 @@ namespace unordered ~unordered_map(); -#if !defined(BOOST_NO_RVALUE_REFERENCES) + unordered_map& operator=( + BOOST_COPY_ASSIGN_REF(unordered_map) x) + { + table_ = x.table_; + return *this; + } + + unordered_map& operator=( + BOOST_RV_REF(unordered_map) x) + { + table_.move(x.table_); + return *this; + } + + unordered_map(unordered_map const&); - unordered_map(unordered_map&&); + + unordered_map(BOOST_RV_REF(unordered_map) other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_map(unordered_map&&, allocator_type const&); - unordered_map& operator=(unordered_map const&); - unordered_map& operator=(unordered_map&&); -#else - unordered_map(::boost::unordered::detail::move_from< - unordered_map - >); -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_map& operator=(unordered_map); -#endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) @@ -368,6 +376,7 @@ namespace unordered template class unordered_multimap { + BOOST_COPYABLE_AND_MOVABLE(unordered_multimap) public: typedef K key_type; @@ -455,20 +464,29 @@ namespace unordered ~unordered_multimap(); -#if !defined(BOOST_NO_RVALUE_REFERENCES) - unordered_multimap(unordered_multimap const&); - unordered_multimap(unordered_multimap&&); - unordered_multimap(unordered_multimap&&, allocator_type const&); - unordered_multimap& operator=(unordered_multimap const&); - unordered_multimap& operator=(unordered_multimap&&); -#else - unordered_multimap(::boost::unordered::detail::move_from< - unordered_multimap - >); + unordered_multimap& operator=( + BOOST_COPY_ASSIGN_REF(unordered_multimap) x) + { + table_ = x.table_; + return *this; + } -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_multimap& operator=(unordered_multimap); -#endif + unordered_multimap& operator=( + BOOST_RV_REF(unordered_multimap) x) + { + table_.move(x.table_); + return *this; + } + + unordered_multimap(unordered_multimap const&); + + unordered_multimap(BOOST_RV_REF(unordered_multimap) other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + unordered_multimap(unordered_multimap&&, allocator_type const&); #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) @@ -751,18 +769,13 @@ namespace unordered template unordered_map::~unordered_map() {} -#if !defined(BOOST_NO_RVALUE_REFERENCES) template unordered_map::unordered_map(unordered_map const& other) : table_(other.table_) { } - template - unordered_map::unordered_map(unordered_map&& other) - : table_(other.table_, ::boost::unordered::detail::move_tag()) - { - } +#if !defined(BOOST_NO_RVALUE_REFERENCES) template unordered_map::unordered_map( @@ -771,42 +784,10 @@ namespace unordered { } - template - unordered_map& unordered_map:: - operator=(unordered_map const& x) - { - table_ = x.table_; - return *this; - } - - template - unordered_map& unordered_map:: - operator=(unordered_map&& x) - { - table_.move(x.table_); - return *this; - } -#else - template - unordered_map::unordered_map( - ::boost::unordered::detail::move_from > - other) - : table_(other.source.table_, ::boost::unordered::detail::move_tag()) - { - } - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - template - unordered_map& unordered_map:: - operator=(unordered_map x) - { - table_.move(x.table_); - return *this; - } -#endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template unordered_map::unordered_map( std::initializer_list list, size_type n, @@ -827,6 +808,7 @@ namespace unordered table_.insert_range(list.begin(), list.end()); return *this; } + #endif // size and capacity @@ -1203,7 +1185,6 @@ namespace unordered template unordered_multimap::~unordered_multimap() {} -#if !defined(BOOST_NO_RVALUE_REFERENCES) template unordered_multimap::unordered_multimap( unordered_multimap const& other) @@ -1211,12 +1192,7 @@ namespace unordered { } - template - unordered_multimap::unordered_multimap( - unordered_multimap&& other) - : table_(other.table_, ::boost::unordered::detail::move_tag()) - { - } +#if !defined(BOOST_NO_RVALUE_REFERENCES) template unordered_multimap::unordered_multimap( @@ -1225,41 +1201,6 @@ namespace unordered { } - template - unordered_multimap& unordered_multimap:: - operator=(unordered_multimap const& x) - { - table_ = x.table_; - return *this; - } - - template - unordered_multimap& unordered_multimap:: - operator=(unordered_multimap&& x) - { - table_.move(x.table_); - return *this; - } - -#else - - template - unordered_multimap::unordered_multimap( - ::boost::unordered::detail::move_from< - unordered_multimap > other) - : table_(other.source.table_, ::boost::unordered::detail::move_tag()) - { - } - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - template - unordered_multimap& unordered_multimap:: - operator=(unordered_multimap x) - { - table_.move(x.table_); - return *this; - } -#endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 4f4b0675..de5ea512 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -19,10 +19,6 @@ #include #include -#if defined(BOOST_NO_RVALUE_REFERENCES) -#include -#endif - #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) #include #endif @@ -43,6 +39,7 @@ namespace unordered template class unordered_set { + BOOST_COPYABLE_AND_MOVABLE(unordered_set) public: typedef T key_type; @@ -127,19 +124,29 @@ namespace unordered ~unordered_set(); -#if !defined(BOOST_NO_RVALUE_REFERENCES) + unordered_set& operator=( + BOOST_COPY_ASSIGN_REF(unordered_set) x) + { + table_ = x.table_; + return *this; + } + + unordered_set& operator=( + BOOST_RV_REF(unordered_set) x) + { + table_.move(x.table_); + return *this; + } + unordered_set(unordered_set const&); - unordered_set(unordered_set&&); + + unordered_set(BOOST_RV_REF(unordered_set) other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_set(unordered_set&&, allocator_type const&); - unordered_set& operator=(unordered_set const&); - unordered_set& operator=(unordered_set&&); -#else - unordered_set(::boost::unordered::detail::move_from< - unordered_set - >); -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_set& operator=(unordered_set); -#endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) @@ -349,6 +356,7 @@ namespace unordered template class unordered_multiset { + BOOST_COPYABLE_AND_MOVABLE(unordered_multiset) public: typedef T key_type; @@ -433,20 +441,29 @@ namespace unordered ~unordered_multiset(); -#if !defined(BOOST_NO_RVALUE_REFERENCES) - unordered_multiset(unordered_multiset const&); - unordered_multiset(unordered_multiset&&); - unordered_multiset(unordered_multiset&&, allocator_type const&); - unordered_multiset& operator=(unordered_multiset const&); - unordered_multiset& operator=(unordered_multiset&&); -#else - unordered_multiset(::boost::unordered::detail::move_from< - unordered_multiset - >); + unordered_multiset& operator=( + BOOST_COPY_ASSIGN_REF(unordered_multiset) x) + { + table_ = x.table_; + return *this; + } -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_multiset& operator=(unordered_multiset); -#endif + unordered_multiset& operator=( + BOOST_RV_REF(unordered_multiset) x) + { + table_.move(x.table_); + return *this; + } + + unordered_multiset(unordered_multiset const&); + + unordered_multiset(BOOST_RV_REF(unordered_multiset) other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + unordered_multiset(unordered_multiset&&, allocator_type const&); #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) @@ -716,18 +733,13 @@ namespace unordered template unordered_set::~unordered_set() {} -#if !defined(BOOST_NO_RVALUE_REFERENCES) template unordered_set::unordered_set(unordered_set const& other) : table_(other.table_) { } - template - unordered_set::unordered_set(unordered_set&& other) - : table_(other.table_, ::boost::unordered::detail::move_tag()) - { - } +#if !defined(BOOST_NO_RVALUE_REFERENCES) template unordered_set::unordered_set( @@ -736,42 +748,10 @@ namespace unordered { } - template - unordered_set& unordered_set:: - operator=(unordered_set const& x) - { - table_ = x.table_; - return *this; - } - - template - unordered_set& unordered_set:: - operator=(unordered_set&& x) - { - table_.move(x.table_); - return *this; - } -#else - template - unordered_set::unordered_set( - ::boost::unordered::detail::move_from > - other) - : table_(other.source.table_, ::boost::unordered::detail::move_tag()) - { - } - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - template - unordered_set& unordered_set:: - operator=(unordered_set x) - { - table_.move(x.table_); - return *this; - } -#endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template unordered_set::unordered_set( std::initializer_list list, size_type n, @@ -792,6 +772,7 @@ namespace unordered table_.insert_range(list.begin(), list.end()); return *this; } + #endif // size and capacity @@ -1114,7 +1095,6 @@ namespace unordered template unordered_multiset::~unordered_multiset() {} -#if !defined(BOOST_NO_RVALUE_REFERENCES) template unordered_multiset::unordered_multiset( unordered_multiset const& other) @@ -1122,12 +1102,7 @@ namespace unordered { } - template - unordered_multiset::unordered_multiset( - unordered_multiset&& other) - : table_(other.table_, ::boost::unordered::detail::move_tag()) - { - } +#if !defined(BOOST_NO_RVALUE_REFERENCES) template unordered_multiset::unordered_multiset( @@ -1136,41 +1111,6 @@ namespace unordered { } - template - unordered_multiset& unordered_multiset:: - operator=(unordered_multiset const& x) - { - table_ = x.table_; - return *this; - } - - template - unordered_multiset& unordered_multiset:: - operator=(unordered_multiset&& x) - { - table_.move(x.table_); - return *this; - } - -#else - - template - unordered_multiset::unordered_multiset( - ::boost::unordered::detail::move_from > - other) - : table_(other.source.table_, ::boost::unordered::detail::move_tag()) - { - } - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - template - unordered_multiset& unordered_multiset:: - operator=(unordered_multiset x) - { - table_.move(x.table_); - return *this; - } -#endif #endif #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)