]> git.proxmox.com Git - ceph.git/blob - ceph/src/dmclock/support/src/intrusive_heap.h
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / dmclock / support / src / intrusive_heap.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 /*
5 * Copyright (C) 2016 Red Hat Inc.
6 */
7
8
9 #pragma once
10
11
12 #include <vector>
13 #include <string>
14 #include <iostream>
15 #include <functional>
16
17 #include "assert.h"
18
19
20 namespace crimson {
21 using IntruHeapData = size_t;
22
23 // T = type of data in heap; I = functor that returns a non-const
24 // reference to IntruHeapData; C = functor that compares two const
25 // refs and return true if the first precedes the second
26 template<typename T, typename I, typename C>
27 class IntruHeap {
28
29 static_assert(
30 std::is_same<IntruHeapData&,typename std::result_of<I(T&)>::type>::value,
31 "class I must define operator() to take T& and return a IntruHeapData&.");
32
33 static_assert(
34 std::is_same<bool,typename std::result_of<C(const T&,const T&)>::type>::value,
35 "class C must define operator() to take two const T& and return a bool.");
36
37
38 protected:
39 using index_t = IntruHeapData;
40
41 std::vector<T> data;
42 index_t count;
43 I intru_data_of;
44 C comparator;
45
46 public:
47
48 IntruHeap() :
49 count(0)
50 {
51 // empty
52 }
53
54 IntruHeap(const IntruHeap<T,I,C>& other) :
55 count(other.count)
56 {
57 for (uint i = 0; i < other.count; ++i) {
58 data.push_back(other.data[i]);
59 }
60 }
61
62 bool empty() const { return 0 == count; }
63
64 T& top() { return data[0]; }
65
66 void push(T&& item) {
67 index_t i = count++;
68 intru_data_of(item) = i;
69 data.emplace_back(item);
70 sift_up(i);
71 }
72
73 void push(const T& item) {
74 T copy(item);
75 push(std::move(copy));
76 }
77
78 void pop() {
79 std::swap(data[0], data[--count]);
80 intru_data_of(data[0]) = 0;
81 data.pop_back();
82 sift_down(0);
83 }
84
85 void adjust_up(T& item) {
86 sift_up(intru_data_of(item));
87 }
88
89 void adjust_down(T& item) {
90 sift_down(intru_data_of(item));
91 }
92
93 void adjust(T& item) {
94 sift(intru_data_of(item));
95 }
96
97 friend std::ostream& operator<<(std::ostream& out, const IntruHeap& h) {
98 for (uint i = 0; i < h.count; ++i) {
99 out << h.data[i] << ", ";
100 }
101 return out;
102 }
103
104 std::ostream&
105 display_sorted(std::ostream& out,
106 bool insert_line_breaks = true,
107 std::function<bool(const T&)> filter = all_filter) const {
108 IntruHeap<T,I,C> copy = *this;
109
110 bool first = true;
111 out << "[ ";
112
113 while(!copy.empty()) {
114 const T& top = copy.top();
115 if (filter(top)) {
116 if (!first) {
117 out << ", ";
118 }
119 if (insert_line_breaks) {
120 out << std::endl << " ";
121 }
122 out << copy.top();
123 first = false;
124 }
125 copy.pop();
126 }
127
128 out << " ]";
129 if (insert_line_breaks) {
130 out << std::endl;
131 }
132
133 return out;
134 }
135
136
137 protected:
138
139 // default value of filter parameter to display_sorted
140 static bool all_filter(const T& data) { return true; }
141
142 // when i is negative?
143 static inline index_t parent(index_t i) {
144 assert(0 != i);
145 return (i - 1) / 2;
146 }
147
148 static inline index_t lhs(index_t i) { return 2*i + 1; }
149
150 static inline index_t rhs(index_t i) { return 2*i + 2; }
151
152 void sift_up(index_t i) {
153 while (i > 0) {
154 index_t pi = parent(i);
155 if (!comparator(data[i], data[pi])) {
156 break;
157 }
158
159 std::swap(data[i], data[pi]);
160 intru_data_of(data[i]) = i;
161 intru_data_of(data[pi]) = pi;
162 i = pi;
163 }
164 } // sift_up
165
166 void sift_down(index_t i) {
167 while (i < count) {
168 index_t li = lhs(i);
169 index_t ri = rhs(i);
170
171 if (li < count) {
172 if (comparator(data[li], data[i])) {
173 if (ri < count && comparator(data[ri], data[li])) {
174 std::swap(data[i], data[ri]);
175 intru_data_of(data[i]) = i;
176 intru_data_of(data[ri]) = ri;
177 i = ri;
178 } else {
179 std::swap(data[i], data[li]);
180 intru_data_of(data[i]) = i;
181 intru_data_of(data[li]) = li;
182 i = li;
183 }
184 } else if (ri < count && comparator(data[ri], data[i])) {
185 std::swap(data[i], data[ri]);
186 intru_data_of(data[i]) = i;
187 intru_data_of(data[ri]) = ri;
188 i = ri;
189 } else {
190 break;
191 }
192 } else {
193 break;
194 }
195 }
196 } // sift_down
197
198 void sift(index_t i) {
199 if (i == 0) {
200 // if we're at top, can only go down
201 sift_down(i);
202 } else {
203 index_t pi = parent(i);
204 if (comparator(data[i], data[pi])) {
205 // if we can go up, we will
206 sift_up(i);
207 } else {
208 // otherwise we'll try to go down
209 sift_down(i);
210 }
211 }
212 } // sift
213 }; // class IntruHeap
214 } // namespace crimson