@@ -1347,35 +1347,164 @@ namespace lib_interval_tree
1347
1347
return punch({min, max});
1348
1348
}
1349
1349
1350
+ // TODO: private
1350
1351
/**
1351
- * Only works with deoverlapped trees.
1352
- * Removes all intervals from the given interval and produces a tree that contains the remaining intervals.
1353
- * This is basically the other punch overload with ival = [tree_lowest, tree_highest]
1352
+ * @brief Finds the first interval that is right of the given value and does not contain it.
1353
+ *
1354
+ * @param low
1355
+ * @return node_type*
1354
1356
*/
1355
- interval_tree punch(interval_type const& ival ) const
1357
+ node_type* find_first_not_right_of_i(value_type search_value ) const
1356
1358
{
1357
1359
if (empty())
1358
- return {};
1360
+ return nullptr;
1361
+
1362
+ // There can be no interval strictly right of the value, if the value
1363
+ // is larger than the max.
1364
+ if (search_value > root_->max_)
1365
+ return nullptr;
1366
+
1367
+ const auto is_interval_strictly_right_of_value = [search_value](node_type* node) {
1368
+ return node->low() > search_value ||
1369
+ (node->low() == search_value && !node->interval()->within(search_value));
1370
+ };
1371
+
1372
+ auto* node = root_;
1373
+
1374
+ // If the interval is not strictly right of the value, we can only go down right
1375
+ // And dont have to check left.
1376
+ while (!is_interval_strictly_right_of_value(node) && node->right_)
1377
+ node = node->right_;
1378
+
1379
+ bool go_left = false;
1380
+ bool go_right = false;
1381
+ do
1382
+ {
1383
+ go_left = node->left_ && is_interval_strictly_right_of_value(node->left_);
1384
+ go_right = node->right_ && is_interval_strictly_right_of_value(node->right_);
1385
+
1386
+ if (go_left)
1387
+ node = node->left_;
1388
+ else if (go_right)
1389
+ node = node->right_;
1390
+ } while (go_left || go_right);
1391
+
1392
+ if (is_interval_strictly_right_of_value(node))
1393
+ return node;
1394
+
1395
+ // We only end up when node == root_, otherwise we never went down the tree to begin with.
1396
+ return nullptr;
1397
+ }
1359
1398
1399
+ /**
1400
+ * Only works with deoverlapped trees.
1401
+ * Removes all intervals from the given interval and produces a tree that contains the remaining intervals.
1402
+ * This is basically the other punch overload with ival = [tree_lowest, tree_highest]
1403
+ *
1404
+ * @param ival The range in which to punch out the gaps as a new tree
1405
+ */
1406
+ interval_tree punch(interval_type const& ival) const
1407
+ {
1360
1408
interval_tree result;
1361
- auto i = std::begin(*this);
1362
- if (ival.low() < i->interval()->low())
1363
- result.insert({ival.low(), i->interval()->low()});
1364
1409
1365
- for (auto e = end(); i != e; ++i )
1410
+ if (empty() )
1366
1411
{
1367
- auto next = i;
1368
- ++next;
1369
- if (next != e)
1370
- result.insert({i->interval()->high(), next->interval()->low()});
1371
- else
1372
- break;
1412
+ // Nothing to punch, so return the whole interval
1413
+ result.insert(ival);
1414
+ return result;
1373
1415
}
1374
1416
1375
- if (i != end() && i->interval()->high() < ival.high())
1376
- result.insert({i->interval()->high(), ival.high()});
1417
+ // These two helper functions help to offset the adjacent interval edge depending on the interval type.
1377
1418
1378
- return result;
1419
+ const auto low_with_offset_1 = [](interval_type const& interval) {
1420
+ return interval.low() + (interval.within(interval.low()) ? 1 : 0);
1421
+ };
1422
+ const auto low_with_offset_minus_1 = [](interval_type const& interval) {
1423
+ INTERVAL_TREE_CONSTEXPR_IF(std::is_unsigned<value_type>::value)
1424
+ {
1425
+ return static_cast<value_type>(
1426
+ static_cast<std::make_signed<value_type>>(interval.low()) -
1427
+ (interval.within(interval.low()) ? 1 : 0)
1428
+ );
1429
+ }
1430
+ return interval.low() - (interval.within(interval.low()) ? 1 : 0);
1431
+ };
1432
+ const auto high_with_offset_1 = [](interval_type const& interval) {
1433
+ return interval.high() + (interval.within(interval.high()) ? 1 : 0);
1434
+ };
1435
+ const auto high_with_offset_minus_1 = [](interval_type const& interval) {
1436
+ INTERVAL_TREE_CONSTEXPR_IF(std::is_unsigned<value_type>::value)
1437
+ {
1438
+ return static_cast<value_type>(
1439
+ static_cast<std::make_signed<value_type>>(interval.high()) -
1440
+ (interval.within(interval.high()) ? 1 : 0)
1441
+ );
1442
+ }
1443
+ return interval.high() - (interval.within(interval.high()) ? 1 : 0);
1444
+ };
1445
+ const auto is_empty_interval = [](interval_type const& interval) {
1446
+ return !interval.within(interval.low()) && !interval.within(interval.high());
1447
+ };
1448
+ const auto insert_if_not_empty = [&](value_type left, value_type right) {
1449
+ if (left <= right)
1450
+ {
1451
+ const auto interval = interval_type{left, right};
1452
+ if (!is_empty_interval(interval))
1453
+ result.insert(interval);
1454
+ }
1455
+ };
1456
+
1457
+ auto* first_not_right = find_first_not_right_of_i(ival.low);
1458
+ if (first_not_right == nullptr)
1459
+ {
1460
+ // There is no interval not fully right of the interval. So ival is either fully right of the rest of
1461
+ // the tree or the last interval overlaps ival.
1462
+
1463
+ auto last = crbegin();
1464
+ if (!ival.overlaps(*crbegin()))
1465
+ {
1466
+ // ival is fully right of the tree, so just return a tree with this interval:
1467
+ result.insert(ival);
1468
+ return result;
1469
+ }
1470
+
1471
+ if (std::max(ival.high(), last->high()) == last.high())
1472
+ {
1473
+ // The slice is not going beyond the last interval:
1474
+ return {};
1475
+ }
1476
+
1477
+ // Slice off the part overlapping over the end of last:
1478
+ // TODO:
1479
+ // if ()
1480
+ }
1481
+ else
1482
+ {
1483
+ // There is an interval left of or inside ival.
1484
+
1485
+ const auto low = [&]() {
1486
+ if (first_not_right->interval()->overlap(ival))
1487
+ {
1488
+ const auto joined = ival.join(*first_not_right->interval()).high();
1489
+ return joined.high() + (joined.within(joined.high()) ? 1 : 0);
1490
+ }
1491
+ else
1492
+ {
1493
+ return ival.low();
1494
+ }
1495
+ }();
1496
+
1497
+ auto next = increment({first_not_right});
1498
+
1499
+ if (next == end())
1500
+ {
1501
+ value_type high = next->low() - (next->interval()->within(next->low() - 1));
1502
+ }
1503
+ else
1504
+ {
1505
+ // TODO:
1506
+ }
1507
+ }
1379
1508
}
1380
1509
1381
1510
iterator begin()
0 commit comments