1 // boost heap: helper classes for stable priority queues
2 //
3 // Copyright (C) 2010 Tim Blechmann
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_HEAP_DETAIL_STABLE_HEAP_HPP
10 #define BOOST_HEAP_DETAIL_STABLE_HEAP_HPP
11 
12 #include <limits>
13 #include <stdexcept>
14 #include <utility>
15 
16 #include <boost/cstdint.hpp>
17 #include <boost/throw_exception.hpp>
18 #include <boost/iterator/iterator_adaptor.hpp>
19 
20 #include <boost/heap/policies.hpp>
21 #include <boost/heap/heap_merge.hpp>
22 
23 namespace boost  {
24 namespace heap   {
25 namespace detail {
26 
27 template<bool ConstantSize, class SizeType>
28 struct size_holder
29 {
30     static const bool constant_time_size = ConstantSize;
31     typedef SizeType  size_type;
32 
size_holderboost::heap::detail::size_holder33     size_holder(void):
34         size_(0)
35     {}
36 
37 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
size_holderboost::heap::detail::size_holder38     size_holder(size_holder && rhs):
39         size_(rhs.size_)
40     {
41         rhs.size_ = 0;
42     }
43 
size_holderboost::heap::detail::size_holder44     size_holder(size_holder const & rhs):
45         size_(rhs.size_)
46     {}
47 
operator =boost::heap::detail::size_holder48     size_holder & operator=(size_holder && rhs)
49     {
50         size_ = rhs.size_;
51         rhs.size_ = 0;
52         return *this;
53     }
54 
operator =boost::heap::detail::size_holder55     size_holder & operator=(size_holder const & rhs)
56     {
57         size_ = rhs.size_;
58         return *this;
59     }
60 #endif
61 
get_sizeboost::heap::detail::size_holder62     SizeType get_size() const
63     {  return size_;  }
64 
set_sizeboost::heap::detail::size_holder65     void set_size(SizeType size)
66     {  size_ = size; }
67 
decrementboost::heap::detail::size_holder68     void decrement()
69     {  --size_; }
70 
incrementboost::heap::detail::size_holder71     void increment()
72     {  ++size_; }
73 
addboost::heap::detail::size_holder74     void add(SizeType value)
75     {  size_ += value; }
76 
subboost::heap::detail::size_holder77     void sub(SizeType value)
78     {  size_ -= value; }
79 
swapboost::heap::detail::size_holder80     void swap(size_holder & rhs)
81     {  std::swap(size_, rhs.size_); }
82 
83     SizeType size_;
84 };
85 
86 template<class SizeType>
87 struct size_holder<false, SizeType>
88 {
89     static const bool constant_time_size = false;
90     typedef SizeType  size_type;
91 
size_holderboost::heap::detail::size_holder92     size_holder(void)
93     {}
94 
95 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
size_holderboost::heap::detail::size_holder96     size_holder(size_holder && rhs)
97     {}
98 
size_holderboost::heap::detail::size_holder99     size_holder(size_holder const & rhs)
100     {}
101 
operator =boost::heap::detail::size_holder102     size_holder & operator=(size_holder && rhs)
103     {
104         return *this;
105     }
106 
operator =boost::heap::detail::size_holder107     size_holder & operator=(size_holder const & rhs)
108     {
109         return *this;
110     }
111 #endif
112 
get_sizeboost::heap::detail::size_holder113     size_type get_size() const
114     {  return 0;  }
115 
set_sizeboost::heap::detail::size_holder116     void set_size(size_type)
117     {}
118 
decrementboost::heap::detail::size_holder119     void decrement()
120     {}
121 
incrementboost::heap::detail::size_holder122     void increment()
123     {}
124 
addboost::heap::detail::size_holder125     void add(SizeType value)
126     {}
127 
subboost::heap::detail::size_holder128     void sub(SizeType value)
129     {}
130 
swapboost::heap::detail::size_holder131     void swap(size_holder & rhs)
132     {}
133 };
134 
135 // note: MSVC does not implement lookup correctly, we therefore have to place the Cmp object as member inside the
136 //       struct. of course, this prevents EBO and significantly reduces the readability of this code
137 template <typename T,
138           typename Cmp,
139           bool constant_time_size,
140           typename StabilityCounterType = boost::uintmax_t,
141           bool stable = false
142          >
143 struct heap_base:
144 #ifndef BOOST_MSVC
145     Cmp,
146 #endif
147     size_holder<constant_time_size, size_t>
148 {
149     typedef StabilityCounterType stability_counter_type;
150     typedef T value_type;
151     typedef T internal_type;
152     typedef size_holder<constant_time_size, size_t> size_holder_type;
153     typedef Cmp value_compare;
154     typedef Cmp internal_compare;
155     static const bool is_stable = stable;
156 
157 #ifdef BOOST_MSVC
158     Cmp cmp_;
159 #endif
160 
heap_baseboost::heap::detail::heap_base161     heap_base (Cmp const & cmp = Cmp()):
162 #ifndef BOOST_MSVC
163         Cmp(cmp)
164 #else
165         cmp_(cmp)
166 #endif
167     {}
168 
169 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
heap_baseboost::heap::detail::heap_base170     heap_base(heap_base && rhs):
171 #ifndef BOOST_MSVC
172         Cmp(std::move(static_cast<Cmp&>(rhs))),
173 #else
174         cmp_(std::move(rhs.cmp_)),
175 #endif
176         size_holder_type(std::move(static_cast<size_holder_type&>(rhs)))
177     {}
178 
heap_baseboost::heap::detail::heap_base179     heap_base(heap_base const & rhs):
180 #ifndef BOOST_MSVC
181         Cmp(static_cast<Cmp const &>(rhs)),
182 #else
183         cmp_(rhs.value_comp()),
184 #endif
185         size_holder_type(static_cast<size_holder_type const &>(rhs))
186     {}
187 
operator =boost::heap::detail::heap_base188     heap_base & operator=(heap_base && rhs)
189     {
190         value_comp_ref().operator=(std::move(rhs.value_comp_ref()));
191         size_holder_type::operator=(std::move(static_cast<size_holder_type&>(rhs)));
192         return *this;
193     }
194 
operator =boost::heap::detail::heap_base195     heap_base & operator=(heap_base const & rhs)
196     {
197         value_comp_ref().operator=(rhs.value_comp());
198         size_holder_type::operator=(static_cast<size_holder_type const &>(rhs));
199         return *this;
200     }
201 #endif
202 
operator ()boost::heap::detail::heap_base203     bool operator()(internal_type const & lhs, internal_type const & rhs) const
204     {
205         return value_comp().operator()(lhs, rhs);
206     }
207 
make_nodeboost::heap::detail::heap_base208     internal_type make_node(T const & val)
209     {
210         return val;
211     }
212 
213 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
make_nodeboost::heap::detail::heap_base214     T && make_node(T && val)
215     {
216         return std::forward<T>(val);
217     }
218 #endif
219 
220 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
221     template <class... Args>
make_nodeboost::heap::detail::heap_base222     internal_type make_node(Args && ... val)
223     {
224         return internal_type(std::forward<Args>(val)...);
225     }
226 #endif
227 
get_valueboost::heap::detail::heap_base228     static T & get_value(internal_type & val)
229     {
230         return val;
231     }
232 
get_valueboost::heap::detail::heap_base233     static T const & get_value(internal_type const & val)
234     {
235         return val;
236     }
237 
value_compboost::heap::detail::heap_base238     Cmp const & value_comp(void) const
239     {
240 #ifndef BOOST_MSVC
241         return *this;
242 #else
243         return cmp_;
244 #endif
245     }
246 
get_internal_cmpboost::heap::detail::heap_base247     Cmp const & get_internal_cmp(void) const
248     {
249         return value_comp();
250     }
251 
swapboost::heap::detail::heap_base252     void swap(heap_base & rhs)
253     {
254         std::swap(value_comp_ref(), rhs.value_comp_ref());
255         size_holder<constant_time_size, size_t>::swap(rhs);
256     }
257 
get_stability_countboost::heap::detail::heap_base258     stability_counter_type get_stability_count(void) const
259     {
260         return 0;
261     }
262 
set_stability_countboost::heap::detail::heap_base263     void set_stability_count(stability_counter_type)
264     {}
265 
266     template <typename Heap1, typename Heap2>
267     friend struct heap_merge_emulate;
268 
269 private:
value_comp_refboost::heap::detail::heap_base270     Cmp & value_comp_ref(void)
271     {
272 #ifndef BOOST_MSVC
273         return *this;
274 #else
275         return cmp_;
276 #endif
277     }
278 };
279 
280 
281 template <typename T,
282           typename Cmp,
283           bool constant_time_size,
284           typename StabilityCounterType
285          >
286 struct heap_base<T, Cmp, constant_time_size, StabilityCounterType, true>:
287 #ifndef BOOST_MSVC
288     Cmp,
289 #endif
290     size_holder<constant_time_size, size_t>
291 {
292     typedef StabilityCounterType stability_counter_type;
293     typedef T value_type;
294 
295     struct internal_type
296     {
297 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
298         template <class ...Args>
internal_typeboost::heap::detail::heap_base::internal_type299         internal_type(stability_counter_type cnt, Args && ... args):
300             first(std::forward<Args>(args)...), second(cnt)
301         {}
302 #endif
303 
internal_typeboost::heap::detail::heap_base::internal_type304         internal_type(stability_counter_type const & cnt, T const & value):
305             first(value), second(cnt)
306         {}
307 
308         T first;
309         stability_counter_type second;
310     };
311 
312     typedef size_holder<constant_time_size, size_t> size_holder_type;
313     typedef Cmp value_compare;
314 
315 #ifdef BOOST_MSVC
316     Cmp cmp_;
317 #endif
318 
heap_baseboost::heap::detail::heap_base319     heap_base (Cmp const & cmp = Cmp()):
320 #ifndef BOOST_MSVC
321         Cmp(cmp),
322 #else
323         cmp_(cmp),
324 #endif
325         counter_(0)
326     {}
327 
328 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
heap_baseboost::heap::detail::heap_base329     heap_base(heap_base && rhs):
330 #ifndef BOOST_MSVC
331         Cmp(std::move(static_cast<Cmp&>(rhs))),
332 #else
333         cmp_(std::move(rhs.cmp_)),
334 #endif
335         size_holder_type(std::move(static_cast<size_holder_type&>(rhs))), counter_(rhs.counter_)
336     {
337         rhs.counter_ = 0;
338     }
339 
heap_baseboost::heap::detail::heap_base340     heap_base(heap_base const & rhs):
341 #ifndef BOOST_MSVC
342         Cmp(static_cast<Cmp const&>(rhs)),
343 #else
344         cmp_(rhs.value_comp()),
345 #endif
346         size_holder_type(static_cast<size_holder_type const &>(rhs)), counter_(rhs.counter_)
347     {}
348 
operator =boost::heap::detail::heap_base349     heap_base & operator=(heap_base && rhs)
350     {
351         value_comp_ref().operator=(std::move(rhs.value_comp_ref()));
352         size_holder_type::operator=(std::move(static_cast<size_holder_type&>(rhs)));
353 
354         counter_ = rhs.counter_;
355         rhs.counter_ = 0;
356         return *this;
357     }
358 
operator =boost::heap::detail::heap_base359     heap_base & operator=(heap_base const & rhs)
360     {
361         value_comp_ref().operator=(rhs.value_comp());
362         size_holder_type::operator=(static_cast<size_holder_type const &>(rhs));
363 
364         counter_ = rhs.counter_;
365         return *this;
366     }
367 #endif
368 
operator ()boost::heap::detail::heap_base369     bool operator()(internal_type const & lhs, internal_type const & rhs) const
370     {
371         return get_internal_cmp()(lhs, rhs);
372     }
373 
operator ()boost::heap::detail::heap_base374     bool operator()(T const & lhs, T const & rhs) const
375     {
376         return value_comp()(lhs, rhs);
377     }
378 
make_nodeboost::heap::detail::heap_base379     internal_type make_node(T const & val)
380     {
381         stability_counter_type count = ++counter_;
382         if (counter_ == (std::numeric_limits<stability_counter_type>::max)())
383             BOOST_THROW_EXCEPTION(std::runtime_error("boost::heap counter overflow"));
384         return internal_type(count, val);
385     }
386 
387 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
388     template <class... Args>
make_nodeboost::heap::detail::heap_base389     internal_type make_node(Args&&... args)
390     {
391         stability_counter_type count = ++counter_;
392         if (counter_ == (std::numeric_limits<stability_counter_type>::max)())
393             BOOST_THROW_EXCEPTION(std::runtime_error("boost::heap counter overflow"));
394         return internal_type (count, std::forward<Args>(args)...);
395     }
396 #endif
397 
get_valueboost::heap::detail::heap_base398     static T & get_value(internal_type & val)
399     {
400         return val.first;
401     }
402 
get_valueboost::heap::detail::heap_base403     static T const & get_value(internal_type const & val)
404     {
405         return val.first;
406     }
407 
value_compboost::heap::detail::heap_base408     Cmp const & value_comp(void) const
409     {
410 #ifndef BOOST_MSVC
411         return *this;
412 #else
413         return cmp_;
414 #endif
415     }
416 
417     struct internal_compare:
418         Cmp
419     {
internal_compareboost::heap::detail::heap_base::internal_compare420         internal_compare(Cmp const & cmp = Cmp()):
421             Cmp(cmp)
422         {}
423 
operator ()boost::heap::detail::heap_base::internal_compare424         bool operator()(internal_type const & lhs, internal_type const & rhs) const
425         {
426             if (Cmp::operator()(lhs.first, rhs.first))
427                 return true;
428 
429             if (Cmp::operator()(rhs.first, lhs.first))
430                 return false;
431 
432             return lhs.second > rhs.second;
433         }
434     };
435 
get_internal_cmpboost::heap::detail::heap_base436     internal_compare get_internal_cmp(void) const
437     {
438         return internal_compare(value_comp());
439     }
440 
swapboost::heap::detail::heap_base441     void swap(heap_base & rhs)
442     {
443 #ifndef BOOST_MSVC
444         std::swap(static_cast<Cmp&>(*this), static_cast<Cmp&>(rhs));
445 #else
446         std::swap(cmp_, rhs.cmp_);
447 #endif
448         std::swap(counter_, rhs.counter_);
449         size_holder<constant_time_size, size_t>::swap(rhs);
450     }
451 
get_stability_countboost::heap::detail::heap_base452     stability_counter_type get_stability_count(void) const
453     {
454         return counter_;
455     }
456 
set_stability_countboost::heap::detail::heap_base457     void set_stability_count(stability_counter_type new_count)
458     {
459         counter_ = new_count;
460     }
461 
462     template <typename Heap1, typename Heap2>
463     friend struct heap_merge_emulate;
464 
465 private:
value_comp_refboost::heap::detail::heap_base466     Cmp & value_comp_ref(void)
467     {
468 #ifndef BOOST_MSVC
469         return *this;
470 #else
471         return cmp_;
472 #endif
473     }
474 
475     stability_counter_type counter_;
476 };
477 
478 template <typename node_pointer,
479           typename extractor,
480           typename reference
481          >
482 struct node_handle
483 {
node_handleboost::heap::detail::node_handle484     explicit node_handle(node_pointer n = 0):
485         node_(n)
486     {}
487 
operator *boost::heap::detail::node_handle488     reference operator*() const
489     {
490         return extractor::get_value(node_->value);
491     }
492 
operator ==boost::heap::detail::node_handle493     bool operator==(node_handle const & rhs) const
494     {
495         return node_ == rhs.node_;
496     }
497 
operator !=boost::heap::detail::node_handle498     bool operator!=(node_handle const & rhs) const
499     {
500         return node_ != rhs.node_;
501     }
502 
503     node_pointer node_;
504 };
505 
506 template <typename value_type,
507           typename internal_type,
508           typename extractor
509          >
510 struct value_extractor
511 {
operator ()boost::heap::detail::value_extractor512     value_type const & operator()(internal_type const & data) const
513     {
514         return extractor::get_value(data);
515     }
516 };
517 
518 template <typename T,
519           typename ContainerIterator,
520           typename Extractor>
521 class stable_heap_iterator:
522     public boost::iterator_adaptor<stable_heap_iterator<T, ContainerIterator, Extractor>,
523                                    ContainerIterator,
524                                    T const,
525                                    boost::random_access_traversal_tag>
526 {
527     typedef boost::iterator_adaptor<stable_heap_iterator,
528                                     ContainerIterator,
529                                     T const,
530                                     boost::random_access_traversal_tag> super_t;
531 
532 public:
stable_heap_iterator(void)533     stable_heap_iterator(void):
534         super_t(0)
535     {}
536 
stable_heap_iterator(ContainerIterator const & it)537     explicit stable_heap_iterator(ContainerIterator const & it):
538         super_t(it)
539     {}
540 
541 private:
542     friend class boost::iterator_core_access;
543 
dereference() const544     T const & dereference() const
545     {
546         return Extractor::get_value(*super_t::base());
547     }
548 };
549 
550 template <typename T, typename Parspec, bool constant_time_size>
551 struct make_heap_base
552 {
553     typedef typename parameter::binding<Parspec, tag::compare, std::less<T> >::type compare_argument;
554     typedef typename parameter::binding<Parspec, tag::allocator, std::allocator<T> >::type allocator_argument;
555     typedef typename parameter::binding<Parspec, tag::stability_counter_type, boost::uintmax_t >::type stability_counter_type;
556 
557     static const bool is_stable = extract_stable<Parspec>::value;
558 
559     typedef heap_base<T, compare_argument, constant_time_size, stability_counter_type, is_stable> type;
560 };
561 
562 
563 template <typename Alloc>
564 struct extract_allocator_types
565 {
566     typedef typename Alloc::size_type size_type;
567     typedef typename Alloc::difference_type difference_type;
568     typedef typename Alloc::reference reference;
569     typedef typename Alloc::const_reference const_reference;
570     typedef typename Alloc::pointer pointer;
571     typedef typename Alloc::const_pointer const_pointer;
572 };
573 
574 
575 } /* namespace detail */
576 } /* namespace heap */
577 } /* namespace boost */
578 
579 #endif /* BOOST_HEAP_DETAIL_STABLE_HEAP_HPP */
580