UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
range_set.hpp
1
42#ifndef UFO_CONTAINER_RANGE_SET_HPP
43#define UFO_CONTAINER_RANGE_SET_HPP
44
45// UFO
46#include <ufo/core/range.hpp>
47
48namespace ufo
49{
50template <typename Key>
52{
53 public:
54 //
55 // Tags
56 //
57
58 using key_type = Range<Key>;
59 using value_type = key_type;
60 using size_type = typename std::vector<value_type>::size_type; // Should this be Key?
61 using difference_type = typename std::vector<value_type>::difference_type;
62 using key_compare = typename key_type::Comparator;
63 using value_compare = typename value_type::Comparator;
64 using allocator_type = typename std::vector<value_type>::allocator_type;
65 using reference = typename std::vector<value_type>::reference;
66 using const_reference = typename std::vector<value_type>::const_reference;
67 using pointer = typename std::vector<value_type>::pointer;
68 using const_pointer = typename std::vector<value_type>::const_pointer;
69 using iterator = typename std::vector<value_type>::const_iterator;
70 using const_iterator = typename std::vector<value_type>::const_iterator;
71 using reverse_iterator = typename std::vector<value_type>::const_reverse_iterator;
72 using const_reverse_iterator = typename std::vector<value_type>::const_reverse_iterator;
73 // FIXME: using node_type =
74 // FIXME: using insert_return_type =
75
76 //
77 // Constructors
78 //
79
80 RangeSet() {}
81
82 template <class InputIt,
83 typename = std::enable_if_t<std::is_base_of_v<
84 std::input_iterator_tag,
85 typename std::iterator_traits<InputIt>::iterator_category>>>
86 RangeSet(InputIt first, InputIt last)
87 {
88 insert(first, last);
89 }
90
91 RangeSet(Range<Key> const& range) { insert(range); }
92
93 RangeSet(Range<Key>&& range) { insert(std::move(range)); }
94
95 RangeSet(RangeSet const& other) : ranges_(other.ranges_) {}
96
97 template <typename Key2>
98 RangeSet(RangeSet<Key2> const& other)
99 {
100 // FIXME: Make sure it does not throw
101 insert(std::cbegin(other), std::cend(other));
102 }
103
104 RangeSet(RangeSet&& other) : ranges_(std::move(other.ranges_)) {}
105
106 RangeSet(std::initializer_list<value_type> init) { insert(init); }
107
108 RangeSet(std::initializer_list<Key> init) { insert(init); }
109
110 //
111 // Destructor
112 //
113
114 ~RangeSet() {}
115
116 //
117 // Assignment operator
118 //
119
120 RangeSet& operator=(RangeSet const& other)
121 {
122 ranges_ = other.ranges_;
123 return *this;
124 }
125
126 template <typename Key2>
127 RangeSet& operator=(RangeSet<Key2> const& other)
128 {
129 // FIXME: Make sure it does not throw
130 clear();
131 insert(std::cbegin(other), std::cend(other));
132 return *this;
133 }
134
135 RangeSet& operator=(RangeSet&& other) noexcept(
136 std::allocator_traits<allocator_type>::is_always_equal::value &&
137 std::is_nothrow_move_assignable<value_compare>::value) // FIXME: Look
138 // at noexcept
139 {
140 ranges_ = std::move(other.ranges_);
141 return *this;
142 }
143
144 RangeSet& operator=(std::initializer_list<value_type> ilist)
145 {
146 clear();
147 insert(ilist);
148 return *this;
149 }
150
151 //
152 // Get allocator
153 //
154
155 allocator_type get_allocator() const noexcept { return ranges_.get_allocator(); }
156
157 //
158 // Iterators
159 //
160
161 iterator begin() noexcept { return std::begin(ranges_); }
162
163 const_iterator begin() const noexcept { return std::begin(ranges_); }
164
165 const_iterator cbegin() const noexcept { return std::cbegin(ranges_); }
166
167 iterator end() noexcept { return std::end(ranges_); }
168
169 const_iterator end() const noexcept { return std::end(ranges_); }
170
171 const_iterator cend() const noexcept { return std::cend(ranges_); }
172
173 reverse_iterator rbegin() noexcept { return std::rbegin(ranges_); }
174
175 const_reverse_iterator rbegin() const noexcept { return std::rbegin(ranges_); }
176
177 const_reverse_iterator crbegin() const noexcept { return std::crbegin(ranges_); }
178
179 reverse_iterator rend() noexcept { return std::rend(ranges_); }
180
181 const_reverse_iterator rend() const noexcept { return std::rend(ranges_); }
182
183 const_reverse_iterator crend() const noexcept { return std::crend(ranges_); }
184
185 //
186 // Capacity
187 //
188
189 [[nodiscard]] bool empty() const noexcept { return ranges_.empty(); }
190
191 [[nodiscard]] size_type size() const noexcept { return ranges_.size(); }
192
193 [[nodiscard]] size_type max_size() const noexcept { return ranges_.max_size(); }
194
195 [[nodiscard]] size_type numRanges() const noexcept { return size(); }
196
197 template <typename Key2 = Key>
198 [[nodiscard]] std::enable_if_t<std::is_integral_v<Key2>, size_type> numValues() const
199 {
200 return std::accumulate(begin(), end(), numRanges(), [](auto cur, auto range) {
201 return cur + (range.upper() - range.lower());
202 });
203 }
204
205 //
206 // Modifiers
207 //
208
209 void clear() noexcept { ranges_.clear(); }
210
211 std::pair<iterator, bool> insert(value_type value)
212 {
213 // Subtract one to easily determine if [lower, upper] should be combined
214 // with a range [X, lower - 1]. E.g., [8, 15] should be combined with [1, 7]
215 // to become [1, 15]. Also note the protection against underflow
216 Key const lower_up = decrement(value.lower());
217
218 // Add one to easily determine if [lower, upper] should be combined with a
219 // range [upper + 1, X]. E.g., [4, 15] should be combined with [16, 21] to
220 // become [4, 21]. Also note the protection against overflow
221 Key const upper_op = increment(value.upper());
222
223 auto [lower, upper] = equal_range(lower_up, value.upper());
224
225 auto dist = std::distance(begin(), lower);
226 bool inserted = false;
227
228 if (end() == lower) {
229 inserted = true;
230
231 // Add new range to the end
232 // E.g., [21, 35] should be added at the end of [1, 4], [7, 15] to become
233 // [1, 4], [7, 15], [21, 35].
234 ranges_.push_back(value);
235 } else if (lower == upper && upper_op < upper->lower()) {
236 inserted = true;
237
238 // Add new range to the front or middle
239 // E.g., [4, 7] should be added to the middle of [0, 2], [9, 24] to become
240 // [0, 2], [4, 7], [9, 24].
241 ranges_.insert(lower, value);
242 } else {
243 // Combine range with other range(s)
244
245 // Note: lower and upper are const_iterator here
246 auto nc_lower = std::next(std::begin(ranges_), dist);
247
248 inserted = value.lower() < lower->lower();
249
250 nc_lower->setRange(std::min(lower->lower(), value.lower()), lower->upper());
251 if (end() == upper || upper_op < upper->lower()) {
252 inserted = inserted || lower->upper() < value.upper();
253
254 // New range stretches [lower, upper)
255 // E.g., [21, 25] should be combinded with [4, 22], [24, 24], [100, 150]
256 // to become [4, 25], [100, 150].
257 nc_lower->setRange(lower->lower(), std::max(lower->upper(), value.upper()));
258 erase(std::next(lower), upper);
259 } else {
260 inserted = inserted || lower != upper;
261
262 // New range stretches [lower, upper]
263 // E.g., [0, 50] should be combinded with [5, 15], [45, 55], [88, 99] to
264 // become [0, 55], [88, 99].
265 nc_lower->setRange(lower->lower(), upper->upper());
266 erase(std::next(lower), std::next(upper));
267 }
268 }
269
270 return {std::next(begin(), dist), inserted};
271 }
272
273 iterator insert(const_iterator hint, value_type value)
274 {
275 // FIXME: Use hint
276 return insert(value).first;
277 }
278
279 template <class InputIt,
280 typename = std::enable_if_t<std::is_base_of_v<
281 std::input_iterator_tag,
282 typename std::iterator_traits<InputIt>::iterator_category>>>
283 void insert(InputIt first, InputIt last)
284 {
285 // FIXME: Correct?
286 std::for_each(first, last, [this](auto&&... args) { this->insert(args...); });
287 }
288
289 void insert(std::initializer_list<value_type> ilist)
290 {
291 insert(std::cbegin(ilist), std::cend(ilist));
292 }
293
294 // FIXME: insert_return_type insert(node_type&& nh);
295
296 // FIXME: iterator insert(const_iterator hint, node_type&& nh);
297
298 template <class... Args>
299 std::pair<iterator, bool> emplace(Args&&... args)
300 {
301 return insert(value_type(std::forward<Args>(args)...));
302 }
303
304 template <class... Args>
305 iterator emplace_hint(const_iterator hint, Args&&... args)
306 {
307 return insert(hint, value_type(std::forward<Args>(args)...));
308 }
309
310 iterator erase(const_iterator pos) { return ranges_.erase(pos); }
311
312 iterator erase(const_iterator first, const_iterator last)
313 {
314 return ranges_.erase(first, last);
315 }
316
317 size_type erase(key_type key)
318 {
319 // FIXME: What should num_removed correspond to in here?
320
321 auto [lower, upper] = equal_range(key);
322
323 auto nc_lower = std::next(std::begin(ranges_), std::distance(begin(), lower));
324 auto nc_upper = std::next(std::begin(ranges_), std::distance(begin(), upper));
325
326 Key const lower_up = decrement(key.lower());
327 Key const upper_op = increment(key.upper());
328
329 size_type num_removed = 0;
330
331 if (end() == lower || (lower == upper && key.upper() < lower->lower())) {
332 // Nothing to erase
333 } else if (lower == upper) {
334 num_removed = 1;
335
336 if (key.lower() <= lower->lower()) {
337 // Erase lower part of a single range
338 nc_lower->setRange(upper_op, lower->upper());
339 } else {
340 // Erase middle part of a single range (split it into two ranges)
341 auto cur_upper = lower->upper();
342 nc_lower->setRange(lower->lower(), lower_up);
343 ranges_.emplace(std::next(lower), upper_op, cur_upper);
344 }
345 } else {
346 if (end() != upper) {
347 num_removed = upper->lower() < upper_op ? 1 : 0;
348 nc_upper->setRange(std::max(upper->lower(), upper_op), upper->upper());
349 }
350
351 num_removed += std::distance(lower, upper);
352
353 if (key.lower() <= lower->lower()) {
354 // Erase [lower, upper) ranges
355 ranges_.erase(lower, upper);
356 } else {
357 // Erase (lower, upper) ranges
358 nc_lower->setRange(lower->lower(), lower_up);
359 ranges_.erase(std::next(lower), upper);
360 }
361 }
362
363 return num_removed;
364 }
365
366 template <typename Key2>
367 size_type erase(Range<Key2> key)
368 {
369 return erase(key_type(key));
370 }
371
372 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
373 size_type erase(K key)
374 {
375 return erase(key_type(key));
376 }
377
378 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
379 size_type erase(K lower, K upper)
380 {
381 return erase(key_type(lower, upper));
382 }
383
384 void swap(RangeSet& other) noexcept(
385 std::allocator_traits<allocator_type>::is_always_equal::value &&
386 std::is_nothrow_move_assignable<value_compare>::value) // FIXME: Look
387 // at noexcept
388 {
389 ranges_.swap(other.ranges_);
390 }
391
392 // FIXME: node_type extract(const_iterator position);
393
394 // FIXME: node_type extract(key_type const& k);
395
396 // void merge(RangeSet& source)
397 // {
398 // // FIXME: Implement
399 // }
400
401 // void merge(RangeSet&& source)
402 // {
403 // // FIXME: Implement
404 // }
405
406 //
407 // Lookup
408 //
409 [[nodiscard]] size_type count(key_type key) const { return contains(key) ? 1 : 0; }
410
411 template <typename Key2>
412 [[nodiscard]] size_type count(Range<Key2> key)
413 {
414 return count(key_type(key));
415 }
416
417 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
418 [[nodiscard]] size_type count(K key)
419 {
420 return count(key_type(key));
421 }
422
423 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
424 [[nodiscard]] size_type count(K lower, K upper)
425 {
426 return count(key_type(lower, upper));
427 }
428
429 iterator find(key_type key)
430 {
431 auto lower = lower_bound(key);
432
433 return end() != lower && lower->lower() <= key.lower() &&
434 lower->upper() >= key.upper()
435 ? lower
436 : end();
437 }
438
439 template <typename Key2>
440 iterator find(Range<Key2> key)
441 {
442 return find(key_type(key));
443 }
444
445 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
446 iterator find(K key)
447 {
448 return find(key_type(key));
449 }
450
451 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
452 iterator find(K lower, K upper)
453 {
454 return find(key_type(lower, upper));
455 }
456
457 const_iterator find(key_type key) const
458 {
459 auto lower = lower_bound(key);
460
461 return end() != lower && lower->lower() <= key.lower() &&
462 lower->upper() >= key.upper()
463 ? lower
464 : end();
465 }
466
467 template <typename Key2>
468 const_iterator find(Range<Key2> key) const
469 {
470 return find(key_type(key));
471 }
472
473 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
474 const_iterator find(K key) const
475 {
476 return find(key_type(key));
477 }
478
479 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
480 const_iterator find(K lower, K upper) const
481 {
482 return find(key_type(lower, upper));
483 }
484
485 [[nodiscard]] bool contains(key_type key) const
486 {
487 auto lower = lower_bound(key);
488 return end() != lower && lower->lower() <= key.lower() &&
489 lower->upper() >= key.upper();
490 }
491
492 template <typename Key2>
493 [[nodiscard]] bool contains(Range<Key2> key) const
494 {
495 return contains(key_type(key));
496 }
497
498 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
499 [[nodiscard]] bool contains(K key) const
500 {
501 return contains(key_type(key));
502 }
503
504 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
505 [[nodiscard]] bool contains(K lower, K upper) const
506 {
507 return contains(key_type(lower, upper));
508 }
509
510 [[nodiscard]] std::pair<iterator, iterator> equal_range(key_type key)
511 {
512 typename value_compare::range_t const s_range{key.lower(), key.upper()};
513 return std::equal_range(begin(), end(), s_range, comp_);
514 }
515
516 template <typename Key2>
517 [[nodiscard]] std::pair<iterator, iterator> equal_range(Range<Key2> key)
518 {
519 return equal_range(key_type(key));
520 }
521
522 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
523 [[nodiscard]] std::pair<iterator, iterator> equal_range(K key)
524 {
525 return equal_range(key_type(key));
526 }
527
528 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
529 [[nodiscard]] std::pair<iterator, iterator> equal_range(K lower, K upper)
530 {
531 return equal_range(key_type(lower, upper));
532 }
533
534 [[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(key_type key) const
535 {
536 typename value_compare::range_t const s_range{key.lower(), key.upper()};
537 return std::equal_range(begin(), end(), s_range, comp_);
538 }
539
540 template <typename Key2>
541 [[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(
542 Range<Key2> key) const
543 {
544 return equal_range(key_type(key));
545 }
546
547 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
548 [[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(K key) const
549 {
550 return equal_range(key_type(key));
551 }
552
553 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
554 [[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(K lower,
555 K upper) const
556 {
557 return equal_range(key_type(lower, upper));
558 }
559
560 [[nodiscard]] iterator lower_bound(key_type key)
561 {
562 typename key_compare::range_t const s_range{key.lower(), key.upper()};
563 return std::lower_bound(begin(), end(), s_range, comp_);
564 }
565
566 template <typename Key2>
567 [[nodiscard]] iterator lower_bound(Range<Key2> key)
568 {
569 return lower_bound(key_type(key));
570 }
571
572 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
573 [[nodiscard]] iterator lower_bound(K key)
574 {
575 return lower_bound(key_type(key));
576 }
577
578 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
579 [[nodiscard]] iterator lower_bound(K lower, K upper)
580 {
581 return lower_bound(key_type(lower, upper));
582 }
583
584 [[nodiscard]] const_iterator lower_bound(key_type key) const
585 {
586 typename key_compare::range_t const s_range{key.lower(), key.upper()};
587 return std::lower_bound(begin(), end(), s_range, comp_);
588 }
589
590 template <typename Key2>
591 [[nodiscard]] const_iterator lower_bound(Range<Key2> key) const
592 {
593 return lower_bound(key_type(key));
594 }
595
596 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
597 [[nodiscard]] const_iterator lower_bound(K key) const
598 {
599 return lower_bound(key_type(key));
600 }
601
602 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
603 [[nodiscard]] const_iterator lower_bound(K lower, K upper) const
604 {
605 return lower_bound(key_type(lower, upper));
606 }
607
608 [[nodiscard]] iterator upper_bound(key_type key)
609 {
610 typename key_compare::range_t const s_range{key.lower(), key.upper()};
611 return std::upper_bound(begin(), end(), s_range, comp_);
612 }
613
614 template <typename Key2>
615 [[nodiscard]] iterator upper_bound(Range<Key2> key)
616 {
617 return upper_bound(key_type(key));
618 }
619
620 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
621 [[nodiscard]] iterator upper_bound(K key)
622 {
623 return upper_bound(key_type(key));
624 }
625
626 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
627 [[nodiscard]] iterator upper_bound(K lower, K upper)
628 {
629 return upper_bound(key_type(lower, upper));
630 }
631
632 [[nodiscard]] const_iterator upper_bound(key_type key) const
633 {
634 typename key_compare::range_t const s_range{key.lower(), key.upper()};
635 return std::upper_bound(begin(), end(), s_range, comp_);
636 }
637
638 template <typename Key2>
639 [[nodiscard]] const_iterator upper_bound(Range<Key2> key) const
640 {
641 return upper_bound(key_type(key));
642 }
643
644 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
645 [[nodiscard]] const_iterator upper_bound(K key) const
646 {
647 return upper_bound(key_type(key));
648 }
649
650 template <typename K, typename = std::enable_if_t<std::is_arithmetic_v<K>>>
651 [[nodiscard]] const_iterator upper_bound(K lower, K upper) const
652 {
653 return upper_bound(key_type(lower, upper));
654 }
655
656 //
657 // (De)serialize
658 //
659
660 std::ostream& writeData(std::ostream& out_stream) const
661 {
662 size_type num = numRanges();
663 out_stream.write(reinterpret_cast<char*>(&num), sizeof(size_type));
664 // FIXME: Add comp_
665 // FIXME: Does this work?
666 return out_stream.write(reinterpret_cast<char*>(ranges_.data()),
667 sizeof(value_type) * num);
668 }
669
670 std::istream& readData(std::istream& in_stream)
671 {
672 size_type num;
673 in_stream.read(reinterpret_cast<char*>(&num), sizeof(size_type));
674 if (0 == num) {
675 clear();
676 return in_stream;
677 }
678 // FIXME: Add comp_
679 ranges_.resize(num);
680 // FIXME: Does this work?
681 return in_stream.read(reinterpret_cast<char*>(ranges_.data()),
682 sizeof(value_type) * num);
683 }
684
685 //
686 // Observers
687 //
688
689 key_compare key_comp() const { return comp_; }
690
691 value_compare value_comp() const { return comp_; }
692
693 //
694 // Friends
695 //
696
697 template <typename K>
698 friend bool operator==(RangeSet<K> const& lhs, RangeSet<K> const& rhs);
699 template <typename K>
700 friend bool operator!=(RangeSet<K> const& lhs, RangeSet<K> const& rhs);
701 template <typename K>
702 friend bool operator<(RangeSet<K> const& lhs, RangeSet<K> const& rhs);
703 template <typename K>
704 friend bool operator<=(RangeSet<K> const& lhs, RangeSet<K> const& rhs);
705 template <typename K>
706 friend bool operator>(RangeSet<K> const& lhs, RangeSet<K> const& rhs);
707 template <typename K>
708 friend bool operator>=(RangeSet<K> const& lhs, RangeSet<K> const& rhs);
709
710 template <typename K>
711 friend void swap(RangeSet<K>& lhs, RangeSet<K>& rhs) noexcept(noexcept(lhs.swap(rhs)));
712
713 template <typename K, class Pred>
714 friend size_type erase_if(RangeSet<K>& range_set, Pred pred);
715
716 template <typename K>
717 friend std::ostream& operator<<(std::ostream& os, RangeSet<K> const& range_set);
718
719 protected:
720 static constexpr Key increment(Key value)
721 {
722 if constexpr (std::is_floating_point_v<Key>) {
723 return std::nextafter(value, std::numeric_limits<Key>::max());
724 } else {
725 return std::max(value, value + 1);
726 }
727 }
728
729 static constexpr Key decrement(Key value)
730 {
731 if constexpr (std::is_floating_point_v<Key>) {
732 return std::nextafter(value, std::numeric_limits<Key>::lowest());
733 } else {
734 return std::min(value, value - 1);
735 }
736 }
737
738 protected:
739 std::vector<value_type> ranges_;
740 value_compare comp_;
741};
742
743template <typename Key>
744bool operator==(RangeSet<Key> const& lhs, RangeSet<Key> const& rhs)
745{
746 // FIXME: Implement correctly
747 return lhs.ranges_ == rhs.ranges_;
748}
749
750template <typename Key>
751bool operator!=(RangeSet<Key> const& lhs, RangeSet<Key> const& rhs)
752{
753 // FIXME: Implement correctly
754 return lhs.ranges_ != rhs.ranges_;
755}
756
757template <typename Key>
758bool operator<(RangeSet<Key> const& lhs, RangeSet<Key> const& rhs)
759{
760 // FIXME: Implement correctly
761 return lhs.ranges_ < rhs.ranges_;
762}
763
764template <typename Key>
765bool operator<=(RangeSet<Key> const& lhs, RangeSet<Key> const& rhs)
766{
767 // FIXME: Implement correctly
768 return lhs.ranges_ <= rhs.ranges_;
769}
770
771template <typename Key>
772bool operator>(RangeSet<Key> const& lhs, RangeSet<Key> const& rhs)
773{
774 // FIXME: Implement correctly
775 return lhs.ranges_ > rhs.ranges_;
776}
777
778template <typename Key>
779bool operator>=(RangeSet<Key> const& lhs, RangeSet<Key> const& rhs)
780{
781 // FIXME: Implement correctly
782 return lhs.ranges_ >= rhs.ranges_;
783}
784
785template <typename Key>
786void swap(RangeSet<Key>& lhs, RangeSet<Key>& rhs) noexcept(noexcept(lhs.swap(rhs)))
787{
788 lhs.swap(rhs);
789}
790
791template <typename Key, class Pred>
792typename RangeSet<Key>::size_type erase_if(RangeSet<Key>& range_set, Pred pred)
793{
794 auto old_size = range_set.size();
795 for (auto it = std::begin(range_set), last = std::end(range_set); it != last;) {
796 if (pred(*it)) {
797 it = range_set.erase(it);
798 } else {
799 ++it;
800 }
801 }
802 return old_size - range_set.size();
803}
804
805template <typename Key>
806std::ostream& operator<<(std::ostream& os, RangeSet<Key> const& range_set)
807{
808 if (!range_set.empty()) {
809 std::copy(std::cbegin(range_set), std::prev(std::cend(range_set)),
810 std::ostream_iterator<typename RangeSet<Key>::value_type>(os, ", "));
811 os << *std::prev(std::end(range_set));
812 }
813 return os;
814}
815
826template <typename Key1, typename Key2>
827[[nodiscard]] bool rangesIncludes(RangeSet<Key1> const& a, RangeSet<Key2> const& b)
828{
829 auto a_first = std::begin(a);
830 auto a_last = std::end(a);
831 auto b_first = std::begin(b);
832 auto b_last = std::end(b);
833 while (b_first != b_last) {
834 if (a_first == a_last || a_first->lower() > b_first->upper()) {
835 return false;
836 }
837 if (a_first->lower() <= b_first->lower() && a_first->upper() >= b_first->upper()) {
838 ++b_first;
839 } else {
840 ++a_first;
841 }
842 }
843 return true;
844}
845
856template <typename Key1, typename Key2>
858 RangeSet<Key2> const& b)
859{
860 // FIXME: Implement efficiently
861 RangeSet<Key1> output = a;
862 for (auto range : b) {
863 output.erase(range);
864 }
865 return output;
866}
867
868template <typename Key1, typename Key2>
869[[nodiscard]] RangeSet<Key1> rangesIntersection(RangeSet<Key1> const& a,
870 RangeSet<Key2> const& b)
871{
872 // FIXME: Implement efficiently
873 RangeSet<Key1> output;
874 for (auto range : a) {
875 if (b.contains(range)) {
876 output.insert(range);
877 }
878 }
879 for (auto range : b) {
880 if (a.contains(range)) {
881 output.insert(range);
882 }
883 }
884 return output;
885}
886
887template <typename Key1, typename Key2>
888[[nodiscard]] RangeSet<Key1> rangesSymmetricDifference(RangeSet<Key1> const& a,
889 RangeSet<Key2> const& b)
890{
891 // FIXME: Implement efficiently
892 RangeSet<Key1> output = a;
893 for (auto range : b) {
894 output.erase(range);
895 }
896 RangeSet<Key1> temp = b;
897 for (auto range : a) {
898 temp.erase(range);
899 }
900 output.insert(std::begin(temp), std::end(temp));
901 return output;
902}
903
904template <typename Key1, typename Key2>
905[[nodiscard]] RangeSet<Key1> rangesUnion(RangeSet<Key1> const& a, RangeSet<Key2> const& b)
906{
907 // FIXME: Implement efficiently
908 RangeSet<Key1> output = a;
909 for (auto range : b) {
910 output.insert(range);
911 }
912 return output;
913}
914} // namespace ufo
915
916#endif // UFO_CONTAINER_RANGE_SET_HPP
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr T b(Lab< T, Flags > color) noexcept
Returns the un-weighted blue–yellow axis value.
Definition lab.hpp:326
bool rangesIncludes(RangeSet< Key1 > const &a, RangeSet< Key2 > const &b)
Returns true if b is a subsequence of a.
constexpr T a(Lab< T, Flags > color) noexcept
Returns the un-weighted green–red axis value.
Definition lab.hpp:310
RangeSet< Key1 > rangesDifference(RangeSet< Key1 > const &a, RangeSet< Key2 > const &b)
Creates a new RangeSet containing the ranges in a which are not find in b.
Comparator for interval ordering in associative containers.
Definition range.hpp:106
Represents a closed interval [lower, upper] of a scalar type.
Definition range.hpp:66
value_type lower
Lower bound of the interval (inclusive).
Definition range.hpp:75
value_type upper
Upper bound of the interval (inclusive).
Definition range.hpp:80