Skip to content

Commit 6501e3a

Browse files
committed
Added erase range function.
1 parent 14bc215 commit 6501e3a

File tree

2 files changed

+164
-18
lines changed

2 files changed

+164
-18
lines changed

include/interval-tree/interval_tree.hpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,45 @@ namespace lib_interval_tree
12051205
return next;
12061206
}
12071207

1208+
/**
1209+
* @brief Erases all elements that overlap with ival, if retainSlices is true, the left and right overhanging
1210+
* parts are reinserted.
1211+
*
1212+
* ( i1 )
1213+
* ( i2 )
1214+
* ( erase )
1215+
* yields for retainSlices = true:
1216+
* (i1rest) (i2rest)
1217+
*
1218+
* Edge behavior depends on the interval type, or rather the slice implementation.
1219+
*
1220+
* @param ival The interval to erase.
1221+
* @param retainSlice If true, retains the non-overlapping parts of the intervals.
1222+
*/
1223+
template <typename interval_t = interval_type>
1224+
#ifdef LIB_INTERVAL_TREE_CONCEPTS
1225+
requires detail::has_slice<interval_t>
1226+
void
1227+
#else
1228+
typename std::enable_if<detail::has_slice<interval_t>, void>::type
1229+
#endif
1230+
erase_range(interval_t const& ival, bool retainSlices = false)
1231+
{
1232+
const auto iter = insert_overlap(ival, false, true);
1233+
if (!retainSlices)
1234+
{
1235+
erase(iter);
1236+
return;
1237+
}
1238+
1239+
const auto slices = iter->slice(ival);
1240+
erase(iter);
1241+
if (slices.left_slice)
1242+
insert(slices.left_slice.value());
1243+
if (slices.right_slice)
1244+
insert(slices.right_slice.value());
1245+
}
1246+
12081247
/**
12091248
* Returns the size of the object.
12101249
*/

tests/erase_tests.hpp

Lines changed: 125 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct Oracle
1616
template <typename numerical_type, typename interval_kind_ = lib_interval_tree::closed>
1717
class OracleInterval : public lib_interval_tree::interval<numerical_type, interval_kind_>
1818
{
19-
public:
19+
public:
2020
using lib_interval_tree::interval<numerical_type, interval_kind_>::low_;
2121
using lib_interval_tree::interval<numerical_type, interval_kind_>::high_;
2222

@@ -60,26 +60,27 @@ class OracleInterval : public lib_interval_tree::interval<numerical_type, interv
6060
{
6161
return OracleInterval{oracle_, std::min(low_, other.low_), std::max(high_, other.high_)};
6262
}
63-
private:
63+
64+
private:
6465
Oracle* oracle_;
6566
};
6667

6768
template <typename numerical_type, typename interval_kind_ = lib_interval_tree::closed>
68-
OracleInterval <numerical_type, interval_kind_> makeSafeOracleInterval(Oracle* oracle, numerical_type lhs, numerical_type rhs)
69+
OracleInterval<numerical_type, interval_kind_>
70+
makeSafeOracleInterval(Oracle* oracle, numerical_type lhs, numerical_type rhs)
6971
{
70-
return OracleInterval <numerical_type, interval_kind_>{oracle, std::min(lhs, rhs), std::max(lhs, rhs)};
72+
return OracleInterval<numerical_type, interval_kind_>{oracle, std::min(lhs, rhs), std::max(lhs, rhs)};
7173
}
7274

73-
class EraseTests
74-
: public ::testing::Test
75+
class EraseTests : public ::testing::Test
7576
{
76-
public:
77+
public:
7778
using interval_type = OracleInterval<int>;
7879

79-
public:
80+
public:
8081
auto makeTree()
8182
{
82-
lib_interval_tree::interval_tree_t <int> regularTree;
83+
lib_interval_tree::interval_tree_t<int> regularTree;
8384
regularTree.insert({16, 21});
8485
regularTree.insert({8, 9});
8586
regularTree.insert({25, 30});
@@ -93,12 +94,12 @@ class EraseTests
9394
return regularTree;
9495
}
9596

96-
protected:
97+
protected:
9798
Oracle oracle;
98-
lib_interval_tree::interval_tree <OracleInterval<int>> tree;
99+
lib_interval_tree::interval_tree<OracleInterval<int>> tree;
99100
std::default_random_engine gen;
100-
std::uniform_int_distribution <int> distSmall{-500, 500};
101-
std::uniform_int_distribution <int> distLarge{-50000, 50000};
101+
std::uniform_int_distribution<int> distSmall{-500, 500};
102+
std::uniform_int_distribution<int> distLarge{-50000, 50000};
102103
};
103104

104105
TEST_F(EraseTests, EraseSingleElement)
@@ -170,7 +171,7 @@ TEST_F(EraseTests, RandomEraseTest)
170171

171172
for (int i = 0; i != deleteAmount; ++i)
172173
{
173-
std::uniform_int_distribution <int> dist{0, amount - i - 1};
174+
std::uniform_int_distribution<int> dist{0, amount - i - 1};
174175
auto end = dist(gen);
175176
auto iter = tree.begin();
176177
for (int j = 0; j != end; ++j)
@@ -183,16 +184,14 @@ TEST_F(EraseTests, RandomEraseTest)
183184
testTreeHeightHealth(tree);
184185
}
185186

186-
187-
188187
TEST_F(EraseTests, MassiveDeleteEntireTreeWithEraseReturnIterator)
189188
{
190189
constexpr int amount = 1000;
191190

192191
for (int i = 0; i != amount; ++i)
193192
tree.insert(makeSafeOracleInterval(&oracle, distSmall(gen), distSmall(gen)));
194193

195-
for(auto iter = tree.begin(); !tree.empty();)
194+
for (auto iter = tree.begin(); !tree.empty();)
196195
{
197196
iter = tree.erase(iter);
198197
}
@@ -255,11 +254,119 @@ TEST_F(EraseTests, CanEraseEntireTreeUsingReturnedIterator)
255254

256255
TEST_F(EraseTests, FromNuiTest)
257256
{
258-
lib_interval_tree::interval_tree_t <int> tree;
257+
lib_interval_tree::interval_tree_t<int> tree;
259258
tree.insert({0, 0});
260259
tree.insert({4, 4});
261260
tree.insert({13, 13});
262261

263262
auto iter = tree.erase(tree.find({4, 4}));
264263
EXPECT_EQ(*iter, (decltype(tree)::interval_type{13, 13})) << *iter;
265264
}
265+
266+
TEST_F(EraseTests, EraseRangeOnEmptyTreeDoesNothing)
267+
{
268+
lib_interval_tree::interval_tree_t<int> tree;
269+
ASSERT_NO_FATAL_FAILURE(tree.erase_range({0, 10}, false));
270+
EXPECT_TRUE(tree.empty());
271+
}
272+
273+
TEST_F(EraseTests, EraseRangeOnIntervalInsideRangeIsRemoved)
274+
{
275+
lib_interval_tree::interval_tree_t<int> tree;
276+
tree.insert({0, 10});
277+
278+
tree.erase_range({-10, 20}, false);
279+
EXPECT_TRUE(tree.empty());
280+
}
281+
282+
TEST_F(EraseTests, EraseRangeOnIntervalEncompassingRangeIsRemoved)
283+
{
284+
lib_interval_tree::interval_tree_t<int> tree;
285+
tree.insert({0, 10});
286+
287+
tree.erase_range({3, 5}, false);
288+
EXPECT_TRUE(tree.empty());
289+
}
290+
291+
TEST_F(EraseTests, NonOverlappingIntervalIsNotRemoved)
292+
{
293+
lib_interval_tree::interval_tree_t<int> tree;
294+
tree.insert({0, 10});
295+
296+
tree.erase_range({20, 30}, false);
297+
EXPECT_EQ(tree.size(), 1);
298+
EXPECT_EQ(*tree.begin(), (decltype(tree)::interval_type{0, 10}));
299+
}
300+
301+
TEST_F(EraseTests, NonOverlappingIntervalIsNotRemoved2)
302+
{
303+
lib_interval_tree::interval_tree_t<int> tree;
304+
tree.insert({0, 10});
305+
tree.insert({25, 35});
306+
307+
tree.erase_range({20, 30}, false);
308+
EXPECT_EQ(tree.size(), 1);
309+
EXPECT_EQ(*tree.begin(), (decltype(tree)::interval_type{0, 10}));
310+
}
311+
312+
TEST_F(EraseTests, EraseRangeOnIntervalWithLeftSlice)
313+
{
314+
lib_interval_tree::interval_tree_t<int> tree;
315+
tree.insert({0, 10});
316+
317+
tree.erase_range({-5, 5}, true);
318+
EXPECT_EQ(tree.size(), 1);
319+
EXPECT_EQ(*tree.begin(), (decltype(tree)::interval_type{5, 10}));
320+
}
321+
322+
TEST_F(EraseTests, EraseRangeOnIntervalWithRightSlice)
323+
{
324+
lib_interval_tree::interval_tree_t<int> tree;
325+
tree.insert({0, 10});
326+
327+
tree.erase_range({5, 15}, true);
328+
EXPECT_EQ(tree.size(), 1);
329+
EXPECT_EQ(*tree.begin(), (decltype(tree)::interval_type{0, 5}));
330+
}
331+
332+
TEST_F(EraseTests, EraseRangeMiddleCutOut)
333+
{
334+
lib_interval_tree::interval_tree_t<int> tree;
335+
tree.insert({0, 10});
336+
337+
tree.erase_range({3, 5}, true);
338+
EXPECT_EQ(tree.size(), 2);
339+
EXPECT_EQ(*tree.begin(), (decltype(tree)::interval_type{0, 3}));
340+
EXPECT_EQ(*(++tree.begin()), (decltype(tree)::interval_type{5, 10}));
341+
}
342+
343+
TEST_F(EraseTests, EraseRangeLeftSliceIsNotReinsertedIfParamIsFalse)
344+
{
345+
lib_interval_tree::interval_tree_t<int> tree;
346+
tree.insert({0, 10});
347+
348+
tree.erase_range({-5, 5}, false);
349+
EXPECT_TRUE(tree.empty());
350+
}
351+
352+
TEST_F(EraseTests, EraseRangeRightSliceIsNotReinsertedIfParamIsFalse)
353+
{
354+
lib_interval_tree::interval_tree_t<int> tree;
355+
tree.insert({0, 10});
356+
357+
tree.erase_range({5, 15}, false);
358+
EXPECT_TRUE(tree.empty());
359+
}
360+
361+
TEST_F(EraseTests, SlicesAreReinsertedWithMultioverlap)
362+
{
363+
lib_interval_tree::interval_tree_t<int> tree;
364+
tree.insert({0, 10});
365+
tree.insert({5, 15});
366+
tree.insert({10, 20});
367+
368+
tree.erase_range({3, 12}, true);
369+
EXPECT_EQ(tree.size(), 2);
370+
EXPECT_EQ(*tree.begin(), (decltype(tree)::interval_type{0, 3}));
371+
EXPECT_EQ(*(++tree.begin()), (decltype(tree)::interval_type{12, 20}));
372+
}

0 commit comments

Comments
 (0)