stable_heap.hpp 15 KB

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