// boost heap: helper classes for stable priority queues // // Copyright (C) 2010 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_STABLE_HEAP_HPP #define BOOST_HEAP_DETAIL_STABLE_HEAP_HPP #include #include #include #include #include #include #include #include #include #include namespace boost { namespace heap { namespace detail { template struct size_holder { static const bool constant_time_size = ConstantSize; typedef SizeType size_type; size_holder(void) BOOST_NOEXCEPT: size_(0) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES size_holder(size_holder && rhs) BOOST_NOEXCEPT: size_(rhs.size_) { rhs.size_ = 0; } size_holder(size_holder const & rhs) BOOST_NOEXCEPT: size_(rhs.size_) {} size_holder & operator=(size_holder && rhs) BOOST_NOEXCEPT { size_ = rhs.size_; rhs.size_ = 0; return *this; } size_holder & operator=(size_holder const & rhs) BOOST_NOEXCEPT { size_ = rhs.size_; return *this; } #endif SizeType get_size() const BOOST_NOEXCEPT { return size_; } void set_size(SizeType size) BOOST_NOEXCEPT { size_ = size; } void decrement() BOOST_NOEXCEPT { --size_; } void increment() BOOST_NOEXCEPT { ++size_; } void add(SizeType value) BOOST_NOEXCEPT { size_ += value; } void sub(SizeType value) BOOST_NOEXCEPT { size_ -= value; } void swap(size_holder & rhs) BOOST_NOEXCEPT { std::swap(size_, rhs.size_); } SizeType size_; }; template struct size_holder { static const bool constant_time_size = false; typedef SizeType size_type; size_holder(void) BOOST_NOEXCEPT {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES size_holder(size_holder && rhs) BOOST_NOEXCEPT {} size_holder(size_holder const & rhs) BOOST_NOEXCEPT {} size_holder & operator=(size_holder && rhs) BOOST_NOEXCEPT { return *this; } size_holder & operator=(size_holder const & rhs) BOOST_NOEXCEPT { return *this; } #endif size_type get_size() const BOOST_NOEXCEPT { return 0; } void set_size(size_type) BOOST_NOEXCEPT {} void decrement() BOOST_NOEXCEPT {} void increment() BOOST_NOEXCEPT {} void add(SizeType /*value*/) BOOST_NOEXCEPT {} void sub(SizeType /*value*/) BOOST_NOEXCEPT {} void swap(size_holder & /*rhs*/) BOOST_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 struct heap_base: #ifndef BOOST_MSVC Cmp, #endif size_holder { typedef StabilityCounterType stability_counter_type; typedef T value_type; typedef T internal_type; typedef size_holder size_holder_type; typedef Cmp value_compare; 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 {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES heap_base(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible::value): #ifndef BOOST_MSVC Cmp(std::move(static_cast(rhs))), #else cmp_(std::move(rhs.cmp_)), #endif size_holder_type(std::move(static_cast(rhs))) {} heap_base(heap_base const & rhs): #ifndef BOOST_MSVC Cmp(static_cast(rhs)), #else cmp_(rhs.value_comp()), #endif size_holder_type(static_cast(rhs)) {} heap_base & operator=(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_assignable::value) { value_comp_ref().operator=(std::move(rhs.value_comp_ref())); size_holder_type::operator=(std::move(static_cast(rhs))); return *this; } heap_base & operator=(heap_base const & rhs) { value_comp_ref().operator=(rhs.value_comp()); size_holder_type::operator=(static_cast(rhs)); return *this; } #endif bool operator()(internal_type const & lhs, internal_type const & rhs) const { return value_comp().operator()(lhs, rhs); } internal_type make_node(T const & val) { return val; } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES T && make_node(T && val) { return std::forward(val); } #endif #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template internal_type make_node(Args && ... val) { return internal_type(std::forward(val)...); } #endif static T & get_value(internal_type & val) BOOST_NOEXCEPT { return val; } static T const & get_value(internal_type const & val) BOOST_NOEXCEPT { return val; } Cmp const & value_comp(void) const BOOST_NOEXCEPT { #ifndef BOOST_MSVC return *this; #else return cmp_; #endif } Cmp const & get_internal_cmp(void) const BOOST_NOEXCEPT { return value_comp(); } void swap(heap_base & rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible::value && boost::is_nothrow_move_assignable::value) { std::swap(value_comp_ref(), rhs.value_comp_ref()); size_holder::swap(rhs); } stability_counter_type get_stability_count(void) const BOOST_NOEXCEPT { return 0; } void set_stability_count(stability_counter_type) BOOST_NOEXCEPT {} template friend struct heap_merge_emulate; private: Cmp & value_comp_ref(void) { #ifndef BOOST_MSVC return *this; #else return cmp_; #endif } }; template struct heap_base: #ifndef BOOST_MSVC Cmp, #endif size_holder { typedef StabilityCounterType stability_counter_type; typedef T value_type; struct internal_type { #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template internal_type(stability_counter_type cnt, Args && ... args): first(std::forward(args)...), second(cnt) {} #endif internal_type(stability_counter_type const & cnt, T const & value): first(value), second(cnt) {} T first; stability_counter_type second; }; typedef size_holder 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) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES heap_base(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible::value): #ifndef BOOST_MSVC Cmp(std::move(static_cast(rhs))), #else cmp_(std::move(rhs.cmp_)), #endif size_holder_type(std::move(static_cast(rhs))), counter_(rhs.counter_) { rhs.counter_ = 0; } heap_base(heap_base const & rhs): #ifndef BOOST_MSVC Cmp(static_cast(rhs)), #else cmp_(rhs.value_comp()), #endif size_holder_type(static_cast(rhs)), counter_(rhs.counter_) {} heap_base & operator=(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_assignable::value) { value_comp_ref().operator=(std::move(rhs.value_comp_ref())); size_holder_type::operator=(std::move(static_cast(rhs))); counter_ = rhs.counter_; rhs.counter_ = 0; return *this; } heap_base & operator=(heap_base const & rhs) { value_comp_ref().operator=(rhs.value_comp()); size_holder_type::operator=(static_cast(rhs)); counter_ = rhs.counter_; return *this; } #endif bool operator()(internal_type const & lhs, internal_type const & rhs) const { return get_internal_cmp()(lhs, rhs); } bool operator()(T const & lhs, T const & rhs) const { return value_comp()(lhs, rhs); } internal_type make_node(T const & val) { stability_counter_type count = ++counter_; if (counter_ == (std::numeric_limits::max)()) BOOST_THROW_EXCEPTION(std::runtime_error("boost::heap counter overflow")); return internal_type(count, val); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template internal_type make_node(Args&&... args) { stability_counter_type count = ++counter_; if (counter_ == (std::numeric_limits::max)()) BOOST_THROW_EXCEPTION(std::runtime_error("boost::heap counter overflow")); return internal_type (count, std::forward(args)...); } #endif static T & get_value(internal_type & val) BOOST_NOEXCEPT { return val.first; } static T const & get_value(internal_type const & val) BOOST_NOEXCEPT { return val.first; } Cmp const & value_comp(void) const BOOST_NOEXCEPT { #ifndef BOOST_MSVC return *this; #else return cmp_; #endif } struct internal_compare: Cmp { internal_compare(Cmp const & cmp = Cmp()): Cmp(cmp) {} bool operator()(internal_type const & lhs, internal_type const & rhs) const { if (Cmp::operator()(lhs.first, rhs.first)) return true; if (Cmp::operator()(rhs.first, lhs.first)) return false; return lhs.second > rhs.second; } }; internal_compare get_internal_cmp(void) const { return internal_compare(value_comp()); } void swap(heap_base & rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible::value && boost::is_nothrow_move_assignable::value) { #ifndef BOOST_MSVC std::swap(static_cast(*this), static_cast(rhs)); #else std::swap(cmp_, rhs.cmp_); #endif std::swap(counter_, rhs.counter_); size_holder::swap(rhs); } stability_counter_type get_stability_count(void) const { return counter_; } void set_stability_count(stability_counter_type new_count) { counter_ = new_count; } template friend struct heap_merge_emulate; private: Cmp & value_comp_ref(void) BOOST_NOEXCEPT { #ifndef BOOST_MSVC return *this; #else return cmp_; #endif } stability_counter_type counter_; }; template struct node_handle { explicit node_handle(node_pointer n = 0): node_(n) {} reference operator*() const { return extractor::get_value(node_->value); } bool operator==(node_handle const & rhs) const { return node_ == rhs.node_; } bool operator!=(node_handle const & rhs) const { return node_ != rhs.node_; } node_pointer node_; }; template struct value_extractor { value_type const & operator()(internal_type const & data) const { return extractor::get_value(data); } }; template class stable_heap_iterator: public boost::iterator_adaptor, ContainerIterator, T const, boost::random_access_traversal_tag> { typedef boost::iterator_adaptor super_t; public: stable_heap_iterator(void): super_t(0) {} explicit stable_heap_iterator(ContainerIterator const & it): super_t(it) {} private: friend class boost::iterator_core_access; T const & dereference() const { return Extractor::get_value(*super_t::base()); } }; template struct make_heap_base { typedef typename parameter::binding >::type compare_argument; typedef typename parameter::binding >::type allocator_argument; typedef typename parameter::binding::type stability_counter_type; static const bool is_stable = extract_stable::value; typedef heap_base type; }; template struct extract_allocator_types { typedef typename Alloc::size_type size_type; typedef typename Alloc::difference_type difference_type; typedef typename Alloc::reference reference; typedef typename Alloc::const_reference const_reference; typedef typename Alloc::pointer pointer; typedef typename Alloc::const_pointer const_pointer; }; } /* namespace detail */ } /* namespace heap */ } /* namespace boost */ #endif /* BOOST_HEAP_DETAIL_STABLE_HEAP_HPP */