Skip to content

Commit e92ec94

Browse files
committed
Added recursive insert_overlap for single interval returns.
1 parent 9d2e062 commit e92ec94

File tree

5 files changed

+98
-49
lines changed

5 files changed

+98
-49
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ int main()
4242
tree.insert({19, 20});
4343

4444
tree.deoverlap();
45-
45+
4646
for (auto const& i : tree)
4747
{
4848
std::cout << "[" << i.low() << ", " << i.high() << "]\n";
@@ -69,7 +69,7 @@ Creates an interval where the borders are sorted so the lower border is the firs
6969

7070
- [Members of IntervalTree<Interval>](#members-of-intervaltreeinterval)
7171
- [iterator insert(interval_type const& ival)](#iterator-insertinterval_type-const-ival)
72-
- [iterator insert_overlap(interval_type const& ival)](#iterator-insert_overlapinterval_type-const-ival)
72+
- [iterator insert_overlap(interval_type const& ival, bool, bool)](#iterator-insert_overlapinterval_type-const-ival-bool-bool)
7373
- [iterator erase(iterator iter)](#iterator-eraseiterator-iter)
7474
- [size_type size() const](#size_type-size-const)
7575
- [(const)iterator find(interval_type const& ival)](#constiterator-findinterval_type-const-ival)
@@ -100,20 +100,20 @@ Creates an interval where the borders are sorted so the lower border is the firs
100100
- [reverse_iterator crend()](#reverse_iterator-crend)
101101

102102
### iterator insert(interval_type const& ival)
103-
Adds an interval into the tree.
103+
Adds an interval into the tree.
104104
#### Parameters
105105
* `ival` An interval
106106

107107
**Returns**: An iterator to the inserted element.
108108

109109
---
110-
### iterator insert_overlap(interval_type const& ival)
110+
### iterator insert_overlap(interval_type const& ival, bool, bool)
111111
Inserts an interval into the tree if no other interval overlaps it.
112112
Otherwise merge the interval with the one being overlapped.
113113
#### Parameters
114114
* `ival` An interval
115115
* `exclusive` Exclude borders from overlap check. Defaults to false.
116-
* `mergeSetOverlapping` If the result of interval::join is a collection of intervals, shall each be inserted with more overlap searches? Defaults to false
116+
* `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.
117117

118118
**Returns**: An iterator to the inserted element.
119119

@@ -325,7 +325,7 @@ Returns a past the end const_iterator in reverse.
325325
**Returns**: past the end const_iterator.
326326

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

330330
There are 6 types of intervals:
331331
- 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
@@ -1022,20 +1022,22 @@ namespace lib_interval_tree
10221022
* Otherwise merge the interval with the being overlapped.
10231023
*
10241024
* @param ival The interval
1025-
* @param exclusive Exclude borders.
1026-
* @param mergeSetOverlapping If the result of interval::join is a collection of intervals, shall each be
1027-
* inserted with more overlap searches?
1025+
* @param exclusive Exclude borders regardeless of interval type.
1026+
* @param recursive If the result of interval::join is a collection of intervals, shall each be
1027+
* inserted with more overlap searches? If the result is a single interval shall it insert_overlap or insert?
1028+
* Be careful to not produce overlapping merge sets when doing recursive insertion, or it will recurse
1029+
* endlessly.
10281030
*/
1029-
iterator insert_overlap(interval_type const& ival, bool exclusive = false, bool mergeSetOverlapping = false)
1031+
iterator insert_overlap(interval_type const& ival, bool exclusive = false, bool recursive = false)
10301032
{
10311033
auto iter = overlap_find(ival, exclusive);
10321034
if (iter == end())
10331035
return insert(ival);
10341036
else
10351037
{
1036-
auto mergeSet = iter.interval().join(ival);
1038+
auto merge_set = iter.interval().join(ival);
10371039
erase(iter);
1038-
return insert_merge_set(mergeSet, mergeSetOverlapping);
1040+
return insert_merge_set(std::move(merge_set), exclusive, recursive);
10391041
}
10401042
}
10411043

@@ -1484,17 +1486,17 @@ namespace lib_interval_tree
14841486
};
14851487

14861488
template <typename MergeSet>
1487-
iterator insert_merge_set(MergeSet const& merge_set, bool mergeSetOverlapping)
1489+
iterator insert_merge_set(MergeSet const& merge_set, bool exclusive, bool recursive)
14881490
{
1489-
if (mergeSetOverlapping)
1491+
if (recursive)
14901492
{
14911493
for (auto iter = merge_set.begin(), end = merge_set.end(); iter != end;)
14921494
{
14931495
auto next = iter;
14941496
if (++next == end)
1495-
return insert_overlap(*iter);
1497+
return insert_overlap(*iter, exclusive, recursive);
14961498
else
1497-
insert_overlap(*iter);
1499+
insert_overlap(*iter, exclusive, recursive);
14981500
iter = std::move(next);
14991501
}
15001502
return end();
@@ -1513,8 +1515,10 @@ namespace lib_interval_tree
15131515
return end();
15141516
}
15151517
}
1516-
iterator insert_merge_set(interval_type const& interval, bool)
1518+
iterator insert_merge_set(interval_type const& interval, bool exclusive, bool recursive)
15171519
{
1520+
if (recursive)
1521+
return insert_overlap(interval, exclusive, recursive);
15181522
return insert(interval);
15191523
}
15201524

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)