Skip to content

Commit a92a5c5

Browse files
committed
WIP: punch feature
1 parent 8253035 commit a92a5c5

File tree

6 files changed

+480
-163
lines changed

6 files changed

+480
-163
lines changed

README.md

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ Create a build folder, navigate there, run cmake and build the tree-tests target
6161
You might have to adapt the linker line for gtest, if you built it yourself and didn't install it into your system.
6262
If you want to generate the pretty drawings, install cairo, pull the submodule and pass INT_TREE_DRAW_EXAMPLES=on to the cmake command line to generate a drawings/make_drawings executeable.
6363

64+
Some features of this library require the presence of an optional type.
65+
If you are using C++17 and up, it will be std::optional.
66+
Otherwise you can specify INTERVAL_TREE_HAVE_BOOST_OPTIONAL to use boost::optional.
67+
And if neither, a reduced version of optional is provided in the library, not perfectly exchangeable with std::optional, but sufficient for the library to work.
68+
6469
## Draw Dot Graph
6570
This draws a dot graph of the tree:
6671
```c++
@@ -137,37 +142,73 @@ Options are:
137142

138143
## Members of IntervalTree<Interval>
139144

140-
- [Members of IntervalTree<Interval>](#members-of-intervaltreeinterval)
141-
- [iterator insert(interval_type const& ival)](#iterator-insertinterval_type-const-ival)
142-
- [iterator insert_overlap(interval_type const& ival, bool, bool)](#iterator-insert_overlapinterval_type-const-ival-bool-bool)
145+
- [interval-tree](#interval-tree)
146+
- [How an interval tree looks like:](#how-an-interval-tree-looks-like)
147+
- [Example](#example)
148+
- [Compile \& Run Testing](#compile--run-testing)
149+
- [Draw Dot Graph](#draw-dot-graph)
150+
- [Free Functions](#free-functions)
151+
- [interval\<NumericT, Kind\> make\_safe\_interval(NumericT border1, NumericT border2)](#intervalnumerict-kind-make_safe_intervalnumerict-border1-numerict-border2)
152+
- [draw\_dot\_graph(std::ostream\& os, interval\_tree\_t const\& tree, DrawOptions const\& options)](#draw_dot_graphstdostream-os-interval_tree_t-const-tree-drawoptions-const-options)
153+
- [Members of IntervalTree](#members-of-intervaltree)
154+
- [iterator insert(interval\_type const\& ival)](#iterator-insertinterval_type-const-ival)
155+
- [Parameters](#parameters)
156+
- [iterator insert\_overlap(interval\_type const\& ival, bool, bool)](#iterator-insert_overlapinterval_type-const-ival-bool-bool)
157+
- [Parameters](#parameters-1)
143158
- [iterator erase(iterator iter)](#iterator-eraseiterator-iter)
144-
- [size_type size() const](#size_type-size-const)
145-
- [(const)iterator find(interval_type const& ival)](#constiterator-findinterval_type-const-ival)
146-
- [(const)iterator find(interval_type const& ival, CompareFunctionT const& compare)](#constiterator-findinterval_type-const-ival-comparefunctiont-const-compare)
147-
- [(const)iterator find_all(interval_type const& ival, OnFindFunctionT const& on_find)](#constiterator-find_allinterval_type-const-ival-onfindfunctiont-const-on_find)
159+
- [Parameters](#parameters-2)
160+
- [size\_type size() const](#size_type-size-const)
161+
- [(const)iterator find(interval\_type const\& ival)](#constiterator-findinterval_type-const-ival)
162+
- [Parameters](#parameters-3)
163+
- [(const)iterator find(interval\_type const\& ival, CompareFunctionT const\& compare)](#constiterator-findinterval_type-const-ival-comparefunctiont-const-compare)
164+
- [Parameters](#parameters-4)
165+
- [(const)iterator find\_all(interval\_type const\& ival, OnFindFunctionT const\& on\_find)](#constiterator-find_allinterval_type-const-ival-onfindfunctiont-const-on_find)
166+
- [Parameters](#parameters-5)
148167
- [Example](#example-1)
149-
- [(const)iterator find_all(interval_type const& ival, OnFindFunctionT const& on_find, CompareFunctionT const& compare)](#constiterator-find_allinterval_type-const-ival-onfindfunctiont-const-on_find-comparefunctiont-const-compare)
150-
- [(const)iterator find_next_in_subtree(iterator from, interval_type const& ival)](#constiterator-find_next_in_subtreeiterator-from-interval_type-const-ival)
151-
- [(const)iterator find_next_in_subtree(iterator from, interval_type const& ival, CompareFunctionT const& compare)](#constiterator-find_next_in_subtreeiterator-from-interval_type-const-ival-comparefunctiont-const-compare)
152-
- [(const)iterator overlap_find(interval_type const& ival, bool exclusive)](#constiterator-overlap_findinterval_type-const-ival-bool-exclusive)
153-
- [(const)iterator overlap_find_all(interval_type const& ival, OnFindFunctionT const& on_find, bool exclusive)](#constiterator-overlap_find_allinterval_type-const-ival-onfindfunctiont-const-on_find-bool-exclusive)
168+
- [(const)iterator find\_all(interval\_type const\& ival, OnFindFunctionT const\& on\_find, CompareFunctionT const\& compare)](#constiterator-find_allinterval_type-const-ival-onfindfunctiont-const-on_find-comparefunctiont-const-compare)
169+
- [Parameters](#parameters-6)
170+
- [(const)iterator find\_next\_in\_subtree(iterator from, interval\_type const\& ival)](#constiterator-find_next_in_subtreeiterator-from-interval_type-const-ival)
171+
- [Parameters](#parameters-7)
172+
- [(const)iterator find\_next\_in\_subtree(iterator from, interval\_type const\& ival, CompareFunctionT const\& compare)](#constiterator-find_next_in_subtreeiterator-from-interval_type-const-ival-comparefunctiont-const-compare)
173+
- [Parameters](#parameters-8)
174+
- [(const)iterator overlap\_find(interval\_type const\& ival, bool exclusive)](#constiterator-overlap_findinterval_type-const-ival-bool-exclusive)
175+
- [Parameters](#parameters-9)
176+
- [(const)iterator overlap\_find\_all(interval\_type const\& ival, OnFindFunctionT const\& on\_find, bool exclusive)](#constiterator-overlap_find_allinterval_type-const-ival-onfindfunctiont-const-on_find-bool-exclusive)
177+
- [Parameters](#parameters-10)
154178
- [Example](#example-2)
155-
- [(const)iterator overlap_find_next_in_subtree(interval_type const& ival, bool exclusive)](#constiterator-overlap_find_next_in_subtreeinterval_type-const-ival-bool-exclusive)
156-
- [interval_tree& deoverlap()](#interval_tree-deoverlap)
179+
- [(const)iterator overlap\_find\_next\_in\_subtree(interval\_type const\& ival, bool exclusive)](#constiterator-overlap_find_next_in_subtreeinterval_type-const-ival-bool-exclusive)
180+
- [Parameters](#parameters-11)
181+
- [interval\_tree\& deoverlap()](#interval_tree-deoverlap)
157182
- [After deoverlap](#after-deoverlap)
158-
- [interval_tree& deoverlap_copy()](#interval_tree-deoverlap_copy)
159-
- [interval_tree punch(interval_type const& ival)](#interval_tree-punchinterval_type-const-ival)
160-
- [After punching (with [0, 50])](#after-punching-with-0-50)
161-
- [interval_tree punch()](#interval_tree-punch)
183+
- [interval\_tree deoverlap\_copy()](#interval_tree-deoverlap_copy)
184+
- [interval\_tree punch(interval\_type const\& ival)](#interval_tree-punchinterval_type-const-ival)
185+
- [After punching (with \[0, 50\])](#after-punching-with-0-50)
186+
- [interval\_tree punch()](#interval_tree-punch)
162187
- [bool empty() const noexcept](#bool-empty-const-noexcept)
163188
- [iterator begin()](#iterator-begin)
164189
- [iterator end()](#iterator-end)
165190
- [iterator cbegin()](#iterator-cbegin)
166191
- [iterator cend()](#iterator-cend)
167-
- [reverse_iterator rbegin()](#reverse_iterator-rbegin)
168-
- [reverse_iterator rend()](#reverse_iterator-rend)
169-
- [reverse_iterator crbegin()](#reverse_iterator-crbegin)
170-
- [reverse_iterator crend()](#reverse_iterator-crend)
192+
- [reverse\_iterator rbegin()](#reverse_iterator-rbegin)
193+
- [reverse\_iterator rend()](#reverse_iterator-rend)
194+
- [reverse\_iterator crbegin()](#reverse_iterator-crbegin)
195+
- [reverse\_iterator crend()](#reverse_iterator-crend)
196+
- [Members of Interval](#members-of-interval)
197+
- [using value\_type](#using-value_type)
198+
- [using interval\_kind](#using-interval_kind)
199+
- [friend bool operator==(interval const\& lhs, interval const\& other)](#friend-bool-operatorinterval-const-lhs-interval-const-other)
200+
- [friend bool operator!=(interval const\& lhs, interval const\& other)](#friend-bool-operatorinterval-const-lhs-interval-const-other-1)
201+
- [value\_type low() const](#value_type-low-const)
202+
- [value\_type high() const](#value_type-high-const)
203+
- [\[\[deprecated\]\] bool overlaps(value\_type l, value\_type h) const](#deprecated-bool-overlapsvalue_type-l-value_type-h-const)
204+
- [bool overlaps\_exclusive(value\_type l, value\_type h) const](#bool-overlaps_exclusivevalue_type-l-value_type-h-const)
205+
- [bool overlaps(interval const\& other) const](#bool-overlapsinterval-const-other-const)
206+
- [bool overlaps\_exclusive(interval const\& other) const](#bool-overlaps_exclusiveinterval-const-other-const)
207+
- [bool within(value\_type value) const](#bool-withinvalue_type-value-const)
208+
- [bool within(interval const\& other) const](#bool-withininterval-const-other-const)
209+
- [value\_type operator-(interval const\& other) const](#value_type-operator-interval-const-other-const)
210+
- [value\_type size() const](#value_type-size-const)
211+
- [interval join(interval const\& other) const](#interval-joininterval-const-other-const)
171212

172213
### iterator insert(interval_type const& ival)
173214
Adds an interval into the tree.

include/interval-tree/interval_tree.hpp

Lines changed: 108 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "interval_types.hpp"
55
#include "tree_hooks.hpp"
66
#include "feature_test.hpp"
7+
#include "optional.hpp"
78

89
#include <string>
910
#include <stdexcept>
@@ -21,6 +22,13 @@ namespace lib_interval_tree
2122
double_black
2223
};
2324
// ############################################################################################################
25+
template <typename interval_type>
26+
struct slice_type
27+
{
28+
optional<interval_type> left_slice{};
29+
optional<interval_type> right_slice{};
30+
};
31+
// ############################################################################################################
2432
using default_interval_value_type = int;
2533
// ############################################################################################################
2634
template <typename numerical_type, typename interval_kind_>
@@ -201,6 +209,37 @@ namespace lib_interval_tree
201209
{
202210
return interval_kind::size(low_, high_);
203211
}
212+
213+
/**
214+
* @brief Extrudes other from this interval returning what is remaining.
215+
*
216+
* @param other
217+
* @return slice_type<interval>
218+
*/
219+
slice_type<interval> extrude(interval const& other) const
220+
{
221+
if (!overlaps(other))
222+
return {};
223+
224+
slice_type<interval> slices{};
225+
if (low_ < other.low_)
226+
{
227+
auto slice = interval{low_, interval_kind::left_slice_upper_bound(other.low_)};
228+
// >= comparison avoids overflows in case of unsigned integers
229+
if (slice.high_ >= slice.low_ && slice.size() > 0)
230+
slices.left_slice = std::move(slice);
231+
}
232+
// low_ == other.low_ does not produce a left slice in any case.
233+
if (other.high_ > high_)
234+
{
235+
auto slice = interval{interval_kind::right_slice_lower_bound(high_), other.high_};
236+
// >= comparison avoids overflows in case of unsigned integers
237+
if (slice.high_ >= slice.low_ && slice.size() > 0)
238+
slices.right_slice = std::move(slice);
239+
}
240+
// high_ == other.high_ does not produce a right slice in any case.
241+
return slices;
242+
}
204243
};
205244

206245
template <typename numerical_type>
@@ -323,6 +362,37 @@ namespace lib_interval_tree
323362
return right_border_;
324363
}
325364

365+
/**
366+
* @brief Extrudes other from this interval returning what is remaining.
367+
*
368+
* @param other
369+
* @return slice_type<interval>
370+
*/
371+
slice_type<interval> extrude(interval const& other) const
372+
{
373+
if (!overlaps(other))
374+
return {};
375+
376+
slice_type<interval> slices{};
377+
if (low_ < other.low_)
378+
{
379+
auto slice = interval{low_, interval_kind::left_slice_upper_bound(other.low_, other.left_border())};
380+
// >= comparison avoids overflows in case of unsigned integers
381+
if (slice.high_ >= slice.low_ && slice.size() > 0)
382+
slices.left_slice = std::move(slice);
383+
}
384+
// low_ == other.low_ does not produce a left slice in any case.
385+
if (other.high_ > high_)
386+
{
387+
auto slice = interval{interval_kind::right_slice_lower_bound(high_, right_border_), other.high_};
388+
// >= comparison avoids overflows in case of unsigned integers
389+
if (slice.high_ >= slice.low_ && slice.size() > 0)
390+
slices.right_slice = std::move(slice);
391+
}
392+
// high_ == other.high_ does not produce a right slice in any case.
393+
return slices;
394+
}
395+
326396
protected:
327397
interval_border left_border_;
328398
interval_border right_border_;
@@ -1410,97 +1480,58 @@ namespace lib_interval_tree
14101480
return result;
14111481
}
14121482

1413-
// These two helper functions help to offset the adjacent interval edge depending on the interval type.
1414-
1415-
const auto low_with_offset_1 = [](interval_type const& interval) {
1416-
return interval.low() + (interval.within(interval.low()) ? 1 : 0);
1417-
};
1418-
const auto low_with_offset_minus_1 = [](interval_type const& interval) {
1419-
INTERVAL_TREE_CONSTEXPR_IF(std::is_unsigned<value_type>::value)
1420-
{
1421-
return static_cast<value_type>(
1422-
static_cast<std::make_signed<value_type>>(interval.low()) -
1423-
(interval.within(interval.low()) ? 1 : 0)
1424-
);
1425-
}
1426-
return interval.low() - (interval.within(interval.low()) ? 1 : 0);
1427-
};
1428-
const auto high_with_offset_1 = [](interval_type const& interval) {
1429-
return interval.high() + (interval.within(interval.high()) ? 1 : 0);
1430-
};
1431-
const auto high_with_offset_minus_1 = [](interval_type const& interval) {
1432-
INTERVAL_TREE_CONSTEXPR_IF(std::is_unsigned<value_type>::value)
1433-
{
1434-
return static_cast<value_type>(
1435-
static_cast<std::make_signed<value_type>>(interval.high()) -
1436-
(interval.within(interval.high()) ? 1 : 0)
1437-
);
1438-
}
1439-
return interval.high() - (interval.within(interval.high()) ? 1 : 0);
1440-
};
1441-
const auto is_empty_interval = [](interval_type const& interval) {
1442-
return !interval.within(interval.low()) && !interval.within(interval.high());
1443-
};
1444-
const auto insert_if_not_empty = [&](value_type left, value_type right) {
1445-
if (left <= right)
1446-
{
1447-
const auto interval = interval_type{left, right};
1448-
if (!is_empty_interval(interval))
1449-
result.insert(interval);
1450-
}
1451-
};
1452-
1453-
auto* first_not_right = find_first_not_right_of_i(ival.low);
1483+
auto* first_not_right = find_first_not_right_of_i(ival.low());
14541484
if (first_not_right == nullptr)
14551485
{
1456-
// There is no interval not fully right of the interval. So ival is either fully right of the rest of
1457-
// the tree or the last interval overlaps ival.
1486+
// [LAST] [ival]
1487+
// or
1488+
// [LAST]
1489+
// [ival]
1490+
// or
1491+
// [ LAST ]
1492+
// [ival]
14581493

14591494
auto last = crbegin();
1460-
if (!ival.overlaps(*crbegin()))
1495+
if (!ival.overlaps(*last))
14611496
{
1497+
// [LAST] [ival]
14621498
// ival is fully right of the tree, so just return a tree with this interval:
14631499
result.insert(ival);
14641500
return result;
14651501
}
14661502

1467-
if (std::max(ival.high(), last->high()) == last.high())
1468-
{
1469-
// The slice is not going beyond the last interval:
1470-
return {};
1471-
}
1472-
1473-
// Slice off the part overlapping over the end of last:
1474-
// TODO:
1475-
// if ()
1503+
const auto slices = last->extrude(ival);
1504+
if (slices.right_slice)
1505+
result.insert(std::move(slices.right_slice).value());
14761506
}
14771507
else
14781508
{
1479-
// There is an interval left of or inside ival.
1480-
1481-
const auto low = [&]() {
1482-
if (first_not_right->interval()->overlap(ival))
1483-
{
1484-
const auto joined = ival.join(*first_not_right->interval()).high();
1485-
return joined.high() + (joined.within(joined.high()) ? 1 : 0);
1486-
}
1487-
else
1488-
{
1489-
return ival.low();
1490-
}
1491-
}();
1492-
1493-
auto next = increment({first_not_right});
1494-
1495-
if (next == end())
1496-
{
1497-
value_type high = next->low() - (next->interval()->within(next->low() - 1));
1498-
}
1499-
else
1500-
{
1501-
// TODO:
1502-
}
1509+
// // There is an interval left of or inside ival.
1510+
1511+
// const auto low = [&]() {
1512+
// if (first_not_right->interval()->overlap(ival))
1513+
// {
1514+
// const auto joined = ival.join(*first_not_right->interval()).high();
1515+
// return joined.high() + (joined.within(joined.high()) ? 1 : 0);
1516+
// }
1517+
// else
1518+
// {
1519+
// return ival.low();
1520+
// }
1521+
// }();
1522+
1523+
// auto next = increment({first_not_right});
1524+
1525+
// if (next == end())
1526+
// {
1527+
// value_type high = next->low() - (next->interval()->within(next->low() - 1));
1528+
// }
1529+
// else
1530+
// {
1531+
// // TODO:
1532+
// }
15031533
}
1534+
return result;
15041535
}
15051536

15061537
iterator begin()

0 commit comments

Comments
 (0)