Skip to content

Commit 14f1092

Browse files
authored
Merge pull request #20 from 5cript/intervals_may_join_into_parts
Intervals may join into parts
2 parents b7a23aa + 6c60a38 commit 14f1092

File tree

4 files changed

+165
-8
lines changed

4 files changed

+165
-8
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ Otherwise merge the interval with the one being overlapped.
9999
#### Parameters
100100
* `ival` An interval
101101
* `exclusive` Exclude borders from overlap check. Defaults to false.
102+
* `mergeSetOverlapping` If the result of interval::join is a collection of intervals, shall each be inserted with more overlap searches? Defaults to false
102103

103104
**Returns**: An iterator to the inserted element.
104105

Diff for: include/interval-tree/interval_tree.hpp

+39-4
Original file line numberDiff line numberDiff line change
@@ -767,17 +767,18 @@ namespace lib_interval_tree
767767
*
768768
* @param ival The interval
769769
* @param exclusive Exclude borders.
770+
* @param mergeSetOverlapping If the result of interval::join is a collection of intervals, shall each be inserted with more overlap searches?
770771
*/
771-
iterator insert_overlap(interval_type const& ival, bool exclusive = false)
772+
iterator insert_overlap(interval_type const& ival, bool exclusive = false, bool mergeSetOverlapping = false)
772773
{
773774
auto iter = overlap_find(ival, exclusive);
774775
if (iter == end())
775776
return insert(ival);
776777
else
777778
{
778-
auto merged = iter->interval().join(ival);
779-
erase(iter);
780-
return insert(merged);
779+
auto mergeSet = iter->interval().join(ival);
780+
erase(iter);
781+
return insert_merge_set(mergeSet, mergeSetOverlapping);
781782
}
782783
}
783784

@@ -1160,6 +1161,40 @@ namespace lib_interval_tree
11601161
return nullptr;
11611162
};
11621163

1164+
template <typename MergeSet>
1165+
iterator insert_merge_set(MergeSet const& merge_set, bool mergeSetOverlapping)
1166+
{
1167+
if (mergeSetOverlapping)
1168+
{
1169+
for (auto iter = merge_set.begin(), end = merge_set.end(); iter != end;)
1170+
{
1171+
auto next = iter;
1172+
if (++next == end)
1173+
return insert_overlap(*iter);
1174+
else
1175+
insert_overlap(*iter);
1176+
iter = std::move(next);
1177+
}
1178+
return end();
1179+
}
1180+
else
1181+
{
1182+
for (auto iter = merge_set.begin(), end = merge_set.end(); iter != end;)
1183+
{
1184+
auto next = iter;
1185+
if (++next == end)
1186+
return insert(*iter);
1187+
else
1188+
insert(*iter);
1189+
iter = std::move(next);
1190+
}
1191+
return end();
1192+
}
1193+
}
1194+
iterator insert_merge_set(interval_type const& interval, bool) {
1195+
return insert(interval);
1196+
}
1197+
11631198
void clear_subtree(node_type* node)
11641199
{
11651200
if (node)

Diff for: tests/insert_tests.hpp

+22-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
#pragma once
22

33
#include "test_utility.hpp"
4+
#include "multi_join_interval.hpp"
45

56
#include <ctime>
67
#include <random>
78
#include <cmath>
89

10+
11+
912
class InsertTests
1013
: public ::testing::Test
1114
{
@@ -17,17 +20,17 @@ class InsertTests
1720
std::default_random_engine gen;
1821
std::uniform_int_distribution <int> distSmall{-500, 500};
1922
std::uniform_int_distribution <int> distLarge{-50000, 50000};
20-
};
21-
23+
};
24+
2225
TEST_F(InsertTests, InsertIntoEmpty1)
2326
{
2427
auto inserted_interval = types::interval_type{0, 16};
2528

2629
tree.insert(inserted_interval);
2730
EXPECT_EQ(*tree.begin(), inserted_interval);
2831
EXPECT_EQ(tree.size(), 1);
29-
}
30-
32+
}
33+
3134
TEST_F(InsertTests, InsertIntoEmpty2)
3235
{
3336
auto inserted_interval = types::interval_type{-45, 16};
@@ -80,3 +83,18 @@ TEST_F(InsertTests, RBPropertyInsertTest)
8083

8184
testRedBlackPropertyViolation(tree);
8285
}
86+
87+
TEST_F(InsertTests, IntervalsMayReturnMultipleIntervalsForJoin)
88+
{
89+
using interval_type = multi_join_interval <int>;
90+
using tree_type = lib_interval_tree::interval_tree<interval_type>;
91+
92+
auto multiJoinTree = tree_type{};
93+
94+
multiJoinTree.insert({0, 1});
95+
multiJoinTree.insert_overlap({0, 2});
96+
97+
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}));
100+
}

Diff for: tests/multi_join_interval.hpp

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#pragma once
2+
3+
#include <interval-tree/interval_types.hpp>
4+
#include <algorithm>
5+
#include <vector>
6+
7+
template <typename numerical_type, typename interval_kind_ = lib_interval_tree::closed>
8+
struct multi_join_interval
9+
{
10+
public:
11+
using value_type = numerical_type;
12+
using interval_kind = interval_kind_;
13+
14+
#ifndef INTERVAL_TREE_SAFE_INTERVALS
15+
#if __cplusplus >= 201703L
16+
constexpr
17+
#endif
18+
multi_join_interval(value_type low, value_type high)
19+
: low_{low}
20+
, high_{high}
21+
{
22+
if (low > high)
23+
throw std::invalid_argument("Low border is not lower or equal to high border.");
24+
}
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
35+
virtual ~multi_join_interval() = default;
36+
friend bool operator==(multi_join_interval const& lhs, multi_join_interval const& other)
37+
{
38+
return lhs.low_ == other.low_ && lhs.high_ == other.high_;
39+
}
40+
friend bool operator!=(multi_join_interval const& lhs, multi_join_interval const& other)
41+
{
42+
return lhs.low_ != other.low_ || lhs.high_ != other.high_;
43+
}
44+
value_type low() const
45+
{
46+
return low_;
47+
}
48+
value_type high() const
49+
{
50+
return high_;
51+
}
52+
bool overlaps(value_type l, value_type h) const
53+
{
54+
return low_ <= h && l <= high_;
55+
}
56+
bool overlaps_exclusive(value_type l, value_type h) const
57+
{
58+
return low_ < h && l < high_;
59+
}
60+
bool overlaps(multi_join_interval const& other) const
61+
{
62+
return overlaps(other.low_, other.high_);
63+
}
64+
bool overlaps_exclusive(multi_join_interval const& other) const
65+
{
66+
return overlaps_exclusive(other.low_, other.high_);
67+
}
68+
bool within(value_type value) const
69+
{
70+
return interval_kind::within(low_, high_, value);
71+
}
72+
bool within(multi_join_interval const& other) const
73+
{
74+
return low_ <= other.low_ && high_ >= other.high_;
75+
}
76+
value_type operator-(multi_join_interval const& other) const
77+
{
78+
if (overlaps(other))
79+
return 0;
80+
if (high_ < other.low_)
81+
return other.low_ - high_;
82+
else
83+
return low_ - other.high_;
84+
}
85+
value_type size() const
86+
{
87+
return high_ - low_;
88+
}
89+
std::vector<multi_join_interval> join(multi_join_interval const& other) const
90+
{
91+
const auto min = std::min(low_, other.low_);
92+
const auto max = std::max(high_, other.high_);
93+
const auto avg = (min + max) / 2;
94+
return {
95+
{min, avg},
96+
{avg, max},
97+
};
98+
}
99+
100+
protected:
101+
value_type low_;
102+
value_type high_;
103+
};

0 commit comments

Comments
 (0)