1010#include < stdexcept>
1111#include < iterator>
1212#include < type_traits>
13+ #include < cassert>
1314
1415namespace lib_interval_tree
1516{
@@ -218,21 +219,19 @@ namespace lib_interval_tree
218219 */
219220 slice_type<interval> extrude (interval const & other) const
220221 {
221- if (!overlaps (other))
222- return {};
223-
224222 slice_type<interval> slices{};
225223 if (low_ < other.low_ )
226224 {
227- auto slice = interval{low_, interval_kind::left_slice_upper_bound (other.low_ )};
225+ auto slice = interval{low_, std::min ( interval_kind::left_slice_upper_bound (other.low_ ), high_ )};
228226 // >= comparison avoids overflows in case of unsigned integers
229227 if (slice.high_ >= slice.low_ && slice.size () > 0 )
230228 slices.left_slice = std::move (slice);
231229 }
232230 // low_ == other.low_ does not produce a left slice in any case.
233- if (other. high_ > high_)
231+ if (high_ > other. high_ )
234232 {
235- auto slice = interval{interval_kind::right_slice_lower_bound (high_), other.high_ };
233+ // FIXME: think: is the max violating edge conditions?
234+ auto slice = interval{std::max (interval_kind::right_slice_lower_bound (other.high_ ), low_), high_};
236235 // >= comparison avoids overflows in case of unsigned integers
237236 if (slice.high_ >= slice.low_ && slice.size () > 0 )
238237 slices.right_slice = std::move (slice);
@@ -376,15 +375,25 @@ namespace lib_interval_tree
376375 slice_type<interval> slices{};
377376 if (low_ < other.low_ )
378377 {
379- auto slice = interval{low_, interval_kind::left_slice_upper_bound (other.low_ , other.left_border ())};
378+ auto slice = interval{
379+ low_,
380+ std::min (other.low_ , high_),
381+ left_border_,
382+ other.left_border () == interval_border::open ? interval_border::closed : interval_border::open
383+ };
380384 // >= comparison avoids overflows in case of unsigned integers
381385 if (slice.high_ >= slice.low_ && slice.size () > 0 )
382386 slices.left_slice = std::move (slice);
383387 }
384388 // low_ == other.low_ does not produce a left slice in any case.
385- if (other. high_ > high_)
389+ if (high_ > other. high_ )
386390 {
387- auto slice = interval{interval_kind::right_slice_lower_bound (high_, right_border_), other.high_ };
391+ auto slice = interval{
392+ std::max (other.high_ , low_),
393+ high_,
394+ right_border_ == interval_border::open ? interval_border::closed : interval_border::open,
395+ other.right_border ()
396+ };
388397 // >= comparison avoids overflows in case of unsigned integers
389398 if (slice.high_ >= slice.low_ && slice.size () > 0 )
390399 slices.right_slice = std::move (slice);
@@ -1415,12 +1424,13 @@ namespace lib_interval_tree
14151424
14161425 // TODO: private
14171426 /* *
1418- * @brief Finds the first interval that is right of the given value and does not contain it.
1427+ * @brief Finds the interval that is right of the given value and does not contain it.
1428+ * Only works with deoverlapped trees.
14191429 *
14201430 * @param low
14211431 * @return node_type*
14221432 */
1423- node_type* find_first_not_right_of_i (value_type search_value) const
1433+ node_type* find_directly_right_of_i (value_type search_value) const
14241434 {
14251435 if (empty ())
14261436 return nullptr ;
@@ -1458,18 +1468,62 @@ namespace lib_interval_tree
14581468 if (is_interval_strictly_right_of_value (node))
14591469 return node;
14601470
1461- // We only end up when node == root_, otherwise we never went down the tree to begin with.
1471+ // We only end up here when node == root_, otherwise we never went down the tree to begin with.
14621472 return nullptr ;
14631473 }
14641474
1475+ /* *
1476+ * @brief Find the interval that is left of the given value or contains it.
1477+ * Only works in deoverlapped trees. Because a deoverlapped tree is indistinguishable
1478+ * from a regular binary search tree. The tree is then also sorted by the upper interval bound.
1479+ * Making this search possible in the first place.
1480+ *
1481+ * @param search_value
1482+ * @return node_type*
1483+ */
1484+ node_type* find_leftest_interval_of_value_i (value_type search_value) const
1485+ {
1486+ if (empty ())
1487+ return nullptr ;
1488+
1489+ auto * node = root_;
1490+
1491+ // low of a node is always lower than the lows of all nodes right of that node
1492+ // high of a node is always lower than the lows of all nodes right of that node
1493+
1494+ bool go_left = false ;
1495+ bool go_right = false ;
1496+
1497+ do
1498+ {
1499+ go_right = search_value > node->high ();
1500+ if (go_right)
1501+ {
1502+ go_right &= node->right_ != nullptr ;
1503+ if (go_right)
1504+ node = node->right_ ;
1505+ continue ;
1506+ }
1507+
1508+ go_left = node->left_ != nullptr && search_value < node->low ();
1509+ if (go_left)
1510+ node = node->left_ ;
1511+ } while (go_left || go_right);
1512+
1513+ if (search_value < node->low ())
1514+ return nullptr ;
1515+
1516+ return node;
1517+ }
1518+
14651519 /* *
14661520 * Only works with deoverlapped trees.
14671521 * Removes all intervals from the given interval and produces a tree that contains the remaining intervals.
14681522 * This is basically the other punch overload with ival = [tree_lowest, tree_highest]
14691523 *
14701524 * @param ival The range in which to punch out the gaps as a new tree
14711525 */
1472- interval_tree punch (interval_type const & ival) const
1526+ interval_tree punch (interval_type ival) const
14731527 {
14741528 interval_tree result;
14751529
@@ -1480,57 +1534,48 @@ namespace lib_interval_tree
14801534 return result;
14811535 }
14821536
1483- auto * first_not_right = find_first_not_right_of_i (ival.low ());
1484- if (first_not_right == nullptr )
1537+ auto * left_of_or_contains = find_leftest_interval_of_value_i (ival.low ());
1538+
1539+ const_iterator iter{nullptr , this };
1540+ if (left_of_or_contains == nullptr )
14851541 {
1486- // [LAST] [ival]
1487- // or
1488- // [LAST]
1489- // [ival]
1490- // or
1491- // [ LAST ]
1492- // [ival]
1493-
1494- auto last = crbegin ();
1495- if (!ival.overlaps (*last))
1542+ iter = cbegin ();
1543+ // not adjacent or overlapping?
1544+ if (ival.high () < iter->low ())
14961545 {
1497- // [LAST] [ival]
1498- // ival is fully right of the tree, so just return a tree with this interval:
14991546 result.insert (ival);
15001547 return result;
15011548 }
1502-
1503- const auto slices = last->extrude (ival);
1504- if (slices.right_slice )
1505- result.insert (std::move (slices.right_slice ).value ());
15061549 }
15071550 else
15081551 {
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- // }
1552+ iter = const_iterator{left_of_or_contains, this };
15331553 }
1554+
1555+ slice_type<interval_type> ex;
1556+ bool insert_remaining = false ;
1557+ for (; iter != cend (); ++iter)
1558+ {
1559+ ex = ival.extrude (*iter);
1560+ if (ex.left_slice )
1561+ result.insert (*ex.left_slice );
1562+
1563+ if (ex.right_slice )
1564+ {
1565+ ival = std::move (*ex.right_slice );
1566+ // TODO: Can I avoid assigning this every loop? -> maybe by extracting the first iteration?
1567+ insert_remaining = true ;
1568+ }
1569+ else
1570+ {
1571+ insert_remaining = false ;
1572+ break ;
1573+ }
1574+ }
1575+
1576+ if (insert_remaining && ival.size () > 0 )
1577+ result.insert (ival);
1578+
15341579 return result;
15351580 }
15361581
0 commit comments