Skip to content

Commit 4dbd09a

Browse files
committed
Merge branch 'master' of github.com:5cript/interval-tree
2 parents bc19a6a + 75f395e commit 4dbd09a

File tree

6 files changed

+115
-37
lines changed

6 files changed

+115
-37
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Creates an interval where the borders are sorted so the lower border is the firs
6767
- [Example](#example-1)
6868
- [(const)iterator find_all(interval_type const& ival, OnFindFunctionT const& on_find, CompareFunctionT const& compare)](#constiterator-find_allinterval_type-const-ival-onfindfunctiont-const-on_find-comparefunctiont-const-compare)
6969
- [(const)iterator find_next_in_subtree(iterator from, interval_type const& ival)](#constiterator-find_next_in_subtreeiterator-from-interval_type-const-ival)
70-
- [(const)iterator find_next(iterator from, interval_type const& ival, CompareFunctionT const& compare)](#constiterator-find_nextiterator-from-interval_type-const-ival-comparefunctiont-const-compare)
70+
- [(const)iterator find_next_in_subtree(iterator from, interval_type const& ival, CompareFunctionT const& compare)](#constiterator-find_next_in_subtreeiterator-from-interval_type-const-ival-comparefunctiont-const-compare)
7171
- [(const)iterator overlap_find(interval_type const& ival, bool exclusive)](#constiterator-overlap_findinterval_type-const-ival-bool-exclusive)
7272
- [(const)iterator overlap_find_all(interval_type const& ival, OnFindFunctionT const& on_find, bool exclusive)](#constiterator-overlap_find_allinterval_type-const-ival-onfindfunctiont-const-on_find-bool-exclusive)
7373
- [Example](#example-2)
@@ -127,11 +127,11 @@ Finds the first interval in the interval tree that has an exact match.
127127

128128
---
129129
### (const)iterator find(interval_type const& ival, CompareFunctionT const& compare)
130-
Finds the first interval in the interval tree that has the following statement evaluate to true: compare(ival, interval_in_tree);
130+
Finds the first interval in the interval tree that has the following statement evaluate to true: compare(interval_in_tree, ival);
131131
Allows for propper float comparisons.
132132
#### Parameters
133133
* `ival` The interval to find.
134-
* `compare` The compare function to compare intervals with.
134+
* `compare` The compare function to compare intervals with. Function is called like so: compare(interval_in_tree, ival).
135135

136136
**Returns**: An iterator to the found element, or std::end(tree).
137137

@@ -160,7 +160,7 @@ tree.find_all({3, 7}, [](auto iter) /* iter will be const_iterator if tree is co
160160
Find all intervals in the tree that the compare function returns true for.
161161
#### Parameters
162162
* `ival` The interval to find.
163-
* `compare` The compare function to compare intervals with.
163+
* `compare` The compare function to compare intervals with. Function is called like so: compare(interval_in_tree, ival).
164164
* `on_find` A function of type bool(iterator) that is called when an interval was found.
165165
Return true to continue, false to preemptively abort search.
166166

@@ -177,13 +177,13 @@ You cannot find all matches this way, use find_all for that.
177177
**Returns**: An iterator to the found element, or std::end(tree).
178178

179179
---
180-
### (const)iterator find_next(iterator from, interval_type const& ival, CompareFunctionT const& compare)
180+
### (const)iterator find_next_in_subtree(iterator from, interval_type const& ival, CompareFunctionT const& compare)
181181
Finds the next exact match EXCLUDING from in the subtree originating from "from".
182182
You cannot find all matches this way, use find_all for that.
183183
#### Parameters
184184
* `from` The iterator to start from (including this iterator!)
185185
* `ival` The interval to find.
186-
* `compare` The compare function to compare intervals with.
186+
* `compare` The compare function to compare intervals with. Function is called like so: compare(interval_in_tree, ival).
187187

188188
**Returns**: An iterator to the found element, or std::end(tree).
189189

interval_tree.hpp

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,19 @@ namespace lib_interval_tree
3737
* Constructs an interval. low MUST be smaller than high.
3838
*/
3939
#ifndef INTERVAL_TREE_SAFE_INTERVALS
40+
#if __cplusplus >= 201703L
41+
constexpr
42+
#endif
4043
interval(value_type low, value_type high)
4144
: low_{low}
4245
, high_{high}
4346
{
4447
assert(low <= high);
4548
}
4649
#else
50+
#if __cplusplus >= 201703L
51+
constexpr
52+
#endif
4753
interval(value_type low, value_type high)
4854
: low_{std::min(low, high)}
4955
, high_{std::max(low, high)}
@@ -173,6 +179,9 @@ namespace lib_interval_tree
173179
* Creates a safe interval that puts the lower bound left automatically.
174180
*/
175181
template <typename numerical_type, typename interval_kind_ = closed>
182+
#if __cplusplus >= 201703L
183+
constexpr
184+
#endif
176185
interval <numerical_type, interval_kind_> make_safe_interval(numerical_type lhs, numerical_type rhs)
177186
{
178187
return interval <numerical_type, interval_kind_>{std::min(lhs, rhs), std::max(lhs, rhs)};
@@ -621,6 +630,7 @@ namespace lib_interval_tree
621630
using iterator = interval_tree_iterator <node_type>;
622631
using const_iterator = const_interval_tree_iterator <node_type>;
623632
using size_type = long long;
633+
using this_type = interval_tree<interval_type>;
624634

625635
public:
626636
friend const_interval_tree_iterator <node_type>;
@@ -854,14 +864,14 @@ namespace lib_interval_tree
854864
{
855865
if (root_ == nullptr)
856866
return;
857-
find_all_i<iterator>(root_, ival, on_find, compare);
867+
find_all_i<this_type, iterator>(this, root_, ival, on_find, compare);
858868
}
859869
template <typename FunctionT, typename CompareFunctionT>
860870
void find_all(interval_type const& ival, FunctionT const& on_find, CompareFunctionT const& compare) const
861871
{
862872
if (root_ == nullptr)
863873
return;
864-
find_all_i<const_iterator>(root_, ival, on_find, compare);
874+
find_all_i<this_type, const_iterator>(this, root_, ival, on_find, compare);
865875
}
866876

867877
template <typename FunctionT>
@@ -950,19 +960,19 @@ namespace lib_interval_tree
950960
if (root_ == nullptr)
951961
return;
952962
if (exclusive)
953-
overlap_find_all_i<true, iterator>(root_, ival, on_find);
963+
overlap_find_all_i<this_type, true, iterator>(this, root_, ival, on_find);
954964
else
955-
overlap_find_all_i<false, iterator>(root_, ival, on_find);
965+
overlap_find_all_i<this_type, false, iterator>(this, root_, ival, on_find);
956966
}
957967
template <typename FunctionT>
958968
void overlap_find_all(interval_type const& ival, FunctionT const& on_find, bool exclusive = false) const
959969
{
960970
if (root_ == nullptr)
961971
return;
962972
if (exclusive)
963-
overlap_find_all_i<true, const_iterator>(root_, ival, on_find);
973+
overlap_find_all_i<this_type, true, const_iterator>(this, root_, ival, on_find);
964974
else
965-
overlap_find_all_i<false, const_iterator>(root_, ival, on_find);
975+
overlap_find_all_i<this_type, false, const_iterator>(this, root_, ival, on_find);
966976
}
967977

968978
/**
@@ -1114,36 +1124,43 @@ namespace lib_interval_tree
11141124
return nullptr;
11151125
};
11161126

1117-
template <typename IteratorT, typename FunctionT, typename ComparatorFunctionT>
1118-
bool find_all_i(node_type* ptr, interval_type const& ival, FunctionT const& on_find, ComparatorFunctionT const& compare)
1127+
template <typename ThisType, typename IteratorT, typename FunctionT, typename ComparatorFunctionT>
1128+
static bool find_all_i
1129+
(
1130+
typename std::conditional<std::is_same<IteratorT, iterator>::value, ThisType, ThisType const>::type* self,
1131+
node_type* ptr,
1132+
interval_type const& ival,
1133+
FunctionT const& on_find,
1134+
ComparatorFunctionT const& compare
1135+
)
11191136
{
11201137
if (compare(ptr->interval(), ival))
11211138
{
1122-
if (!on_find(IteratorT{ptr, this}))
1139+
if (!on_find(IteratorT{ptr, self}))
11231140
return false;
11241141
}
11251142
if (ptr->left_ && ival.high() <= ptr->left_->max())
11261143
{
11271144
// no right? can only continue left
11281145
if (!ptr->right_ || ival.low() > ptr->right_->max())
1129-
return find_all_i<IteratorT>(ptr->left_, ival, on_find, compare);
1146+
return find_all_i<ThisType, IteratorT>(self, ptr->left_, ival, on_find, compare);
11301147

1131-
if (!find_all_i<IteratorT>(ptr->left_, ival, on_find, compare))
1148+
if (!find_all_i<ThisType, IteratorT>(self, ptr->left_, ival, on_find, compare))
11321149
return false;
11331150
}
11341151
if (ptr->right_ && ival.high() <= ptr->right_->max())
11351152
{
11361153
if (!ptr->left_ || ival.low() > ptr->left_->max())
1137-
return find_all_i<IteratorT>(ptr->right_, ival, on_find, compare);
1154+
return find_all_i<ThisType, IteratorT>(self, ptr->right_, ival, on_find, compare);
11381155

1139-
if (!find_all_i<IteratorT>(ptr->right_, ival, on_find, compare))
1156+
if (!find_all_i<ThisType, IteratorT>(self, ptr->right_, ival, on_find, compare))
11401157
return false;
11411158
}
11421159
return true;
11431160
}
11441161

11451162
template <typename ComparatorFunctionT>
1146-
node_type* find_i(node_type* ptr, interval_type const& ival, ComparatorFunctionT const& compare)
1163+
node_type* find_i(node_type* ptr, interval_type const& ival, ComparatorFunctionT const& compare) const
11471164
{
11481165
if (compare(ptr->interval(), ival))
11491166
return ptr;
@@ -1153,7 +1170,7 @@ namespace lib_interval_tree
11531170

11541171
// excludes ptr
11551172
template <typename ComparatorFunctionT>
1156-
node_type* find_i_ex(node_type* ptr, interval_type const& ival, ComparatorFunctionT const& compare)
1173+
node_type* find_i_ex(node_type* ptr, interval_type const& ival, ComparatorFunctionT const& compare) const
11571174
{
11581175
if (ptr->left_ && ival.high() <= ptr->left_->max())
11591176
{
@@ -1178,7 +1195,7 @@ namespace lib_interval_tree
11781195
}
11791196

11801197
template <bool Exclusive>
1181-
node_type* overlap_find_i(node_type* ptr, interval_type const& ival)
1198+
node_type* overlap_find_i(node_type* ptr, interval_type const& ival) const
11821199
{
11831200
#if __cplusplus >= 201703L
11841201
if constexpr (Exclusive)
@@ -1198,8 +1215,14 @@ namespace lib_interval_tree
11981215
return overlap_find_i_ex<Exclusive>(ptr, ival);
11991216
}
12001217

1201-
template <bool Exclusive, typename IteratorT, typename FunctionT>
1202-
bool overlap_find_all_i(node_type* ptr, interval_type const& ival, FunctionT const& on_find)
1218+
template <typename ThisType, bool Exclusive, typename IteratorT, typename FunctionT>
1219+
static bool overlap_find_all_i
1220+
(
1221+
typename std::conditional<std::is_same<IteratorT, iterator>::value, ThisType, ThisType const>::type* self,
1222+
node_type* ptr,
1223+
interval_type const& ival,
1224+
FunctionT const& on_find
1225+
)
12031226
{
12041227
#if __cplusplus >= 201703L
12051228
if constexpr (Exclusive)
@@ -1209,7 +1232,7 @@ namespace lib_interval_tree
12091232
{
12101233
if (ptr->interval().overlaps_exclusive(ival))
12111234
{
1212-
if (!on_find(IteratorT{ptr, this}))
1235+
if (!on_find(IteratorT{ptr, self}))
12131236
{
12141237
return false;
12151238
}
@@ -1219,7 +1242,7 @@ namespace lib_interval_tree
12191242
{
12201243
if (ptr->interval().overlaps(ival))
12211244
{
1222-
if (!on_find(IteratorT{ptr, this}))
1245+
if (!on_find(IteratorT{ptr, self}))
12231246
{
12241247
return false;
12251248
}
@@ -1230,25 +1253,25 @@ namespace lib_interval_tree
12301253
// no right? can only continue left
12311254
// or interval low is bigger than max of right branch.
12321255
if (!ptr->right_ || ival.low() > ptr->right_->max())
1233-
return overlap_find_all_i<Exclusive, IteratorT>(ptr->left_, ival, on_find);
1256+
return overlap_find_all_i<ThisType, Exclusive, IteratorT>(self, ptr->left_, ival, on_find);
12341257

1235-
if (!overlap_find_all_i<Exclusive, IteratorT>(ptr->left_, ival, on_find))
1258+
if (!overlap_find_all_i<ThisType, Exclusive, IteratorT>(self, ptr->left_, ival, on_find))
12361259
return false;
12371260
}
12381261
if (ptr->right_ && ptr->right_->max() >= ival.low())
12391262
{
12401263
if (!ptr->left_ || ival.low() > ptr->right_->max())
1241-
return overlap_find_all_i<Exclusive, IteratorT>(ptr->right_, ival, on_find);
1264+
return overlap_find_all_i<ThisType, Exclusive, IteratorT>(self, ptr->right_, ival, on_find);
12421265

1243-
if (!overlap_find_all_i<Exclusive, IteratorT>(ptr->right_, ival, on_find))
1266+
if (!overlap_find_all_i<ThisType, Exclusive, IteratorT>(self, ptr->right_, ival, on_find))
12441267
return false;
12451268
}
12461269
return true;
12471270
}
12481271

12491272
// excludes ptr
12501273
template <bool Exclusive>
1251-
node_type* overlap_find_i_ex(node_type* ptr, interval_type const& ival)
1274+
node_type* overlap_find_i_ex(node_type* ptr, interval_type const& ival) const
12521275
{
12531276
if (ptr->left_ && ptr->left_->max() >= ival.low())
12541277
{

tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ file(GLOB sources "*.cpp")
2424
# Add Executable
2525
add_executable(tree-tests ${sources})
2626

27-
target_link_libraries(tree-tests gtest)
27+
target_link_libraries(tree-tests gtest gmock)
2828

2929
# Options
3030
if(DRAW_EXAMPLES)

tests/find_tests.hpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ TEST_F(FindTests, WillFindRoot)
3232
EXPECT_EQ(tree.find({0, 1}), std::begin(tree));
3333
}
3434

35+
TEST_F(FindTests, WillFindRootOnConstTree)
36+
{
37+
tree.insert({0, 1});
38+
[](auto const& tree)
39+
{
40+
EXPECT_EQ(tree.find({0, 1}), std::begin(tree));
41+
}(tree);
42+
}
43+
3544
TEST_F(FindTests, WillFindInBiggerTree)
3645
{
3746
tree.insert({16, 21});
@@ -137,3 +146,23 @@ TEST_F(FindTests, CanFindAllElementsBackInStrictlyAscendingOverlappingIntervals)
137146
ASSERT_NE(tree.find(ival), std::end(tree));
138147
}
139148
}
149+
150+
TEST_F(FindTests, CanFindAllOnConstTree)
151+
{
152+
const auto targetInterval = lib_interval_tree::make_safe_interval(16, 21);
153+
tree.insert(targetInterval);
154+
tree.insert({8, 9});
155+
tree.insert({25, 30});
156+
std::vector <decltype(tree)::interval_type> intervals;
157+
auto findWithConstTree = [&intervals, &targetInterval](auto const& tree)
158+
{
159+
tree.find_all(targetInterval, [&intervals](auto const& iter) {
160+
intervals.emplace_back(*iter);
161+
return true;
162+
});
163+
};
164+
findWithConstTree(tree);
165+
166+
ASSERT_EQ(intervals.size(), 1);
167+
EXPECT_EQ(intervals[0], targetInterval);
168+
}

tests/interval_tests.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#pragma once
22

3-
#include <boost/preprocessor/comma.hpp>
4-
53
#include <limits>
64

75
class IntervalTests
@@ -30,13 +28,13 @@ class DistanceTests
3028
{
3129
public:
3230
using types = IntervalTypes <int>;
33-
};
31+
};
3432

3533
TEST_F(IntervalTests, FailBadBorders)
3634
{
3735
auto f = []()
3836
{
39-
[[maybe_unused]] auto ival = types::interval_type{1 BOOST_PP_COMMA() 0};
37+
[[maybe_unused]] auto ival = types::interval_type{1, 0};
4038
};
4139

4240
EXPECT_DEATH(f(), "low <= high");

tests/overlap_find_tests.hpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ TEST_F(OverlapFindTests, WillFindOverlapWithRoot)
2828
EXPECT_EQ(tree.overlap_find({2, 7}), std::begin(tree));
2929
}
3030

31+
TEST_F(OverlapFindTests, WillFindOverlapWithRootOnConstTree)
32+
{
33+
tree.insert({2, 4});
34+
[](auto const& tree) {
35+
EXPECT_EQ(tree.overlap_find({2, 7}), std::begin(tree));
36+
}(tree);
37+
}
38+
3139
TEST_F(OverlapFindTests, WillFindOverlapWithRootIfMatchingExactly)
3240
{
3341
tree.insert({2, 7});
@@ -149,4 +157,24 @@ TEST_F(OverlapFindTests, WillFindSingleOverlapInBiggerTree)
149157
EXPECT_NE(iter, std::end(tree));
150158
EXPECT_EQ(iter->low(), 1000);
151159
EXPECT_EQ(iter->high(), 2000);
152-
}
160+
}
161+
162+
TEST_F(FindTests, CanOverlapFindAllOnConstTree)
163+
{
164+
const auto targetInterval = lib_interval_tree::make_safe_interval(16, 21);
165+
tree.insert(targetInterval);
166+
tree.insert({8, 9});
167+
tree.insert({25, 30});
168+
std::vector <decltype(tree)::interval_type> intervals;
169+
auto findWithConstTree = [&intervals, &targetInterval](auto const& tree)
170+
{
171+
tree.overlap_find_all(targetInterval, [&intervals](auto const& iter) {
172+
intervals.emplace_back(*iter);
173+
return true;
174+
});
175+
};
176+
findWithConstTree(tree);
177+
178+
ASSERT_EQ(intervals.size(), 1);
179+
EXPECT_EQ(intervals[0], targetInterval);
180+
}

0 commit comments

Comments
 (0)