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::internal {
13 
14 template <class Scalar, typename Value>
15 class Interval {
16 public:
17  Scalar start;
18  Scalar stop;
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 
26 template <class Scalar, typename Value>
28  return i.start;
29 }
30 
31 template <class Scalar, typename Value>
33  return i.stop;
34 }
35 
36 template <class Scalar, typename Value>
37 std::ostream& operator<<(std::ostream& out, const Interval<Scalar, Value>& i) {
38  out << "Interval(" << i.start << ", " << i.stop << "): " << i.value;
39  return out;
40 }
41 
42 template <class Scalar, class Value>
43 class IntervalTree {
44 public:
46  using interval_vector = std::vector<interval>;
47 
49  bool operator()(const interval& a, const interval& b) {
50  return a.start < b.start;
51  }
52  };
53 
54  struct IntervalStopCmp {
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 
67  std::unique_ptr<IntervalTree> clone() const {
68  return std::unique_ptr<IntervalTree>(new IntervalTree(*this));
69  }
70 
71  IntervalTree(const IntervalTree& other)
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 
77  IntervalTree& operator=(IntervalTree&&) = default;
78  IntervalTree(IntervalTree&&) = default;
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 {
133  intervals.push_back(interval);
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  }
227  std::for_each(intervals.begin(), intervals.end(), f);
228  if (right) {
229  right->visit_all(f);
230  }
231  }
232 
233  std::pair<Scalar, Scalar> extent() const {
234  struct Extent {
235  std::pair<Scalar, Scalar> x{std::numeric_limits<Scalar>::max(),
236  std::numeric_limits<Scalar>::min()};
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) {
245  extent(interval);
246  });
247  return extent.x;
248  }
249 
250  // Check all constraints.
251  // If first is false, second is invalid.
252  std::pair<bool, std::pair<Scalar, Scalar>> is_valid() const {
253  const auto minmaxStop =
254  std::minmax_element(intervals.begin(), intervals.end(), IntervalStopCmp());
255  const auto minmaxStart =
256  std::minmax_element(intervals.begin(), intervals.end(), IntervalStartCmp());
257 
258  std::pair<bool, std::pair<Scalar, Scalar>> result = {
259  true, {std::numeric_limits<Scalar>::max(), std::numeric_limits<Scalar>::min()}};
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  }
290  if (!std::is_sorted(intervals.begin(), intervals.end(), IntervalStartCmp())) {
291  result.first = false;
292  }
293  return result;
294  }
295 
296 private:
298  std::unique_ptr<IntervalTree> left;
299  std::unique_ptr<IntervalTree> right;
300  Scalar center;
301 };
302 
303 } // namespace mcap::internal
detail::first
auto first(const T &value, const Tail &...) -> const T &
Definition: compile.h:60
mcap::internal::IntervalTree::empty
bool empty() const
Definition: intervaltree.hpp:209
mcap::internal::IntervalTree::operator=
IntervalTree & operator=(const IntervalTree &other)
Definition: intervaltree.hpp:80
nonstd::span_lite::size_t
span_CONFIG_SIZE_TYPE size_t
Definition: span.hpp:576
s
XmlRpcServer s
mcap::internal::IntervalTree::~IntervalTree
~IntervalTree()=default
mcap::internal::IntervalTree::visit_overlapping
void visit_overlapping(const Scalar &start, const Scalar &stop, UnaryFunction f) const
Definition: intervaltree.hpp:172
mcap::internal::IntervalTree::IntervalStopCmp::operator()
bool operator()(const interval &a, const interval &b)
Definition: intervaltree.hpp:55
mcap::internal::IntervalTree::intervals
interval_vector intervals
Definition: intervaltree.hpp:297
mcap::internal::IntervalTree::visit_contained
void visit_contained(const Scalar &start, const Scalar &stop, UnaryFunction f) const
Definition: intervaltree.hpp:184
mcap::internal::IntervalTree::IntervalTree
IntervalTree(const IntervalTree &other)
Definition: intervaltree.hpp:71
mqtt_test_proto.x
x
Definition: mqtt_test_proto.py:34
mcap::internal::IntervalTree::clone
std::unique_ptr< IntervalTree > clone() const
Definition: intervaltree.hpp:67
mcap::internal::IntervalTree::IntervalTree
IntervalTree()
Definition: intervaltree.hpp:60
f
f
mcap::internal::IntervalTree::center
Scalar center
Definition: intervaltree.hpp:300
mcap::internal::IntervalTree::is_valid
std::pair< bool, std::pair< Scalar, Scalar > > is_valid() const
Definition: intervaltree.hpp:252
mcap::internal::IntervalTree::left
std::unique_ptr< IntervalTree > left
Definition: intervaltree.hpp:298
mcap::internal::Interval::stop
Scalar stop
Definition: intervaltree.hpp:18
mcap::internal
Definition: crc32.hpp:5
mcap::internal::Interval
Definition: intervaltree.hpp:15
mcap::internal::IntervalTree::IntervalStartCmp
Definition: intervaltree.hpp:48
mcap::internal::Interval::start
Scalar start
Definition: intervaltree.hpp:17
mcap::internal::IntervalTree::visit_overlapping
void visit_overlapping(const Scalar &pos, UnaryFunction f) const
Definition: intervaltree.hpp:166
backward::details::move
const T & move(const T &v)
Definition: backward.hpp:394
mcap::internal::intervalStop
Value intervalStop(const Interval< Scalar, Value > &i)
Definition: intervaltree.hpp:32
mcap::internal::IntervalTree::right
std::unique_ptr< IntervalTree > right
Definition: intervaltree.hpp:299
mcap::internal::IntervalTree::visit_all
void visit_all(UnaryFunction f) const
Definition: intervaltree.hpp:223
mcap::internal::IntervalTree::visit_near
void visit_near(const Scalar &start, const Scalar &stop, UnaryFunction f) const
Definition: intervaltree.hpp:150
mcap::internal::Interval::value
Value value
Definition: intervaltree.hpp:19
mcap::internal::IntervalTree< ByteOffset, mcap::ChunkIndex >::interval_vector
std::vector< interval > interval_vector
Definition: intervaltree.hpp:46
mcap::internal::IntervalTree::extent
std::pair< Scalar, Scalar > extent() const
Definition: intervaltree.hpp:233
mcap::internal::intervalStart
Value intervalStart(const Interval< Scalar, Value > &i)
Definition: intervaltree.hpp:27
sort
static int sort(lua_State *L)
Definition: ltablib.c:398
start
ROSCPP_DECL void start()
mcap::internal::IntervalTree::interval
Interval< Scalar, Value > interval
Definition: intervaltree.hpp:45
mcap::internal::IntervalTree::find_contained
interval_vector find_contained(const Scalar &start, const Scalar &stop) const
Definition: intervaltree.hpp:201
assert
#define assert(condition)
Definition: lz4.c:271
mcap::internal::IntervalTree::IntervalStartCmp::operator()
bool operator()(const interval &a, const interval &b)
Definition: intervaltree.hpp:49
std
mcap::internal::operator<<
std::ostream & operator<<(std::ostream &out, const Interval< Scalar, Value > &i)
Definition: intervaltree.hpp:37
mcap::internal::IntervalTree::operator=
IntervalTree & operator=(IntervalTree &&)=default
mcap::internal::IntervalTree::IntervalStopCmp
Definition: intervaltree.hpp:54
mcap::internal::IntervalTree::find_overlapping
interval_vector find_overlapping(const Scalar &start, const Scalar &stop) const
Definition: intervaltree.hpp:193
mcap::internal::IntervalTree
Definition: intervaltree.hpp:43
mcap::internal::Interval::Interval
Interval(const Scalar &s, const Scalar &e, const Value &v)
Definition: intervaltree.hpp:20
Value
Definition: lobject.h:49
mcap::internal::IntervalTree::IntervalTree
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)
Definition: intervaltree.hpp:88
detail::for_each
FMT_CONSTEXPR void for_each(index_sequence< Is... >, Tuple &&t, F &&f)
Definition: ranges.h:226
nullptr
#define nullptr
Definition: backward.hpp:386


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Nov 11 2024 03:23:44