stable_heap.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  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. #ifndef BOOST_HEAP_DETAIL_STABLE_HEAP_HPP
  9. #define BOOST_HEAP_DETAIL_STABLE_HEAP_HPP
  10. #include <limits>
  11. #include <stdexcept>
  12. #include <utility>
  13. #include <boost/cstdint.hpp>
  14. #include <boost/throw_exception.hpp>
  15. #include <boost/iterator/iterator_adaptor.hpp>
  16. #include <boost/heap/policies.hpp>
  17. #include <boost/heap/heap_merge.hpp>
  18. #include <boost/type_traits/is_nothrow_move_constructible.hpp>
  19. #include <boost/type_traits/is_nothrow_move_assignable.hpp>
  20. namespace boost {
  21. namespace heap {
  22. namespace detail {
  23. template<bool ConstantSize, class SizeType>
  24. struct size_holder
  25. {
  26. static const bool constant_time_size = ConstantSize;
  27. typedef SizeType size_type;
  28. size_holder(void) BOOST_NOEXCEPT:
  29. size_(0)
  30. {}
  31. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  32. size_holder(size_holder && rhs) BOOST_NOEXCEPT:
  33. size_(rhs.size_)
  34. {
  35. rhs.size_ = 0;
  36. }
  37. size_holder(size_holder const & rhs) BOOST_NOEXCEPT:
  38. size_(rhs.size_)
  39. {}
  40. size_holder & operator=(size_holder && rhs) BOOST_NOEXCEPT
  41. {
  42. size_ = rhs.size_;
  43. rhs.size_ = 0;
  44. return *this;
  45. }
  46. size_holder & operator=(size_holder const & rhs) BOOST_NOEXCEPT
  47. {
  48. size_ = rhs.size_;
  49. return *this;
  50. }
  51. #endif
  52. SizeType get_size() const BOOST_NOEXCEPT
  53. { return size_; }
  54. void set_size(SizeType size) BOOST_NOEXCEPT
  55. { size_ = size; }
  56. void decrement() BOOST_NOEXCEPT
  57. { --size_; }
  58. void increment() BOOST_NOEXCEPT
  59. { ++size_; }
  60. void add(SizeType value) BOOST_NOEXCEPT
  61. { size_ += value; }
  62. void sub(SizeType value) BOOST_NOEXCEPT
  63. { size_ -= value; }
  64. void swap(size_holder & rhs) BOOST_NOEXCEPT
  65. { std::swap(size_, rhs.size_); }
  66. SizeType size_;
  67. };
  68. template<class SizeType>
  69. struct size_holder<false, SizeType>
  70. {
  71. static const bool constant_time_size = false;
  72. typedef SizeType size_type;
  73. size_holder(void) BOOST_NOEXCEPT
  74. {}
  75. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  76. size_holder(size_holder && rhs) BOOST_NOEXCEPT
  77. {}
  78. size_holder(size_holder const & rhs) BOOST_NOEXCEPT
  79. {}
  80. size_holder & operator=(size_holder && rhs) BOOST_NOEXCEPT
  81. {
  82. return *this;
  83. }
  84. size_holder & operator=(size_holder const & rhs) BOOST_NOEXCEPT
  85. {
  86. return *this;
  87. }
  88. #endif
  89. size_type get_size() const BOOST_NOEXCEPT
  90. { return 0; }
  91. void set_size(size_type) BOOST_NOEXCEPT
  92. {}
  93. void decrement() BOOST_NOEXCEPT
  94. {}
  95. void increment() BOOST_NOEXCEPT
  96. {}
  97. void add(SizeType /*value*/) BOOST_NOEXCEPT
  98. {}
  99. void sub(SizeType /*value*/) BOOST_NOEXCEPT
  100. {}
  101. void swap(size_holder & /*rhs*/) BOOST_NOEXCEPT
  102. {}
  103. };
  104. // note: MSVC does not implement lookup correctly, we therefore have to place the Cmp object as member inside the
  105. // struct. of course, this prevents EBO and significantly reduces the readability of this code
  106. template <typename T,
  107. typename Cmp,
  108. bool constant_time_size,
  109. typename StabilityCounterType = boost::uintmax_t,
  110. bool stable = false
  111. >
  112. struct heap_base:
  113. #ifndef BOOST_MSVC
  114. Cmp,
  115. #endif
  116. size_holder<constant_time_size, size_t>
  117. {
  118. typedef StabilityCounterType stability_counter_type;
  119. typedef T value_type;
  120. typedef T internal_type;
  121. typedef size_holder<constant_time_size, size_t> size_holder_type;
  122. typedef Cmp value_compare;
  123. typedef Cmp internal_compare;
  124. static const bool is_stable = stable;
  125. #ifdef BOOST_MSVC
  126. Cmp cmp_;
  127. #endif
  128. heap_base (Cmp const & cmp = Cmp()):
  129. #ifndef BOOST_MSVC
  130. Cmp(cmp)
  131. #else
  132. cmp_(cmp)
  133. #endif
  134. {}
  135. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  136. heap_base(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<Cmp>::value):
  137. #ifndef BOOST_MSVC
  138. Cmp(std::move(static_cast<Cmp&>(rhs))),
  139. #else
  140. cmp_(std::move(rhs.cmp_)),
  141. #endif
  142. size_holder_type(std::move(static_cast<size_holder_type&>(rhs)))
  143. {}
  144. heap_base(heap_base const & rhs):
  145. #ifndef BOOST_MSVC
  146. Cmp(static_cast<Cmp const &>(rhs)),
  147. #else
  148. cmp_(rhs.value_comp()),
  149. #endif
  150. size_holder_type(static_cast<size_holder_type const &>(rhs))
  151. {}
  152. heap_base & operator=(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_assignable<Cmp>::value)
  153. {
  154. value_comp_ref().operator=(std::move(rhs.value_comp_ref()));
  155. size_holder_type::operator=(std::move(static_cast<size_holder_type&>(rhs)));
  156. return *this;
  157. }
  158. heap_base & operator=(heap_base const & rhs)
  159. {
  160. value_comp_ref().operator=(rhs.value_comp());
  161. size_holder_type::operator=(static_cast<size_holder_type const &>(rhs));
  162. return *this;
  163. }
  164. #endif
  165. bool operator()(internal_type const & lhs, internal_type const & rhs) const
  166. {
  167. return value_comp().operator()(lhs, rhs);
  168. }
  169. internal_type make_node(T const & val)
  170. {
  171. return val;
  172. }
  173. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  174. T && make_node(T && val)
  175. {
  176. return std::forward<T>(val);
  177. }
  178. #endif
  179. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  180. template <class... Args>
  181. internal_type make_node(Args && ... val)
  182. {
  183. return internal_type(std::forward<Args>(val)...);
  184. }
  185. #endif
  186. static T & get_value(internal_type & val) BOOST_NOEXCEPT
  187. {
  188. return val;
  189. }
  190. static T const & get_value(internal_type const & val) BOOST_NOEXCEPT
  191. {
  192. return val;
  193. }
  194. Cmp const & value_comp(void) const BOOST_NOEXCEPT
  195. {
  196. #ifndef BOOST_MSVC
  197. return *this;
  198. #else
  199. return cmp_;
  200. #endif
  201. }
  202. Cmp const & get_internal_cmp(void) const BOOST_NOEXCEPT
  203. {
  204. return value_comp();
  205. }
  206. void swap(heap_base & rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<Cmp>::value && boost::is_nothrow_move_assignable<Cmp>::value)
  207. {
  208. std::swap(value_comp_ref(), rhs.value_comp_ref());
  209. size_holder<constant_time_size, size_t>::swap(rhs);
  210. }
  211. stability_counter_type get_stability_count(void) const BOOST_NOEXCEPT
  212. {
  213. return 0;
  214. }
  215. void set_stability_count(stability_counter_type) BOOST_NOEXCEPT
  216. {}
  217. template <typename Heap1, typename Heap2>
  218. friend struct heap_merge_emulate;
  219. private:
  220. Cmp & value_comp_ref(void)
  221. {
  222. #ifndef BOOST_MSVC
  223. return *this;
  224. #else
  225. return cmp_;
  226. #endif
  227. }
  228. };
  229. template <typename T,
  230. typename Cmp,
  231. bool constant_time_size,
  232. typename StabilityCounterType
  233. >
  234. struct heap_base<T, Cmp, constant_time_size, StabilityCounterType, true>:
  235. #ifndef BOOST_MSVC
  236. Cmp,
  237. #endif
  238. size_holder<constant_time_size, size_t>
  239. {
  240. typedef StabilityCounterType stability_counter_type;
  241. typedef T value_type;
  242. struct internal_type
  243. {
  244. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  245. template <class ...Args>
  246. internal_type(stability_counter_type cnt, Args && ... args):
  247. first(std::forward<Args>(args)...), second(cnt)
  248. {}
  249. #endif
  250. internal_type(stability_counter_type const & cnt, T const & value):
  251. first(value), second(cnt)
  252. {}
  253. T first;
  254. stability_counter_type second;
  255. };
  256. typedef size_holder<constant_time_size, size_t> size_holder_type;
  257. typedef Cmp value_compare;
  258. #ifdef BOOST_MSVC
  259. Cmp cmp_;
  260. #endif
  261. heap_base (Cmp const & cmp = Cmp()):
  262. #ifndef BOOST_MSVC
  263. Cmp(cmp),
  264. #else
  265. cmp_(cmp),
  266. #endif
  267. counter_(0)
  268. {}
  269. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  270. heap_base(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<Cmp>::value):
  271. #ifndef BOOST_MSVC
  272. Cmp(std::move(static_cast<Cmp&>(rhs))),
  273. #else
  274. cmp_(std::move(rhs.cmp_)),
  275. #endif
  276. size_holder_type(std::move(static_cast<size_holder_type&>(rhs))), counter_(rhs.counter_)
  277. {
  278. rhs.counter_ = 0;
  279. }
  280. heap_base(heap_base const & rhs):
  281. #ifndef BOOST_MSVC
  282. Cmp(static_cast<Cmp const&>(rhs)),
  283. #else
  284. cmp_(rhs.value_comp()),
  285. #endif
  286. size_holder_type(static_cast<size_holder_type const &>(rhs)), counter_(rhs.counter_)
  287. {}
  288. heap_base & operator=(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_assignable<Cmp>::value)
  289. {
  290. value_comp_ref().operator=(std::move(rhs.value_comp_ref()));
  291. size_holder_type::operator=(std::move(static_cast<size_holder_type&>(rhs)));
  292. counter_ = rhs.counter_;
  293. rhs.counter_ = 0;
  294. return *this;
  295. }
  296. heap_base & operator=(heap_base const & rhs)
  297. {
  298. value_comp_ref().operator=(rhs.value_comp());
  299. size_holder_type::operator=(static_cast<size_holder_type const &>(rhs));
  300. counter_ = rhs.counter_;
  301. return *this;
  302. }
  303. #endif
  304. bool operator()(internal_type const & lhs, internal_type const & rhs) const
  305. {
  306. return get_internal_cmp()(lhs, rhs);
  307. }
  308. bool operator()(T const & lhs, T const & rhs) const
  309. {
  310. return value_comp()(lhs, rhs);
  311. }
  312. internal_type make_node(T const & val)
  313. {
  314. stability_counter_type count = ++counter_;
  315. if (counter_ == (std::numeric_limits<stability_counter_type>::max)())
  316. BOOST_THROW_EXCEPTION(std::runtime_error("boost::heap counter overflow"));
  317. return internal_type(count, val);
  318. }
  319. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  320. template <class... Args>
  321. internal_type make_node(Args&&... args)
  322. {
  323. stability_counter_type count = ++counter_;
  324. if (counter_ == (std::numeric_limits<stability_counter_type>::max)())
  325. BOOST_THROW_EXCEPTION(std::runtime_error("boost::heap counter overflow"));
  326. return internal_type (count, std::forward<Args>(args)...);
  327. }
  328. #endif
  329. static T & get_value(internal_type & val) BOOST_NOEXCEPT
  330. {
  331. return val.first;
  332. }
  333. static T const & get_value(internal_type const & val) BOOST_NOEXCEPT
  334. {
  335. return val.first;
  336. }
  337. Cmp const & value_comp(void) const BOOST_NOEXCEPT
  338. {
  339. #ifndef BOOST_MSVC
  340. return *this;
  341. #else
  342. return cmp_;
  343. #endif
  344. }
  345. struct internal_compare:
  346. Cmp
  347. {
  348. internal_compare(Cmp const & cmp = Cmp()):
  349. Cmp(cmp)
  350. {}
  351. bool operator()(internal_type const & lhs, internal_type const & rhs) const
  352. {
  353. if (Cmp::operator()(lhs.first, rhs.first))
  354. return true;
  355. if (Cmp::operator()(rhs.first, lhs.first))
  356. return false;
  357. return lhs.second > rhs.second;
  358. }
  359. };
  360. internal_compare get_internal_cmp(void) const
  361. {
  362. return internal_compare(value_comp());
  363. }
  364. void swap(heap_base & rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<Cmp>::value && boost::is_nothrow_move_assignable<Cmp>::value)
  365. {
  366. #ifndef BOOST_MSVC
  367. std::swap(static_cast<Cmp&>(*this), static_cast<Cmp&>(rhs));
  368. #else
  369. std::swap(cmp_, rhs.cmp_);
  370. #endif
  371. std::swap(counter_, rhs.counter_);
  372. size_holder<constant_time_size, size_t>::swap(rhs);
  373. }
  374. stability_counter_type get_stability_count(void) const
  375. {
  376. return counter_;
  377. }
  378. void set_stability_count(stability_counter_type new_count)
  379. {
  380. counter_ = new_count;
  381. }
  382. template <typename Heap1, typename Heap2>
  383. friend struct heap_merge_emulate;
  384. private:
  385. Cmp & value_comp_ref(void) BOOST_NOEXCEPT
  386. {
  387. #ifndef BOOST_MSVC
  388. return *this;
  389. #else
  390. return cmp_;
  391. #endif
  392. }
  393. stability_counter_type counter_;
  394. };
  395. template <typename node_pointer,
  396. typename extractor,
  397. typename reference
  398. >
  399. struct node_handle
  400. {
  401. explicit node_handle(node_pointer n = 0):
  402. node_(n)
  403. {}
  404. reference operator*() const
  405. {
  406. return extractor::get_value(node_->value);
  407. }
  408. bool operator==(node_handle const & rhs) const
  409. {
  410. return node_ == rhs.node_;
  411. }
  412. bool operator!=(node_handle const & rhs) const
  413. {
  414. return node_ != rhs.node_;
  415. }
  416. node_pointer node_;
  417. };
  418. template <typename value_type,
  419. typename internal_type,
  420. typename extractor
  421. >
  422. struct value_extractor
  423. {
  424. value_type const & operator()(internal_type const & data) const
  425. {
  426. return extractor::get_value(data);
  427. }
  428. };
  429. template <typename T,
  430. typename ContainerIterator,
  431. typename Extractor>
  432. class stable_heap_iterator:
  433. public boost::iterator_adaptor<stable_heap_iterator<T, ContainerIterator, Extractor>,
  434. ContainerIterator,
  435. T const,
  436. boost::random_access_traversal_tag>
  437. {
  438. typedef boost::iterator_adaptor<stable_heap_iterator,
  439. ContainerIterator,
  440. T const,
  441. boost::random_access_traversal_tag> super_t;
  442. public:
  443. stable_heap_iterator(void):
  444. super_t(0)
  445. {}
  446. explicit stable_heap_iterator(ContainerIterator const & it):
  447. super_t(it)
  448. {}
  449. private:
  450. friend class boost::iterator_core_access;
  451. T const & dereference() const
  452. {
  453. return Extractor::get_value(*super_t::base());
  454. }
  455. };
  456. template <typename T, typename Parspec, bool constant_time_size>
  457. struct make_heap_base
  458. {
  459. typedef typename parameter::binding<Parspec, tag::compare, std::less<T> >::type compare_argument;
  460. typedef typename parameter::binding<Parspec, tag::allocator, std::allocator<T> >::type allocator_argument;
  461. typedef typename parameter::binding<Parspec, tag::stability_counter_type, boost::uintmax_t >::type stability_counter_type;
  462. static const bool is_stable = extract_stable<Parspec>::value;
  463. typedef heap_base<T, compare_argument, constant_time_size, stability_counter_type, is_stable> type;
  464. };
  465. template <typename Alloc>
  466. struct extract_allocator_types
  467. {
  468. #ifdef BOOST_NO_CXX11_ALLOCATOR
  469. typedef typename Alloc::size_type size_type;
  470. typedef typename Alloc::difference_type difference_type;
  471. typedef typename Alloc::reference reference;
  472. typedef typename Alloc::const_reference const_reference;
  473. typedef typename Alloc::pointer pointer;
  474. typedef typename Alloc::const_pointer const_pointer;
  475. #else
  476. typedef std::allocator_traits<Alloc> traits;
  477. typedef typename traits::size_type size_type;
  478. typedef typename traits::difference_type difference_type;
  479. typedef typename Alloc::value_type& reference;
  480. typedef typename Alloc::value_type const& const_reference;
  481. typedef typename traits::pointer pointer;
  482. typedef typename traits::const_pointer const_pointer;
  483. #endif
  484. };
  485. } /* namespace detail */
  486. } /* namespace heap */
  487. } /* namespace boost */
  488. #endif /* BOOST_HEAP_DETAIL_STABLE_HEAP_HPP */