Itoyori  v0.0.1
block_region_set.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <limits>
4 #include <forward_list>
5 
6 #include "ityr/common/util.hpp"
7 #include "ityr/ori/util.hpp"
8 
9 namespace ityr::ori {
10 
11 template <typename T>
12 struct region {
13  template <typename T1, typename T2>
14  region(T1 b, T2 e) {
15  ITYR_CHECK(0 <= b);
16  ITYR_CHECK(static_cast<uint64_t>(b) <= static_cast<uint64_t>(std::numeric_limits<T>::max()));
17  ITYR_CHECK(0 <= e);
18  ITYR_CHECK(static_cast<uint64_t>(e) <= static_cast<uint64_t>(std::numeric_limits<T>::max()));
19  begin = static_cast<T>(b);
20  end = static_cast<T>(e);
21  }
22 
23  std::size_t size() const { return end - begin; }
24 
25  T begin;
26  T end;
27 };
28 
29 template <typename T>
30 inline bool operator==(const region<T>& r1, const region<T>& r2) noexcept {
31  return r1.begin == r2.begin && r1.end == r2.end;
32 }
33 
34 template <typename T>
35 inline bool operator!=(const region<T>& r1, const region<T>& r2) noexcept {
36  return !(r1 == r2);
37 }
38 
39 template <typename T>
40 inline bool overlap(const region<T>& r1, const region<T>& r2) {
41  return r1.begin < r2.end && r2.begin < r1.end;
42 }
43 
44 template <typename T>
45 inline bool contiguous(const region<T>& r1, const region<T>& r2) {
46  return r1.begin == r2.end || r1.end == r2.begin;
47 }
48 
49 template <typename T>
50 inline region<T> get_union(const region<T>& r1, const region<T>& r2) {
51  ITYR_CHECK((overlap(r1, r2) || contiguous(r1, r2)));
52  return {std::min(r1.begin, r2.begin), std::max(r1.end, r2.end)};
53 }
54 
55 template <typename T>
56 inline region<T> get_intersection(const region<T>& r1, const region<T>& r2) {
57  ITYR_CHECK(overlap(r1, r2));
58  return {std::max(r1.begin, r2.begin), std::min(r1.end, r2.end)};
59 }
60 
61 template <typename T>
62 class region_set {
63 public:
64  using iterator = typename std::forward_list<region<T>>::iterator;
65  using const_iterator = typename std::forward_list<region<T>>::const_iterator;
66 
68  region_set(std::initializer_list<region<T>> regions)
69  : regions_(regions) {}
70 
71  auto& get() { return regions_; }
72  const auto& get() const { return regions_; }
73 
74  iterator before_begin() { return regions_.before_begin(); }
75  iterator begin() { return regions_.begin(); }
76  iterator end() { return regions_.end(); }
77 
78  const_iterator before_begin() const { return regions_.cbefore_begin(); }
79  const_iterator begin() const { return regions_.cbegin(); }
80  const_iterator end() const { return regions_.cend(); }
81 
82  bool empty() const {
83  return regions_.empty();
84  }
85 
86  void clear() {
87  regions_.clear();
88  }
89 
90  iterator add(const region<T>& r, iterator begin_it) {
91  auto it = begin_it;
92 
93  // skip until it overlaps r (or r < it)
94  while (std::next(it) != regions_.end() &&
95  std::next(it)->end < r.begin) it++;
96 
97  if (std::next(it) == regions_.end() ||
98  r.end < std::next(it)->begin) {
99  // no overlap
100  it = regions_.insert_after(it, r);
101  } else {
102  // at least two regions are overlapping -> merge
103  it++;
104  *it = get_union(*it, r);
105 
106  while (std::next(it) != regions_.end() &&
107  it->end >= std::next(it)->begin) {
108  *it = get_union(*it, *std::next(it));
109  regions_.erase_after(it);
110  }
111  }
112 
113  // return an iterator to the added element
114  return it;
115  }
116 
117  iterator add(const region<T>& r) {
118  return add(r, regions_.before_begin());
119  }
120 
121  void remove(const region<T>& r) {
122  auto it = regions_.before_begin();
123 
124  while (std::next(it) != regions_.end()) {
125  if (r.end <= std::next(it)->begin) break;
126 
127  if (std::next(it)->end <= r.begin) {
128  // no overlap
129  it++;
130  } else if (r.begin <= std::next(it)->begin && std::next(it)->end <= r.end) {
131  // r contains std::next(it)
132  regions_.erase_after(it);
133  // do not increment it
134  } else if (r.begin <= std::next(it)->begin && r.end <= std::next(it)->end) {
135  // the left end of std::next(it) is overlaped
136  std::next(it)->begin = r.end;
137  it++;
138  } else if (std::next(it)->begin <= r.begin && std::next(it)->end <= r.end) {
139  // the right end of std::next(it) is overlaped
140  std::next(it)->end = r.begin;
141  it++;
142  } else if (std::next(it)->begin <= r.begin && r.end <= std::next(it)->end) {
143  // std::next(it) contains r
144  region<T> new_r = {std::next(it)->begin, r.begin};
145  std::next(it)->begin = r.end;
146  regions_.insert_after(it, new_r);
147  it++;
148  } else {
149  common::die("Something is wrong in region<T>s::remove()\n");
150  }
151  }
152  }
153 
154  bool include(const region<T>& r) const {
155  for (const auto& r_ : regions_) {
156  if (r.begin < r_.begin) break;
157  if (r.end <= r_.end) return true;
158  }
159  return false;
160  }
161 
163  region_set<T> ret;
164  std::forward_list<region<T>>& regs = ret.regions_;
165 
166  auto it = regs.before_begin();
167  for (auto [b, e] : regions_) {
168  if (r.begin < b) {
169  it = regs.insert_after(it, {r.begin, std::min(b, r.end)});
170  }
171  if (r.begin < e) {
172  r.begin = e;
173  if (r.begin >= r.end) break;
174  }
175  }
176  if (r.begin < r.end) {
177  regs.insert_after(it, r);
178  }
179  return ret;
180  }
181 
183  region_set<T> ret;
184  std::forward_list<region<T>>& regs = ret.get();
185 
186  auto it_ret = regs.before_begin();
187  auto it = regions_.begin();
188 
189  while (it != regions_.end()) {
190  if (it->end <= r.begin) {
191  it++;
192  continue;
193  }
194 
195  if (r.end <= it->begin) {
196  break;
197  }
198 
199  it_ret = regs.insert_after(it_ret, get_intersection(*it, r));
200 
201  if (r.end < it->end) {
202  break;
203  }
204 
205  it++;
206  }
207 
208  return ret;
209  }
210 
212  region_set<T> ret;
213  std::forward_list<region<T>>& regs = ret.get();
214 
215  auto it_ret = regs.before_begin();
216  auto it1 = regions_.begin();
217  auto it2 = rs.begin();
218 
219  while (it1 != regions_.end() && it2 != rs.end()) {
220  if (it1->end <= it2->begin) {
221  it1++;
222  continue;
223  }
224 
225  if (it2->end <= it1->begin) {
226  it2++;
227  continue;
228  }
229 
230  it_ret = regs.insert_after(it_ret, get_intersection(*it1, *it2));
231 
232  if (it1->end <= it2->end) {
233  it1++;
234  } else {
235  it2++;
236  }
237  }
238 
239  return ret;
240  }
241 
242  std::size_t size() const {
243  std::size_t ret = 0;
244  for (auto&& reg : regions_) {
245  ret += reg.size();
246  }
247  return ret;
248  }
249 
250 private:
251  std::forward_list<region<T>> regions_;
252 };
253 
254 template <typename T>
255 inline bool operator==(const region_set<T>& rs1, const region_set<T>& rs2) noexcept {
256  return rs1.get() == rs2.get();
257 }
258 
259 template <typename T>
260 inline bool operator!=(const region_set<T>& rs1, const region_set<T>& rs2) noexcept {
261  return !(rs1 == rs2);
262 }
263 
264 template <typename T>
266  return rs.complement(r);
267 }
268 
269 template <typename T>
271  return rs.intersection(r);
272 }
273 
274 template <typename T>
276  return rs1.intersection(rs2);
277 }
278 
281 
282 ITYR_TEST_CASE("[ityr::ori::block_region_set] add") {
283  block_region_set brs;
284  brs.add({2, 5});
285  ITYR_CHECK(brs == (block_region_set{{2, 5}}));
286  brs.add({11, 20});
287  ITYR_CHECK(brs == (block_region_set{{2, 5}, {11, 20}}));
288  brs.add({20, 21});
289  ITYR_CHECK(brs == (block_region_set{{2, 5}, {11, 21}}));
290  brs.add({15, 23});
291  ITYR_CHECK(brs == (block_region_set{{2, 5}, {11, 23}}));
292  brs.add({8, 23});
293  ITYR_CHECK(brs == (block_region_set{{2, 5}, {8, 23}}));
294  brs.add({7, 25});
295  ITYR_CHECK(brs == (block_region_set{{2, 5}, {7, 25}}));
296  brs.add({0, 7});
297  ITYR_CHECK(brs == (block_region_set{{0, 25}}));
298  brs.add({30, 50});
299  ITYR_CHECK(brs == (block_region_set{{0, 25}, {30, 50}}));
300  brs.add({30, 50});
301  ITYR_CHECK(brs == (block_region_set{{0, 25}, {30, 50}}));
302  brs.add({35, 45});
303  ITYR_CHECK(brs == (block_region_set{{0, 25}, {30, 50}}));
304  brs.add({60, 100});
305  ITYR_CHECK(brs == (block_region_set{{0, 25}, {30, 50}, {60, 100}}));
306  brs.add({0, 120});
307  ITYR_CHECK(brs == (block_region_set{{0, 120}}));
308  brs.add({200, 300});
309  ITYR_CHECK(brs == (block_region_set{{0, 120}, {200, 300}}));
310  brs.add({600, 700});
311  ITYR_CHECK(brs == (block_region_set{{0, 120}, {200, 300}, {600, 700}}));
312  brs.add({400, 500});
313  ITYR_CHECK(brs == (block_region_set{{0, 120}, {200, 300}, {400, 500}, {600, 700}}));
314  brs.add({300, 600});
315  ITYR_CHECK(brs == (block_region_set{{0, 120}, {200, 700}}));
316  brs.add({50, 600});
317  ITYR_CHECK(brs == (block_region_set{{0, 700}}));
318 }
319 
320 ITYR_TEST_CASE("[ityr::ori::block_region_set] remove") {
321  block_region_set brs{{2, 5}, {6, 9}, {11, 20}, {50, 100}};
322  brs.remove({6, 9});
323  ITYR_CHECK(brs == (block_region_set{{2, 5}, {11, 20}, {50, 100}}));
324  brs.remove({4, 10});
325  ITYR_CHECK(brs == (block_region_set{{2, 4}, {11, 20}, {50, 100}}));
326  brs.remove({70, 80});
327  ITYR_CHECK(brs == (block_region_set{{2, 4}, {11, 20}, {50, 70}, {80, 100}}));
328  brs.remove({18, 55});
329  ITYR_CHECK(brs == (block_region_set{{2, 4}, {11, 18}, {55, 70}, {80, 100}}));
330  brs.remove({10, 110});
331  ITYR_CHECK(brs == (block_region_set{{2, 4}}));
332  brs.remove({2, 4});
333  ITYR_CHECK(brs == (block_region_set{}));
334  brs.remove({2, 4});
335  ITYR_CHECK(brs == (block_region_set{}));
336 }
337 
338 ITYR_TEST_CASE("[ityr::ori::block_region_set] include") {
339  block_region_set brs{{2, 5}, {6, 9}, {11, 20}, {50, 100}};
340  ITYR_CHECK(brs.include({2, 5}));
341  ITYR_CHECK(brs.include({3, 5}));
342  ITYR_CHECK(brs.include({2, 4}));
343  ITYR_CHECK(brs.include({3, 4}));
344  ITYR_CHECK(brs.include({7, 9}));
345  ITYR_CHECK(brs.include({50, 100}));
346  ITYR_CHECK(!brs.include({9, 11}));
347  ITYR_CHECK(!brs.include({3, 6}));
348  ITYR_CHECK(!brs.include({7, 10}));
349  ITYR_CHECK(!brs.include({2, 100}));
350  ITYR_CHECK(!brs.include({0, 3}));
351 }
352 
353 ITYR_TEST_CASE("[ityr::ori::block_region_set] complement") {
354  block_region_set brs{{2, 5}, {6, 9}, {11, 20}, {50, 100}};
355  ITYR_CHECK(brs.complement({0, 120}) == block_region_set({{0, 2}, {5, 6}, {9, 11}, {20, 50}, {100, 120}}));
356  ITYR_CHECK(brs.complement({0, 100}) == block_region_set({{0, 2}, {5, 6}, {9, 11}, {20, 50}}));
357  ITYR_CHECK(brs.complement({0, 25}) == block_region_set({{0, 2}, {5, 6}, {9, 11}, {20, 25}}));
358  ITYR_CHECK(brs.complement({8, 15}) == block_region_set({{9, 11}}));
359  ITYR_CHECK(brs.complement({30, 40}) == block_region_set({{30, 40}}));
360  ITYR_CHECK(brs.complement({50, 100}) == block_region_set({}));
361  ITYR_CHECK(brs.complement({60, 90}) == block_region_set({}));
362  ITYR_CHECK(brs.complement({2, 5}) == block_region_set({}));
363  ITYR_CHECK(brs.complement({2, 6}) == block_region_set({{5, 6}}));
364  block_region_set brs_empty{};
365  ITYR_CHECK(brs_empty.complement({0, 100}) == block_region_set({{0, 100}}));
366 }
367 
368 ITYR_TEST_CASE("[ityr::ori::block_region_set] intersection") {
369  ITYR_CHECK((get_intersection(block_region_set{{2, 5}, {11, 20}, {25, 27}, {50, 100}},
370  block_region_set{{3, 4}, {9, 15}, {16, 19}, {50, 100}})) ==
371  (block_region_set{{3, 4}, {11, 15}, {16, 19}, {50, 100}}));
373  block_region_set{{3, 4}, {9, 15}, {16, 19}, {50, 100}})) ==
374  (block_region_set{}));
375  ITYR_CHECK((get_intersection(block_region_set{{2, 5}, {11, 20}, {25, 27}, {50, 100}},
376  block_region_set{})) ==
377  (block_region_set{}));
379  block_region_set{})) ==
380  (block_region_set{}));
381 }
382 
383 }
Definition: block_region_set.hpp:62
auto & get()
Definition: block_region_set.hpp:71
void remove(const region< T > &r)
Definition: block_region_set.hpp:121
region_set< T > intersection(const region_set< T > &rs) const
Definition: block_region_set.hpp:211
region_set< T > complement(region< T > r) const
Definition: block_region_set.hpp:162
iterator before_begin()
Definition: block_region_set.hpp:74
bool empty() const
Definition: block_region_set.hpp:82
iterator end()
Definition: block_region_set.hpp:76
const_iterator before_begin() const
Definition: block_region_set.hpp:78
const auto & get() const
Definition: block_region_set.hpp:72
iterator add(const region< T > &r, iterator begin_it)
Definition: block_region_set.hpp:90
iterator add(const region< T > &r)
Definition: block_region_set.hpp:117
region_set< T > intersection(const region< T > &r) const
Definition: block_region_set.hpp:182
iterator begin()
Definition: block_region_set.hpp:75
const_iterator end() const
Definition: block_region_set.hpp:80
typename std::forward_list< region< T > >::iterator iterator
Definition: block_region_set.hpp:64
void clear()
Definition: block_region_set.hpp:86
region_set(std::initializer_list< region< T >> regions)
Definition: block_region_set.hpp:68
const_iterator begin() const
Definition: block_region_set.hpp:79
bool include(const region< T > &r) const
Definition: block_region_set.hpp:154
typename std::forward_list< region< T > >::const_iterator const_iterator
Definition: block_region_set.hpp:65
std::size_t size() const
Definition: block_region_set.hpp:242
region_set()
Definition: block_region_set.hpp:67
#define ITYR_CHECK(cond)
Definition: util.hpp:48
Definition: block_region_set.hpp:9
region< T > get_union(const region< T > &r1, const region< T > &r2)
Definition: block_region_set.hpp:50
region_set< block_size_t > block_region_set
Definition: block_region_set.hpp:280
bool contiguous(const region< T > &r1, const region< T > &r2)
Definition: block_region_set.hpp:45
bool overlap(const region< T > &r1, const region< T > &r2)
Definition: block_region_set.hpp:40
region_set< T > get_complement(const region_set< T > &rs, const region< T > &r)
Definition: block_region_set.hpp:265
bool operator==(const region< T > &r1, const region< T > &r2) noexcept
Definition: block_region_set.hpp:30
region< T > get_intersection(const region< T > &r1, const region< T > &r2)
Definition: block_region_set.hpp:56
bool operator!=(const region< T > &r1, const region< T > &r2) noexcept
Definition: block_region_set.hpp:35
monoid< T, min_functor<>, highest< T > > min
Definition: reducer.hpp:101
monoid< T, max_functor<>, lowest< T > > max
Definition: reducer.hpp:104
Definition: block_region_set.hpp:12
std::size_t size() const
Definition: block_region_set.hpp:23
region(T1 b, T2 e)
Definition: block_region_set.hpp:14
T begin
Definition: block_region_set.hpp:25
T end
Definition: block_region_set.hpp:26