Skip to content

Commit 0c2ae27

Browse files
authored
Merge pull request #23 from 5cript/feat/reverse-iteration
Added reverse iterator.
2 parents 856a208 + 27592c9 commit 0c2ae27

File tree

4 files changed

+242
-66
lines changed

4 files changed

+242
-66
lines changed

include/interval-tree/interval_tree.hpp

Lines changed: 146 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,10 @@ namespace lib_interval_tree
200200

201201
public:
202202
friend lib_interval_tree::interval_tree <interval_type>;
203-
friend lib_interval_tree::const_interval_tree_iterator <node <numerical_type, interval_type> >;
204-
friend lib_interval_tree::interval_tree_iterator <node <numerical_type, interval_type> >;
203+
friend lib_interval_tree::const_interval_tree_iterator <node <numerical_type, interval_type>, true>;
204+
friend lib_interval_tree::const_interval_tree_iterator <node <numerical_type, interval_type>, false>;
205+
friend lib_interval_tree::interval_tree_iterator <node <numerical_type, interval_type>, true>;
206+
friend lib_interval_tree::interval_tree_iterator <node <numerical_type, interval_type>, false>;
205207

206208
public:
207209
node(node* parent, interval_type interval)
@@ -404,7 +406,12 @@ namespace lib_interval_tree
404406
owner_type owner_;
405407
};
406408
//############################################################################################################
407-
template <typename node_type>
409+
template <typename T>
410+
inline void increment(T& iter);
411+
template <typename T>
412+
inline void increment_reverse(T& iter);
413+
//############################################################################################################
414+
template <typename node_type, bool reverse>
408415
class const_interval_tree_iterator
409416
: public basic_interval_tree_iterator <node_type,
410417
interval_tree <typename node_type::interval_type> const*>
@@ -425,37 +432,19 @@ namespace lib_interval_tree
425432
const_interval_tree_iterator& operator=(const_interval_tree_iterator const&) = default;
426433
const_interval_tree_iterator& operator=(const_interval_tree_iterator&&) noexcept = default;
427434

435+
friend void increment<const_interval_tree_iterator<node_type, reverse>>(const_interval_tree_iterator<node_type, reverse>& iter);
436+
friend void increment_reverse<const_interval_tree_iterator<node_type, reverse>>(const_interval_tree_iterator<node_type, reverse>& iter);
437+
428438
const_interval_tree_iterator& operator++()
429439
{
430-
if (!node_)
431-
{
432-
node_ = owner_->root_;
433-
434-
if (!node_)
435-
return *this;
436-
437-
while(node_->left_)
438-
node_ = node_->left_;
439-
}
440-
441-
if (node_->right_)
442-
{
443-
node_ = node_->right_;
444-
445-
while (node_->left_)
446-
node_ = node_->left_;
447-
}
440+
#if __cplusplus >= 201703L
441+
if constexpr (reverse)
442+
#else
443+
if (reverse)
444+
#endif
445+
increment_reverse(*this);
448446
else
449-
{
450-
auto* parent = node_->parent_;
451-
while (parent != nullptr && node_ == parent->right_)
452-
{
453-
node_ = parent;
454-
parent = parent->parent_;
455-
}
456-
node_ = parent;
457-
}
458-
447+
increment(*this);
459448
return *this;
460449
}
461450

@@ -525,7 +514,7 @@ namespace lib_interval_tree
525514
}
526515
};
527516
//############################################################################################################
528-
template <typename node_type>
517+
template <typename node_type, bool reverse = false>
529518
class interval_tree_iterator
530519
: public basic_interval_tree_iterator <node_type,
531520
interval_tree <typename node_type::interval_type>*>
@@ -546,37 +535,19 @@ namespace lib_interval_tree
546535
interval_tree_iterator& operator=(interval_tree_iterator const&) = default;
547536
interval_tree_iterator& operator=(interval_tree_iterator&&) noexcept = default;
548537

538+
friend void increment<interval_tree_iterator<node_type, reverse>>(interval_tree_iterator<node_type, reverse>& iter);
539+
friend void increment_reverse<interval_tree_iterator<node_type, reverse>>(interval_tree_iterator<node_type, reverse>& iter);
540+
549541
interval_tree_iterator& operator++()
550542
{
551-
if (!node_)
552-
{
553-
node_ = owner_->root_;
554-
555-
if (!node_)
556-
return *this;
557-
558-
while(node_->left_)
559-
node_ = node_->left_;
560-
}
561-
562-
if (node_->right_)
563-
{
564-
node_ = node_->right_;
565-
566-
while (node_->left_)
567-
node_ = node_->left_;
568-
}
543+
#if __cplusplus >= 201703L
544+
if constexpr (reverse)
545+
#else
546+
if (reverse)
547+
#endif
548+
increment_reverse(*this);
569549
else
570-
{
571-
auto* parent = node_->parent_;
572-
while (parent != nullptr && node_ == parent->right_)
573-
{
574-
node_ = parent;
575-
parent = parent->parent_;
576-
}
577-
node_ = parent;
578-
}
579-
550+
increment(*this);
580551
return *this;
581552
}
582553

@@ -645,6 +616,71 @@ namespace lib_interval_tree
645616
{
646617
}
647618
};
619+
//############################################################################################################
620+
template <typename T>
621+
inline void increment(T& iter)
622+
{
623+
if (!iter.node_)
624+
{
625+
iter.node_ = iter.owner_->root_;
626+
627+
if (!iter.node_)
628+
return;
629+
630+
while(iter.node_->left_)
631+
iter.node_ = iter.node_->left_;
632+
}
633+
634+
if (iter.node_->right_)
635+
{
636+
iter.node_ = iter.node_->right_;
637+
638+
while (iter.node_->left_)
639+
iter.node_ = iter.node_->left_;
640+
}
641+
else
642+
{
643+
auto* parent = iter.node_->parent_;
644+
while (parent != nullptr && iter.node_ == parent->right_)
645+
{
646+
iter.node_ = parent;
647+
parent = parent->parent_;
648+
}
649+
iter.node_ = parent;
650+
}
651+
}
652+
template <typename T>
653+
inline void increment_reverse(T& iter)
654+
{
655+
if (!iter.node_)
656+
{
657+
iter.node_ = iter.owner_->root_;
658+
659+
if (!iter.node_)
660+
return;
661+
662+
while(iter.node_->right_)
663+
iter.node_ = iter.node_->right_;
664+
}
665+
666+
if (iter.node_->left_)
667+
{
668+
iter.node_ = iter.node_->left_;
669+
670+
while (iter.node_->right_)
671+
iter.node_ = iter.node_->right_;
672+
}
673+
else
674+
{
675+
auto* parent = iter.node_->parent_;
676+
while (parent != nullptr && iter.node_ == parent->left_)
677+
{
678+
iter.node_ = parent;
679+
parent = parent->parent_;
680+
}
681+
iter.node_ = parent;
682+
}
683+
}
648684
//############################################################################################################
649685
template <typename IntervalT = interval <int, closed>>
650686
class interval_tree
@@ -653,14 +689,18 @@ namespace lib_interval_tree
653689
using interval_type = IntervalT;
654690
using value_type = typename interval_type::value_type;
655691
using node_type = node <value_type, interval_type>;
656-
using iterator = interval_tree_iterator <node_type>;
657-
using const_iterator = const_interval_tree_iterator <node_type>;
692+
using iterator = interval_tree_iterator <node_type, false>;
693+
using const_iterator = const_interval_tree_iterator <node_type, false>;
694+
using reverse_iterator = interval_tree_iterator <node_type, true>;
695+
using const_reverse_iterator = const_interval_tree_iterator <node_type, true>;
658696
using size_type = long long;
659697
using this_type = interval_tree<interval_type>;
660698

661699
public:
662-
friend const_interval_tree_iterator <node_type>;
663-
friend interval_tree_iterator <node_type>;
700+
friend const_interval_tree_iterator <node_type, true>;
701+
friend const_interval_tree_iterator <node_type, false>;
702+
friend interval_tree_iterator <node_type, true>;
703+
friend interval_tree_iterator <node_type, false>;
664704

665705
public:
666706
interval_tree()
@@ -1124,6 +1164,23 @@ namespace lib_interval_tree
11241164
return {nullptr, this};
11251165
}
11261166

1167+
reverse_iterator rbegin()
1168+
{
1169+
if (!root_)
1170+
return {nullptr, this};
1171+
1172+
auto* iter = root_;
1173+
1174+
while (iter->right_)
1175+
iter = iter->right_;
1176+
1177+
return{iter, this};
1178+
}
1179+
reverse_iterator rend()
1180+
{
1181+
return {nullptr, this};
1182+
}
1183+
11271184
const_iterator cbegin() const
11281185
{
11291186
if (!root_)
@@ -1149,6 +1206,31 @@ namespace lib_interval_tree
11491206
return cend();
11501207
}
11511208

1209+
const_reverse_iterator crbegin() const
1210+
{
1211+
if (!root_)
1212+
return {nullptr, this};
1213+
1214+
auto* iter = root_;
1215+
1216+
while (iter->right_)
1217+
iter = iter->right_;
1218+
1219+
return const_reverse_iterator{iter, this};
1220+
}
1221+
const_reverse_iterator crend() const
1222+
{
1223+
return const_reverse_iterator{nullptr, this};
1224+
}
1225+
const_reverse_iterator rbegin() const
1226+
{
1227+
return crbegin();
1228+
}
1229+
const_reverse_iterator rend() const
1230+
{
1231+
return crend();
1232+
}
1233+
11521234
/**
11531235
* Returns wether or not the tree is empty
11541236
*/

include/interval-tree/interval_tree_fwd.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ namespace lib_interval_tree
1414
template <typename node_type, typename owner_type>
1515
class basic_interval_tree_iterator;
1616

17-
template <typename node_type>
17+
template <typename node_type, bool reverse>
1818
class const_interval_tree_iterator;
1919

20-
template <typename node_type>
20+
template <typename node_type, bool reverse>
2121
class interval_tree_iterator;
2222
}

tests/iteration_tests.hpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#pragma once
2+
3+
#include <ctime>
4+
#include <random>
5+
#include <cmath>
6+
7+
class IterationTests
8+
: public ::testing::Test
9+
{
10+
public:
11+
using types = IntervalTypes <int>;
12+
void makeTree1()
13+
{
14+
tree.insert({1, 5});
15+
tree.insert({8, 9});
16+
tree.insert({3, 7});
17+
tree.insert({10, 15});
18+
tree.insert({-5, 8});
19+
tree.insert({20, 25});
20+
tree.insert({-10, -5});
21+
}
22+
23+
void makeTree2()
24+
{
25+
for (int i = 0; i < 100; ++i)
26+
tree.insert({i * 2, i * 2 + 1});
27+
}
28+
29+
protected:
30+
IntervalTypes <int>::tree_type tree;
31+
std::default_random_engine gen;
32+
std::uniform_int_distribution <int> distLarge{-50000, 50000};
33+
};
34+
35+
TEST_F(IterationTests, TreeIterationIsInOrder)
36+
{
37+
makeTree1();
38+
auto iter = std::begin(tree);
39+
EXPECT_EQ(iter->low(), -10);
40+
++iter;
41+
EXPECT_EQ(iter->low(), -5);
42+
++iter;
43+
EXPECT_EQ(iter->low(), 1);
44+
++iter;
45+
EXPECT_EQ(iter->low(), 3);
46+
++iter;
47+
EXPECT_EQ(iter->low(), 8);
48+
++iter;
49+
EXPECT_EQ(iter->low(), 10);
50+
++iter;
51+
EXPECT_EQ(iter->low(), 20);
52+
}
53+
54+
TEST_F(IterationTests, TreeIterationIsInOrder2)
55+
{
56+
makeTree2();
57+
auto iter = std::begin(tree);
58+
for (int i = 0; i < 100; ++i)
59+
{
60+
EXPECT_EQ(iter->low(), i * 2);
61+
++iter;
62+
}
63+
}
64+
65+
TEST_F(IterationTests, ReverseIterationIsReverseInOrder)
66+
{
67+
makeTree1();
68+
auto iter = std::rbegin(tree);
69+
EXPECT_EQ(iter->low(), 20);
70+
++iter;
71+
EXPECT_EQ(iter->low(), 10);
72+
++iter;
73+
EXPECT_EQ(iter->low(), 8);
74+
++iter;
75+
EXPECT_EQ(iter->low(), 3);
76+
++iter;
77+
EXPECT_EQ(iter->low(), 1);
78+
++iter;
79+
EXPECT_EQ(iter->low(), -5);
80+
++iter;
81+
EXPECT_EQ(iter->low(), -10);
82+
}
83+
84+
TEST_F(IterationTests, ReverseIterationIsReverseInOrder2)
85+
{
86+
makeTree2();
87+
auto iter = std::rbegin(tree);
88+
for (int i = 99; i >= 0; --i)
89+
{
90+
EXPECT_EQ(iter->low(), i * 2);
91+
++iter;
92+
}
93+
}

tests/tests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "find_tests.hpp"
1212
#include "overlap_find_tests.hpp"
1313
#include "float_overlap_tests.hpp"
14+
#include "iteration_tests.hpp"
1415

1516
int main(int argc, char** argv)
1617
{

0 commit comments

Comments
 (0)