10
10
#include < stdexcept>
11
11
#include < iterator>
12
12
#include < type_traits>
13
+ #include < cassert>
13
14
14
15
namespace lib_interval_tree
15
16
{
@@ -218,21 +219,19 @@ namespace lib_interval_tree
218
219
*/
219
220
slice_type<interval> extrude (interval const & other) const
220
221
{
221
- if (!overlaps (other))
222
- return {};
223
-
224
222
slice_type<interval> slices{};
225
223
if (low_ < other.low_ )
226
224
{
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_ )};
228
226
// >= comparison avoids overflows in case of unsigned integers
229
227
if (slice.high_ >= slice.low_ && slice.size () > 0 )
230
228
slices.left_slice = std::move (slice);
231
229
}
232
230
// low_ == other.low_ does not produce a left slice in any case.
233
- if (other. high_ > high_)
231
+ if (high_ > other. high_ )
234
232
{
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_};
236
235
// >= comparison avoids overflows in case of unsigned integers
237
236
if (slice.high_ >= slice.low_ && slice.size () > 0 )
238
237
slices.right_slice = std::move (slice);
@@ -376,15 +375,25 @@ namespace lib_interval_tree
376
375
slice_type<interval> slices{};
377
376
if (low_ < other.low_ )
378
377
{
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
+ };
380
384
// >= comparison avoids overflows in case of unsigned integers
381
385
if (slice.high_ >= slice.low_ && slice.size () > 0 )
382
386
slices.left_slice = std::move (slice);
383
387
}
384
388
// low_ == other.low_ does not produce a left slice in any case.
385
- if (other. high_ > high_)
389
+ if (high_ > other. high_ )
386
390
{
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
+ };
388
397
// >= comparison avoids overflows in case of unsigned integers
389
398
if (slice.high_ >= slice.low_ && slice.size () > 0 )
390
399
slices.right_slice = std::move (slice);
@@ -1415,12 +1424,13 @@ namespace lib_interval_tree
1415
1424
1416
1425
// TODO: private
1417
1426
/* *
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.
1419
1429
*
1420
1430
* @param low
1421
1431
* @return node_type*
1422
1432
*/
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
1424
1434
{
1425
1435
if (empty ())
1426
1436
return nullptr ;
@@ -1458,18 +1468,62 @@ namespace lib_interval_tree
1458
1468
if (is_interval_strictly_right_of_value (node))
1459
1469
return node;
1460
1470
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.
1462
1472
return nullptr ;
1463
1473
}
1464
1474
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
+
1465
1519
/* *
1466
1520
* Only works with deoverlapped trees.
1467
1521
* Removes all intervals from the given interval and produces a tree that contains the remaining intervals.
1468
1522
* This is basically the other punch overload with ival = [tree_lowest, tree_highest]
1469
1523
*
1470
1524
* @param ival The range in which to punch out the gaps as a new tree
1471
1525
*/
1472
- interval_tree punch (interval_type const & ival) const
1526
+ interval_tree punch (interval_type ival) const
1473
1527
{
1474
1528
interval_tree result;
1475
1529
@@ -1480,57 +1534,48 @@ namespace lib_interval_tree
1480
1534
return result;
1481
1535
}
1482
1536
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 )
1485
1541
{
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 ())
1496
1545
{
1497
- // [LAST] [ival]
1498
- // ival is fully right of the tree, so just return a tree with this interval:
1499
1546
result.insert (ival);
1500
1547
return result;
1501
1548
}
1502
-
1503
- const auto slices = last->extrude (ival);
1504
- if (slices.right_slice )
1505
- result.insert (std::move (slices.right_slice ).value ());
1506
1549
}
1507
1550
else
1508
1551
{
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 };
1533
1553
}
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
+
1534
1579
return result;
1535
1580
}
1536
1581
0 commit comments