stable_heap.hpp 14 KB

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