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 
12 namespace mcap {
13 
14 namespace internal {
15 
16 template <class Scalar, typename Value>
17 class Interval {
18 public:
19  Scalar start;
20  Scalar stop;
22  Interval(const Scalar& s, const Scalar& e, const Value& v)
23  : start(std::min(s, e))
24  , stop(std::max(s, e))
25  , value(v) {}
26 };
27 
28 template <class Scalar, typename Value>
30  return i.start;
31 }
32 
33 template <class Scalar, typename Value>
35  return i.stop;
36 }
37 
38 template <class Scalar, typename Value>
39 std::ostream& operator<<(std::ostream& out, const Interval<Scalar, Value>& i) {
40  out << "Interval(" << i.start << ", " << i.stop << "): " << i.value;
41  return out;
42 }
43 
44 template <class Scalar, class Value>
45 class IntervalTree {
46 public:
48  using interval_vector = std::vector<interval>;
49 
51  bool operator()(const interval& a, const interval& b) {
52  return a.start < b.start;
53  }
54  };
55 
56  struct IntervalStopCmp {
57  bool operator()(const interval& a, const interval& b) {
58  return a.stop < b.stop;
59  }
60  };
61 
63  : left(nullptr)
64  , right(nullptr)
65  , center(Scalar(0)) {}
66 
67  ~IntervalTree() = default;
68 
69  std::unique_ptr<IntervalTree> clone() const {
70  return std::unique_ptr<IntervalTree>(new IntervalTree(*this));
71  }
72 
73  IntervalTree(const IntervalTree& other)
74  : intervals(other.intervals)
75  , left(other.left ? other.left->clone() : nullptr)
76  , right(other.right ? other.right->clone() : nullptr)
77  , center(other.center) {}
78 
79  IntervalTree& operator=(IntervalTree&&) = default;
80  IntervalTree(IntervalTree&&) = default;
81 
83  center = other.center;
84  intervals = other.intervals;
85  left = other.left ? other.left->clone() : nullptr;
86  right = other.right ? other.right->clone() : nullptr;
87  return *this;
88  }
89 
90  IntervalTree(interval_vector&& ivals, std::size_t depth = 16, std::size_t minbucket = 64,
91  std::size_t maxbucket = 512, Scalar leftextent = 0, Scalar rightextent = 0)
92  : left(nullptr)
93  , right(nullptr) {
94  --depth;
95  const auto minmaxStop = std::minmax_element(ivals.begin(), ivals.end(), IntervalStopCmp());
96  const auto minmaxStart = std::minmax_element(ivals.begin(), ivals.end(), IntervalStartCmp());
97  if (!ivals.empty()) {
98  center = (minmaxStart.first->start + minmaxStop.second->stop) / 2;
99  }
100  if (leftextent == 0 && rightextent == 0) {
101  // sort intervals by start
102  std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
103  } else {
104  assert(std::is_sorted(ivals.begin(), ivals.end(), IntervalStartCmp()));
105  }
106  if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket)) {
107  std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
108  intervals = std::move(ivals);
109  assert(is_valid().first);
110  return;
111  } else {
112  Scalar leftp = 0;
113  Scalar rightp = 0;
114 
115  if (leftextent || rightextent) {
116  leftp = leftextent;
117  rightp = rightextent;
118  } else {
119  leftp = ivals.front().start;
120  rightp = std::max_element(ivals.begin(), ivals.end(), IntervalStopCmp())->stop;
121  }
122 
123  interval_vector lefts;
124  interval_vector rights;
125 
126  for (typename interval_vector::const_iterator i = ivals.begin(); i != ivals.end(); ++i) {
127  const interval& interval = *i;
128  if (interval.stop < center) {
129  lefts.push_back(interval);
130  } else if (interval.start > center) {
131  rights.push_back(interval);
132  } else {
133  assert(interval.start <= center);
134  assert(center <= interval.stop);
135  intervals.push_back(interval);
136  }
137  }
138 
139  if (!lefts.empty()) {
140  left.reset(new IntervalTree(std::move(lefts), depth, minbucket, maxbucket, leftp, center));
141  }
142  if (!rights.empty()) {
143  right.reset(
144  new IntervalTree(std::move(rights), depth, minbucket, maxbucket, center, rightp));
145  }
146  }
147  assert(is_valid().first);
148  }
149 
150  // Call f on all intervals near the range [start, stop]:
151  template <class UnaryFunction>
152  void visit_near(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
153  if (!intervals.empty() && !(stop < intervals.front().start)) {
154  for (auto& i : intervals) {
155  f(i);
156  }
157  }
158  if (left && start <= center) {
159  left->visit_near(start, stop, f);
160  }
161  if (right && stop >= center) {
162  right->visit_near(start, stop, f);
163  }
164  }
165 
166  // Call f on all intervals crossing pos
167  template <class UnaryFunction>
168  void visit_overlapping(const Scalar& pos, UnaryFunction f) const {
169  visit_overlapping(pos, pos, f);
170  }
171 
172  // Call f on all intervals overlapping [start, stop]
173  template <class UnaryFunction>
174  void visit_overlapping(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
175  auto filterF = [&](const interval& interval) {
176  if (interval.stop >= start && interval.start <= stop) {
177  // Only apply f if overlapping
178  f(interval);
179  }
180  };
181  visit_near(start, stop, filterF);
182  }
183 
184  // Call f on all intervals contained within [start, stop]
185  template <class UnaryFunction>
186  void visit_contained(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
187  auto filterF = [&](const interval& interval) {
188  if (start <= interval.start && interval.stop <= stop) {
189  f(interval);
190  }
191  };
192  visit_near(start, stop, filterF);
193  }
194 
195  interval_vector find_overlapping(const Scalar& start, const Scalar& stop) const {
197  visit_overlapping(start, stop, [&](const interval& interval) {
198  result.emplace_back(interval);
199  });
200  return result;
201  }
202 
203  interval_vector find_contained(const Scalar& start, const Scalar& stop) const {
205  visit_contained(start, stop, [&](const interval& interval) {
206  result.push_back(interval);
207  });
208  return result;
209  }
210 
211  bool empty() const {
212  if (left && !left->empty()) {
213  return false;
214  }
215  if (!intervals.empty()) {
216  return false;
217  }
218  if (right && !right->empty()) {
219  return false;
220  }
221  return true;
222  }
223 
224  template <class UnaryFunction>
225  void visit_all(UnaryFunction f) const {
226  if (left) {
227  left->visit_all(f);
228  }
229  std::for_each(intervals.begin(), intervals.end(), f);
230  if (right) {
231  right->visit_all(f);
232  }
233  }
234 
235  std::pair<Scalar, Scalar> extent() const {
236  struct Extent {
237  std::pair<Scalar, Scalar> x{std::numeric_limits<Scalar>::max(),
238  std::numeric_limits<Scalar>::min()};
239  void operator()(const interval& interval) {
240  x.first = std::min(x.first, interval.start);
241  x.second = std::max(x.second, interval.stop);
242  }
243  };
244  Extent extent;
245 
246  visit_all([&](const interval& interval) {
247  extent(interval);
248  });
249  return extent.x;
250  }
251 
252  // Check all constraints.
253  // If first is false, second is invalid.
254  std::pair<bool, std::pair<Scalar, Scalar>> is_valid() const {
255  const auto minmaxStop =
256  std::minmax_element(intervals.begin(), intervals.end(), IntervalStopCmp());
257  const auto minmaxStart =
258  std::minmax_element(intervals.begin(), intervals.end(), IntervalStartCmp());
259 
260  std::pair<bool, std::pair<Scalar, Scalar>> result = {
261  true, {std::numeric_limits<Scalar>::max(), std::numeric_limits<Scalar>::min()}};
262  if (!intervals.empty()) {
263  result.second.first = std::min(result.second.first, minmaxStart.first->start);
264  result.second.second = std::min(result.second.second, minmaxStop.second->stop);
265  }
266  if (left) {
267  auto valid = left->is_valid();
268  result.first &= valid.first;
269  result.second.first = std::min(result.second.first, valid.second.first);
270  result.second.second = std::min(result.second.second, valid.second.second);
271  if (!result.first) {
272  return result;
273  }
274  if (valid.second.second >= center) {
275  result.first = false;
276  return result;
277  }
278  }
279  if (right) {
280  auto valid = right->is_valid();
281  result.first &= valid.first;
282  result.second.first = std::min(result.second.first, valid.second.first);
283  result.second.second = std::min(result.second.second, valid.second.second);
284  if (!result.first) {
285  return result;
286  }
287  if (valid.second.first <= center) {
288  result.first = false;
289  return result;
290  }
291  }
292  if (!std::is_sorted(intervals.begin(), intervals.end(), IntervalStartCmp())) {
293  result.first = false;
294  }
295  return result;
296  }
297 
298 private:
300  std::unique_ptr<IntervalTree> left;
301  std::unique_ptr<IntervalTree> right;
302  Scalar center;
303 };
304 
305 } // namespace internal
306 
307 } // namespace mcap
std::unique_ptr< IntervalTree > left
bool operator()(const interval &a, const interval &b)
#define nullptr
Definition: backward.hpp:386
lu_byte right
Definition: lparser.c:1227
span_CONFIG_SIZE_TYPE size_t
Definition: span.hpp:561
IntervalTree & operator=(const IntervalTree &other)
interval_vector find_overlapping(const Scalar &start, const Scalar &stop) const
lu_byte left
Definition: lparser.c:1226
std::pair< Scalar, Scalar > extent() const
Value intervalStop(const Interval< Scalar, Value > &i)
Definition: lobject.h:49
void visit_overlapping(const Scalar &pos, UnaryFunction f) const
#define assert(condition)
Definition: lz4.c:245
void for_each(index_sequence< Is... >, Tuple &&tup, F &&f) FMT_NOEXCEPT
Definition: ranges.h:226
static int sort(lua_State *L)
Definition: ltablib.c:398
IntervalTree(const IntervalTree &other)
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)
void visit_all(UnaryFunction f) const
std::pair< bool, std::pair< Scalar, Scalar > > is_valid() const
const T & move(const T &v)
Definition: backward.hpp:394
bool operator()(const interval &a, const interval &b)
const T & first(const T &value, const Tail &...)
Definition: compile.h:178
void visit_overlapping(const Scalar &start, const Scalar &stop, UnaryFunction f) const
void visit_near(const Scalar &start, const Scalar &stop, UnaryFunction f) const
Value intervalStart(const Interval< Scalar, Value > &i)
std::unique_ptr< IntervalTree > clone() const
interval_vector find_contained(const Scalar &start, const Scalar &stop) const
void visit_contained(const Scalar &start, const Scalar &stop, UnaryFunction f) const
Interval(const Scalar &s, const Scalar &e, const Value &v)
std::unique_ptr< IntervalTree > right


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:01:02