Skip to content

Commit

Permalink
Merge pull request #23 from 5cript/feat/reverse-iteration
Browse files Browse the repository at this point in the history
Added reverse iterator.
  • Loading branch information
5cript authored Jul 23, 2024
2 parents 856a208 + 27592c9 commit 0c2ae27
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 66 deletions.
210 changes: 146 additions & 64 deletions include/interval-tree/interval_tree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,10 @@ namespace lib_interval_tree

public:
friend lib_interval_tree::interval_tree <interval_type>;
friend lib_interval_tree::const_interval_tree_iterator <node <numerical_type, interval_type> >;
friend lib_interval_tree::interval_tree_iterator <node <numerical_type, interval_type> >;
friend lib_interval_tree::const_interval_tree_iterator <node <numerical_type, interval_type>, true>;
friend lib_interval_tree::const_interval_tree_iterator <node <numerical_type, interval_type>, false>;
friend lib_interval_tree::interval_tree_iterator <node <numerical_type, interval_type>, true>;
friend lib_interval_tree::interval_tree_iterator <node <numerical_type, interval_type>, false>;

public:
node(node* parent, interval_type interval)
Expand Down Expand Up @@ -404,7 +406,12 @@ namespace lib_interval_tree
owner_type owner_;
};
//############################################################################################################
template <typename node_type>
template <typename T>
inline void increment(T& iter);
template <typename T>
inline void increment_reverse(T& iter);
//############################################################################################################
template <typename node_type, bool reverse>
class const_interval_tree_iterator
: public basic_interval_tree_iterator <node_type,
interval_tree <typename node_type::interval_type> const*>
Expand All @@ -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<node_type, reverse>>(const_interval_tree_iterator<node_type, reverse>& iter);
friend void increment_reverse<const_interval_tree_iterator<node_type, reverse>>(const_interval_tree_iterator<node_type, reverse>& 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;
}

Expand Down Expand Up @@ -525,7 +514,7 @@ namespace lib_interval_tree
}
};
//############################################################################################################
template <typename node_type>
template <typename node_type, bool reverse = false>
class interval_tree_iterator
: public basic_interval_tree_iterator <node_type,
interval_tree <typename node_type::interval_type>*>
Expand All @@ -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<node_type, reverse>>(interval_tree_iterator<node_type, reverse>& iter);
friend void increment_reverse<interval_tree_iterator<node_type, reverse>>(interval_tree_iterator<node_type, reverse>& 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;
}

Expand Down Expand Up @@ -645,6 +616,71 @@ namespace lib_interval_tree
{
}
};
//############################################################################################################
template <typename T>
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 <typename T>
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 <typename IntervalT = interval <int, closed>>
class interval_tree
Expand All @@ -653,14 +689,18 @@ namespace lib_interval_tree
using interval_type = IntervalT;
using value_type = typename interval_type::value_type;
using node_type = node <value_type, interval_type>;
using iterator = interval_tree_iterator <node_type>;
using const_iterator = const_interval_tree_iterator <node_type>;
using iterator = interval_tree_iterator <node_type, false>;
using const_iterator = const_interval_tree_iterator <node_type, false>;
using reverse_iterator = interval_tree_iterator <node_type, true>;
using const_reverse_iterator = const_interval_tree_iterator <node_type, true>;
using size_type = long long;
using this_type = interval_tree<interval_type>;

public:
friend const_interval_tree_iterator <node_type>;
friend interval_tree_iterator <node_type>;
friend const_interval_tree_iterator <node_type, true>;
friend const_interval_tree_iterator <node_type, false>;
friend interval_tree_iterator <node_type, true>;
friend interval_tree_iterator <node_type, false>;

public:
interval_tree()
Expand Down Expand Up @@ -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_)
Expand All @@ -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
*/
Expand Down
4 changes: 2 additions & 2 deletions include/interval-tree/interval_tree_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ namespace lib_interval_tree
template <typename node_type, typename owner_type>
class basic_interval_tree_iterator;

template <typename node_type>
template <typename node_type, bool reverse>
class const_interval_tree_iterator;

template <typename node_type>
template <typename node_type, bool reverse>
class interval_tree_iterator;
}
93 changes: 93 additions & 0 deletions tests/iteration_tests.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#pragma once

#include <ctime>
#include <random>
#include <cmath>

class IterationTests
: public ::testing::Test
{
public:
using types = IntervalTypes <int>;
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 <int>::tree_type tree;
std::default_random_engine gen;
std::uniform_int_distribution <int> 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;
}
}
1 change: 1 addition & 0 deletions tests/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit 0c2ae27

Please sign in to comment.