1 #ifndef DASYNQ_STABLE_HEAP_INCLUDED
2 #define DASYNQ_STABLE_HEAP_INCLUDED 1
4 // Convert an "unstable" priority queue (which doesn't use FIFO ordering for same-priority elements)
5 // into a "stable" queue (which does deliver same-priority elements in FIFO order). This is done by
6 // adding a generation counter to each element added to the queue, and using it as a second-order
7 // priority key (after the original key).
9 // The generation counter is a 64-bit integer and can not realistically overflow.
24 template <typename ...U>
25 stable_prio(uint64_t o, U... u) : p(u...), order(o)
29 // zero-argument constructor should not really be needed, but some
30 // heap implementations aren't yet perfect.
36 template <typename P, typename C>
37 class compare_stable_prio
40 bool operator()(const stable_prio<P> &a, const stable_prio<P> &b)
50 return a.order < b.order;
55 template <template <typename H1, typename H2, typename H3> class H, typename T, typename P, typename C = std::less<P>>
56 class stable_heap : private H<T,stable_prio<P>,compare_stable_prio<P,C>>
58 using Base = H<T,stable_prio<P>,compare_stable_prio<P,C>>;
60 // using H<T,P,compare_stable_prio<P,C>>:H; // inherit constructors
63 uint64_t sequence = 0;
67 using handle_t = typename Base::handle_t;
68 using handle_t_r = typename Base::handle_t_r;
70 bool insert(handle_t & index, P pval = P())
72 auto sp = stable_prio<P>(sequence++, pval);
73 return Base::insert(index, sp);
76 template <typename ...U> void allocate(handle_t & hnd, U&& ...u)
78 Base::allocate(hnd, std::forward<U>(u)...);
81 static void init_handle(handle_t &hndl)
83 Base::init_handle(hndl);
86 T &node_data(handle_t &hndl)
88 return Base::node_data(hndl);
91 bool is_queued(handle_t & hnd)
93 return Base::is_queued(hnd);
96 decltype(std::declval<Base>().get_root()) get_root()
98 return Base::get_root();
106 void deallocate(handle_t_r index)
108 Base::deallocate(index);
111 void remove(handle_t_r hnd)
118 return Base::empty();
122 } // namespace dasynq