diff --git a/include/interval-tree/interval_tree.hpp b/include/interval-tree/interval_tree.hpp index 4f4432e..61543df 100644 --- a/include/interval-tree/interval_tree.hpp +++ b/include/interval-tree/interval_tree.hpp @@ -200,8 +200,10 @@ namespace lib_interval_tree public: friend lib_interval_tree::interval_tree ; - friend lib_interval_tree::const_interval_tree_iterator >; - friend lib_interval_tree::interval_tree_iterator >; + friend lib_interval_tree::const_interval_tree_iterator , true>; + friend lib_interval_tree::const_interval_tree_iterator , false>; + friend lib_interval_tree::interval_tree_iterator , true>; + friend lib_interval_tree::interval_tree_iterator , false>; public: node(node* parent, interval_type interval) @@ -404,7 +406,12 @@ namespace lib_interval_tree owner_type owner_; }; //############################################################################################################ - template + template + inline void increment(T& iter); + template + inline void increment_reverse(T& iter); +//############################################################################################################ + template class const_interval_tree_iterator : public basic_interval_tree_iterator const*> @@ -425,37 +432,19 @@ namespace lib_interval_tree const_interval_tree_iterator& operator=(const_interval_tree_iterator const&) = default; const_interval_tree_iterator& operator=(const_interval_tree_iterator&&) noexcept = default; + friend void increment>(const_interval_tree_iterator& iter); + friend void increment_reverse>(const_interval_tree_iterator& iter); + const_interval_tree_iterator& operator++() { - if (!node_) - { - node_ = owner_->root_; - - if (!node_) - return *this; - - while(node_->left_) - node_ = node_->left_; - } - - if (node_->right_) - { - node_ = node_->right_; - - while (node_->left_) - node_ = node_->left_; - } +#if __cplusplus >= 201703L + if constexpr (reverse) +#else + if (reverse) +#endif + increment_reverse(*this); else - { - auto* parent = node_->parent_; - while (parent != nullptr && node_ == parent->right_) - { - node_ = parent; - parent = parent->parent_; - } - node_ = parent; - } - + increment(*this); return *this; } @@ -525,7 +514,7 @@ namespace lib_interval_tree } }; //############################################################################################################ - template + template class interval_tree_iterator : public basic_interval_tree_iterator *> @@ -546,37 +535,19 @@ namespace lib_interval_tree interval_tree_iterator& operator=(interval_tree_iterator const&) = default; interval_tree_iterator& operator=(interval_tree_iterator&&) noexcept = default; + friend void increment>(interval_tree_iterator& iter); + friend void increment_reverse>(interval_tree_iterator& iter); + interval_tree_iterator& operator++() { - if (!node_) - { - node_ = owner_->root_; - - if (!node_) - return *this; - - while(node_->left_) - node_ = node_->left_; - } - - if (node_->right_) - { - node_ = node_->right_; - - while (node_->left_) - node_ = node_->left_; - } +#if __cplusplus >= 201703L + if constexpr (reverse) +#else + if (reverse) +#endif + increment_reverse(*this); else - { - auto* parent = node_->parent_; - while (parent != nullptr && node_ == parent->right_) - { - node_ = parent; - parent = parent->parent_; - } - node_ = parent; - } - + increment(*this); return *this; } @@ -645,6 +616,71 @@ namespace lib_interval_tree { } }; +//############################################################################################################ + template + inline void increment(T& iter) + { + if (!iter.node_) + { + iter.node_ = iter.owner_->root_; + + if (!iter.node_) + return; + + while(iter.node_->left_) + iter.node_ = iter.node_->left_; + } + + if (iter.node_->right_) + { + iter.node_ = iter.node_->right_; + + while (iter.node_->left_) + iter.node_ = iter.node_->left_; + } + else + { + auto* parent = iter.node_->parent_; + while (parent != nullptr && iter.node_ == parent->right_) + { + iter.node_ = parent; + parent = parent->parent_; + } + iter.node_ = parent; + } + } + template + inline void increment_reverse(T& iter) + { + if (!iter.node_) + { + iter.node_ = iter.owner_->root_; + + if (!iter.node_) + return; + + while(iter.node_->right_) + iter.node_ = iter.node_->right_; + } + + if (iter.node_->left_) + { + iter.node_ = iter.node_->left_; + + while (iter.node_->right_) + iter.node_ = iter.node_->right_; + } + else + { + auto* parent = iter.node_->parent_; + while (parent != nullptr && iter.node_ == parent->left_) + { + iter.node_ = parent; + parent = parent->parent_; + } + iter.node_ = parent; + } + } //############################################################################################################ template > class interval_tree @@ -653,14 +689,18 @@ namespace lib_interval_tree using interval_type = IntervalT; using value_type = typename interval_type::value_type; using node_type = node ; - using iterator = interval_tree_iterator ; - using const_iterator = const_interval_tree_iterator ; + using iterator = interval_tree_iterator ; + using const_iterator = const_interval_tree_iterator ; + using reverse_iterator = interval_tree_iterator ; + using const_reverse_iterator = const_interval_tree_iterator ; using size_type = long long; using this_type = interval_tree; public: - friend const_interval_tree_iterator ; - friend interval_tree_iterator ; + friend const_interval_tree_iterator ; + friend const_interval_tree_iterator ; + friend interval_tree_iterator ; + friend interval_tree_iterator ; public: interval_tree() @@ -1124,6 +1164,23 @@ namespace lib_interval_tree return {nullptr, this}; } + reverse_iterator rbegin() + { + if (!root_) + return {nullptr, this}; + + auto* iter = root_; + + while (iter->right_) + iter = iter->right_; + + return{iter, this}; + } + reverse_iterator rend() + { + return {nullptr, this}; + } + const_iterator cbegin() const { if (!root_) @@ -1149,6 +1206,31 @@ namespace lib_interval_tree return cend(); } + const_reverse_iterator crbegin() const + { + if (!root_) + return {nullptr, this}; + + auto* iter = root_; + + while (iter->right_) + iter = iter->right_; + + return const_reverse_iterator{iter, this}; + } + const_reverse_iterator crend() const + { + return const_reverse_iterator{nullptr, this}; + } + const_reverse_iterator rbegin() const + { + return crbegin(); + } + const_reverse_iterator rend() const + { + return crend(); + } + /** * Returns wether or not the tree is empty */ diff --git a/include/interval-tree/interval_tree_fwd.hpp b/include/interval-tree/interval_tree_fwd.hpp index b4c348d..5bc0cda 100644 --- a/include/interval-tree/interval_tree_fwd.hpp +++ b/include/interval-tree/interval_tree_fwd.hpp @@ -14,9 +14,9 @@ namespace lib_interval_tree template class basic_interval_tree_iterator; - template + template class const_interval_tree_iterator; - template + template class interval_tree_iterator; } diff --git a/tests/iteration_tests.hpp b/tests/iteration_tests.hpp new file mode 100644 index 0000000..b04f68c --- /dev/null +++ b/tests/iteration_tests.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include +#include +#include + +class IterationTests + : public ::testing::Test +{ +public: + using types = IntervalTypes ; + void makeTree1() + { + tree.insert({1, 5}); + tree.insert({8, 9}); + tree.insert({3, 7}); + tree.insert({10, 15}); + tree.insert({-5, 8}); + tree.insert({20, 25}); + tree.insert({-10, -5}); + } + + void makeTree2() + { + for (int i = 0; i < 100; ++i) + tree.insert({i * 2, i * 2 + 1}); + } + +protected: + IntervalTypes ::tree_type tree; + std::default_random_engine gen; + std::uniform_int_distribution distLarge{-50000, 50000}; +}; + +TEST_F(IterationTests, TreeIterationIsInOrder) +{ + makeTree1(); + auto iter = std::begin(tree); + EXPECT_EQ(iter->low(), -10); + ++iter; + EXPECT_EQ(iter->low(), -5); + ++iter; + EXPECT_EQ(iter->low(), 1); + ++iter; + EXPECT_EQ(iter->low(), 3); + ++iter; + EXPECT_EQ(iter->low(), 8); + ++iter; + EXPECT_EQ(iter->low(), 10); + ++iter; + EXPECT_EQ(iter->low(), 20); +} + +TEST_F(IterationTests, TreeIterationIsInOrder2) +{ + makeTree2(); + auto iter = std::begin(tree); + for (int i = 0; i < 100; ++i) + { + EXPECT_EQ(iter->low(), i * 2); + ++iter; + } +} + +TEST_F(IterationTests, ReverseIterationIsReverseInOrder) +{ + makeTree1(); + auto iter = std::rbegin(tree); + EXPECT_EQ(iter->low(), 20); + ++iter; + EXPECT_EQ(iter->low(), 10); + ++iter; + EXPECT_EQ(iter->low(), 8); + ++iter; + EXPECT_EQ(iter->low(), 3); + ++iter; + EXPECT_EQ(iter->low(), 1); + ++iter; + EXPECT_EQ(iter->low(), -5); + ++iter; + EXPECT_EQ(iter->low(), -10); +} + +TEST_F(IterationTests, ReverseIterationIsReverseInOrder2) +{ + makeTree2(); + auto iter = std::rbegin(tree); + for (int i = 99; i >= 0; --i) + { + EXPECT_EQ(iter->low(), i * 2); + ++iter; + } +} \ No newline at end of file diff --git a/tests/tests.cpp b/tests/tests.cpp index 20af9a8..76b1f20 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -11,6 +11,7 @@ #include "find_tests.hpp" #include "overlap_find_tests.hpp" #include "float_overlap_tests.hpp" +#include "iteration_tests.hpp" int main(int argc, char** argv) {