Skip to content

Commit a423348

Browse files
committed
Reworked how closed/closed_adjacent/open intervals punch out.
1 parent 2546b67 commit a423348

File tree

5 files changed

+434
-88
lines changed

5 files changed

+434
-88
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ Options are:
182182
- [After deoverlap](#after-deoverlap)
183183
- [interval\_tree deoverlap\_copy()](#interval_tree-deoverlap_copy)
184184
- [interval\_tree punch(interval\_type const\& ival)](#interval_tree-punchinterval_type-const-ival)
185-
- [Before punching (closed intervals)](#before-punching-closed-intervals)
185+
- [Before punching (closed\_adjacent intervals)](#before-punching-closed_adjacent-intervals)
186186
- [After punching (with \[-10, 60\])](#after-punching-with--10-60)
187187
- [interval\_tree punch()](#interval_tree-punch)
188188
- [bool empty() const noexcept](#bool-empty-const-noexcept)
@@ -371,14 +371,15 @@ Same as deoverlap, but not inplace
371371
### interval_tree punch(interval_type const& ival)
372372
Cuts the intervals of the tree out of the given interval. Like a cookie cutter cuts out of dough.
373373
This will return a new interval_tree containing the gaps between the intervals in the tree and the given interval.
374-
Closed (and closed adjacent) intervals are treated as exclusive on the borders. [0,5][6,10] will not produce another interval between 5 and 6 as they are considered within the intervals and nothing fits inbetween.
375-
Open intervals will not behave like this, so (0,5)(6,10) will produce a new interval (5,6).
374+
Closed adjacent intervals are treated as exclusive on the borders. [0,5]a[6,10]a will not produce another interval between 5 and 6 as they are considered within the intervals and nothing fits inbetween.
375+
Regular closed intervals will not behave like this, so [0,5][6,10] will produce a new interval [5,6].
376+
Open intervals with integral numbers will also not produce the gap (5, 6), because (5, 6) is empty for integers, not for floats.
376377

377378
**IMPORTANT! The tree must be deoverlapped, or the result is undefined.**
378379
`ival` can be any subrange of the tree, including encompassing the whole tree.
379380

380381
**Returns**: A new interval_tree containing the gaps.
381-
### Before punching (closed intervals)
382+
### Before punching (closed_adjacent intervals)
382383
![BeforePunch](https://private-user-images.githubusercontent.com/6238896/471147224-5c631e00-dea4-4b75-a3bf-6fdd8ec1440b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTM1NjI1MzQsIm5iZiI6MTc1MzU2MjIzNCwicGF0aCI6Ii82MjM4ODk2LzQ3MTE0NzIyNC01YzYzMWUwMC1kZWE0LTRiNzUtYTNiZi02ZmRkOGVjMTQ0MGIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDcyNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTA3MjZUMjAzNzE0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZDQ0NWIwMTcwMjZhNDA1YmUwNGI1YTIzNTBhZTQ5OTNhMWFiOTU5ZmU0N2E3NDI0NTQ0MzYwODA4N2E2MGFiZiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.P5zLeXg0-9bd20Thj6pfq_WxriMn4GC_lDSLzzGKMbw)
383384
### After punching (with [-10, 60])
384385
![AfterPunch](https://private-user-images.githubusercontent.com/6238896/471147227-5c226d1d-d544-4a43-89a4-b3545145107d.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTM1NjI1MzQsIm5iZiI6MTc1MzU2MjIzNCwicGF0aCI6Ii82MjM4ODk2LzQ3MTE0NzIyNy01YzIyNmQxZC1kNTQ0LTRhNDMtODlhNC1iMzU0NTE0NTEwN2QucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDcyNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTA3MjZUMjAzNzE0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NmE2ZDUzMjU2ZTNjZWQ0Y2QzYjQ3ZGUyYjgyNWM2NDViYTAxMTdlY2RjYmQyMzg4OWFmZDlhMWU5YjY4NjlmZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.Infe9i281LDOEC5GeBFuLHVE6Xjqw7KvcUo-gv3hjpk)

include/interval-tree/interval_tree.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,6 @@ namespace lib_interval_tree
256256
// low_ == other.low_ does not produce a left slice in any case.
257257
if (high_ > other.high_)
258258
{
259-
// FIXME: think: is the max violating edge conditions?
260259
auto slice = interval{std::max(interval_kind::right_slice_lower_bound(other.high_), low_), high_};
261260
// >= comparison avoids overflows in case of unsigned integers
262261
if (slice.high_ >= slice.low_ && slice.size() > 0)

include/interval-tree/interval_types.hpp

Lines changed: 37 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -115,63 +115,13 @@ namespace lib_interval_tree
115115
}
116116

117117
template <typename numerical_type>
118-
#ifdef LIB_INTERVAL_TREE_CONCEPTS
119-
requires(std::is_signed_v<numerical_type> && !std::is_floating_point_v<numerical_type>)
120-
static inline numerical_type
121-
#else
122-
static inline typename std::enable_if<
123-
std::is_signed<numerical_type>::value && !std::is_floating_point<numerical_type>::value,
124-
numerical_type>::type
125-
#endif
126-
left_slice_upper_bound(numerical_type value)
127-
{
128-
return value - 1;
129-
}
130-
131-
template <typename numerical_type>
132-
#ifdef LIB_INTERVAL_TREE_CONCEPTS
133-
requires(std::is_floating_point_v<numerical_type>)
134-
static inline numerical_type
135-
#else
136-
static inline typename std::enable_if<std::is_floating_point<numerical_type>::value, numerical_type>::type
137-
#endif
138-
left_slice_upper_bound(numerical_type value)
139-
{
140-
return value;
141-
}
142-
143-
template <typename numerical_type>
144-
#ifdef LIB_INTERVAL_TREE_CONCEPTS
145-
requires std::is_unsigned_v<numerical_type>
146-
static inline numerical_type
147-
#else
148-
static inline typename std::enable_if<std::is_unsigned<numerical_type>::value, numerical_type>::type
149-
#endif
150-
left_slice_upper_bound(numerical_type value)
151-
{
152-
return value > 0 ? value - 1 : 0;
153-
}
154-
155-
template <typename numerical_type>
156-
#ifdef LIB_INTERVAL_TREE_CONCEPTS
157-
requires(!std::is_floating_point_v<numerical_type>)
158-
static inline numerical_type
159-
#else
160-
static inline typename std::enable_if<!std::is_floating_point<numerical_type>::value, numerical_type>::type
161-
#endif
162-
right_slice_lower_bound(numerical_type value)
118+
static inline numerical_type left_slice_upper_bound(numerical_type high)
163119
{
164-
return value + 1;
120+
return high;
165121
}
166122

167123
template <typename numerical_type>
168-
#ifdef LIB_INTERVAL_TREE_CONCEPTS
169-
requires std::is_floating_point_v<numerical_type>
170-
static inline numerical_type
171-
#else
172-
static inline typename std::enable_if<std::is_floating_point<numerical_type>::value, numerical_type>::type
173-
#endif
174-
right_slice_lower_bound(numerical_type value)
124+
static inline numerical_type right_slice_lower_bound(numerical_type value)
175125
{
176126
return value;
177127
}
@@ -299,16 +249,30 @@ namespace lib_interval_tree
299249

300250
template <typename numerical_type>
301251
#ifdef LIB_INTERVAL_TREE_CONCEPTS
302-
requires std::is_signed_v<numerical_type>
252+
requires(std::is_signed_v<numerical_type> && !std::is_floating_point_v<numerical_type>)
303253
static inline numerical_type
304254
#else
305-
static inline typename std::enable_if<std::is_signed<numerical_type>::value, numerical_type>::type
255+
static inline typename std::enable_if<
256+
std::is_signed<numerical_type>::value && !std::is_floating_point<numerical_type>::value,
257+
numerical_type>::type
306258
#endif
307259
left_slice_upper_bound(numerical_type value)
308260
{
309261
return value - 1;
310262
}
311263

264+
template <typename numerical_type>
265+
#ifdef LIB_INTERVAL_TREE_CONCEPTS
266+
requires(std::is_floating_point_v<numerical_type>)
267+
static inline numerical_type
268+
#else
269+
static inline typename std::enable_if<std::is_floating_point<numerical_type>::value, numerical_type>::type
270+
#endif
271+
left_slice_upper_bound(numerical_type value)
272+
{
273+
return value;
274+
}
275+
312276
template <typename numerical_type>
313277
#ifdef LIB_INTERVAL_TREE_CONCEPTS
314278
requires std::is_unsigned_v<numerical_type>
@@ -322,10 +286,27 @@ namespace lib_interval_tree
322286
}
323287

324288
template <typename numerical_type>
325-
static inline numerical_type right_slice_lower_bound(numerical_type value)
289+
#ifdef LIB_INTERVAL_TREE_CONCEPTS
290+
requires(!std::is_floating_point_v<numerical_type>)
291+
static inline numerical_type
292+
#else
293+
static inline typename std::enable_if<!std::is_floating_point<numerical_type>::value, numerical_type>::type
294+
#endif
295+
right_slice_lower_bound(numerical_type value)
326296
{
327297
return value + 1;
328298
}
299+
template <typename numerical_type>
300+
#ifdef LIB_INTERVAL_TREE_CONCEPTS
301+
requires std::is_floating_point_v<numerical_type>
302+
static inline numerical_type
303+
#else
304+
static inline typename std::enable_if<std::is_floating_point<numerical_type>::value, numerical_type>::type
305+
#endif
306+
right_slice_lower_bound(numerical_type value)
307+
{
308+
return value;
309+
}
329310
};
330311

331312
enum class interval_border

tests/interval_tests.hpp

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -901,14 +901,25 @@ TEST_F(IntervalTests, CanFindDynamicIntervalUsingComparisonFunction)
901901
EXPECT_EQ(iter->right_border(), interval_border::closed);
902902
}
903903

904+
TEST_F(IntervalTests, ClosedAdjacentSliceLeftOverlap)
905+
{
906+
// [ this ]
907+
// [ls][param]
908+
const auto result = i<closed_adjacent>(1, 8).slice(i<closed_adjacent>(5, 100));
909+
ASSERT_TRUE(result.left_slice);
910+
EXPECT_EQ(result.left_slice->low(), 1);
911+
EXPECT_EQ(result.left_slice->high(), 4);
912+
EXPECT_FALSE(result.right_slice);
913+
}
914+
904915
TEST_F(IntervalTests, ClosedSliceLeftOverlap)
905916
{
906917
// [ this ]
907918
// [ls][param]
908919
const auto result = i<closed>(1, 8).slice(i<closed>(5, 100));
909920
ASSERT_TRUE(result.left_slice);
910921
EXPECT_EQ(result.left_slice->low(), 1);
911-
EXPECT_EQ(result.left_slice->high(), 4);
922+
EXPECT_EQ(result.left_slice->high(), 5);
912923
EXPECT_FALSE(result.right_slice);
913924
}
914925

@@ -924,13 +935,25 @@ TEST_F(IntervalTests, OpenSliceLeftOverlap)
924935
EXPECT_FALSE(result.right_slice);
925936
}
926937

938+
TEST_F(IntervalTests, ClosedAdjacentRightRemains)
939+
{
940+
// [ this ]
941+
// [param][rs]
942+
const auto result = i<closed_adjacent>(8, 15).slice(i<closed_adjacent>(8, 12));
943+
ASSERT_TRUE(result.right_slice);
944+
EXPECT_EQ(result.right_slice->low(), 13);
945+
EXPECT_EQ(result.right_slice->high(), 15);
946+
EXPECT_FALSE(result.left_slice);
947+
}
948+
927949
TEST_F(IntervalTests, ClosedRightRemains)
928950
{
929951
// [ this ]
930952
// [param][rs]
953+
using lib_interval_tree::closed;
931954
const auto result = i<closed>(8, 15).slice(i<closed>(8, 12));
932955
ASSERT_TRUE(result.right_slice);
933-
EXPECT_EQ(result.right_slice->low(), 13);
956+
EXPECT_EQ(result.right_slice->low(), 12);
934957
EXPECT_EQ(result.right_slice->high(), 15);
935958
EXPECT_FALSE(result.left_slice);
936959
}
@@ -947,11 +970,11 @@ TEST_F(IntervalTests, OpenRightRemains)
947970
EXPECT_FALSE(result.left_slice);
948971
}
949972

950-
TEST_F(IntervalTests, ClosedMiddleExtrusion)
973+
TEST_F(IntervalTests, ClosedAdjacentMiddleExtrusion)
951974
{
952975
// [ this ]
953976
// [ls][param][rs]
954-
const auto result = i<closed>(0, 10).slice(i<closed>(5, 8));
977+
const auto result = i<closed_adjacent>(0, 10).slice(i<closed_adjacent>(5, 8));
955978
ASSERT_TRUE(result.left_slice);
956979
EXPECT_EQ(result.left_slice->low(), 0);
957980
EXPECT_EQ(result.left_slice->high(), 4);
@@ -972,4 +995,18 @@ TEST_F(IntervalTests, OpenMiddleExtrusion)
972995
ASSERT_TRUE(result.right_slice);
973996
EXPECT_EQ(result.right_slice->low(), 8);
974997
EXPECT_EQ(result.right_slice->high(), 10);
998+
}
999+
1000+
TEST_F(IntervalTests, ClosedMiddleExtrusion)
1001+
{
1002+
// [ this ]
1003+
// [ls][param][rs]
1004+
using lib_interval_tree::closed;
1005+
const auto result = i<closed>(0, 10).slice(i<closed>(5, 8));
1006+
ASSERT_TRUE(result.left_slice);
1007+
EXPECT_EQ(result.left_slice->low(), 0);
1008+
EXPECT_EQ(result.left_slice->high(), 5);
1009+
ASSERT_TRUE(result.right_slice);
1010+
EXPECT_EQ(result.right_slice->low(), 8);
1011+
EXPECT_EQ(result.right_slice->high(), 10);
9751012
}

0 commit comments

Comments
 (0)