stable_heap.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  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. #endif
  140. size_holder_type(std::move(static_cast<size_holder_type&>(rhs)))
  141. #ifdef BOOST_MSVC
  142. , cmp_(std::move(rhs.cmp_))
  143. #endif
  144. {}
  145. heap_base(heap_base const & rhs):
  146. #ifndef BOOST_MSVC
  147. Cmp(static_cast<Cmp const &>(rhs)),
  148. #endif
  149. size_holder_type(static_cast<size_holder_type const &>(rhs))
  150. #ifdef BOOST_MSVC
  151. , cmp_(rhs.value_comp())
  152. #endif
  153. {}
  154. heap_base & operator=(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_assignable<Cmp>::value)
  155. {
  156. value_comp_ref().operator=(std::move(rhs.value_comp_ref()));
  157. size_holder_type::operator=(std::move(static_cast<size_holder_type&>(rhs)));
  158. return *this;
  159. }
  160. heap_base & operator=(heap_base const & rhs)
  161. {
  162. value_comp_ref().operator=(rhs.value_comp());
  163. size_holder_type::operator=(static_cast<size_holder_type const &>(rhs));
  164. return *this;
  165. }
  166. #endif
  167. bool operator()(internal_type const & lhs, internal_type const & rhs) const
  168. {
  169. return value_comp().operator()(lhs, rhs);
  170. }
  171. internal_type make_node(T const & val)
  172. {
  173. return val;
  174. }
  175. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  176. T && make_node(T && val)
  177. {
  178. return std::forward<T>(val);
  179. }
  180. #endif
  181. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  182. template <class... Args>
  183. internal_type make_node(Args && ... val)
  184. {
  185. return internal_type(std::forward<Args>(val)...);
  186. }
  187. #endif
  188. static T & get_value(internal_type & val) BOOST_NOEXCEPT
  189. {
  190. return val;
  191. }
  192. static T const & get_value(internal_type const & val) BOOST_NOEXCEPT
  193. {
  194. return val;
  195. }
  196. Cmp const & value_comp(void) const BOOST_NOEXCEPT
  197. {
  198. #ifndef BOOST_MSVC
  199. return *this;
  200. #else
  201. return cmp_;
  202. #endif
  203. }
  204. Cmp const & get_internal_cmp(void) const BOOST_NOEXCEPT
  205. {
  206. return value_comp();
  207. }
  208. void swap(heap_base & rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<Cmp>::value && boost::is_nothrow_move_assignable<Cmp>::value)
  209. {
  210. std::swap(value_comp_ref(), rhs.value_comp_ref());
  211. size_holder<constant_time_size, size_t>::swap(rhs);
  212. }
  213. stability_counter_type get_stability_count(void) const BOOST_NOEXCEPT
  214. {
  215. return 0;
  216. }
  217. void set_stability_count(stability_counter_type) BOOST_NOEXCEPT
  218. {}
  219. template <typename Heap1, typename Heap2>
  220. friend struct heap_merge_emulate;
  221. private:
  222. Cmp & value_comp_ref(void)
  223. {
  224. #ifndef BOOST_MSVC
  225. return *this;
  226. #else
  227. return cmp_;
  228. #endif
  229. }
  230. };
  231. template <typename T,
  232. typename Cmp,
  233. bool constant_time_size,
  234. typename StabilityCounterType
  235. >
  236. struct heap_base<T, Cmp, constant_time_size, StabilityCounterType, true>:
  237. #ifndef BOOST_MSVC
  238. Cmp,
  239. #endif
  240. size_holder<constant_time_size, size_t>
  241. {
  242. typedef StabilityCounterType stability_counter_type;
  243. typedef T value_type;
  244. struct internal_type
  245. {
  246. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  247. template <class ...Args>
  248. internal_type(stability_counter_type cnt, Args && ... args):
  249. first(std::forward<Args>(args)...), second(cnt)
  250. {}
  251. #endif
  252. internal_type(stability_counter_type const & cnt, T const & value):
  253. first(value), second(cnt)
  254. {}
  255. T first;
  256. stability_counter_type second;
  257. };
  258. typedef size_holder<constant_time_size, size_t> size_holder_type;
  259. typedef Cmp value_compare;
  260. #ifdef BOOST_MSVC
  261. Cmp cmp_;
  262. #endif
  263. heap_base (Cmp const & cmp = Cmp()):
  264. #ifndef BOOST_MSVC
  265. Cmp(cmp),
  266. #else
  267. cmp_(cmp),
  268. #endif
  269. counter_(0)
  270. {}
  271. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  272. heap_base(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<Cmp>::value):
  273. #ifndef BOOST_MSVC
  274. Cmp(std::move(static_cast<Cmp&>(rhs))),
  275. #else
  276. cmp_(std::move(rhs.cmp_)),
  277. #endif
  278. size_holder_type(std::move(static_cast<size_holder_type&>(rhs))), counter_(rhs.counter_)
  279. {
  280. rhs.counter_ = 0;
  281. }
  282. heap_base(heap_base const & rhs):
  283. #ifndef BOOST_MSVC
  284. Cmp(static_cast<Cmp const&>(rhs)),
  285. #else
  286. cmp_(rhs.value_comp()),
  287. #endif
  288. size_holder_type(static_cast<size_holder_type const &>(rhs)), counter_(rhs.counter_)
  289. {}
  290. heap_base & operator=(heap_base && rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_assignable<Cmp>::value)
  291. {
  292. value_comp_ref().operator=(std::move(rhs.value_comp_ref()));
  293. size_holder_type::operator=(std::move(static_cast<size_holder_type&>(rhs)));
  294. counter_ = rhs.counter_;
  295. rhs.counter_ = 0;
  296. return *this;
  297. }
  298. heap_base & operator=(heap_base const & rhs)
  299. {
  300. value_comp_ref().operator=(rhs.value_comp());
  301. size_holder_type::operator=(static_cast<size_holder_type const &>(rhs));
  302. counter_ = rhs.counter_;
  303. return *this;
  304. }
  305. #endif
  306. bool operator()(internal_type const & lhs, internal_type const & rhs) const
  307. {
  308. return get_internal_cmp()(lhs, rhs);
  309. }
  310. bool operator()(T const & lhs, T const & rhs) const
  311. {
  312. return value_comp()(lhs, rhs);
  313. }
  314. internal_type make_node(T const & val)
  315. {
  316. stability_counter_type count = ++counter_;
  317. if (counter_ == (std::numeric_limits<stability_counter_type>::max)())
  318. BOOST_THROW_EXCEPTION(std::runtime_error("boost::heap counter overflow"));
  319. return internal_type(count, val);
  320. }
  321. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  322. template <class... Args>
  323. internal_type make_node(Args&&... args)
  324. {
  325. stability_counter_type count = ++counter_;
  326. if (counter_ == (std::numeric_limits<stability_counter_type>::max)())
  327. BOOST_THROW_EXCEPTION(std::runtime_error("boost::heap counter overflow"));
  328. return internal_type (count, std::forward<Args>(args)...);
  329. }
  330. #endif
  331. static T & get_value(internal_type & val) BOOST_NOEXCEPT
  332. {
  333. return val.first;
  334. }
  335. static T const & get_value(internal_type const & val) BOOST_NOEXCEPT
  336. {
  337. return val.first;
  338. }
  339. Cmp const & value_comp(void) const BOOST_NOEXCEPT
  340. {
  341. #ifndef BOOST_MSVC
  342. return *this;
  343. #else
  344. return cmp_;
  345. #endif
  346. }
  347. struct internal_compare:
  348. Cmp
  349. {
  350. internal_compare(Cmp const & cmp = Cmp()):
  351. Cmp(cmp)
  352. {}
  353. bool operator()(internal_type const & lhs, internal_type const & rhs) const
  354. {
  355. if (Cmp::operator()(lhs.first, rhs.first))
  356. return true;
  357. if (Cmp::operator()(rhs.first, lhs.first))
  358. return false;
  359. return lhs.second > rhs.second;
  360. }
  361. };
  362. internal_compare get_internal_cmp(void) const
  363. {
  364. return internal_compare(value_comp());
  365. }
  366. void swap(heap_base & rhs) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<Cmp>::value && boost::is_nothrow_move_assignable<Cmp>::value)
  367. {
  368. #ifndef BOOST_MSVC
  369. std::swap(static_cast<Cmp&>(*this), static_cast<Cmp&>(rhs));
  370. #else
  371. std::swap(cmp_, rhs.cmp_);
  372. #endif
  373. std::swap(counter_, rhs.counter_);
  374. size_holder<constant_time_size, size_t>::swap(rhs);
  375. }
  376. stability_counter_type get_stability_count(void) const
  377. {
  378. return counter_;
  379. }
  380. void set_stability_count(stability_counter_type new_count)
  381. {
  382. counter_ = new_count;
  383. }
  384. template <typename Heap1, typename Heap2>
  385. friend struct heap_merge_emulate;
  386. private:
  387. Cmp & value_comp_ref(void) BOOST_NOEXCEPT
  388. {
  389. #ifndef BOOST_MSVC
  390. return *this;
  391. #else
  392. return cmp_;
  393. #endif
  394. }
  395. stability_counter_type counter_;
  396. };
  397. template <typename node_pointer,
  398. typename extractor,
  399. typename reference
  400. >
  401. struct node_handle
  402. {
  403. explicit node_handle(node_pointer n = 0):
  404. node_(n)
  405. {}
  406. reference operator*() const
  407. {
  408. return extractor::get_value(node_->value);
  409. }
  410. bool operator==(node_handle const & rhs) const
  411. {
  412. return node_ == rhs.node_;
  413. }
  414. bool operator!=(node_handle const & rhs) const
  415. {
  416. return node_ != rhs.node_;
  417. }
  418. node_pointer node_;
  419. };
  420. template <typename value_type,
  421. typename internal_type,
  422. typename extractor
  423. >
  424. struct value_extractor
  425. {
  426. value_type const & operator()(internal_type const & data) const
  427. {
  428. return extractor::get_value(data);
  429. }
  430. };
  431. template <typename T,
  432. typename ContainerIterator,
  433. typename Extractor>
  434. class stable_heap_iterator:
  435. public boost::iterator_adaptor<stable_heap_iterator<T, ContainerIterator, Extractor>,
  436. ContainerIterator,
  437. T const,
  438. boost::random_access_traversal_tag>
  439. {
  440. typedef boost::iterator_adaptor<stable_heap_iterator,
  441. ContainerIterator,
  442. T const,
  443. boost::random_access_traversal_tag> super_t;
  444. public:
  445. stable_heap_iterator(void):
  446. super_t(0)
  447. {}
  448. explicit stable_heap_iterator(ContainerIterator const & it):
  449. super_t(it)
  450. {}
  451. private:
  452. friend class boost::iterator_core_access;
  453. T const & dereference() const
  454. {
  455. return Extractor::get_value(*super_t::base());
  456. }
  457. };
  458. template <typename T, typename Parspec, bool constant_time_size>
  459. struct make_heap_base
  460. {
  461. typedef typename parameter::binding<Parspec, tag::compare, std::less<T> >::type compare_argument;
  462. typedef typename parameter::binding<Parspec, tag::allocator, std::allocator<T> >::type allocator_argument;
  463. typedef typename parameter::binding<Parspec, tag::stability_counter_type, boost::uintmax_t >::type stability_counter_type;
  464. static const bool is_stable = extract_stable<Parspec>::value;
  465. typedef heap_base<T, compare_argument, constant_time_size, stability_counter_type, is_stable> type;
  466. };
  467. template <typename Alloc>
  468. struct extract_allocator_types
  469. {
  470. #ifdef BOOST_NO_CXX11_ALLOCATOR
  471. typedef typename Alloc::size_type size_type;
  472. typedef typename Alloc::difference_type difference_type;
  473. typedef typename Alloc::reference reference;
  474. typedef typename Alloc::const_reference const_reference;
  475. typedef typename Alloc::pointer pointer;
  476. typedef typename Alloc::const_pointer const_pointer;
  477. #else
  478. typedef std::allocator_traits<Alloc> traits;
  479. typedef typename traits::size_type size_type;
  480. typedef typename traits::difference_type difference_type;
  481. typedef typename Alloc::value_type& reference;
  482. typedef typename Alloc::value_type const& const_reference;
  483. typedef typename traits::pointer pointer;
  484. typedef typename traits::const_pointer const_pointer;
  485. #endif
  486. };
  487. } /* namespace detail */
  488. } /* namespace heap */
  489. } /* namespace boost */
  490. #endif /* BOOST_HEAP_DETAIL_STABLE_HEAP_HPP */