Skip to content

Commit 05a01fc

Browse files
authored
Merge pull request #50 from 5cript/feat/recursive_insert_overlap
Added recursive insert_overlap for single interval returns.
2 parents 8232ca5 + e92ec94 commit 05a01fc

File tree

5 files changed

+97
-48
lines changed

5 files changed

+97
-48
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ Options are:
139139

140140
- [Members of IntervalTree<Interval>](#members-of-intervaltreeinterval)
141141
- [iterator insert(interval_type const& ival)](#iterator-insertinterval_type-const-ival)
142-
- [iterator insert_overlap(interval_type const& ival)](#iterator-insert_overlapinterval_type-const-ival)
142+
- [iterator insert_overlap(interval_type const& ival, bool, bool)](#iterator-insert_overlapinterval_type-const-ival-bool-bool)
143143
- [iterator erase(iterator iter)](#iterator-eraseiterator-iter)
144144
- [size_type size() const](#size_type-size-const)
145145
- [(const)iterator find(interval_type const& ival)](#constiterator-findinterval_type-const-ival)
@@ -170,20 +170,20 @@ Options are:
170170
- [reverse_iterator crend()](#reverse_iterator-crend)
171171

172172
### iterator insert(interval_type const& ival)
173-
Adds an interval into the tree.
173+
Adds an interval into the tree.
174174
#### Parameters
175175
* `ival` An interval
176176

177177
**Returns**: An iterator to the inserted element.
178178

179179
---
180-
### iterator insert_overlap(interval_type const& ival)
180+
### iterator insert_overlap(interval_type const& ival, bool, bool)
181181
Inserts an interval into the tree if no other interval overlaps it.
182182
Otherwise merge the interval with the one being overlapped.
183183
#### Parameters
184184
* `ival` An interval
185185
* `exclusive` Exclude borders from overlap check. Defaults to false.
186-
* `mergeSetOverlapping` If the result of interval::join is a collection of intervals, shall each be inserted with more overlap searches? Defaults to false
186+
* `recursive` If the result of interval::join is a collection of intervals, shall each be inserted with more overlap searches? If the result is a single interval, shall it be inserted via insert_overlap or insert? Defaults to false. recursive=true picks insert_overlap. Also be careful to not produce overlapping merge sets when doing recursive insertion, or it will recurse endlessly.
187187

188188
**Returns**: An iterator to the inserted element.
189189

@@ -395,7 +395,7 @@ Returns a past the end const_iterator in reverse.
395395
**Returns**: past the end const_iterator.
396396

397397
## Members of Interval
398-
___You can implement your own interval if you provide the same functions, except (within, operator-, size, operator!=).___
398+
___You can implement your own interval if you provide the same functions, except (operator-, size, operator!=).___
399399

400400
There are 6 types of intervals:
401401
- open: (a, b)

include/interval-tree/feature_test.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,22 @@
2222
# else
2323
# define LIB_INTERVAL_TREE_FALLTHROUGH __attribute__((fallthrough))
2424
# endif
25+
#endif
26+
27+
// if constexpr is supported, use it, otherwise use plain if and pray the compiler optimizes it.
28+
#if __cplusplus >= 201703L
29+
# define INTERVAL_TREE_CONSTEXPR_IF if constexpr
30+
#else
31+
# define INTERVAL_TREE_CONSTEXPR_IF if
32+
#endif
33+
34+
// enum { value = value_ } or static constexpr
35+
#if __cplusplus >= 201703L
36+
# define INTERVAL_TREE_META_VALUE(type, name, the_value) static constexpr type name = the_value
37+
#else
38+
# define INTERVAL_TREE_META_VALUE(type, name, the_value) \
39+
enum : type \
40+
{ \
41+
name = the_value \
42+
}
2543
#endif

include/interval-tree/interval_tree.hpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,20 +1018,22 @@ namespace lib_interval_tree
10181018
* Otherwise merge the interval with the being overlapped.
10191019
*
10201020
* @param ival The interval
1021-
* @param exclusive Exclude borders.
1022-
* @param mergeSetOverlapping If the result of interval::join is a collection of intervals, shall each be
1023-
* inserted with more overlap searches?
1021+
* @param exclusive Exclude borders regardeless of interval type.
1022+
* @param recursive If the result of interval::join is a collection of intervals, shall each be
1023+
* inserted with more overlap searches? If the result is a single interval shall it insert_overlap or insert?
1024+
* Be careful to not produce overlapping merge sets when doing recursive insertion, or it will recurse
1025+
* endlessly.
10241026
*/
1025-
iterator insert_overlap(interval_type const& ival, bool exclusive = false, bool mergeSetOverlapping = false)
1027+
iterator insert_overlap(interval_type const& ival, bool exclusive = false, bool recursive = false)
10261028
{
10271029
auto iter = overlap_find(ival, exclusive);
10281030
if (iter == end())
10291031
return insert(ival);
10301032
else
10311033
{
1032-
auto mergeSet = iter.interval().join(ival);
1034+
auto merge_set = iter.interval().join(ival);
10331035
erase(iter);
1034-
return insert_merge_set(mergeSet, mergeSetOverlapping);
1036+
return insert_merge_set(std::move(merge_set), exclusive, recursive);
10351037
}
10361038
}
10371039

@@ -1480,17 +1482,17 @@ namespace lib_interval_tree
14801482
};
14811483

14821484
template <typename MergeSet>
1483-
iterator insert_merge_set(MergeSet const& merge_set, bool mergeSetOverlapping)
1485+
iterator insert_merge_set(MergeSet const& merge_set, bool exclusive, bool recursive)
14841486
{
1485-
if (mergeSetOverlapping)
1487+
if (recursive)
14861488
{
14871489
for (auto iter = merge_set.begin(), end = merge_set.end(); iter != end;)
14881490
{
14891491
auto next = iter;
14901492
if (++next == end)
1491-
return insert_overlap(*iter);
1493+
return insert_overlap(*iter, exclusive, recursive);
14921494
else
1493-
insert_overlap(*iter);
1495+
insert_overlap(*iter, exclusive, recursive);
14941496
iter = std::move(next);
14951497
}
14961498
return end();
@@ -1509,8 +1511,10 @@ namespace lib_interval_tree
15091511
return end();
15101512
}
15111513
}
1512-
iterator insert_merge_set(interval_type const& interval, bool)
1514+
iterator insert_merge_set(interval_type const& interval, bool exclusive, bool recursive)
15131515
{
1516+
if (recursive)
1517+
return insert_overlap(interval, exclusive, recursive);
15141518
return insert(interval);
15151519
}
15161520

tests/insert_tests.hpp

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,16 @@
77
#include <random>
88
#include <cmath>
99

10-
11-
12-
class InsertTests
13-
: public ::testing::Test
10+
class InsertTests : public ::testing::Test
1411
{
15-
public:
16-
using types = IntervalTypes <int>;
12+
public:
13+
using types = IntervalTypes<int>;
1714

18-
protected:
19-
IntervalTypes <int>::tree_type tree;
15+
protected:
16+
IntervalTypes<int>::tree_type tree;
2017
std::default_random_engine gen;
21-
std::uniform_int_distribution <int> distSmall{-500, 500};
22-
std::uniform_int_distribution <int> distLarge{-50000, 50000};
18+
std::uniform_int_distribution<int> distSmall{-500, 500};
19+
std::uniform_int_distribution<int> distLarge{-50000, 50000};
2320
};
2421

2522
TEST_F(InsertTests, InsertIntoEmpty1)
@@ -86,15 +83,50 @@ TEST_F(InsertTests, RBPropertyInsertTest)
8683

8784
TEST_F(InsertTests, IntervalsMayReturnMultipleIntervalsForJoin)
8885
{
89-
using interval_type = multi_join_interval <int>;
86+
using interval_type = multi_join_interval<int>;
9087
using tree_type = lib_interval_tree::interval_tree<interval_type>;
9188

9289
auto multiJoinTree = tree_type{};
9390

94-
multiJoinTree.insert({0, 1});
95-
multiJoinTree.insert_overlap({0, 2});
91+
multiJoinTree.insert({0, 2});
92+
multiJoinTree.insert_overlap({0, 4});
9693

9794
EXPECT_EQ(multiJoinTree.size(), 2);
98-
EXPECT_EQ(*multiJoinTree.begin(), (interval_type{0, 1})) << multiJoinTree.begin()->low() << multiJoinTree.begin()->high();
99-
EXPECT_EQ(*++multiJoinTree.begin(), (interval_type{1, 2}));
95+
EXPECT_EQ(*multiJoinTree.begin(), (interval_type{0, 1}))
96+
<< multiJoinTree.begin()->low() << multiJoinTree.begin()->high();
97+
EXPECT_EQ(*++multiJoinTree.begin(), (interval_type{3, 4}));
98+
}
99+
100+
TEST_F(InsertTests, IntervalsMayReturnMultipleIntervalsForJoinAndJoinRecursively)
101+
{
102+
using interval_type = multi_join_interval<int>;
103+
using tree_type = lib_interval_tree::interval_tree<interval_type>;
104+
105+
auto multiJoinTree = tree_type{};
106+
107+
multiJoinTree.insert({0, 10});
108+
multiJoinTree.insert({5, 10});
109+
multiJoinTree.insert_overlap({0, 20}, false, true);
110+
111+
EXPECT_EQ(multiJoinTree.size(), 3);
112+
113+
auto iter = multiJoinTree.begin();
114+
115+
EXPECT_EQ(*iter, (interval_type{0, 4})) << multiJoinTree.begin()->low() << multiJoinTree.begin()->high();
116+
EXPECT_EQ(*++iter, (interval_type{6, 10})) << multiJoinTree.begin()->low() << multiJoinTree.begin()->high();
117+
EXPECT_EQ(*++iter, (interval_type{11, 20})) << multiJoinTree.begin()->low() << multiJoinTree.begin()->high();
118+
}
119+
120+
TEST_F(InsertTests, CanInsertOverlapRecursively)
121+
{
122+
using tree_type = lib_interval_tree::interval_tree<types::interval_type>;
123+
124+
auto tree = tree_type{};
125+
tree.insert({0, 9});
126+
tree.insert({20, 29});
127+
tree.insert_overlap({8, 21}, false, true);
128+
129+
EXPECT_EQ(tree.size(), 1);
130+
EXPECT_EQ(tree.begin()->low(), 0);
131+
EXPECT_EQ(tree.begin()->high(), 29);
100132
}

tests/multi_join_interval.hpp

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,27 @@
77
template <typename numerical_type, typename interval_kind_ = lib_interval_tree::closed>
88
struct multi_join_interval
99
{
10-
public:
10+
public:
1111
using value_type = numerical_type;
1212
using interval_kind = interval_kind_;
1313

14-
#ifndef INTERVAL_TREE_SAFE_INTERVALS
1514
#if __cplusplus >= 201703L
1615
constexpr
1716
#endif
18-
multi_join_interval(value_type low, value_type high)
17+
multi_join_interval(value_type low, value_type high)
1918
: low_{low}
2019
, high_{high}
2120
{
2221
if (low > high)
2322
throw std::invalid_argument("Low border is not lower or equal to high border.");
2423
}
25-
#else
26-
#if __cplusplus >= 201703L
27-
constexpr
28-
#endif
29-
multi_join_interval(value_type low, value_type high)
30-
: low_{std::min(low, high)}
31-
, high_{std::max(low, high)}
32-
{
33-
}
34-
#endif
24+
3525
virtual ~multi_join_interval() = default;
26+
multi_join_interval(multi_join_interval const&) = default;
27+
multi_join_interval(multi_join_interval&&) noexcept = default;
28+
multi_join_interval& operator=(multi_join_interval const&) = default;
29+
multi_join_interval& operator=(multi_join_interval&&) noexcept = default;
30+
3631
friend bool operator==(multi_join_interval const& lhs, multi_join_interval const& other)
3732
{
3833
return lhs.low_ == other.low_ && lhs.high_ == other.high_;
@@ -91,13 +86,13 @@ struct multi_join_interval
9186
const auto min = std::min(low_, other.low_);
9287
const auto max = std::max(high_, other.high_);
9388
const auto avg = (min + max) / 2;
94-
return {
95-
{min, avg},
96-
{avg, max},
89+
return std::vector<multi_join_interval>{
90+
multi_join_interval{min, avg - 1},
91+
multi_join_interval{avg + 1, max},
9792
};
9893
}
9994

100-
protected:
95+
protected:
10196
value_type low_;
10297
value_type high_;
10398
};

0 commit comments

Comments
 (0)