pjmsg_mcap_wrapper
Loading...
Searching...
No Matches
intervaltree.hpp
Go to the documentation of this file.
1// Adapted from <https://github.com/ekg/intervaltree/blob/master/IntervalTree.h>
2
3#pragma once
4
5#include <algorithm>
6#include <cassert>
7#include <iostream>
8#include <limits>
9#include <memory>
10#include <vector>
11
12namespace mcap::internal {
13
14template <class Scalar, typename Value>
15class Interval {
16public:
17 Scalar start;
18 Scalar stop;
19 Value value;
20 Interval(const Scalar& s, const Scalar& e, const Value& v)
21 : start(std::min(s, e))
22 , stop(std::max(s, e))
23 , value(v) {}
24};
25
26template <class Scalar, typename Value>
28 return i.start;
29}
30
31template <class Scalar, typename Value>
33 return i.stop;
34}
35
36template <class Scalar, typename Value>
38 out << "Interval(" << i.start << ", " << i.stop << "): " << i.value;
39 return out;
40}
41
42template <class Scalar, class Value>
44public:
47
49 bool operator()(const interval& a, const interval& b) {
50 return a.start < b.start;
51 }
52 };
53
55 bool operator()(const interval& a, const interval& b) {
56 return a.stop < b.stop;
57 }
58 };
59
61 : left(nullptr)
62 , right(nullptr)
63 , center(Scalar(0)) {}
64
65 ~IntervalTree() = default;
66
70
72 : intervals(other.intervals)
73 , left(other.left ? other.left->clone() : nullptr)
74 , right(other.right ? other.right->clone() : nullptr)
75 , center(other.center) {}
76
79
81 center = other.center;
82 intervals = other.intervals;
83 left = other.left ? other.left->clone() : nullptr;
84 right = other.right ? other.right->clone() : nullptr;
85 return *this;
86 }
87
88 IntervalTree(interval_vector&& ivals, std::size_t depth = 16, std::size_t minbucket = 64,
89 std::size_t maxbucket = 512, Scalar leftextent = 0, Scalar rightextent = 0)
90 : left(nullptr)
91 , right(nullptr) {
92 --depth;
93 const auto minmaxStop = std::minmax_element(ivals.begin(), ivals.end(), IntervalStopCmp());
94 const auto minmaxStart = std::minmax_element(ivals.begin(), ivals.end(), IntervalStartCmp());
95 if (!ivals.empty()) {
96 center = (minmaxStart.first->start + minmaxStop.second->stop) / 2;
97 }
98 if (leftextent == 0 && rightextent == 0) {
99 // sort intervals by start
100 std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
101 } else {
102 assert(std::is_sorted(ivals.begin(), ivals.end(), IntervalStartCmp()));
103 }
104 if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket)) {
105 std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
106 intervals = std::move(ivals);
107 assert(is_valid().first);
108 return;
109 } else {
110 Scalar leftp = 0;
111 Scalar rightp = 0;
112
113 if (leftextent || rightextent) {
114 leftp = leftextent;
115 rightp = rightextent;
116 } else {
117 leftp = ivals.front().start;
118 rightp = std::max_element(ivals.begin(), ivals.end(), IntervalStopCmp())->stop;
119 }
120
121 interval_vector lefts;
122 interval_vector rights;
123
124 for (typename interval_vector::const_iterator i = ivals.begin(); i != ivals.end(); ++i) {
125 const interval& interval = *i;
126 if (interval.stop < center) {
127 lefts.push_back(interval);
128 } else if (interval.start > center) {
129 rights.push_back(interval);
130 } else {
131 assert(interval.start <= center);
132 assert(center <= interval.stop);
134 }
135 }
136
137 if (!lefts.empty()) {
138 left.reset(new IntervalTree(std::move(lefts), depth, minbucket, maxbucket, leftp, center));
139 }
140 if (!rights.empty()) {
141 right.reset(
142 new IntervalTree(std::move(rights), depth, minbucket, maxbucket, center, rightp));
143 }
144 }
145 assert(is_valid().first);
146 }
147
148 // Call f on all intervals near the range [start, stop]:
149 template <class UnaryFunction>
150 void visit_near(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
151 if (!intervals.empty() && !(stop < intervals.front().start)) {
152 for (auto& i : intervals) {
153 f(i);
154 }
155 }
156 if (left && start <= center) {
157 left->visit_near(start, stop, f);
158 }
159 if (right && stop >= center) {
160 right->visit_near(start, stop, f);
161 }
162 }
163
164 // Call f on all intervals crossing pos
165 template <class UnaryFunction>
166 void visit_overlapping(const Scalar& pos, UnaryFunction f) const {
167 visit_overlapping(pos, pos, f);
168 }
169
170 // Call f on all intervals overlapping [start, stop]
171 template <class UnaryFunction>
172 void visit_overlapping(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
173 auto filterF = [&](const interval& interval) {
174 if (interval.stop >= start && interval.start <= stop) {
175 // Only apply f if overlapping
176 f(interval);
177 }
178 };
179 visit_near(start, stop, filterF);
180 }
181
182 // Call f on all intervals contained within [start, stop]
183 template <class UnaryFunction>
184 void visit_contained(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
185 auto filterF = [&](const interval& interval) {
186 if (start <= interval.start && interval.stop <= stop) {
187 f(interval);
188 }
189 };
190 visit_near(start, stop, filterF);
191 }
192
193 interval_vector find_overlapping(const Scalar& start, const Scalar& stop) const {
194 interval_vector result;
195 visit_overlapping(start, stop, [&](const interval& interval) {
196 result.emplace_back(interval);
197 });
198 return result;
199 }
200
201 interval_vector find_contained(const Scalar& start, const Scalar& stop) const {
202 interval_vector result;
203 visit_contained(start, stop, [&](const interval& interval) {
204 result.push_back(interval);
205 });
206 return result;
207 }
208
209 bool empty() const {
210 if (left && !left->empty()) {
211 return false;
212 }
213 if (!intervals.empty()) {
214 return false;
215 }
216 if (right && !right->empty()) {
217 return false;
218 }
219 return true;
220 }
221
222 template <class UnaryFunction>
223 void visit_all(UnaryFunction f) const {
224 if (left) {
225 left->visit_all(f);
226 }
228 if (right) {
229 right->visit_all(f);
230 }
231 }
232
234 struct Extent {
237 void operator()(const interval& interval) {
238 x.first = std::min(x.first, interval.start);
239 x.second = std::max(x.second, interval.stop);
240 }
241 };
242 Extent extent;
243
244 visit_all([&](const interval& interval) {
246 });
247 return extent.x;
248 }
249
250 // Check all constraints.
251 // If first is false, second is invalid.
253 const auto minmaxStop =
255 const auto minmaxStart =
257
260 if (!intervals.empty()) {
261 result.second.first = std::min(result.second.first, minmaxStart.first->start);
262 result.second.second = std::min(result.second.second, minmaxStop.second->stop);
263 }
264 if (left) {
265 auto valid = left->is_valid();
266 result.first &= valid.first;
267 result.second.first = std::min(result.second.first, valid.second.first);
268 result.second.second = std::min(result.second.second, valid.second.second);
269 if (!result.first) {
270 return result;
271 }
272 if (valid.second.second >= center) {
273 result.first = false;
274 return result;
275 }
276 }
277 if (right) {
278 auto valid = right->is_valid();
279 result.first &= valid.first;
280 result.second.first = std::min(result.second.first, valid.second.first);
281 result.second.second = std::min(result.second.second, valid.second.second);
282 if (!result.first) {
283 return result;
284 }
285 if (valid.second.first <= center) {
286 result.first = false;
287 return result;
288 }
289 }
291 result.first = false;
292 }
293 return result;
294 }
295
296private:
300 Scalar center;
301};
302
303} // namespace mcap::internal
T begin(T... args)
std::unique_ptr< IntervalTree > left
interval_vector find_contained(const Scalar &start, const Scalar &stop) const
void visit_near(const Scalar &start, const Scalar &stop, UnaryFunction f) const
std::unique_ptr< IntervalTree > clone() const
void visit_overlapping(const Scalar &pos, UnaryFunction f) const
std::unique_ptr< IntervalTree > right
void visit_all(UnaryFunction f) const
IntervalTree(interval_vector &&ivals, std::size_t depth=16, std::size_t minbucket=64, std::size_t maxbucket=512, Scalar leftextent=0, Scalar rightextent=0)
IntervalTree(IntervalTree &&)=default
IntervalTree(const IntervalTree &other)
std::pair< bool, std::pair< Scalar, Scalar > > is_valid() const
IntervalTree & operator=(IntervalTree &&)=default
interval_vector find_overlapping(const Scalar &start, const Scalar &stop) const
std::pair< Scalar, Scalar > extent() const
void visit_contained(const Scalar &start, const Scalar &stop, UnaryFunction f) const
IntervalTree & operator=(const IntervalTree &other)
void visit_overlapping(const Scalar &start, const Scalar &stop, UnaryFunction f) const
Interval< Scalar, Value > interval
Interval(const Scalar &s, const Scalar &e, const Value &v)
T emplace_back(T... args)
T empty(T... args)
T end(T... args)
T for_each(T... args)
T front(T... args)
T is_sorted(T... args)
T max_element(T... args)
T max(T... args)
T min(T... args)
T minmax_element(T... args)
Value intervalStop(const Interval< Scalar, Value > &i)
std::ostream & operator<<(std::ostream &out, const Interval< Scalar, Value > &i)
Value intervalStart(const Interval< Scalar, Value > &i)
T push_back(T... args)
T sort(T... args)
bool operator()(const interval &a, const interval &b)
bool operator()(const interval &a, const interval &b)