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