@@ -1343,35 +1343,164 @@ namespace lib_interval_tree
13431343 return punch ({min, max});
13441344 }
13451345
1346+ // TODO: private
13461347 /* *
1347- * Only works with deoverlapped trees.
1348- * Removes all intervals from the given interval and produces a tree that contains the remaining intervals.
1349- * This is basically the other punch overload with ival = [tree_lowest, tree_highest]
1348+ * @brief Finds the first interval that is right of the given value and does not contain it.
1349+ *
1350+ * @param low
1351+ * @return node_type*
13501352 */
1351- interval_tree punch (interval_type const & ival ) const
1353+ node_type* find_first_not_right_of_i (value_type search_value ) const
13521354 {
13531355 if (empty ())
1354- return {};
1356+ return nullptr ;
1357+
1358+ // There can be no interval strictly right of the value, if the value
1359+ // is larger than the max.
1360+ if (search_value > root_->max_ )
1361+ return nullptr ;
1362+
1363+ const auto is_interval_strictly_right_of_value = [search_value](node_type* node) {
1364+ return node->low () > search_value ||
1365+ (node->low () == search_value && !node->interval ()->within (search_value));
1366+ };
1367+
1368+ auto * node = root_;
1369+
1370+ // If the interval is not strictly right of the value, we can only go down right
1371+ // And dont have to check left.
1372+ while (!is_interval_strictly_right_of_value (node) && node->right_ )
1373+ node = node->right_ ;
1374+
1375+ bool go_left = false ;
1376+ bool go_right = false ;
1377+ do
1378+ {
1379+ go_left = node->left_ && is_interval_strictly_right_of_value (node->left_ );
1380+ go_right = node->right_ && is_interval_strictly_right_of_value (node->right_ );
1381+
1382+ if (go_left)
1383+ node = node->left_ ;
1384+ else if (go_right)
1385+ node = node->right_ ;
1386+ } while (go_left || go_right);
1387+
1388+ if (is_interval_strictly_right_of_value (node))
1389+ return node;
1390+
1391+ // We only end up when node == root_, otherwise we never went down the tree to begin with.
1392+ return nullptr ;
1393+ }
13551394
1395+ /* *
1396+ * Only works with deoverlapped trees.
1397+ * Removes all intervals from the given interval and produces a tree that contains the remaining intervals.
1398+ * This is basically the other punch overload with ival = [tree_lowest, tree_highest]
1399+ *
1400+ * @param ival The range in which to punch out the gaps as a new tree
1401+ */
1402+ interval_tree punch (interval_type const & ival) const
1403+ {
13561404 interval_tree result;
1357- auto i = std::begin (*this );
1358- if (ival.low () < i->interval ()->low ())
1359- result.insert ({ival.low (), i->interval ()->low ()});
13601405
1361- for ( auto e = end (); i != e; ++i )
1406+ if ( empty () )
13621407 {
1363- auto next = i;
1364- ++next;
1365- if (next != e)
1366- result.insert ({i->interval ()->high (), next->interval ()->low ()});
1367- else
1368- break ;
1408+ // Nothing to punch, so return the whole interval
1409+ result.insert (ival);
1410+ return result;
13691411 }
13701412
1371- if (i != end () && i->interval ()->high () < ival.high ())
1372- result.insert ({i->interval ()->high (), ival.high ()});
1413+ // These two helper functions help to offset the adjacent interval edge depending on the interval type.
13731414
1374- return result;
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 );
1454+ if (first_not_right == nullptr )
1455+ {
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.
1458+
1459+ auto last = crbegin ();
1460+ if (!ival.overlaps (*crbegin ()))
1461+ {
1462+ // ival is fully right of the tree, so just return a tree with this interval:
1463+ result.insert (ival);
1464+ return result;
1465+ }
1466+
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 ()
1476+ }
1477+ else
1478+ {
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+ }
1503+ }
13751504 }
13761505
13771506 iterator begin ()
0 commit comments