diff --git a/doc/heap.qbk b/doc/heap.qbk index 827aeda..7354268 100644 --- a/doc/heap.qbk +++ b/doc/heap.qbk @@ -342,6 +342,12 @@ _heap_ provides the following data structures: constraints for the tree structure, all heap operations can be performed in O(log n). ] ] + + [[[classref boost::heap::min_max_heap]] + [ + [@https://en.wikipedia.org/wiki/Min-max_heap Min-max heaps] are a combination of a min heap and max heap in the same tree structure that allow to retrieve both the maximum and the minimum in constant time. + ] + ] ] [table Comparison of amortized complexity @@ -355,6 +361,7 @@ _heap_ provides the following data structures: [[[classref boost::heap::pairing_heap]] [[^O(1)]] [O(2**2*log(log(N)))] [O(log(N))] [O(2**2*log(log(N)))] [O(2**2*log(log(N)))] [O(2**2*log(log(N)))] [O(2**2*log(log(N)))] [O(2**2*log(log(N)))]] [[[classref boost::heap::skew_heap]] [[^O(1)]] [O(log(N))] [O(log(N))] [O(log(N))] [O(log(N))] [O(log(N))] [O(log(N))] [O(log(N+M))]] + [[[classref boost::heap::min_max_heap]] [[^O(1)]] [O(log(N))] [O(log(N))] [O(log(N))] [O(log(N))] [O(log(N))] [O(log(N))] [O((N+M)*log(N+M))]] ] @@ -392,7 +399,7 @@ The data structures can be configured with [@boost:/libs/parameter/doc/html/inde ] [[[classref boost::heap::arity]] - [Specifies the arity of a d-ary heap. For details, please consult the class reference of [classref boost::heap::d_ary_heap]] + [Specifies the arity of a d-ary or a min-max heap. For details, please consult the class reference of [classref boost::heap::d_ary_heap] and [classref boost::heap::min_max_heap].] ] [[[classref boost::heap::store_parent_pointer]] diff --git a/include/boost/heap/d_ary_heap.hpp b/include/boost/heap/d_ary_heap.hpp index 6e54c8c..a81d696 100644 --- a/include/boost/heap/d_ary_heap.hpp +++ b/include/boost/heap/d_ary_heap.hpp @@ -38,13 +38,6 @@ namespace boost { namespace heap { namespace detail { -struct nop_index_updater -{ - template - static void run(T &, std::size_t) - {} -}; - typedef parameter::parameters, boost::parameter::optional, boost::parameter::optional, diff --git a/include/boost/heap/detail/ilog2.hpp b/include/boost/heap/detail/ilog2.hpp index c6b65c6..791ca95 100644 --- a/include/boost/heap/detail/ilog2.hpp +++ b/include/boost/heap/detail/ilog2.hpp @@ -33,7 +33,7 @@ struct log2 { unsigned int operator()(unsigned int value) { - return sizeof(unsigned int)*8 - __builtin_clz(value - 1); + return sizeof(unsigned int)*8 - __builtin_clz(value) - 1; } }; @@ -42,7 +42,7 @@ struct log2 { unsigned long operator()(unsigned long value) { - return sizeof(unsigned long)*8 - __builtin_clzl(value - 1); + return sizeof(unsigned long)*8 - __builtin_clzl(value) - 1; } }; diff --git a/include/boost/heap/detail/mutable_heap.hpp b/include/boost/heap/detail/mutable_heap.hpp index 0fc0c5c..7a2b004 100644 --- a/include/boost/heap/detail/mutable_heap.hpp +++ b/include/boost/heap/detail/mutable_heap.hpp @@ -23,6 +23,13 @@ namespace boost { namespace heap { namespace detail { +struct nop_index_updater +{ + template + static void run(T &, std::size_t) + {} +}; + /* wrapper for a mutable heap container adaptors * * this wrapper introduces an additional indirection. the heap is not constructed from objects, @@ -44,7 +51,7 @@ class priority_queue_mutable_wrapper typedef typename PriorityQueueType::const_pointer const_pointer; static const bool is_stable = PriorityQueueType::is_stable; -private: +protected: typedef std::pair node_type; typedef std::list::type> object_list; @@ -111,7 +118,7 @@ class priority_queue_mutable_wrapper friend class priority_queue_mutable_wrapper; }; -private: +protected: struct indirect_cmp: public value_compare { @@ -214,52 +221,61 @@ class priority_queue_mutable_wrapper typedef typename object_list::difference_type difference_type; - class ordered_iterator: - public boost::iterator_adaptor + class ordered_iterator_facade: + public boost::iterator_adaptor, - q_type::ordered_iterator_dispatcher + >, + public Dispatcher { - typedef boost::iterator_adaptor adaptor_type; typedef const_list_iterator iterator; - typedef typename q_type::ordered_iterator_dispatcher ordered_iterator_dispatcher; + typedef Dispatcher iterator_dispatcher; friend class boost::iterator_core_access; public: - ordered_iterator(void): - adaptor_type(0), unvisited_nodes(indirect_cmp()), q_(NULL) + ordered_iterator_facade(void): + adaptor_type(0), unvisited_nodes(IndirectCmp()), q_(NULL) {} - ordered_iterator(const priority_queue_mutable_wrapper * q, indirect_cmp const & cmp): + ordered_iterator_facade(const Wrapper * q, IndirectCmp const & cmp): adaptor_type(0), unvisited_nodes(cmp), q_(q) {} - ordered_iterator(const_list_iterator it, const priority_queue_mutable_wrapper * q, indirect_cmp const & cmp): + ordered_iterator_facade(const_list_iterator it, const Wrapper * q, IndirectCmp const & cmp): adaptor_type(it), unvisited_nodes(cmp), q_(q) { if (it != q->objects.end()) - discover_nodes(it); + static_cast(this)->discover_nodes(it); } - bool operator!=(ordered_iterator const & rhs) const + ordered_iterator_facade(const_list_iterator it, const Wrapper * q, IndirectCmp const & cmp, Dispatcher const & dispatcher): + adaptor_type(it), Dispatcher(dispatcher), unvisited_nodes(cmp), q_(q) + { + if (it != q->objects.end()) + static_cast(this)->discover_nodes(it); + } + + bool operator!=(ordered_iterator_facade const & rhs) const { return adaptor_type::base() != rhs.base(); } - bool operator==(ordered_iterator const & rhs) const + bool operator==(ordered_iterator_facade const & rhs) const { return !operator!=(rhs); } - private: + protected: void increment(void) { if (unvisited_nodes.empty()) @@ -267,7 +283,7 @@ class priority_queue_mutable_wrapper else { iterator next = unvisited_nodes.top(); unvisited_nodes.pop(); - discover_nodes(next); + static_cast(this)->discover_nodes(next); adaptor_type::base_reference() = next; } } @@ -276,30 +292,56 @@ class priority_queue_mutable_wrapper { return adaptor_type::base()->first; } + + std::priority_queue::type>, + IndirectCmp + > unvisited_nodes; + const Wrapper * q_; + }; - void discover_nodes(iterator current) + class ordered_iterator : public ordered_iterator_facade + { + typedef ordered_iterator_facade facade; + + public: + ordered_iterator(void): + facade() + {} + + ordered_iterator(const priority_queue_mutable_wrapper * q, indirect_cmp const & cmp): + facade(q, cmp) + {} + + ordered_iterator(const_list_iterator it, const priority_queue_mutable_wrapper * q, indirect_cmp const & cmp): + facade(it, q, cmp) + {} + + void discover_nodes(typename facade::iterator current) { size_type current_index = current->second; - const q_type * q = &(q_->q_); + const q_type * q = &(facade::q_->q_); - if (ordered_iterator_dispatcher::is_leaf(q, current_index)) + if (facade::iterator_dispatcher::is_leaf(q, current_index)) return; - std::pair child_range = ordered_iterator_dispatcher::get_child_nodes(q, current_index); + std::pair child_range = facade::iterator_dispatcher::get_child_nodes(q, current_index); for (size_type i = child_range.first; i <= child_range.second; ++i) { - typename q_type::internal_type const & internal_value_at_index = ordered_iterator_dispatcher::get_internal_value(q, i); - typename q_type::value_type const & value_at_index = q_->q_.get_value(internal_value_at_index); + typename q_type::internal_type const & internal_value_at_index = facade::iterator_dispatcher::get_internal_value(q, i); + typename q_type::value_type const & value_at_index = facade::q_->q_.get_value(internal_value_at_index); - unvisited_nodes.push(value_at_index); + facade::unvisited_nodes.push(value_at_index); } } - - std::priority_queue::type>, - indirect_cmp - > unvisited_nodes; - const priority_queue_mutable_wrapper * q_; }; bool empty(void) const @@ -516,6 +558,239 @@ class priority_queue_mutable_wrapper } }; +template +class double_ended_priority_queue_mutable_wrapper: + public priority_queue_mutable_wrapper +{ + typedef priority_queue_mutable_wrapper super_t; + typedef typename super_t::value_compare base_value_compare; + + struct indirect_reverse_cmp: public base_value_compare + { + indirect_reverse_cmp(base_value_compare const & cmp = base_value_compare()): + base_value_compare(cmp) + {} + + bool operator()(typename super_t::const_list_iterator const & lhs, typename super_t::const_list_iterator const & rhs) const + { + return super_t::value_compare::operator()(rhs->first, lhs->first); + } + }; + +public: + double_ended_priority_queue_mutable_wrapper(base_value_compare const & cmp = base_value_compare()): + super_t(cmp) + {} + + double_ended_priority_queue_mutable_wrapper(double_ended_priority_queue_mutable_wrapper const & rhs): + super_t(rhs) + {} + + double_ended_priority_queue_mutable_wrapper & operator=(double_ended_priority_queue_mutable_wrapper const & rhs) + { + super_t::operator=(rhs); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + double_ended_priority_queue_mutable_wrapper (double_ended_priority_queue_mutable_wrapper && rhs): + super_t(std::move(rhs)) + {} + + double_ended_priority_queue_mutable_wrapper & operator=(double_ended_priority_queue_mutable_wrapper && rhs) + { + super_t::operator=(std::move(rhs)); + return *this; + } +#endif + +public: + typename super_t::const_reference min(void) const + { + BOOST_ASSERT(!super_t::empty()); + return super_t::q_.min()->first; + } + + typename super_t::const_reference max(void) const + { + BOOST_ASSERT(!super_t::empty()); + return super_t::q_.max()->first; + } + + void pop_min(void) + { + BOOST_ASSERT(!super_t::empty()); + typename super_t::list_iterator q_min = super_t::q_.min(); + super_t::q_.pop_min(); + super_t::objects.erase(q_min); + } + + void pop_max(void) + { + BOOST_ASSERT(!super_t::empty()); + typename super_t::list_iterator q_max = super_t::q_.max(); + super_t::q_.pop_max(); + super_t::objects.erase(q_max); + } + +public: + template + class ordered_iterator_facade : + public super_t::template ordered_iterator_facade + { + typedef typename super_t::template ordered_iterator_facade facade; + + public: + ordered_iterator_facade(void): + facade() + {} + + ordered_iterator_facade(typename super_t::const_list_iterator it, const double_ended_priority_queue_mutable_wrapper * q, indirect_reverse_cmp const & cmp, typename facade::iterator_dispatcher const & dispatcher): + facade(it, q, cmp, dispatcher) + {} + + void discover_nodes(typename facade::iterator current) + { + typedef typename super_t::size_type size_type; + typedef typename super_t::q_type q_type; + + size_type current_index = current->second; + const q_type * q = &(facade::q_->q_); + + if (facade::iterator_dispatcher::is_leaf(q, current_index)) + return; + + std::pair extra_child_range = std::make_pair(1, 0); + std::pair child_range = facade::iterator_dispatcher::get_child_nodes(q, current_index, extra_child_range); + + for (size_type i = extra_child_range.first; i <= extra_child_range.second; ++i) { + typename q_type::internal_type const & internal_value_at_index = facade::iterator_dispatcher::get_internal_value(q, i); + typename q_type::value_type const & value_at_index = facade::q_->q_.get_value(internal_value_at_index); + + facade::unvisited_nodes.push(value_at_index); + } + + for (size_type i = child_range.first; i <= child_range.second; ++i) { + typename q_type::internal_type const & internal_value_at_index = facade::iterator_dispatcher::get_internal_value(q, i); + typename q_type::value_type const & value_at_index = facade::q_->q_.get_value(internal_value_at_index); + + facade::unvisited_nodes.push(value_at_index); + } + } + }; + +public: + class ordered_iterator : public ordered_iterator_facade + { + typedef ordered_iterator_facade + facade; + + public: + ordered_iterator(void): + facade() + {} + + ordered_iterator(const double_ended_priority_queue_mutable_wrapper * q, typename super_t::indirect_cmp const & cmp): + facade(q, cmp) + {} + + ordered_iterator(typename super_t::const_list_iterator it, const double_ended_priority_queue_mutable_wrapper * q, typename super_t::indirect_cmp const & cmp): + facade(it, q, cmp) + {} + + ordered_iterator(typename super_t::const_list_iterator it, const double_ended_priority_queue_mutable_wrapper * q, typename super_t::indirect_cmp const & cmp, typename facade::iterator_dispatcher const & dispatcher): + facade(it, q, cmp, dispatcher) + {} + }; + + ordered_iterator ordered_begin(void) const + { + if (!super_t::empty()) + return ordered_iterator(super_t::q_.max(), this, typename super_t::indirect_cmp(super_t::q_.value_comp()), typename super_t::q_type::ordered_iterator_dispatcher(super_t::q_.size())); + else + return ordered_end(); + } + + ordered_iterator ordered_end(void) const + { + return ordered_iterator(super_t::objects.end(), this, typename super_t::indirect_cmp(super_t::q_.value_comp()), typename super_t::q_type::ordered_iterator_dispatcher(0)); + } + +public: + class reverse_ordered_iterator : public ordered_iterator_facade + { + typedef ordered_iterator_facade + facade; + + public: + reverse_ordered_iterator(void): + facade() + {} + + reverse_ordered_iterator(typename super_t::const_list_iterator it, const double_ended_priority_queue_mutable_wrapper * q, indirect_reverse_cmp const & cmp, typename facade::iterator_dispatcher const & dispatcher): + facade(it, q, cmp, dispatcher) + {} + + reverse_ordered_iterator(typename super_t::const_list_iterator it, std::pair initial_indexes, const double_ended_priority_queue_mutable_wrapper * q, indirect_reverse_cmp const & cmp, typename facade::iterator_dispatcher const & dispatcher): + facade(it, q, cmp, dispatcher) + { + const typename super_t::q_type * q_ = &(facade::q_->q_); + + for (size_t i = initial_indexes.first; i <= initial_indexes.second; ++i) + if (i != it->second) { + typename super_t::q_type::internal_type const & internal_value_at_index = facade::iterator_dispatcher::get_internal_value(q_, i); + typename super_t::q_type::value_type const & value_at_index = facade::q_->q_.get_value(internal_value_at_index); + + facade::unvisited_nodes.push(value_at_index); + } + } + }; + + reverse_ordered_iterator reverse_ordered_begin(void) const + { + if (!super_t::empty()) { + if (1 < super_t::size()) { + const typename super_t::const_list_iterator it = super_t::q_.min(); + std::pair initial_indexes; + initial_indexes.first = 1; + initial_indexes.second = std::min(PriorityQueueType::D, super_t::size()); + + return reverse_ordered_iterator(it, initial_indexes, this, indirect_reverse_cmp(super_t::q_.value_comp()), typename super_t::q_type::reverse_ordered_iterator_dispatcher(super_t::q_.size())); + } + else + return reverse_ordered_iterator(super_t::q_.min(), this, indirect_reverse_cmp(super_t::q_.value_comp()), typename super_t::q_type::reverse_ordered_iterator_dispatcher(super_t::q_.size())); + } + else + return reverse_ordered_end(); + } + + reverse_ordered_iterator reverse_ordered_end(void) const + { + return reverse_ordered_iterator(super_t::objects.end(), this, indirect_reverse_cmp(super_t::q_.value_comp()), typename super_t::q_type::reverse_ordered_iterator_dispatcher(super_t::q_.size())); + } +}; } /* namespace detail */ } /* namespace heap */ diff --git a/include/boost/heap/detail/ordered_adaptor_iterator.hpp b/include/boost/heap/detail/ordered_adaptor_iterator.hpp index 54b8c38..449bd3c 100644 --- a/include/boost/heap/detail/ordered_adaptor_iterator.hpp +++ b/include/boost/heap/detail/ordered_adaptor_iterator.hpp @@ -31,25 +31,24 @@ namespace detail { * * static internal_type const & get_internal_value(const ContainerType * heap, size_type index); // get internal value at index * * static value_type const & get_value(internal_type const & arg) const; // get value_type from internal_type * + * Requirements for Derived: + * + * * void discover_nodes(size_t index); // return children + * * */ -template -class ordered_adaptor_iterator: - public boost::iterator_facade, - ValueType, - boost::forward_traversal_tag - >, - Dispatcher + > +class ordered_adaptor_iterator_facade : + public boost::iterator_facade, + public Dispatcher { friend class boost::iterator_core_access; @@ -71,29 +70,38 @@ class ordered_adaptor_iterator: } }; +public: const ContainerType * container; size_t current_index; // current index: special value -1 denotes `end' iterator public: - ordered_adaptor_iterator(void): + ordered_adaptor_iterator_facade(void): container(NULL), current_index((std::numeric_limits::max)()), unvisited_nodes(compare_by_heap_value(NULL, ValueCompare())) {} - ordered_adaptor_iterator(const ContainerType * container, ValueCompare const & cmp): + ordered_adaptor_iterator_facade(const ContainerType * container, ValueCompare const & cmp): container(container), current_index(container->size()), unvisited_nodes(compare_by_heap_value(container, ValueCompare())) {} - ordered_adaptor_iterator(size_t initial_index, const ContainerType * container, ValueCompare const & cmp): + ordered_adaptor_iterator_facade(size_t initial_index, const ContainerType * container, ValueCompare const & cmp): + container(container), current_index(initial_index), + unvisited_nodes(compare_by_heap_value(container, cmp)) + { + static_cast(this)->discover_nodes(initial_index); + } + + ordered_adaptor_iterator_facade(size_t initial_index, const ContainerType * container, ValueCompare const & cmp, const Dispatcher & dispatcher): + Dispatcher(dispatcher), container(container), current_index(initial_index), unvisited_nodes(compare_by_heap_value(container, cmp)) { - discover_nodes(initial_index); + static_cast(this)->discover_nodes(initial_index); } -private: - bool equal (ordered_adaptor_iterator const & rhs) const +public: + bool equal (ordered_adaptor_iterator_facade const & rhs) const { if (current_index != rhs.current_index) return false; @@ -111,7 +119,7 @@ class ordered_adaptor_iterator: else { current_index = unvisited_nodes.top(); unvisited_nodes.pop(); - discover_nodes(current_index); + static_cast(this)->discover_nodes(current_index); } } @@ -121,23 +129,145 @@ class ordered_adaptor_iterator: return Dispatcher::get_value(Dispatcher::get_internal_value(container, current_index)); } + std::priority_queue::type>, + compare_by_heap_value + > unvisited_nodes; +}; + + +template +class ordered_adaptor_iterator: + public ordered_adaptor_iterator_facade, + ValueType, + ContainerType, + Alloc, + ValueCompare, + Dispatcher> +{ + typedef ordered_adaptor_iterator_facade, + ValueType, + ContainerType, + Alloc, + ValueCompare, + Dispatcher> + facade; + + friend class boost::iterator_core_access; + +public: + ordered_adaptor_iterator(void) + {} + + ordered_adaptor_iterator(const ContainerType * container, ValueCompare const & cmp): + facade(container, cmp) + {} + + ordered_adaptor_iterator(size_t initial_index, const ContainerType * container, ValueCompare const & cmp): + facade(initial_index, container, cmp) + {} + + ordered_adaptor_iterator(size_t initial_index, const ContainerType * container, ValueCompare const & cmp, const Dispatcher & dispatcher): + facade(initial_index, container, cmp, dispatcher) + {} + +public: void discover_nodes(size_t index) { - if (Dispatcher::is_leaf(container, index)) + if (Dispatcher::is_leaf(facade::container, index)) return; - std::pair child_range = Dispatcher::get_child_nodes(container, index); + std::pair child_range = Dispatcher::get_child_nodes(facade::container, index); for (size_t i = child_range.first; i <= child_range.second; ++i) - unvisited_nodes.push(i); + facade::unvisited_nodes.push(i); } - - std::priority_queue::type>, - compare_by_heap_value - > unvisited_nodes; }; +template +class extended_ordered_adaptor_iterator: + public ordered_adaptor_iterator_facade, + ValueType, + ContainerType, + Alloc, + ValueCompare, + Dispatcher + > +{ + typedef ordered_adaptor_iterator_facade, + ValueType, + ContainerType, + Alloc, + ValueCompare, + Dispatcher + > + facade; + + friend class boost::iterator_core_access; + +public: + extended_ordered_adaptor_iterator(void) + {} + + extended_ordered_adaptor_iterator(size_t initial_index, const ContainerType * container, ValueCompare const & cmp, const Dispatcher & dispatcher): + facade(initial_index, container, cmp, dispatcher) + {} + + extended_ordered_adaptor_iterator(size_t initial_index, std::pair initial_indexes, const ContainerType * container, ValueCompare const & cmp, const Dispatcher & dispatcher): + facade(initial_index, container, cmp, dispatcher) + { + for (size_t i = initial_indexes.first; i <= initial_indexes.second; ++i) + if (i != initial_index) + facade::unvisited_nodes.push(i); + } + + void discover_nodes(size_t index) + { + if (Dispatcher::is_leaf(facade::container, index)) + return; + + std::pair extra_child_range = std::make_pair(1, 0); + std::pair child_range = Dispatcher::get_child_nodes(facade::container, index, extra_child_range); + + for (size_t i = extra_child_range.first; i <= extra_child_range.second; ++i) + facade::unvisited_nodes.push(i); + + for (size_t i = child_range.first; i <= child_range.second; ++i) + facade::unvisited_nodes.push(i); + } +}; } /* namespace detail */ } /* namespace heap */ diff --git a/include/boost/heap/min_max_heap.hpp b/include/boost/heap/min_max_heap.hpp new file mode 100644 index 0000000..63aa193 --- /dev/null +++ b/include/boost/heap/min_max_heap.hpp @@ -0,0 +1,1550 @@ +// // boost heap: min-max heap +// +// The majority of this file comes from d_ary_heap.hpp +// Copyright (C) 2010 Tim Blechmann +// +// The parts related to the implementation of the min-max heap +// are however new. +// Copyright (C) 2019 Grégoire Scano +// +// 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) + +/* Implementation of + @article{Atkinson:1986:MHG:6617.6621, + author = {Atkinson, M. D. and Sack, J.-R. and Santoro, N. and Strothotte, T.}, + title = {Min-max Heaps and Generalized Priority Queues}, + journal = {Commun. ACM}, + issue_date = {Oct. 1986}, + volume = {29}, + number = {10}, + month = {oct}, + year = {1986}, + issn = {0001-0782}, + pages = {996--1000}, + numpages = {5}, + url = {http://doi.acm.org/10.1145/6617.6621}, + doi = {http://dx.doi.org/10.1145/6617.6621}, + acmid = {6621}, + publisher = {ACM}, + address = {New York, NY, USA} + } +*/ + +#ifndef BOOST_HEAP_MIN_MAX_HEAP_HPP +#define BOOST_HEAP_MIN_MAX_HEAP_HPP + +#include +#include // memset + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#ifndef BOOST_DOXYGEN_INVOKED +#ifdef BOOST_HEAP_SANITYCHECKS +#define BOOST_HEAP_ASSERT BOOST_ASSERT +#else +#define BOOST_HEAP_ASSERT(expression) +#endif +#endif + +namespace boost { +namespace heap { +namespace detail { + +template +struct tree_depth; + +template +struct min_max_ordered_iterator_status; + +typedef parameter::parameters, + boost::parameter::optional, + boost::parameter::optional, + boost::parameter::optional, + boost::parameter::optional + > min_max_heap_signature; + +/* base class for min-max heap */ +template +class min_max_heap: + private make_heap_base::type +{ + typedef make_heap_base heap_base_maker; + + typedef typename heap_base_maker::type super_t; + typedef typename super_t::internal_type internal_type; + + typedef typename boost::allocator_rebind::type internal_type_allocator; + typedef std::vector container_type; + + typedef IndexUpdater index_updater; + + container_type q_; + + static const unsigned int D = parameter::binding >::type::value; + + template + friend struct heap_merge_emulate; + +public: + typedef T value_type; + + struct implementation_defined: extract_allocator_types + {}; + + typedef typename implementation_defined::size_type size_type; + typedef typename implementation_defined::difference_type difference_type; + typedef typename implementation_defined::reference reference; + typedef typename implementation_defined::const_reference const_reference; + typedef typename implementation_defined::pointer pointer; + typedef typename implementation_defined::const_pointer const_pointer; + + typedef typename heap_base_maker::compare_argument value_compare; + typedef typename heap_base_maker::allocator_argument allocator_type; + + typedef void * handle_type; + + static const bool is_stable = extract_stable::value; + + /* xtors */ +public: + explicit min_max_heap(const value_compare & cmp = value_compare()) : + super_t(cmp) + {} + + min_max_heap(const min_max_heap & rhs) : + super_t(rhs), q_(rhs.q_) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + min_max_heap(min_max_heap && rhs) : + super_t(std::move(rhs)), q_(std::move(rhs.q_)) + {} + + min_max_heap & operator = (min_max_heap && rhs) + { + super_t::operator = (std::move(rhs)); + q_ = std::move(rhs.q_); + return *this; + } +#endif + + min_max_heap & operator = (min_max_heap const & rhs) + { + static_cast(*this) = static_cast(rhs); + q_ = rhs.q_; + return *this; + } + + void swap(min_max_heap & rhs) + { + super_t::swap(rhs); + std::swap(q_, rhs.q_); + } + /* xtors */ + + /* allocator */ + allocator_type get_allocator(void) const + { + return q_.get_allocator(); + } + /* allocator */ + + /* compare */ + value_compare const & value_comp(void) const + { + return super_t::value_comp(); + } + + template + bool compare(size_type i, size_type j) const + { + BOOST_ASSERT(i < this->size()); + BOOST_ASSERT(j < this->size()); + + if (Regular) + return super_t::operator () (q_[i], q_[j]); + else + return super_t::operator () (q_[j], q_[i]); + } + /* compare */ + + /* container */ + bool empty(void) const + { + return q_.empty(); + } + + size_type size(void) const + { + return q_.size(); + } + + size_type max_size(void) const + { + return q_.max_size(); + } + + void reserve(size_t size) + { + q_.reserve(size); + } + + void clear(void) + { + q_.clear(); + } + /* container */ + + /* indexes */ + void reset_index(size_type index, size_type new_index) + { + BOOST_HEAP_ASSERT(index < q_.size()); + index_updater::run(q_[index], new_index); + } + + bool is_on_compare_level(size_type index) const + { + tree_depth depth; + return !(depth(index) % 2); + } + + size_type root(void) const + { + return 0; + } + + size_type first_child(size_type index) const + { + return D * index + 1; + } + + size_type last_child(size_type index) const + { + return D * (index + 1); + } + + std::pair children(size_type index) const + { + return std::make_pair(first_child(index), last_child(index)); + } + + size_type first_grandchild(size_type index) const + { + return first_child(first_child(index)); + } + + size_type last_grandchild(size_type index) const + { + return last_child(last_child(index)); + } + + std::pair grandchildren(size_type index) const + { + const size_type grandchild = first_grandchild(index); + return std::make_pair(grandchild, grandchild + D * D - 1); + } + + size_type last(void) const + { + return q_.size() - 1; + } + + size_type npos(void) const + { + return -1; + } + + bool is_leaf(size_type index) const + { + return q_.size() <= first_child(index); + } + + bool has_parent(size_type index) const + { + return index != root(); + } + + size_type parent(size_type index) const + { + if (index == root() || index == npos()) + return npos(); + else + return (index - 1) / D; + } + + size_type grandparent(size_type index) const + { + return parent(parent(index)); + } + + template + bool best_between(size_type & best, size_type current, size_type theorical_last) const + { + bool found = false; + + for (const size_type last = std::min(theorical_last, this->last()); current <= last; ++current) + if (compare(current, best)) { + best = current; + found = true; + } + + return found; + } + + template + size_type best_child_or_grandchild(size_type index, bool & is_grandchild) const + { + const std::pair children = this->children(index); + + if(last() < children.first) return npos(); + + const std::pair grandchildren = this->grandchildren(index); + + size_type best = children.first; + + best_between(best, children.first + 1, children.second); + is_grandchild = best_between(best, grandchildren.first, grandchildren.second); + + return best; + } + /* indexes */ + + /* moves */ + void trickle_down(size_type i) + { + if (is_on_compare_level(i)) + trickle_down_impl(i); + else + trickle_down_impl(i); + } + + template + void trickle_down_impl(size_type i) + { + bool is_grandchild; + const size_type m = best_child_or_grandchild(i, is_grandchild); + + if (m < npos()) { + if (is_grandchild) { + if (compare(m, i)) { + swap(i, m); + + const size_type parent = this->parent(m); + + if (compare(parent, m)) + swap(m, parent); + + trickle_down_impl(m); + } + } + else if (compare(m, i)) + swap(i, m); + } + } + + void bubble_up(size_type i) + { + if (is_on_compare_level(i)) + bubble_up_impl(i); + else + bubble_up_impl(i); + } + + template + void bubble_up_impl(size_type i) + { + const size_type parent = this->parent(i); + + if (parent != npos()) { + if (compare(parent, i)) { + swap(i, parent); + bubble_up_impl_(parent); + } + else + bubble_up_impl_(i); + } + } + + template + void bubble_up_impl_(size_type i) + { + const size_type grandparent = this->grandparent(i); + + if (grandparent != npos() && compare(i, grandparent)) { + swap(i, grandparent); + bubble_up_impl_(grandparent); + } + } + /* moves */ + + /* operations */ + void swap(size_type i, size_type j) + { + BOOST_ASSERT(i < size()); + BOOST_ASSERT(j < size()); + + reset_index(i, j); + reset_index(j, i); + + std::swap(q_[i], q_[j]); + } + +protected: + size_type index_of_max(void) const + { + return root(); + } + + size_type index_of_min(void) const + { + size_type best = root(); + + best_between(best, 1, D); + + return best; + } + /* operations */ + + /* interface */ + void push(const value_type & v) + { + q_.push_back(super_t::make_node(v)); + + const size_type index = last(); + reset_index(index, index); + + bubble_up(index); + } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + void emplace(Args&&... args) + { + q_.emplace_back(super_t::make_node(std::forward(args)...)); + reset_index(last(), last()); + bubble_up(last()); + } +#endif + + value_type const & top(void) const + { + return max(); + } + + value_type const & min(void) const + { + BOOST_ASSERT(!empty()); + + return super_t::get_value(q_[index_of_min()]); + } + + value_type const & max(void) const + { + BOOST_ASSERT(!empty()); + + return super_t::get_value(q_[index_of_max()]); + } + + void pop(void) + { + pop_max(); + } + + void pop_min(void) + { + erase(index_of_min()); + } + + void pop_max(void) + { + erase(index_of_max()); + } + +public: + template + struct rebind { + typedef min_max_heap, + boost::heap::stability_counter_type, + boost::heap::arity, + boost::heap::compare, + boost::heap::allocator + >::type, + X + > other; + }; + + template friend class priority_queue_mutable_wrapper; + template friend class double_ended_priority_queue_mutable_wrapper; + + void update(size_type index) + { + bubble_up(index); + trickle_down(index); + } + + void increase(size_type index) + { + update(index); + } + + void decrease(size_type index) + { + update(index); + } + + void erase(size_type index) + { + BOOST_ASSERT(!empty()); + BOOST_ASSERT(index < size()); + + swap(index, last()); + q_.pop_back(); + + if (!empty() && index != size()) + update(index); + } + /* interface */ + + /* iterators */ +public: + typedef detail::stable_heap_iterator iterator; + typedef iterator const_iterator; + +public: + iterator begin(void) + { + return iterator(q_.begin()); + } + + iterator end(void) + { + return iterator(q_.end()); + } + + const_iterator begin(void) const + { + return const_iterator(q_.begin()); + } + + const_iterator end(void) const + { + return const_iterator(q_.end()); + } + +public: + template + struct iterator_dispatcher + { + iterator_dispatcher(size_type max_index = 0) : + status(max_index) + {} + + min_max_ordered_iterator_status status; + + static size_type max_index(const min_max_heap * heap) + { + return heap->last(); + } + + std::pair get_child_nodes(const min_max_heap * heap, size_type index, std::pair & extra_child_nodes) + { + /* As stated in the article, the Hasse diagram is divided in two parts. + * + * The first one starts from the root and consists of even level nodes. + * It can be explored like a regular tree, by skipping nodes on odd levels. + * Thus, the number of children of such nodes is at most D^2 instead of D. + * + * Conversely, successors of odd level nodes converge back to the opposite + * extremum of the root. Such nodes are being pointed to by at most D^2 + * grandchildren. Additionally, they cannot be visited until all of their heirs + * have previously been visited, effectively 'reversing' the typical exploration + * denoted for even level nodes. + * + * The 'min_max_ordered_iterator_status' structure is used to keep track + * of this. It indicates for each node on an odd level whether its heirs + * have been visited. When the last heir is being visited, it adds its + * grandparent to the potential candidates to be visited next. Furthermore, + * when this happens, the markers for its heirs are reset and will then be + * reused to indicate to its own grandfather that it has been visited while + * its siblings may not have yet been visited. + * + * Additionally, if a node on an odd level does not have any child, it must be + * added by its parent. + * + * This method requires O(((D - 1) * (size() - 1) + 1) / D) bytes. + * + * The following specific cases must be addressed (for D = 3): + * 0 1) when 0 is visited, nodes 4-8 are added to the list + * /|\ of potential candidates to be visited next, as well + * / | \ as node 3. This explains the 'extra_child_nodes' as + * / | \ node denoted 4-8 and 3 might not be consecutive in a + * / | \ larger tree where the example would be a subtree. + * / | \ 2) when 8 is visited, it must set its indicator and + * 1 2 3 set the indicator for the non existing node 9 (in + * /|\ /| general for all its right non existing siblings) and + * 4 5 6 7 8 then add node 2 if node 7 has already been visited. If + * not, node 7 will add node 2 when it is visited later on. + */ + const size_type last = heap->last(); + const bool on_compare_level = !(Forward ^ heap->is_on_compare_level(index)); + + if (on_compare_level) { + std::pair children = heap->children(index); + + if (children.first <= last) { + std::pair grandchildren = heap->grandchildren(index); + + if (grandchildren.first <= last) { + if (last < grandchildren.second) { + grandchildren.second = last; + + extra_child_nodes.first = heap->parent(grandchildren.second) + 1; + extra_child_nodes.second = children.second; + } + + return grandchildren; + } + + children.second = std::min(children.second, last); + + return children; + } + }// else is leaf or not on compare level + + status.set(index); + const size_type parent = heap->parent(index); + + if (BOOST_LIKELY(parent != heap->npos())) { + const size_type rightmost_sibling = heap->last_child(parent); + + // if (last < rightmost_sibling) + for(size_type i = last + 1; i <= rightmost_sibling; ++i) + status.set(i); + + if (on_compare_level) { + if(status.is_complete(parent)) { + status.reset(parent); + return std::make_pair(parent, parent); + } + } + else { + const size_type grandparent = heap->parent(parent); + + if (BOOST_LIKELY(grandparent != heap->npos()) + && status.is_complete(grandparent)) { + status.reset(grandparent); + return std::make_pair(grandparent, grandparent); + } + } + } + + return std::make_pair(1, 0); + } + + static internal_type const & get_internal_value(const min_max_heap * heap, size_type index) + { + return heap->q_[index]; + } + + static value_type const & get_value(internal_type const & arg) + { + return super_t::get_value(arg); + } + }; + +public: + struct ordered_iterator_dispatcher : iterator_dispatcher + { + ordered_iterator_dispatcher(size_type max): + iterator_dispatcher(max) + {} + + static bool is_leaf(const min_max_heap * heap, size_type index) + { + return (heap->root() < index && index <= D) || index == heap->last() + 1; + } + }; + +public: + typedef detail::extended_ordered_adaptor_iterator + ordered_iterator; + +public: + ordered_iterator ordered_begin(void) const + { + return ordered_iterator(root(), this, super_t::get_internal_cmp(), ordered_iterator_dispatcher(size())); + } + + ordered_iterator ordered_end(void) const + { + return ordered_iterator(size(), this, super_t::get_internal_cmp(), ordered_iterator_dispatcher(root())); + } + +public: + struct reverse_ordered_iterator_dispatcher : iterator_dispatcher + { + reverse_ordered_iterator_dispatcher(size_type max) : + iterator_dispatcher(max) + {} + + static bool is_leaf(const min_max_heap * heap, size_type index) + { + return index == heap->root() || index == heap->last() + 1; + } + }; + +public: + struct reverse_internal_compare : super_t::internal_compare + { + reverse_internal_compare(value_compare const & cmp = value_compare()) : + super_t::internal_compare(cmp) + {} + + bool operator () (typename super_t::internal_type const & lhs, typename super_t::internal_type const & rhs) const + { + return super_t::internal_compare::operator () (rhs, lhs); + } + }; + +public: + typedef detail::extended_ordered_adaptor_iterator + reverse_ordered_iterator; + +public: + reverse_ordered_iterator reverse_ordered_begin(void) const + { + size_type index_of_min = root(); + std::pair initial_indexes = std::make_pair(1, 0); + + if (1 < size()) { + index_of_min = this->index_of_min(); + // The initial_indexes range will contain index_of_min and this is fine + // as long as the adaptor is storing upcoming indexes in a set. + initial_indexes.first = 1; + initial_indexes.second = std::min(D, last()); + } + + return reverse_ordered_iterator(index_of_min, initial_indexes, this, reverse_internal_compare(super_t::get_internal_cmp()), reverse_ordered_iterator_dispatcher(size())); + } + + reverse_ordered_iterator reverse_ordered_end(void) const + { + return reverse_ordered_iterator(size(), this, reverse_internal_compare(super_t::get_internal_cmp()), reverse_ordered_iterator_dispatcher(0)); + } + /* iterators */ +}; + +template +struct tree_depth +{ + IntType operator () (IntType index) const + { + IntType power = Base; + IntType count = 1; + IntType depth = 0; + + while (count <= index) { + count += power; + power *= Base; + ++depth; + } + + return depth; + } + + /* Alternatively, let f be a function mapping an index n to its corresponding + * depth (or row) r in a D tree, f_D(n)=r and 1 < D. If n is on row r, then + * $\sum_{i=0}^{r} D^{i} <= n < \sum_{i=0}^{r+1} D^{i}$, hence + * $D^{r+1} <= (D-1) * n + 1 < D^{r+2}$ and since log_D is strictly increasing + * $r + 1 <= log_D((D-1) * n + 1) < r + 2$ and then + * because an array index is an integer starting at 0 (r:=r-1); + * $r = log_D((D - 1) * index + 1)$ + * which is slower than the above iterative method for indexes up to 10^10. + */ +}; + +template +struct tree_depth<2, IntType> +{ + IntType operator () (IntType index) const + { + return ::boost::heap::log2(index + 1); + } +}; + +template +struct ipower +{ + ipower(IntType max) + { + if (1 <= max) { + power.resize(max + 1); + power[0] = 1; + + for (IntType exp = 1; exp <= max; ++exp) { + power[exp] = power[exp-1] * Base; + } + } + } + + std::vector power; + + IntType operator () (IntType exp) const + { + return power[exp]; + } + + static IntType pow(IntType exp, IntType res = 1) + { + return exp == 0 ? res : pow(exp - 1, res * Base); + } +}; + +template +struct ipower<2, IntType> +{ + ipower(IntType) {} + + IntType operator () (IntType exp) const + { + return 1 << exp; + } + + static IntType pow(IntType exp) + { + return 1 << exp; + } +}; + +template +struct min_max_ordered_iterator_status_base +{ + min_max_ordered_iterator_status_base(IntType max_index = 0) : + max_depth(boost::heap::detail::tree_depth()(max_index)), + power(max_depth) + { + candidates.resize(1 + (power.pow(max_depth) + 1) / 8, 0); + } + + const IntType max_depth; + const ipower power; + std::vector candidates; + + IntType number_of_final_heirs_for(IntType current_depth) const + { + return power(max_depth - current_depth); + } + + void positions(IntType index, IntType & chunk, IntType & offset, IntType & heirs) + { + IntType depth = boost::heap::detail::tree_depth()(index); + + const IntType local_index = index - (power(depth) - 1)/(Base - 1); + + heirs = number_of_final_heirs_for(depth); + + const IntType candidate_index = local_index * heirs; + + chunk = candidate_index / 8; + offset = candidate_index % 8; + } + + void positions_by_8(IntType index, IntType & chunk, IntType & offset, IntType & heirs_oct, IntType & heirs_left) + { + IntType heirs; + positions(index, chunk, offset, heirs); + + heirs_oct = heirs / 8; + heirs_left = heirs % 8; + } +}; + +template +struct min_max_ordered_iterator_status : min_max_ordered_iterator_status_base +{ + typedef min_max_ordered_iterator_status_base base; + + min_max_ordered_iterator_status(IntType max_index = 0) : + base(max_index) + {} + + void set(IntType index) + { + IntType chunk, offset, heirs; + base::positions(index, chunk, offset, heirs); + + const IntType first_heirs = std::min(heirs, 8 - offset); + if (first_heirs < 8) { + base::candidates[chunk] |= (0xFF >> (offset + (8 - offset - first_heirs))) << (8 - offset - first_heirs); + ++chunk; + heirs -= first_heirs; + } + + const IntType heirs_octuple = heirs / 8; + const IntType last_heirs = heirs % 8; + + std::memset(base::candidates.data() + chunk, 0xFF, heirs_octuple); + chunk += heirs_octuple; + + base::candidates[chunk] |= 0xFF << (8 - last_heirs); + } + + void reset(IntType index) + { + IntType chunk, offset, heirs; + base::positions(index, chunk, offset, heirs); + + const IntType first_heirs = std::min(heirs, 8 - offset); + if (first_heirs < 8) { + base::candidates[chunk] &= ~((0xFF >> (offset + (8 - offset - first_heirs))) << (8 - offset - first_heirs)); + ++chunk; + heirs -= first_heirs; + } + + const IntType heirs_octuple = heirs / 8; + const IntType last_heirs = heirs % 8; + + std::memset(base::candidates.data() + chunk, 0, heirs_octuple); + chunk += heirs_octuple; + + base::candidates[chunk] &= ~(0xFF << (8 - last_heirs)); + } + + bool is_complete(IntType index) + { + IntType chunk, offset, heirs; + base::positions(index, chunk, offset, heirs); + + const IntType first_heirs = std::min(heirs, 8 - offset); + if (first_heirs < 8) { + IntType mask = (0xFF >> (offset + (8 - offset - first_heirs))) << (8 - offset - first_heirs); + if((base::candidates[chunk] & mask) != mask) return false; + ++chunk; + heirs -= first_heirs; + } + + while (8 <= heirs) { + if (base::candidates[chunk] != 0xFF) + return false; + ++chunk; + heirs -= 8; + } + + uint8_t mask = 0xFF << (8 - heirs); + return (heirs && (base::candidates[chunk] & mask) == mask) || !heirs; + } +}; + +template +struct min_max_ordered_iterator_status<2, IntType> : min_max_ordered_iterator_status_base<2, IntType> +{ + typedef min_max_ordered_iterator_status_base<2, IntType> base; + + min_max_ordered_iterator_status(IntType max_index = 0) : + base(max_index) +#ifndef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX + ,masks{0, 0x01, 0x03, 0, 0x0F, 0, 0, 0} {} + const +#else + { + std::memset(masks, 0, 8); + masks[1] = 0x01; + masks[2] = 0x03; + masks[4] = 0x0F; + } +#endif + + uint8_t masks[8]; + + void set(IntType index) + { + IntType chunk, offset, heirs_octuple, heirs_left; + base::positions_by_8(index, chunk, offset, heirs_octuple, heirs_left); + + if (0 < heirs_octuple) + std::memset(base::candidates.data() + chunk, 0xFF, heirs_octuple); + else + base::candidates[chunk] |= masks[heirs_left] << (8 - heirs_left - offset); + } + + void reset(IntType index) + { + IntType chunk, offset, heirs_octuple, heirs_left; + base::positions_by_8(index, chunk, offset, heirs_octuple, heirs_left); + + if (0 < heirs_octuple) + std::memset(base::candidates.data() + chunk, 0, heirs_octuple); + else + base::candidates[chunk] &= ~(masks[heirs_left] << (8 - heirs_left - offset)); + } + + bool is_complete(IntType index) + { + IntType chunk, offset, heirs; + base::positions(index, chunk, offset, heirs); + + if (8 <= heirs) { + do { + if (base::candidates[chunk] != 0xFF) + return false; + ++chunk; + heirs -= 8; + } + while (8 <= heirs); + + return true; + } + else { + const uint8_t mask = masks[heirs] << (8 - heirs - offset); + return (mask && (base::candidates[chunk] & mask) == mask) || !mask; + } + } +}; + +template +struct select_minmax_heap +{ + static const bool is_mutable = extract_mutable::value; + + typedef typename mpl::if_c >, + min_max_heap + >::type type; +}; + +} /* namespace detail */ + +/** + * \class min_max_heap + * \brief min-max heap class + * + * This class implements a double-ended priority queue. Internally, the min-max heap is represented + * as a dynamically sized array (std::vector), that directly stores the values. + * + * The template parameter T is the type to be managed by the container. + * The user can specify additional options and if no options are provided default options are used. + * + * The container supports the following options: + * - \c boost::heap::arity<>, defaults to \c arity<2> + * - \c boost::heap::compare<>, defaults to \c compare > + * - \c boost::heap::stable<>, defaults to \c stable + * - \c boost::heap::stability_counter_type<>, defaults to \c stability_counter_type + * - \c boost::heap::allocator<>, defaults to \c allocator > + * - \c boost::heap::mutable_<>, defaults to \c mutable_ + */ +#ifdef BOOST_DOXYGEN_INVOKED +template +#else +template +#endif +class min_max_heap: + public detail::select_minmax_heap::type>::type +{ + typedef typename detail::min_max_heap_signature::bind::type bound_args; + typedef typename detail::select_minmax_heap::type super_t; + + template + friend struct heap_merge_emulate; + +#ifndef BOOST_DOXYGEN_INVOKED + static const bool is_mutable = detail::extract_mutable::value; + +#define BOOST_HEAP_TYPEDEF_FROM_SUPER_T(NAME) \ + typedef typename super_t::NAME NAME; + + struct implementation_defined + { + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(size_type) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(difference_type) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(value_compare) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(allocator_type) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(reference) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(const_reference) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(pointer) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(const_pointer) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(iterator) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(const_iterator) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(ordered_iterator) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(reverse_ordered_iterator) + BOOST_HEAP_TYPEDEF_FROM_SUPER_T(handle_type) + }; +#undef BOOST_HEAP_TYPEDEF_FROM_SUPER_T + +#endif +public: + static const bool constant_time_size = true; + static const bool has_ordered_iterators = true; + static const bool is_mergable = false; + static const bool has_reserve = true; + static const bool is_stable = super_t::is_stable; + + typedef T value_type; + typedef typename implementation_defined::size_type size_type; + typedef typename implementation_defined::difference_type difference_type; + typedef typename implementation_defined::value_compare value_compare; + typedef typename implementation_defined::allocator_type allocator_type; + typedef typename implementation_defined::reference reference; + typedef typename implementation_defined::const_reference const_reference; + typedef typename implementation_defined::pointer pointer; + typedef typename implementation_defined::const_pointer const_pointer; + /// \copydoc boost::heap::priority_queue::iterator + typedef typename implementation_defined::iterator iterator; + typedef typename implementation_defined::const_iterator const_iterator; + typedef typename implementation_defined::ordered_iterator ordered_iterator; + typedef typename implementation_defined::reverse_ordered_iterator reverse_ordered_iterator; + typedef typename implementation_defined::handle_type handle_type; + +public: + /// \copydoc boost::heap::priority_queue::priority_queue(value_compare const &) + explicit min_max_heap(value_compare const & cmp = value_compare()): + super_t(cmp) + {} + + /// \copydoc boost::heap::priority_queue::priority_queue(priority_queue const &) + min_max_heap(min_max_heap const & rhs): + super_t(rhs) + {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + /// \copydoc boost::heap::priority_queue::priority_queue(priority_queue &&) + min_max_heap(min_max_heap && rhs): + super_t(std::move(rhs)) + {} + + /// \copydoc boost::heap::priority_queue::operator=(priority_queue &&) + min_max_heap & operator=(min_max_heap && rhs) + { + super_t::operator=(std::move(rhs)); + return *this; + } +#endif + + /// \copydoc boost::heap::priority_queue::operator=(priority_queue const &) + min_max_heap & operator=(min_max_heap const & rhs) + { + super_t::operator=(rhs); + return *this; + } + +public: + /// \copydoc boost::heap::priority_queue::empty + bool empty(void) const + { + return super_t::empty(); + } + + /// \copydoc boost::heap::priority_queue::size + size_type size(void) const + { + return super_t::size(); + } + + /// \copydoc boost::heap::priority_queue::max_size + size_type max_size(void) const + { + return super_t::max_size(); + } + + /// \copydoc boost::heap::priority_queue::clear + void clear(void) + { + super_t::clear(); + } + +public: + /// \copydoc boost::heap::priority_queue::get_allocator + allocator_type get_allocator(void) const + { + return super_t::get_allocator(); + } + +public: + /// \copydoc boost::heap::priority_queue::top + value_type const & top(void) const + { + return super_t::max(); + } + + /** + * \b Effects: Returns a const_reference to the max element. + * + * \b Complexity: Constant. + * + * */ + value_type const & max(void) const + { + return super_t::max(); + } + + /** + * \b Effects: Returns a const_reference to the min element. + * + * \b Complexity: Constant. + * + * */ + value_type const & min(void) const + { + return super_t::min(); + } + + /** + * \b Effects: Returns a const_reference to the max element. + * + * \b Complexity: Constant. + * + * */ + value_type const & best(void) const + { + return super_t::max(); + } + + /** + * \b Effects: Returns a const_reference to the min element. + * + * \b Complexity: Constant. + * + * */ + value_type const & worst(void) const + { + return super_t::min(); + } + + /** + * \b Effects: Adds a new element to the priority queue. Returns handle to element + * + * \b Complexity: Logarithmic. + * + * */ + typename boost::conditional::type push(value_type const & v) + { + return super_t::push(v); + } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + /** + * \b Effects: Adds a new element to the priority queue. The element is directly constructed in-place. Returns handle to element. + * + * \b Complexity: Logarithmic. + * + * */ + template + typename boost::conditional::type emplace(Args&&... args) + { + return super_t::emplace(std::forward(args)...); + } +#endif + + /// \copydoc boost::heap::priority_queue::operator<(HeapType const & rhs) const + template + bool operator<(HeapType const & rhs) const + { + return detail::heap_compare(*this, rhs); + } + + /// \copydoc boost::heap::priority_queue::operator>(HeapType const & rhs) const + template + bool operator>(HeapType const & rhs) const + { + return detail::heap_compare(rhs, *this); + } + + /// \copydoc boost::heap::priority_queue::operator>=(HeapType const & rhs) const + template + bool operator>=(HeapType const & rhs) const + { + return !operator<(rhs); + } + + /// \copydoc boost::heap::priority_queue::operator<=(HeapType const & rhs) const + template + bool operator<=(HeapType const & rhs) const + { + return !operator>(rhs); + } + + /// \copydoc boost::heap::priority_queue::operator==(HeapType const & rhs) const + template + bool operator==(HeapType const & rhs) const + { + return detail::heap_equality(*this, rhs); + } + + /// \copydoc boost::heap::priority_queue::operator!=(HeapType const & rhs) const + template + bool operator!=(HeapType const & rhs) const + { + return !(*this == rhs); + } + + /** + * \b Effects: Assigns \c v to the element handled by \c handle & updates the priority queue. + * + * \b Complexity: Logarithmic. + * + * \b Requirement: data structure must be configured as mutable + * */ + void update(handle_type handle, const_reference v) + { + BOOST_STATIC_ASSERT(is_mutable); + super_t::update(handle, v); + } + + /** + * \b Effects: Updates the heap after the element handled by \c handle has been changed. + * + * \b Complexity: Logarithmic. + * + * \b Note: If this is not called, after a handle has been updated, the behavior of the data structure is undefined! + * + * \b Requirement: data structure must be configured as mutable + * */ + void update(handle_type handle) + { + BOOST_STATIC_ASSERT(is_mutable); + super_t::update(handle); + } + + /** + * \b Effects: Assigns \c v to the element handled by \c handle & updates the priority queue. + * + * \b Complexity: Logarithmic. + * + * \b Note: The new value is expected to be greater than the current one + * + * \b Requirement: data structure must be configured as mutable + * */ + void increase(handle_type handle, const_reference v) + { + BOOST_STATIC_ASSERT(is_mutable); + super_t::increase(handle, v); + } + + /** + * \b Effects: Updates the heap after the element handled by \c handle has been changed. + * + * \b Complexity: Logarithmic. + * + * \b Note: The new value is expected to be greater than the current one. If this is not called, after a handle has been updated, the behavior of the data structure is undefined! + * + * \b Requirement: data structure must be configured as mutable + * */ + void increase(handle_type handle) + { + BOOST_STATIC_ASSERT(is_mutable); + super_t::increase(handle); + } + + /** + * \b Effects: Assigns \c v to the element handled by \c handle & updates the priority queue. + * + * \b Complexity: Logarithmic. + * + * \b Note: The new value is expected to be less than the current one + * + * \b Requirement: data structure must be configured as mutable + * */ + void decrease(handle_type handle, const_reference v) + { + BOOST_STATIC_ASSERT(is_mutable); + super_t::decrease(handle, v); + } + + /** + * \b Effects: Updates the heap after the element handled by \c handle has been changed. + * + * \b Complexity: Logarithmic. + * + * \b Note: The new value is expected to be less than the current one. If this is not called, after a handle has been updated, the behavior of the data structure is undefined! + * + * \b Requirement: data structure must be configured as mutable + * */ + void decrease(handle_type handle) + { + BOOST_STATIC_ASSERT(is_mutable); + super_t::decrease(handle); + } + + /** + * \b Effects: Removes the element handled by \c handle from the priority_queue. + * + * \b Complexity: Logarithmic. + * + * \b Requirement: data structure must be configured as mutable + * */ + void erase(handle_type handle) + { + BOOST_STATIC_ASSERT(is_mutable); + super_t::erase(handle); + } + + /** + * \b Effects: Casts an iterator to a node handle. + * + * \b Complexity: Constant. + * + * \b Requirement: data structure must be configured as mutable + * */ + static handle_type s_handle_from_iterator(iterator const & it) + { + BOOST_STATIC_ASSERT(is_mutable); + return super_t::s_handle_from_iterator(it); + } + + /** + * \b Effects: Removes the top element from the priority queue. + * + * \b Complexity: Logarithmic. + * + * */ + void pop(void) + { + super_t::pop_max(); + } + + /** + * \b Effects: Removes the element with the highest priority from the priority queue. + * + * \b Complexity: Logarithmic. + * + * */ + void pop_max(void) + { + super_t::pop_max(); + } + + /** + * \b Effects: Removes the element with the lowest priority from the priority queue. + * + * \b Complexity: Logarithmic. + * + * */ + void pop_min(void) + { + super_t::pop_min(); + } + + /// \copydoc boost::heap::priority_queue::swap + void swap(min_max_heap & rhs) + { + super_t::swap(rhs); + } + + /// \copydoc boost::heap::priority_queue::begin + const_iterator begin(void) const + { + return super_t::begin(); + } + + /// \copydoc boost::heap::priority_queue::begin + iterator begin(void) + { + return super_t::begin(); + } + + /// \copydoc boost::heap::priority_queue::end + iterator end(void) + { + return super_t::end(); + } + + /// \copydoc boost::heap::priority_queue::end + const_iterator end(void) const + { + return super_t::end(); + } + + /** + * \b Effects: Returns an ordered iterator to the first element contained in the priority queue. + * + * \b Spatial complexity: Requires an additional ((D - 1) * (size() - 1) + 1/(8*D) bytes. + * + * \b Note: Ordered iterators traverse the priority queue in heap order. + * */ + ordered_iterator ordered_begin(void) const + { + return super_t::ordered_begin(); + } + + /// \copydoc boost::heap::fibonacci_heap::ordered_end + ordered_iterator ordered_end(void) const + { + return super_t::ordered_end(); + } + + /** + * \b Effects: Returns a reverse ordered iterator to the last element contained in the priority queue. + * + * \b Spatial complexity: Requires an additional ((D - 1) * (size() - 1) + 1/(8*D) bytes. + * + * \b Note: Reverse ordered iterators traverse the priority queue in heap reverse order. + * */ + reverse_ordered_iterator reverse_ordered_begin(void) const + { + return super_t::reverse_ordered_begin(); + } + + /** + * \b Effects: Returns a reverse ordered iterator to the beginning of the priority queue. + * + * \b Note: Reverse ordered iterators traverse the priority queue in heap reverse order. + * */ + reverse_ordered_iterator reverse_ordered_end(void) const + { + return super_t::reverse_ordered_end(); + } + + /// \copydoc boost::heap::priority_queue::reserve + void reserve (size_type element_count) + { + super_t::reserve(element_count); + } + + /// \copydoc boost::heap::priority_queue::value_comp + value_compare const & value_comp(void) const + { + return super_t::value_comp(); + } +}; + +} /* namespace heap */ +} /* namespace boost */ + +#undef BOOST_HEAP_ASSERT + +#endif /* BOOST_HEAP_MIN_MAX_HEAP_HPP */ diff --git a/test/common_heap_tests.hpp b/test/common_heap_tests.hpp index 4454c2a..276e62d 100644 --- a/test/common_heap_tests.hpp +++ b/test/common_heap_tests.hpp @@ -30,14 +30,14 @@ void random_shuffle(RandomIt first, RandomIt last) for (difference_type i = n-1; i > 0; --i) { difference_type j = std::rand() % (i + 1); if (j != i) { - using std::swap; + using std::swap; swap(first[i], first[j]); } } } #else - + using std::random_shuffle; #endif @@ -303,6 +303,32 @@ void pri_queue_test_ordered_iterators(void) } } +template +void pri_queue_test_reverse_ordered_iterators(void) +{ + for (int i = 6; i != test_size; ++i) { + test_data data = make_test_data(i); + test_data shuffled (data); + random_shuffle(shuffled.begin(), shuffled.end()); + pri_queue q; + BOOST_REQUIRE(q.reverse_ordered_begin() == q.reverse_ordered_end()); + fill_q(q, shuffled); + + test_data data_from_queue(q.reverse_ordered_begin(), q.reverse_ordered_end()); + BOOST_REQUIRE(data == data_from_queue); + + for (unsigned long j = 0; j != data.size(); ++j) + BOOST_REQUIRE(std::find(q.reverse_ordered_begin(), q.reverse_ordered_end(), data[j]) != q.reverse_ordered_end()); + + for (unsigned long j = 0; j != data.size(); ++j) + BOOST_REQUIRE(std::find(q.reverse_ordered_begin(), q.reverse_ordered_end(), data[j] + data.size()) == q.reverse_ordered_end()); + + for (unsigned long j = 0; j != data.size(); ++j) { + BOOST_REQUIRE_EQUAL((long)std::distance(q.begin(), q.end()), (long)(data.size() - j)); + q.pop(); + } + } +} template void pri_queue_test_equality(void) diff --git a/test/min_max_heap_test.cpp b/test/min_max_heap_test.cpp new file mode 100644 index 0000000..33c8f18 --- /dev/null +++ b/test/min_max_heap_test.cpp @@ -0,0 +1,456 @@ +// boost heap: min-max heap +// +// Copyright (C) 2019 Grégoire Scano +// +// 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) + +#define BOOST_TEST_MAIN + +#define BOOST_HEAP_SANITYCHECKS + +#include + +#include + +#include "common_heap_tests.hpp" +#include "stable_heap_tests.hpp" +#include "mutable_heap_tests.hpp" +#include "merge_heap_tests.hpp" + +#include +#include + +template +void run_tree_depth_test(void) +{ + boost::heap::detail::tree_depth depth; + + BOOST_REQUIRE(depth(0) == 0); + + unsigned int index = 1; + for (unsigned int i = 1, count = D; i < 32/D; ++i, count *= D) + for (unsigned int j = 0; j < count; ++j, ++index) + BOOST_REQUIRE(depth(index) == i); +} + +BOOST_AUTO_TEST_CASE( tree_depth_test ) +{ + BOOST_REQUIRE(boost::heap::log2(1) == 0); + BOOST_REQUIRE(boost::heap::log2(2) == 1); + + run_tree_depth_test<1>(); + run_tree_depth_test<2>(); + run_tree_depth_test<3>(); + run_tree_depth_test<4>(); + run_tree_depth_test<5>(); +} + +unsigned int last_line_index(unsigned int base, unsigned int max, unsigned int & depth) +{ + depth = 0; + unsigned int first = 0; + unsigned int local = 1; + unsigned int count = 1; + while (count <= max) { + first = count; + local *= base; + count += local; + ++depth; + } + + return first; +} + +void masks(unsigned int base, unsigned int max, unsigned int index, std::set & mask, std::set & umask) +{ + BOOST_REQUIRE(max != 0); + + unsigned int depth; + const unsigned int last_line_left_index = last_line_index(base, max, depth); + mask.clear(); + + std::queue queue; + queue.push(index); + + while (!queue.empty()) { + const unsigned int child = queue.front(); + queue.pop(); + + if (last_line_left_index <= child) + mask.insert(child); + else { + unsigned int current = base * child + 1; + const unsigned int right = base * (child + 1); + + while (current <= right) { + if (current <= max) + queue.push(current); + else + mask.insert(current); + + ++current; + } + } + } + + umask.clear(); + + const unsigned int last_line_right_index = last_line_left_index + std::pow(base, depth) - 1; + + for (unsigned int i = last_line_left_index; i <= last_line_right_index; ++i) + if (mask.find(i) == mask.end()) + umask.insert(i); +} + +BOOST_AUTO_TEST_CASE( min_max_heap_expected_mask_test ) +{ + std::set mask; + std::set umask; + + std::vector values; + for (unsigned int i = 0; i <= 12; ++i) + values.push_back(i); + const std::vector::const_iterator it = values.begin(); + +#define LOCALTEST(base, max, index, begin, end) \ + masks(base, max, index, mask, umask); \ + BOOST_REQUIRE(mask == std::set(it + begin, it + end + 1)); + + LOCALTEST(2, 1, 0, 1, 2); + LOCALTEST(2, 1, 1, 1, 1); + LOCALTEST(2, 2, 0, 1, 2); + LOCALTEST(2, 2, 1, 1, 1); + LOCALTEST(2, 2, 2, 2, 2); + LOCALTEST(2, 3, 0, 3, 6); + LOCALTEST(2, 3, 1, 3, 4); + LOCALTEST(2, 3, 2, 5, 6); + LOCALTEST(2, 3, 3, 3, 3); + LOCALTEST(2, 4, 0, 3, 6); + LOCALTEST(2, 4, 1, 3, 4); + LOCALTEST(2, 4, 2, 5, 6); + LOCALTEST(2, 4, 3, 3, 3); + LOCALTEST(2, 4, 4, 4, 4); + + LOCALTEST(3, 1, 0, 1, 3); + LOCALTEST(3, 1, 1, 1, 1); + LOCALTEST(3, 2, 0, 1, 3); + LOCALTEST(3, 2, 1, 1, 1); + LOCALTEST(3, 2, 2, 2, 2); + LOCALTEST(3, 3, 0, 1, 3); + LOCALTEST(3, 3, 1, 1, 1); + LOCALTEST(3, 3, 2, 2, 2); + LOCALTEST(3, 3, 3, 3, 3); + LOCALTEST(3, 4, 0, 4, 12); + LOCALTEST(3, 4, 1, 4, 6); + LOCALTEST(3, 4, 2, 7, 9); + LOCALTEST(3, 4, 3, 10, 12); + LOCALTEST(3, 4, 4, 4, 4); + LOCALTEST(3, 5, 0, 4, 12); + LOCALTEST(3, 5, 1, 4, 6); + LOCALTEST(3, 5, 2, 7, 9); + LOCALTEST(3, 5, 3, 10, 12); + LOCALTEST(3, 5, 4, 4, 4); + LOCALTEST(3, 5, 5, 5, 5); +#undef LOCALTEST +} + +template +void run_min_max_heap_ordered_iterator_status_test(unsigned int max) +{ + std::set mask; + std::set umask; + + for (unsigned int max_index = 1; max_index <= std::pow(D, max) + 1; ++max_index) { + for (unsigned int index = 0; index <= max_index; ++index) { + masks(D, max_index, index, mask, umask); + + { + boost::heap::detail::min_max_ordered_iterator_status status(max_index); + + for (std::set::const_iterator it = mask.begin(); it != mask.end(); ++it) { + BOOST_REQUIRE(!status.is_complete(index)); + status.set(*it); + BOOST_REQUIRE(status.is_complete(*it)); + } + + BOOST_REQUIRE(status.is_complete(index)); + + for (std::set::const_iterator it = umask.begin(); it != umask.end(); ++it) + BOOST_REQUIRE(!status.is_complete(*it)); + + for (std::set::const_iterator it = mask.begin(); it != mask.end(); ++it) { + status.reset(*it); + BOOST_REQUIRE(!status.is_complete(*it)); + } + + BOOST_REQUIRE(!status.is_complete(index)); + } + + { + boost::heap::detail::min_max_ordered_iterator_status status(max_index); + + status.set(index); + BOOST_REQUIRE(status.is_complete(index)); + + for (std::set::const_iterator it = mask.begin(); it != mask.end(); ++it) + BOOST_REQUIRE(status.is_complete(*it)); + + for (std::set::const_iterator it = umask.begin(); it != umask.end(); ++it) + BOOST_REQUIRE(!status.is_complete(*it)); + + status.reset(index); + BOOST_REQUIRE(!status.is_complete(index)); + + for (std::set::const_iterator it = mask.begin(); it != mask.end(); ++it) + BOOST_REQUIRE(!status.is_complete(*it)); + } + } + } +} + +BOOST_AUTO_TEST_CASE( min_max_heap_ordered_iterator_status_test ) +{ + run_min_max_heap_ordered_iterator_status_test<2>(7); + run_min_max_heap_ordered_iterator_status_test<3>(3); + run_min_max_heap_ordered_iterator_status_test<4>(2); + run_min_max_heap_ordered_iterator_status_test<5>(2); +} + +template +struct dispatcher_queue : boost::heap::detail::min_max_heap +{ + typedef boost::heap::detail::min_max_heap base; + + void clear() + { + base::clear(); + } + + void set(unsigned int i) + { + base::clear(); + + while (0 < i) { + base::push(i); + --i; + } + } +}; + +/* + * Testing the iterator dispatcher for ordered iterator only + * (true template parameter) because the reverse iterator + * dispatcher merely switches the result of is_on_compare_level + * while the tree examination remains the same. +*/ +template +void run_min_max_heap_iterator_dispatcher_upward_test() +{ + typedef typename boost::heap::detail::min_max_heap_signature::bind< + boost::heap::arity, + boost::parameter::void_, + boost::parameter::void_, + boost::parameter::void_, + boost::parameter::void_, + boost::parameter::void_>::type signature; + typedef dispatcher_queue pri_queue; + typedef typename pri_queue::template iterator_dispatcher iterator_dispatcher; + + pri_queue q; + std::pair regular; + std::pair extra; + + { + q.set(D * D + 2); extra.first = 1; extra.second = 0; + iterator_dispatcher dispatcher = iterator_dispatcher(q.size() - 1); + + regular = dispatcher.get_child_nodes(&q, D * D + 1, extra); + BOOST_REQUIRE(regular.first == D && regular.second == D); + BOOST_REQUIRE(extra.first == 1 && extra.second == 0); + } + + q.clear(); + + { + q.set(D * (D * D + 1) + 2); extra.first = 1; extra.second = 0; + iterator_dispatcher dispatcher = iterator_dispatcher(q.size() - 1); + + for (unsigned int i = 1; i <= D; ++i) { + regular = dispatcher.get_child_nodes(&q, D * D + 1 + i, extra); + BOOST_REQUIRE(regular.first == 1 && regular.second == 0); + BOOST_REQUIRE(extra.first == 1 && extra.second == 0); + } + + regular = dispatcher.get_child_nodes(&q, D * (D * D + 1) + 1, extra); + BOOST_REQUIRE(regular.first == D && regular.second == D); + BOOST_REQUIRE(extra.first == 1 && extra.second == 0); + } +} + +BOOST_AUTO_TEST_CASE( min_max_heap_iterator_dispatcher_test ) +{ + typedef boost::heap::detail::min_max_heap_signature::bind< + boost::parameter::void_, + boost::parameter::void_, + boost::parameter::void_, + boost::parameter::void_, + boost::parameter::void_, + boost::parameter::void_>::type signature; + typedef dispatcher_queue pri_queue; + typedef pri_queue::iterator_dispatcher iterator_dispatcher; + + pri_queue q; + std::pair regular; + std::pair extra; + +#define CHECK(size_, index, xr,yr,xe,ye) { \ + q.set(size_); extra.first = 1; extra.second = 0; \ + iterator_dispatcher dispatcher = iterator_dispatcher(q.size()-1); \ + regular = dispatcher.get_child_nodes(&q, index, extra); \ + BOOST_REQUIRE(regular.first == xr); \ + BOOST_REQUIRE(regular.second == yr); \ + BOOST_REQUIRE((!(xe < ye) || (extra.first == xe && extra.second == ye)) \ + || (!(ye < xe) || extra.second < extra.first)); \ + } + + CHECK(1,0,1,0,1,0); + CHECK(2,0,1,1,1,0); + CHECK(3,0,1,2,1,0); + CHECK(4,0,3,3,2,2); + CHECK(5,0,3,4,2,2); + CHECK(6,0,3,5,1,0); + CHECK(7,0,3,6,1,0); + + CHECK(8,3,7,7,1,0); + CHECK(9,3,7,8,1,0); + CHECK(10,3,7,8,1,0); + CHECK(10,4,9,9,1,0); + + CHECK(13,5,11,12,1,0); + +#undef CHECK + + run_min_max_heap_iterator_dispatcher_upward_test<2>(); + run_min_max_heap_iterator_dispatcher_upward_test<3>(); + run_min_max_heap_iterator_dispatcher_upward_test<4>(); + run_min_max_heap_iterator_dispatcher_upward_test<5>(); +} + +template +void run_min_max_heap_test(void) +{ + typedef boost::heap::min_max_heap, + boost::heap::stable, + boost::heap::compare >, + boost::heap::allocator > > pri_queue; + + BOOST_CONCEPT_ASSERT((boost::heap::PriorityQueue)); + + run_concept_check(); + run_common_heap_tests(); + + run_iterator_heap_tests(); + run_copyable_heap_tests(); + run_moveable_heap_tests(); + run_reserve_heap_tests(); + run_merge_tests(); + + run_ordered_iterator_tests(); + run_reverse_ordered_iterator_tests(); + + if (stable) { + typedef boost::heap::min_max_heap, + boost::heap::stable + > stable_pri_queue; + + run_stable_heap_tests(); + } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + cmpthings ord; + boost::heap::min_max_heap, boost::heap::compare, boost::heap::stable > vpq(ord); + vpq.emplace(5, 6, 7); +#endif +} + +BOOST_AUTO_TEST_CASE( min_max_heap_test ) +{ + run_min_max_heap_test<2, false>(); + run_min_max_heap_test<3, false>(); + run_min_max_heap_test<4, false>(); + run_min_max_heap_test<5, false>(); +} + +BOOST_AUTO_TEST_CASE( min_max_heap_stable_test ) +{ + run_min_max_heap_test<2, true>(); + run_min_max_heap_test<3, true>(); + run_min_max_heap_test<4, true>(); + run_min_max_heap_test<5, true>(); +} + +template +void run_min_max_heap_mutable_test(void) +{ + typedef boost::heap::min_max_heap, + boost::heap::arity, + boost::heap::stable + > pri_queue; + + BOOST_CONCEPT_ASSERT((boost::heap::MutablePriorityQueue)); + + run_common_heap_tests(); + run_moveable_heap_tests(); + run_reserve_heap_tests(); + run_mutable_heap_tests(); + + run_merge_tests(); + + run_ordered_iterator_tests(); + run_reverse_ordered_iterator_tests(); + + if (stable) { + typedef boost::heap::min_max_heap, + boost::heap::arity, + boost::heap::stable + > stable_pri_queue; + run_stable_heap_tests(); + } +} + +BOOST_AUTO_TEST_CASE( min_max_heap_mutable_test ) +{ + run_min_max_heap_mutable_test<2, false>(); + run_min_max_heap_mutable_test<3, false>(); + run_min_max_heap_mutable_test<4, false>(); + run_min_max_heap_mutable_test<5, false>(); +} + +BOOST_AUTO_TEST_CASE( min_max_heap_mutable_stable_test ) +{ + run_min_max_heap_mutable_test<2, true>(); + run_min_max_heap_mutable_test<3, true>(); + run_min_max_heap_mutable_test<4, true>(); + run_min_max_heap_mutable_test<5, true>(); +} + +BOOST_AUTO_TEST_CASE( min_max_heap_compare_lookup_test ) +{ + typedef boost::heap::min_max_heap, + boost::heap::compare, + boost::heap::allocator > > pri_queue; + run_common_heap_tests(); +} + +BOOST_AUTO_TEST_CASE( min_max_heap_leak_test ) +{ + typedef boost::heap::min_max_heap, boost::heap::arity<2> > pri_queue; + run_leak_check_test(); +} + diff --git a/test/mutable_heap_tests.hpp b/test/mutable_heap_tests.hpp index 3df1d30..a56fe3a 100644 --- a/test/mutable_heap_tests.hpp +++ b/test/mutable_heap_tests.hpp @@ -323,3 +323,9 @@ void run_ordered_iterator_tests() { pri_queue_test_ordered_iterators(); } + +template +void run_reverse_ordered_iterator_tests() +{ + pri_queue_test_reverse_ordered_iterators(); +}