diff --git a/CMakeLists.txt b/CMakeLists.txt index 1499faa..8677ee8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.23 AND BOOST_HEAP_USE_FILE_SET) set(Headers include/boost/heap/detail/ilog2.hpp include/boost/heap/detail/heap_comparison.hpp + include/boost/heap/detail/heap_utils.hpp include/boost/heap/detail/mutable_heap.hpp include/boost/heap/detail/ordered_adaptor_iterator.hpp include/boost/heap/detail/stable_heap.hpp diff --git a/include/boost/heap/binomial_heap.hpp b/include/boost/heap/binomial_heap.hpp index 8609d13..a72b342 100644 --- a/include/boost/heap/binomial_heap.hpp +++ b/include/boost/heap/binomial_heap.hpp @@ -14,9 +14,11 @@ #include #include +#include #include #include +#include #include #include #include @@ -66,29 +68,10 @@ struct make_binomial_heap_base allocator_type( alloc ) {} - type( type const& rhs ) : - base_type( rhs ), - allocator_type( rhs ) - {} - - type( type&& rhs ) : - base_type( std::move( static_cast< base_type& >( rhs ) ) ), - allocator_type( std::move( static_cast< allocator_type& >( rhs ) ) ) - {} - - type& operator=( type&& rhs ) - { - base_type::operator=( std::move( static_cast< base_type& >( rhs ) ) ); - allocator_type::operator=( std::move( static_cast< allocator_type& >( rhs ) ) ); - return *this; - } - - type& operator=( type const& rhs ) - { - base_type::operator=( static_cast< base_type const& >( rhs ) ); - allocator_type::operator=( static_cast< allocator_type const& >( rhs ) ); - return *this; - } + type( type const& rhs ) = default; + type( type&& rhs ) = default; + type& operator=( type&& rhs ) = default; + type& operator=( type const& rhs ) = default; }; }; @@ -242,16 +225,8 @@ class binomial_heap : /// \copydoc boost::heap::priority_queue::operator=(priority_queue const &) binomial_heap& operator=( binomial_heap const& rhs ) { - if ( this == &rhs ) - return *this; - clear(); - size_holder::set_size( rhs.get_size() ); - static_cast< super_t& >( *this ) = rhs; - - if ( rhs.empty() ) - top_element = nullptr; - else - clone_forest( rhs ); + binomial_heap tmp( rhs ); + do_swap( tmp ); return *this; } @@ -265,7 +240,7 @@ class binomial_heap : } /// \copydoc boost::heap::priority_queue::operator=(priority_queue &&) - binomial_heap& operator=( binomial_heap&& rhs ) + binomial_heap& operator=( binomial_heap&& rhs ) noexcept( std::is_nothrow_move_assignable< super_t >::value ) { clear(); super_t::operator=( std::move( rhs ) ); @@ -327,11 +302,11 @@ class binomial_heap : } /// \copydoc boost::heap::priority_queue::swap - void swap( binomial_heap& rhs ) + BOOST_DEPRECATED( "Use std::swap instead" ) + void swap( binomial_heap& rhs ) noexcept( std::is_nothrow_move_constructible< binomial_heap >::value + && std::is_nothrow_move_assignable< binomial_heap >::value ) { - super_t::swap( rhs ); - std::swap( top_element, rhs.top_element ); - trees.swap( rhs.trees ); + do_swap( rhs ); } /// \copydoc boost::heap::priority_queue::top @@ -408,7 +383,7 @@ class binomial_heap : if ( trees.empty() ) { stability_counter_type stability_count = super_t::get_stability_count(); size_t size = constant_time_size ? size_holder::get_size() : 0; - swap( children ); + do_swap( children ); super_t::set_stability_count( stability_count ); if ( constant_time_size ) @@ -539,7 +514,7 @@ class binomial_heap : return; if ( empty() ) { - swap( rhs ); + do_swap( rhs ); return; } @@ -649,6 +624,12 @@ class binomial_heap : private: #if !defined( BOOST_DOXYGEN_INVOKED ) + void do_swap( binomial_heap& rhs ) noexcept( std::is_nothrow_move_constructible< binomial_heap >::value + && std::is_nothrow_move_assignable< binomial_heap >::value ) + { + detail::swap_via_move( *this, rhs ); + } + void merge_and_clear_nodes( binomial_heap& rhs ) { BOOST_HEAP_ASSERT( !empty() ); diff --git a/include/boost/heap/d_ary_heap.hpp b/include/boost/heap/d_ary_heap.hpp index 470e91e..4521ecb 100644 --- a/include/boost/heap/d_ary_heap.hpp +++ b/include/boost/heap/d_ary_heap.hpp @@ -14,8 +14,10 @@ #include #include +#include #include +#include #include #include #include @@ -54,7 +56,13 @@ typedef parameter::parameters< boost::parameter::required< tag::arity >, /* base class for d-ary heap */ template < typename T, class BoundArgs, class IndexUpdater > -class d_ary_heap : private make_heap_base< T, BoundArgs, false >::type +class d_ary_heap : +#ifndef BOOST_MSVC + private +#else + public +#endif + make_heap_base< T, BoundArgs, false >::type { typedef make_heap_base< T, BoundArgs, false > heap_base_maker; @@ -150,29 +158,10 @@ class d_ary_heap : private make_heap_base< T, BoundArgs, false >::type super_t( cmp ) {} - d_ary_heap( d_ary_heap const& rhs ) : - super_t( rhs ), - q_( rhs.q_ ) - {} - - d_ary_heap( d_ary_heap&& rhs ) : - super_t( std::move( rhs ) ), - q_( std::move( rhs.q_ ) ) - {} - - d_ary_heap& operator=( d_ary_heap&& rhs ) - { - super_t::operator=( std::move( rhs ) ); - q_ = std::move( rhs.q_ ); - return *this; - } - - d_ary_heap& operator=( d_ary_heap const& rhs ) - { - static_cast< super_t& >( *this ) = static_cast< super_t const& >( rhs ); - q_ = rhs.q_; - return *this; - } + d_ary_heap( d_ary_heap const& rhs ) = default; + d_ary_heap( d_ary_heap&& rhs ) = default; + d_ary_heap& operator=( d_ary_heap&& rhs ) = default; + d_ary_heap& operator=( d_ary_heap const& rhs ) = default; bool empty( void ) const { @@ -233,10 +222,13 @@ class d_ary_heap : private make_heap_base< T, BoundArgs, false >::type siftdown( 0 ); } - void swap( d_ary_heap& rhs ) + void do_swap( d_ary_heap& rhs ) noexcept( std::is_nothrow_move_constructible< super_t >::value + && std::is_nothrow_move_assignable< super_t >::value + && std::is_nothrow_move_constructible< container_type >::value + && std::is_nothrow_move_assignable< container_type >::value ) { - super_t::swap( rhs ); - q_.swap( rhs.q_ ); + super_t::do_swap( rhs ); + detail::swap_via_move( q_, rhs.q_ ); } iterator begin( void ) const @@ -509,26 +501,19 @@ class d_ary_heap : {} /// \copydoc boost::heap::priority_queue::priority_queue(priority_queue const &) - d_ary_heap( d_ary_heap const& rhs ) : - super_t( rhs ) - {} + d_ary_heap( d_ary_heap const& rhs ) = default; /// \copydoc boost::heap::priority_queue::priority_queue(priority_queue &&) - d_ary_heap( d_ary_heap&& rhs ) : - super_t( std::move( rhs ) ) - {} + d_ary_heap( d_ary_heap&& rhs ) = default; /// \copydoc boost::heap::priority_queue::operator=(priority_queue &&) - d_ary_heap& operator=( d_ary_heap&& rhs ) - { - super_t::operator=( std::move( rhs ) ); - return *this; - } + d_ary_heap& operator=( d_ary_heap&& rhs ) = default; /// \copydoc boost::heap::priority_queue::operator=(priority_queue const &) d_ary_heap& operator=( d_ary_heap const& rhs ) { - super_t::operator=( rhs ); + d_ary_heap tmp( rhs ); + do_swap( tmp ); return *this; } @@ -746,9 +731,10 @@ class d_ary_heap : } /// \copydoc boost::heap::priority_queue::swap + BOOST_DEPRECATED( "Use std::swap instead" ) void swap( d_ary_heap& rhs ) { - super_t::swap( rhs ); + do_swap( rhs ); } /// \copydoc boost::heap::priority_queue::begin @@ -798,6 +784,13 @@ class d_ary_heap : { return super_t::value_comp(); } + +private: + void do_swap( d_ary_heap& rhs ) noexcept( std::is_nothrow_move_constructible< super_t >::value + && std::is_nothrow_move_assignable< super_t >::value ) + { + super_t::do_swap( rhs ); + } }; }} // namespace boost::heap diff --git a/include/boost/heap/detail/heap_utils.hpp b/include/boost/heap/detail/heap_utils.hpp new file mode 100644 index 0000000..c1237ef --- /dev/null +++ b/include/boost/heap/detail/heap_utils.hpp @@ -0,0 +1,29 @@ +// boost heap: heap utilities +// +// Copyright (C) 2026 Tim Blechmann +// +// 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) + +#ifndef BOOST_HEAP_DETAIL_HEAP_UTILS_HPP +#define BOOST_HEAP_DETAIL_HEAP_UTILS_HPP + +#include +#include + +namespace boost { namespace heap { namespace detail { + + +template < typename T > +inline void swap_via_move( T& lhs, T& rhs ) noexcept( std::is_nothrow_move_constructible< T >::value + && std::is_nothrow_move_assignable< T >::value ) +{ + T tmp( std::move( lhs ) ); + lhs = std::move( rhs ); + rhs = std::move( tmp ); +} + +}}} // namespace boost::heap::detail + +#endif /* BOOST_HEAP_DETAIL_HEAP_UTILS_HPP */ diff --git a/include/boost/heap/detail/mutable_heap.hpp b/include/boost/heap/detail/mutable_heap.hpp index 0119358..afeaa59 100644 --- a/include/boost/heap/detail/mutable_heap.hpp +++ b/include/boost/heap/detail/mutable_heap.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -77,23 +78,13 @@ class priority_queue_mutable_wrapper public: struct handle_type { + handle_type() noexcept = default; + value_type& operator*() const { return iterator->first; } - handle_type( void ) - {} - - handle_type( handle_type const& rhs ) : - iterator( rhs.iterator ) - {} - - handle_type& operator=( handle_type const& rhs ) - { - iterator = rhs.iterator; - return *this; - } bool operator==( handle_type const& rhs ) const { @@ -155,11 +146,8 @@ class priority_queue_mutable_wrapper priority_queue_mutable_wrapper& operator=( priority_queue_mutable_wrapper const& rhs ) { - q_ = rhs.q_; - objects = rhs.objects; - q_.clear(); - for ( typename object_list::iterator it = objects.begin(); it != objects.end(); ++it ) - q_.push( it ); + priority_queue_mutable_wrapper tmp( rhs ); + do_swap( tmp ); return *this; } @@ -365,10 +353,10 @@ class priority_queue_mutable_wrapper return q_.get_allocator(); } - void swap( priority_queue_mutable_wrapper& rhs ) + void do_swap( priority_queue_mutable_wrapper& rhs ) { - objects.swap( rhs.objects ); - q_.swap( rhs.q_ ); + swap_via_move( objects, rhs.objects ); + q_.do_swap( rhs.q_ ); } const_reference top( void ) const diff --git a/include/boost/heap/detail/stable_heap.hpp b/include/boost/heap/detail/stable_heap.hpp index 2272068..4d145b2 100644 --- a/include/boost/heap/detail/stable_heap.hpp +++ b/include/boost/heap/detail/stable_heap.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -30,9 +31,7 @@ struct size_holder static const bool constant_time_size = ConstantSize; typedef SizeType size_type; - size_holder( void ) noexcept : - size_( 0 ) - {} + size_holder( void ) noexcept = default; size_holder( size_holder&& rhs ) noexcept : size_( rhs.size_ ) @@ -40,9 +39,7 @@ struct size_holder rhs.size_ = 0; } - size_holder( size_holder const& rhs ) noexcept : - size_( rhs.size_ ) - {} + size_holder( size_holder const& rhs ) noexcept = default; size_holder& operator=( size_holder&& rhs ) noexcept { @@ -51,11 +48,7 @@ struct size_holder return *this; } - size_holder& operator=( size_holder const& rhs ) noexcept - { - size_ = rhs.size_; - return *this; - } + size_holder& operator=( size_holder const& rhs ) noexcept = default; SizeType get_size() const noexcept { @@ -87,12 +80,12 @@ struct size_holder size_ -= value; } - void swap( size_holder& rhs ) noexcept + void do_swap( size_holder& rhs ) noexcept { - std::swap( size_, rhs.size_ ); + swap_via_move( *this, rhs ); } - SizeType size_; + SizeType size_ {}; }; template < class SizeType > @@ -101,25 +94,6 @@ struct size_holder< false, SizeType > static const bool constant_time_size = false; typedef SizeType size_type; - size_holder( void ) noexcept - {} - - size_holder( size_holder&& ) noexcept - {} - - size_holder( size_holder const& ) noexcept - {} - - size_holder& operator=( size_holder&& ) noexcept - { - return *this; - } - - size_holder& operator=( size_holder const& ) noexcept - { - return *this; - } - size_type get_size() const noexcept { return 0; @@ -140,18 +114,12 @@ struct size_holder< false, SizeType > void sub( SizeType /*value*/ ) noexcept {} - void swap( size_holder& /*rhs*/ ) noexcept + void do_swap( size_holder& /*rhs*/ ) noexcept {} }; -// note: MSVC does not implement lookup correctly, we therefore have to place the Cmp object as member inside the -// struct. of course, this prevents EBO and significantly reduces the readability of this code template < typename T, typename Cmp, bool constant_time_size, typename StabilityCounterType = boost::uintmax_t, bool stable = false > -struct heap_base : -#ifndef BOOST_MSVC - Cmp, -#endif - size_holder< constant_time_size, size_t > +struct heap_base : Cmp, size_holder< constant_time_size, size_t > { typedef StabilityCounterType stability_counter_type; typedef T value_type; @@ -161,38 +129,18 @@ struct heap_base : typedef Cmp internal_compare; static const bool is_stable = stable; -#ifdef BOOST_MSVC - Cmp cmp_; -#endif - heap_base( Cmp const& cmp = Cmp() ) : -#ifndef BOOST_MSVC Cmp( cmp ) -#else - cmp_( cmp ) -#endif {} heap_base( heap_base&& rhs ) noexcept( std::is_nothrow_move_constructible< Cmp >::value ) : -#ifndef BOOST_MSVC Cmp( std::move( static_cast< Cmp& >( rhs ) ) ), -#endif size_holder_type( std::move( static_cast< size_holder_type& >( rhs ) ) ) -#ifdef BOOST_MSVC - , - cmp_( std::move( rhs.cmp_ ) ) -#endif {} heap_base( heap_base const& rhs ) : -#ifndef BOOST_MSVC Cmp( static_cast< Cmp const& >( rhs ) ), -#endif size_holder_type( static_cast< size_holder_type const& >( rhs ) ) -#ifdef BOOST_MSVC - , - cmp_( rhs.value_comp() ) -#endif {} heap_base& operator=( heap_base&& rhs ) noexcept( std::is_nothrow_move_assignable< Cmp >::value ) @@ -242,11 +190,7 @@ struct heap_base : Cmp const& value_comp( void ) const noexcept { -#ifndef BOOST_MSVC return *this; -#else - return cmp_; -#endif } Cmp const& get_internal_cmp( void ) const noexcept @@ -254,11 +198,12 @@ struct heap_base : return value_comp(); } - void swap( heap_base& rhs ) noexcept( std::is_nothrow_move_constructible< Cmp >::value - && std::is_nothrow_move_assignable< Cmp >::value ) + void do_swap( heap_base& rhs ) noexcept( std::is_nothrow_move_constructible< Cmp >::value + && std::is_nothrow_move_assignable< Cmp >::value ) { - std::swap( value_comp_ref(), rhs.value_comp_ref() ); - size_holder< constant_time_size, size_t >::swap( rhs ); + heap_base tmp( std::move( rhs ) ); + rhs = std::move( *this ); + *this = std::move( tmp ); } stability_counter_type get_stability_count( void ) const noexcept @@ -275,20 +220,14 @@ struct heap_base : private: Cmp& value_comp_ref( void ) { -#ifndef BOOST_MSVC return *this; -#else - return cmp_; -#endif } }; template < typename T, typename Cmp, bool constant_time_size, typename StabilityCounterType > struct heap_base< T, Cmp, constant_time_size, StabilityCounterType, true > : -#ifndef BOOST_MSVC Cmp, -#endif size_holder< constant_time_size, size_t > { typedef StabilityCounterType stability_counter_type; @@ -314,41 +253,19 @@ struct heap_base< T, Cmp, constant_time_size, StabilityCounterType, true > : typedef size_holder< constant_time_size, size_t > size_holder_type; typedef Cmp value_compare; -#ifdef BOOST_MSVC - Cmp cmp_; -#endif - heap_base( Cmp const& cmp = Cmp() ) : -#ifndef BOOST_MSVC Cmp( cmp ), -#else - cmp_( cmp ), -#endif counter_( 0 ) {} - heap_base( heap_base&& rhs ) noexcept( std::is_nothrow_move_constructible< Cmp >::value ) : -#ifndef BOOST_MSVC - Cmp( std::move( static_cast< Cmp& >( rhs ) ) ), -#else - cmp_( std::move( rhs.cmp_ ) ), -#endif - size_holder_type( std::move( static_cast< size_holder_type& >( rhs ) ) ), - counter_( rhs.counter_ ) + heap_base( heap_base const& rhs ) = default; + heap_base& operator=( heap_base const& rhs ) = default; + + heap_base( heap_base&& rhs ) noexcept( std::is_nothrow_move_constructible< Cmp >::value ) { - rhs.counter_ = 0; + *this = std::move( rhs ); } - heap_base( heap_base const& rhs ) : -#ifndef BOOST_MSVC - Cmp( static_cast< Cmp const& >( rhs ) ), -#else - cmp_( rhs.value_comp() ), -#endif - size_holder_type( static_cast< size_holder_type const& >( rhs ) ), - counter_( rhs.counter_ ) - {} - heap_base& operator=( heap_base&& rhs ) noexcept( std::is_nothrow_move_assignable< Cmp >::value ) { value_comp_ref().operator=( std::move( rhs.value_comp_ref() ) ); @@ -359,14 +276,6 @@ struct heap_base< T, Cmp, constant_time_size, StabilityCounterType, true > : return *this; } - heap_base& operator=( heap_base const& rhs ) - { - value_comp_ref().operator=( rhs.value_comp() ); - size_holder_type::operator=( static_cast< size_holder_type const& >( rhs ) ); - - counter_ = rhs.counter_; - return *this; - } bool operator()( internal_type const& lhs, internal_type const& rhs ) const { @@ -407,11 +316,7 @@ struct heap_base< T, Cmp, constant_time_size, StabilityCounterType, true > : Cmp const& value_comp( void ) const noexcept { -#ifndef BOOST_MSVC return *this; -#else - return cmp_; -#endif } struct internal_compare : Cmp @@ -437,16 +342,12 @@ struct heap_base< T, Cmp, constant_time_size, StabilityCounterType, true > : return internal_compare( value_comp() ); } - void swap( heap_base& rhs ) noexcept( std::is_nothrow_move_constructible< Cmp >::value - && std::is_nothrow_move_assignable< Cmp >::value ) + void do_swap( heap_base& rhs ) noexcept( std::is_nothrow_move_constructible< Cmp >::value + && std::is_nothrow_move_assignable< Cmp >::value ) { -#ifndef BOOST_MSVC - std::swap( static_cast< Cmp& >( *this ), static_cast< Cmp& >( rhs ) ); -#else - std::swap( cmp_, rhs.cmp_ ); -#endif - std::swap( counter_, rhs.counter_ ); - size_holder< constant_time_size, size_t >::swap( rhs ); + heap_base tmp( std::move( rhs ) ); + rhs = std::move( *this ); + *this = std::move( tmp ); } stability_counter_type get_stability_count( void ) const @@ -465,11 +366,7 @@ struct heap_base< T, Cmp, constant_time_size, StabilityCounterType, true > : private: Cmp& value_comp_ref( void ) noexcept { -#ifndef BOOST_MSVC return *this; -#else - return cmp_; -#endif } stability_counter_type counter_; diff --git a/include/boost/heap/detail/tree_iterator.hpp b/include/boost/heap/detail/tree_iterator.hpp index 02ceb5e..07e3b6f 100644 --- a/include/boost/heap/detail/tree_iterator.hpp +++ b/include/boost/heap/detail/tree_iterator.hpp @@ -90,7 +90,7 @@ struct ordered_tree_iterator_storage : ValueExtractor { struct compare_values_by_handle : ValueCompare { - compare_values_by_handle( ValueCompare const& cmp ) : + explicit compare_values_by_handle( ValueCompare const& cmp ) : ValueCompare( cmp ) {} diff --git a/include/boost/heap/fibonacci_heap.hpp b/include/boost/heap/fibonacci_heap.hpp index a6e9768..5dcafca 100644 --- a/include/boost/heap/fibonacci_heap.hpp +++ b/include/boost/heap/fibonacci_heap.hpp @@ -15,9 +15,11 @@ #include #include +#include #include #include +#include #include #include #include @@ -246,7 +248,7 @@ class fibonacci_heap : } /// \copydoc boost::heap::priority_queue::operator=(priority_queue &&) - fibonacci_heap& operator=( fibonacci_heap&& rhs ) + fibonacci_heap& operator=( fibonacci_heap&& rhs ) noexcept( std::is_nothrow_move_assignable< super_t >::value ) { clear(); @@ -260,16 +262,8 @@ class fibonacci_heap : /// \copydoc boost::heap::priority_queue::operator=(priority_queue const &) fibonacci_heap& operator=( fibonacci_heap const& rhs ) { - if ( this == &rhs ) - return *this; - clear(); - size_holder::set_size( rhs.size() ); - static_cast< super_t& >( *this ) = rhs; - - if ( rhs.empty() ) - top_element = nullptr; - else - clone_forest( rhs ); + fibonacci_heap tmp( rhs ); + do_swap( tmp ); return *this; } @@ -323,11 +317,11 @@ class fibonacci_heap : } /// \copydoc boost::heap::priority_queue::swap - void swap( fibonacci_heap& rhs ) + BOOST_DEPRECATED( "Use std::swap instead" ) + void swap( fibonacci_heap& rhs ) noexcept( std::is_nothrow_move_constructible< fibonacci_heap >::value + && std::is_nothrow_move_assignable< fibonacci_heap >::value ) { - super_t::swap( rhs ); - std::swap( top_element, rhs.top_element ); - roots.swap( rhs.roots ); + do_swap( rhs ); } @@ -654,6 +648,12 @@ class fibonacci_heap : private: #if !defined( BOOST_DOXYGEN_INVOKED ) + void do_swap( fibonacci_heap& rhs ) noexcept( std::is_nothrow_move_constructible< fibonacci_heap >::value + && std::is_nothrow_move_assignable< fibonacci_heap >::value ) + { + detail::swap_via_move( *this, rhs ); + } + void clone_forest( fibonacci_heap const& rhs ) { BOOST_HEAP_ASSERT( roots.empty() ); diff --git a/include/boost/heap/heap_concepts.hpp b/include/boost/heap/heap_concepts.hpp index 502ee26..5484052 100644 --- a/include/boost/heap/heap_concepts.hpp +++ b/include/boost/heap/heap_concepts.hpp @@ -10,6 +10,7 @@ #define BOOST_HEAP_CONCEPTS_HPP #include +#include namespace boost { namespace heap { @@ -34,7 +35,7 @@ struct PriorityQueue : boost::ForwardContainer< C > BOOST_CONCEPT_ASSERT( (boost::Const_BinaryPredicate< value_compare, value_type, value_type >)); - c.swap( c2 ); + std::swap( c, c2 ); c.clear(); a = c.get_allocator(); diff --git a/include/boost/heap/pairing_heap.hpp b/include/boost/heap/pairing_heap.hpp index b47b305..e2c860a 100644 --- a/include/boost/heap/pairing_heap.hpp +++ b/include/boost/heap/pairing_heap.hpp @@ -14,9 +14,11 @@ #include #include +#include #include #include +#include #include #include #include @@ -256,8 +258,9 @@ class pairing_heap : } /// \copydoc boost::heap::priority_queue::operator=(priority_queue &&) - pairing_heap& operator=( pairing_heap&& rhs ) + pairing_heap& operator=( pairing_heap&& rhs ) noexcept( std::is_nothrow_move_assignable< super_t >::value ) { + clear(); super_t::operator=( std::move( rhs ) ); root = rhs.root; rhs.root = nullptr; @@ -267,13 +270,8 @@ class pairing_heap : /// \copydoc boost::heap::priority_queue::operator=(priority_queue const & rhs) pairing_heap& operator=( pairing_heap const& rhs ) { - if ( this == &rhs ) - return *this; - clear(); - size_holder::set_size( rhs.get_size() ); - static_cast< super_t& >( *this ) = rhs; - - clone_tree( rhs ); + pairing_heap tmp( rhs ); + do_swap( tmp ); return *this; } @@ -328,10 +326,11 @@ class pairing_heap : } /// \copydoc boost::heap::priority_queue::swap - void swap( pairing_heap& rhs ) + BOOST_DEPRECATED( "Use std::swap instead" ) + void swap( pairing_heap& rhs ) noexcept( std::is_nothrow_move_constructible< pairing_heap >::value + && std::is_nothrow_move_assignable< pairing_heap >::value ) { - super_t::swap( rhs ); - std::swap( root, rhs.root ); + do_swap( rhs ); } @@ -654,6 +653,12 @@ class pairing_heap : private: #if !defined( BOOST_DOXYGEN_INVOKED ) + void do_swap( pairing_heap& rhs ) noexcept( std::is_nothrow_move_constructible< pairing_heap >::value + && std::is_nothrow_move_assignable< pairing_heap >::value ) + { + detail::swap_via_move( *this, rhs ); + } + void clone_tree( pairing_heap const& rhs ) { BOOST_HEAP_ASSERT( root == nullptr ); diff --git a/include/boost/heap/priority_queue.hpp b/include/boost/heap/priority_queue.hpp index b27577d..98afcc8 100644 --- a/include/boost/heap/priority_queue.hpp +++ b/include/boost/heap/priority_queue.hpp @@ -14,8 +14,10 @@ #include #include +#include #include +#include #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -132,10 +134,7 @@ class priority_queue : * \b Complexity: Linear. * * */ - priority_queue( priority_queue const& rhs ) : - super_t( rhs ), - q_( rhs.q_ ) - {} + priority_queue( priority_queue const& rhs ) = default; /** * \b Effects: C++11-style move constructor. @@ -143,10 +142,7 @@ class priority_queue : * \b Complexity: Constant. * * */ - priority_queue( priority_queue&& rhs ) noexcept( std::is_nothrow_move_constructible< super_t >::value ) : - super_t( std::move( rhs ) ), - q_( std::move( rhs.q_ ) ) - {} + priority_queue( priority_queue&& rhs ) noexcept( std::is_nothrow_move_constructible< super_t >::value ) = default; /** * \b Effects: C++11-style move assignment. @@ -155,11 +151,7 @@ class priority_queue : * * */ priority_queue& operator=( priority_queue&& rhs ) noexcept( std::is_nothrow_move_assignable< super_t >::value ) - { - super_t::operator=( std::move( rhs ) ); - q_ = std::move( rhs.q_ ); - return *this; - } + = default; /** * \b Effects: Assigns priority queue from rhs. @@ -169,8 +161,8 @@ class priority_queue : * */ priority_queue& operator=( priority_queue const& rhs ) { - static_cast< super_t& >( *this ) = static_cast< super_t const& >( rhs ); - q_ = rhs.q_; + priority_queue tmp( rhs ); + do_swap( tmp ); return *this; } @@ -284,12 +276,13 @@ class priority_queue : * * \b Complexity: Constant. * + * \deprecated Use \c std::swap instead. * */ + BOOST_DEPRECATED( "Use std::swap instead" ) void swap( priority_queue& rhs ) noexcept( std::is_nothrow_move_constructible< super_t >::value && std::is_nothrow_move_assignable< super_t >::value ) { - super_t::swap( rhs ); - q_.swap( rhs.q_ ); + do_swap( rhs ); } /** @@ -407,6 +400,14 @@ class priority_queue : { return !( *this == rhs ); } + +private: + void do_swap( priority_queue& rhs ) noexcept( std::is_nothrow_move_constructible< super_t >::value + && std::is_nothrow_move_assignable< super_t >::value ) + { + super_t::do_swap( rhs ); + detail::swap_via_move( q_, rhs.q_ ); + } }; }} // namespace boost::heap diff --git a/include/boost/heap/skew_heap.hpp b/include/boost/heap/skew_heap.hpp index 19f437d..ecce872 100644 --- a/include/boost/heap/skew_heap.hpp +++ b/include/boost/heap/skew_heap.hpp @@ -15,9 +15,11 @@ #include #include +#include #include #include +#include #include #include @@ -377,13 +379,8 @@ class skew_heap : /// \copydoc boost::heap::priority_queue::operator=(priority_queue const & rhs) skew_heap& operator=( skew_heap const& rhs ) { - if ( this == &rhs ) - return *this; - clear(); - size_holder::set_size( rhs.get_size() ); - static_cast< super_t& >( *this ) = rhs; - - clone_tree( rhs ); + skew_heap tmp( rhs ); + do_swap( tmp ); return *this; } @@ -396,8 +393,9 @@ class skew_heap : } /// \copydoc boost::heap::priority_queue::operator=(priority_queue &&) - skew_heap& operator=( skew_heap&& rhs ) + skew_heap& operator=( skew_heap&& rhs ) noexcept( std::is_nothrow_move_assignable< super_t >::value ) { + clear(); super_t::operator=( std::move( rhs ) ); root = rhs.root; rhs.root = nullptr; @@ -480,10 +478,11 @@ class skew_heap : } /// \copydoc boost::heap::priority_queue::swap - void swap( skew_heap& rhs ) + BOOST_DEPRECATED( "Use std::swap instead" ) + void swap( skew_heap& rhs ) noexcept( std::is_nothrow_move_constructible< skew_heap >::value + && std::is_nothrow_move_assignable< skew_heap >::value ) { - super_t::swap( rhs ); - std::swap( root, rhs.root ); + do_swap( rhs ); } /// \copydoc boost::heap::priority_queue::top @@ -753,6 +752,12 @@ class skew_heap : private: #if !defined( BOOST_DOXYGEN_INVOKED ) + void do_swap( skew_heap& rhs ) noexcept( std::is_nothrow_move_constructible< skew_heap >::value + && std::is_nothrow_move_assignable< skew_heap >::value ) + { + detail::swap_via_move( *this, rhs ); + } + struct push_void { static void push( skew_heap* self, const_reference v ) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index aa1dace..db1c5c4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -45,6 +45,7 @@ foreach(Test ${Tests}) set (Libs Boost::heap Boost::unit_test_framework Boost::container + Boost::mpl boost_heap_test_common) source_group( TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${Test}.cpp) diff --git a/test/move_only_types_test.cpp b/test/move_only_types_test.cpp index 55bf0e2..f855c8e 100644 --- a/test/move_only_types_test.cpp +++ b/test/move_only_types_test.cpp @@ -7,6 +7,7 @@ =============================================================================*/ #define BOOST_TEST_MAIN +#include #include #include @@ -128,6 +129,30 @@ void test_move_only_move_semantics( void ) BOOST_REQUIRE_EQUAL( pq2.top().value, 30 ); } +typedef boost::mpl::list< boost::heap::binomial_heap< MoveOnlyInt >, + boost::heap::binomial_heap< MoveOnlyInt, boost::heap::stable< true > >, + boost::heap::fibonacci_heap< MoveOnlyInt >, + boost::heap::fibonacci_heap< MoveOnlyInt, boost::heap::stable< true > >, + boost::heap::pairing_heap< MoveOnlyInt >, + boost::heap::pairing_heap< MoveOnlyInt, boost::heap::stable< true > >, + boost::heap::skew_heap< MoveOnlyInt >, + boost::heap::skew_heap< MoveOnlyInt, boost::heap::stable< true > >, + boost::heap::d_ary_heap< MoveOnlyInt, boost::heap::arity< 4 > >, + boost::heap::d_ary_heap< MoveOnlyInt, boost::heap::arity< 4 >, boost::heap::stable< true > > > + default_heaps; + +BOOST_AUTO_TEST_CASE_TEMPLATE( move_only_basic, Heap, default_heaps ) +{ + test_move_only_basic< Heap >(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( move_only_emplace_temporary, Heap, default_heaps ) +{ + test_move_only_emplace_temporary< Heap >(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + struct CustomCompare { bool operator()( MoveOnlyInt const& lhs, MoveOnlyInt const& rhs ) const @@ -150,103 +175,21 @@ void test_move_only_custom_compare( void ) BOOST_REQUIRE_EQUAL( pq.top().value, 5 ); } -BOOST_AUTO_TEST_CASE( move_only_binomial_heap_basic ) -{ - test_move_only_basic< boost::heap::binomial_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_binomial_heap_emplace_temporary ) -{ - test_move_only_emplace_temporary< boost::heap::binomial_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_binomial_heap_move_semantics ) -{ - test_move_only_move_semantics< boost::heap::binomial_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_binomial_heap_custom_compare ) -{ - test_move_only_custom_compare< boost::heap::binomial_heap< MoveOnlyInt, boost::heap::compare< CustomCompare > > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_fibonacci_heap_basic ) -{ - test_move_only_basic< boost::heap::fibonacci_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_fibonacci_heap_emplace_temporary ) -{ - test_move_only_emplace_temporary< boost::heap::fibonacci_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_fibonacci_heap_move_semantics ) -{ - test_move_only_move_semantics< boost::heap::fibonacci_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_fibonacci_heap_custom_compare ) -{ - test_move_only_custom_compare< boost::heap::fibonacci_heap< MoveOnlyInt, boost::heap::compare< CustomCompare > > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_pairing_heap_basic ) -{ - test_move_only_basic< boost::heap::pairing_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_pairing_heap_emplace_temporary ) -{ - test_move_only_emplace_temporary< boost::heap::pairing_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_pairing_heap_move_semantics ) -{ - test_move_only_move_semantics< boost::heap::pairing_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_pairing_heap_custom_compare ) -{ - test_move_only_custom_compare< boost::heap::pairing_heap< MoveOnlyInt, boost::heap::compare< CustomCompare > > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_skew_heap_basic ) -{ - test_move_only_basic< boost::heap::skew_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_skew_heap_emplace_temporary ) -{ - test_move_only_emplace_temporary< boost::heap::skew_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_skew_heap_move_semantics ) -{ - test_move_only_move_semantics< boost::heap::skew_heap< MoveOnlyInt > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_skew_heap_custom_compare ) -{ - test_move_only_custom_compare< boost::heap::skew_heap< MoveOnlyInt, boost::heap::compare< CustomCompare > > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_d_ary_heap_basic ) -{ - test_move_only_basic< boost::heap::d_ary_heap< MoveOnlyInt, boost::heap::arity< 4 > > >(); -} - -BOOST_AUTO_TEST_CASE( move_only_d_ary_heap_emplace_temporary ) -{ - test_move_only_emplace_temporary< boost::heap::d_ary_heap< MoveOnlyInt, boost::heap::arity< 4 > > >(); -} +// Heaps with custom comparator +typedef boost::mpl::list< + boost::heap::binomial_heap< MoveOnlyInt, boost::heap::compare< CustomCompare > >, + boost::heap::fibonacci_heap< MoveOnlyInt, boost::heap::compare< CustomCompare > >, + boost::heap::pairing_heap< MoveOnlyInt, boost::heap::compare< CustomCompare > >, + boost::heap::skew_heap< MoveOnlyInt, boost::heap::compare< CustomCompare > >, + boost::heap::d_ary_heap< MoveOnlyInt, boost::heap::arity< 4 >, boost::heap::compare< CustomCompare > > > + custom_heaps; -BOOST_AUTO_TEST_CASE( move_only_d_ary_heap_move_semantics ) +BOOST_AUTO_TEST_CASE_TEMPLATE( move_only_move_semantics, Heap, default_heaps ) { - test_move_only_move_semantics< boost::heap::d_ary_heap< MoveOnlyInt, boost::heap::arity< 4 > > >(); + test_move_only_move_semantics< Heap >(); } -BOOST_AUTO_TEST_CASE( move_only_d_ary_heap_custom_compare ) +BOOST_AUTO_TEST_CASE_TEMPLATE( move_only_custom_compare, Heap, custom_heaps ) { - test_move_only_custom_compare< - boost::heap::d_ary_heap< MoveOnlyInt, boost::heap::arity< 4 >, boost::heap::compare< CustomCompare > > >(); + test_move_only_custom_compare< Heap >(); }