Commit cbc90032 authored by Quentin Khan's avatar Quentin Khan

Add FNode pre and post order iterators

parent a01d0d40
#ifndef _SCALFMM____ORDER_NODE_ITERATOR_HPP_
#define _SCALFMM____ORDER_NODE_ITERATOR_HPP_
#include "FNodeIterator.hpp"
namespace scalfmm {
namespace tests {
struct test_PostOrderNodeIterator;
struct test_PreOrderNodeIterator;
}
}
namespace scalfmm_adaptive_iterator_impl {
enum class NodeIteratorOrder {preorder, postorder};
template<class Node, NodeIteratorOrder it_type>
class __OrderNodeIterator : public FNodeIterator<__OrderNodeIterator<Node, it_type>, Node> {
friend scalfmm::tests::test_PostOrderNodeIterator;
friend scalfmm::tests::test_PreOrderNodeIterator;
using base_t = FNodeIterator<__OrderNodeIterator<Node, it_type>, Node>;
using Direction = typename base_t::Direction;
public:
friend base_t;
using base_t::base_t;
using base_t::operator++;
using base_t::operator--;
__OrderNodeIterator& operator++() {
if(it_type == NodeIteratorOrder::preorder) {
return move_iterator_prefix<Direction::forwards>();
} else {
return move_iterator_postfix<Direction::forwards>();
}
}
__OrderNodeIterator& operator--() {
if(it_type == NodeIteratorOrder::preorder) {
return move_iterator_postfix<Direction::backwards>();
} else {
return move_iterator_prefix<Direction::backwards>();
}
}
protected:
/** Moves the cursor to the first node
*
* Resets the iterator to a valid state.
*/
template<Direction dir>
__OrderNodeIterator& move_to_boundary() {
base_t::template goto_root<dir>();
if( (it_type == NodeIteratorOrder::preorder
&& dir == Direction::backwards)
|| (it_type == NodeIteratorOrder::postorder
&& dir == Direction::forwards) )
{
while(! this->_cur->is_leaf()) {
base_t::template move_down<dir>();
}
}
return *this;
}
////////////// POSTORDER TRAVERSAL /////////////////
template<Direction dir>
__OrderNodeIterator& move_iterator_postfix() {
if(base_t::template is_other_end<dir>()) {
return move_to_boundary<dir>();
}
if(base_t::template is_end<dir>()) {
return *this;
}
return next_postfix<dir>();
}
template<Direction dir>
__OrderNodeIterator& next_postfix() {
// Leave current leaf
if(!this->_cur_state.empty()) {
base_t::move_up();
}
// If we visited all the children of the node, we move up
if(!this->_cur_state.empty() && base_t::template at_last_child<dir>()) {
if(dir == Direction::backwards) {
--(this->_cur_state.back());
} else {
++(this->_cur_state.back());
}
return *this;
}
// Moving too far up means we got to the end of the tree
if(this->_cur_state.empty()) {
base_t::template set_end<dir>();
return *this;
}
// Once we moved up enough, we move down to the next node
while(! this->_cur->is_leaf()) {
base_t::template move_down<dir>();
}
return *this;
}
////////////// PREORDER TRAVERSAL //////////////////
template<Direction dir>
__OrderNodeIterator& move_iterator_prefix() {
if(base_t::template is_other_end<dir>()) {
return move_to_boundary<dir>();
}
if(base_t::template is_end<dir>()) {
return *this;
}
if(this->_cur->is_leaf()) {
return leaf_next_prefix<dir>();
} else {
return node_next_prefix<dir>();
}
}
template<Direction dir>
__OrderNodeIterator& leaf_next_prefix() {
// Leave current leaf
if(!this->_cur_state.empty()) {
base_t::move_up();
}
// If we visited all the children of the node, we move up
while(!this->_cur_state.empty() && base_t::template at_last_child<dir>()) {
base_t::move_up();
}
// Moving too far up means we got to the end of the tree
if(this->_cur_state.empty()) {
base_t::template set_end<dir>();
return *this;
}
// Once we moved up enough, we move down to the next node
base_t::template move_down<dir>();
return *this;
}
template<Direction dir>
__OrderNodeIterator& node_next_prefix() {
base_t::template move_down<dir>();
return *this;
}
////////////////////////////////////////////////////////////
};
}
template<class Node>
using FPreOrderNodeIterator = scalfmm_adaptive_iterator_impl::
__OrderNodeIterator<Node,scalfmm_adaptive_iterator_impl::
NodeIteratorOrder::preorder>;
template<class Node>
using FPostOrderNodeIterator = scalfmm_adaptive_iterator_impl::
__OrderNodeIterator<Node,scalfmm_adaptive_iterator_impl::
NodeIteratorOrder::postorder>;
#endif
#include <cassert>
#include <iterator>
#include "test_Abstract.hpp"
#include "MockParticle.hpp"
#include "Adaptive/new/FTree.hpp"
#include "Adaptive/new/FNode.hpp"
#include "Adaptive/new/FPrePostOrderNodeIterator.hpp"
#include "Utils/make_unique.hpp"
namespace scalfmm {
namespace tests {
struct test_PostOrderNodeIterator : public test_Abstract<test_PostOrderNodeIterator> {
using Real = double;
constexpr static std::size_t Dim = 3;
using tree_t = FTree<std::vector<MockParticle<Real, Dim> >, NodeEmptyData >;
using node_t = typename tree_t::node_t;
using box_t = typename tree_t::box_t;
using iterator_t = FPostOrderNodeIterator<node_t>;
tree_t* tree = nullptr;
node_t* root = nullptr;
box_t box {{0,0,0}, 100};
public:
/** Sets up a tree in which only the root node and its second child
* have children.
*
* 0 ___________________o____ ...
* | | | |
* 1 o ___o____ o o ...
* ||||||||
* 2 oooooooo
*/
void set_up() {
assert(nullptr == tree);
tree = new tree_t(box);
root = tree->root();
root->split();
root->getChild(1)->split();
}
void tear_down() {
delete tree;
tree = nullptr;
}
void run_all() {
RUN(test_constructor_default);
RUN(test_constructor_custom);
RUN(test_constructor_copy);
RUN(test_constructor_move);
RUN(test_operator_copy);
RUN(test_operator_move);
RUN(test_prefix_increment);
RUN(test_prefix_decrement);
RUN(test_incr_inverse_decr);
RUN(test_single_node_tree);
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_constructor_default() {
iterator_t a;
assert(a._root == nullptr);
assert(a._cur == nullptr);
assert(a._is_end == false);
assert(a._is_rend == false);
}
void test_constructor_custom() {
iterator_t a(root);
assert(a._root == root);
assert(a._cur == root->getChild(0));
assert(a._is_end == false);
assert(a._is_rend == false);
//assert(a._cur_state == decltype(a._cur_state) ({-1}));
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_constructor_copy () {
iterator_t a(root);
iterator_t b(a);
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_constructor_move () {
auto a = std::make_unique<iterator_t>(root);
iterator_t b(std::move(*a));
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_operator_copy () {
iterator_t a(root);
iterator_t b;
b = a;
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_operator_move () {
auto a = std::make_unique<iterator_t>(root);
iterator_t b;
b = std::move(*a);
}
/** Tests a single node tree */
void test_single_node_tree() {
tree_t stree(box);
node_t* sroot = stree.root();
iterator_t it(sroot);
assert(it.operator->() == sroot);
assert(it._is_end == false);
assert(it._is_rend == false);
++it;
assert(it._is_end == true);
assert(it._is_rend == false);
--it;
assert(it.operator->() == sroot);
--it;
assert(it._is_end == false);
assert(it._is_rend == true);
++it;
assert(it.operator->() == sroot);
assert(it._is_end == false);
assert(it._is_rend == false);
}
/** Walks the tree, checking each step */
void test_prefix_increment() {
iterator_t it(root);
assert(root->getChild(0) == &(*it));
++it;
assert(root->getChild(1)->getChild(0) == &(*it));
++it;
assert(root->getChild(1)->getChild(1) == &(*it));
++it;
assert(root->getChild(1)->getChild(2) == &(*it));
++it;
assert(root->getChild(1)->getChild(3) == &(*it));
++it;
assert(root->getChild(1)->getChild(4) == &(*it));
++it;
assert(root->getChild(1)->getChild(5) == &(*it));
++it;
assert(root->getChild(1)->getChild(6) == &(*it));
++it;
assert(root->getChild(1)->getChild(7) == &(*it));
++it;
assert(root->getChild(1) == &(*it));
++it;
assert(root->getChild(2) == &(*it));
++it;
assert(root->getChild(3) == &(*it));
++it;
assert(root->getChild(4) == &(*it));
++it;
assert(root->getChild(5) == &(*it));
++it;
assert(root->getChild(6) == &(*it));
++it;
assert(root->getChild(7) == &(*it));
++it;
assert(root == &(*it));
iterator_t it2(++it);
++it;
assert(it2 == it);
assert(it2._is_end == true);
assert(it2._is_rend == false);
}
/** Moves iterator past the end and plays back the walk */
void test_prefix_decrement() {
iterator_t it(root);
for(int i = 0; i < 17; ++i) {
++it;
}
assert(it._is_end == true);
--it;
assert(it._is_end == false);
assert(root == &(*it));
--it;
assert(root->getChild(7) == &(*it));
--it;
assert(root->getChild(6) == &(*it));
--it;
assert(root->getChild(5) == &(*it));
--it;
assert(root->getChild(4) == &(*it));
--it;
assert(root->getChild(3) == &(*it));
--it;
assert(root->getChild(2) == &(*it));
--it;
assert(root->getChild(1) == &(*it));
--it;
assert(root->getChild(1)->getChild(7) == &(*it));
--it;
assert(root->getChild(1)->getChild(6) == &(*it));
--it;
assert(root->getChild(1)->getChild(5) == &(*it));
--it;
assert(root->getChild(1)->getChild(4) == &(*it));
--it;
assert(root->getChild(1)->getChild(3) == &(*it));
--it;
assert(root->getChild(1)->getChild(2) == &(*it));
--it;
assert(root->getChild(1)->getChild(1) == &(*it));
--it;
assert(root->getChild(1)->getChild(0) == &(*it));
--it;
assert(root->getChild(0) == &(*it));
--it;
assert(it._is_rend == true);
}
void print(iterator_t it) {
int i = 0;
while(! it._is_end) {
std::cout << i++ << " " << (it++)._cur << std::endl;
}
}
void test_incr_inverse_decr() {
iterator_t it(root);
while(! (it)._is_end) {
auto cur = it._cur;
++it;
auto cur2 = it._cur;
--it;
assert(cur == it._cur);
++it;
assert(cur2 == it._cur);
}
while(! (it)._is_rend) {
auto cur = it._cur;
--it;
auto cur2 = it._cur;
++it;
assert(cur == it._cur);
--it;
assert(cur2 == it._cur);
}
}
};
}
}
int main() {
scalfmm::tests::test_PostOrderNodeIterator().run_all();
}
#include <cassert>
#include <iterator>
#include "test_Abstract.hpp"
#include "MockParticle.hpp"
#include "Adaptive/new/FTree.hpp"
#include "Adaptive/new/FNode.hpp"
#include "Adaptive/new/FPrePostOrderNodeIterator.hpp"
#include "Utils/make_unique.hpp"
namespace scalfmm {
namespace tests {
struct test_PreOrderNodeIterator : public test_Abstract<test_PreOrderNodeIterator> {
using Real = double;
constexpr static std::size_t Dim = 3;
using tree_t = FTree<std::vector<MockParticle<Real, Dim> >, NodeEmptyData >;
using node_t = typename tree_t::node_t;
using box_t = typename tree_t::box_t;
using iterator_t = FPreOrderNodeIterator<node_t>;
tree_t* tree = nullptr;
node_t* root = nullptr;
box_t box {{0,0,0}, 100};
public:
/** Sets up a tree in which only the root node and its second child
* have children.
*
* 0 ___________________o____ ...
* | | | |
* 1 o ___o____ o o ...
* ||||||||
* 2 oooooooo
*/
void set_up() {
assert(nullptr == tree);
tree = new tree_t(box);
root = tree->root();
root->split();
root->getChild(1)->split();
}
void tear_down() {
delete tree;
tree = nullptr;
}
void run_all() {
RUN(test_constructor_default);
RUN(test_constructor_custom);
RUN(test_constructor_copy);
RUN(test_constructor_move);
RUN(test_operator_copy);
RUN(test_operator_move);
RUN(test_prefix_increment);
RUN(test_prefix_decrement);
RUN(test_incr_inverse_decr);
RUN(test_single_node_tree);
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_constructor_default() {
iterator_t a;
assert(a._root == nullptr);
assert(a._cur == nullptr);
assert(a._is_end == false);
assert(a._is_rend == false);
}
void test_constructor_custom() {
iterator_t a(root);
assert(a._root == root);
assert(a._cur == root);
assert(a._is_end == false);
assert(a._is_rend == false);
assert(a._cur_state == decltype(a._cur_state) ({-1}));
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_constructor_copy () {
iterator_t a(root);
iterator_t b(a);
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_constructor_move () {
auto a = std::make_unique<iterator_t>(root);
iterator_t b(std::move(*a));
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_operator_copy () {
iterator_t a(root);
iterator_t b;
b = a;
}
/** Tested for NodeIterator, testing that it is correctly accessible */
void test_operator_move () {
auto a = std::make_unique<iterator_t>(root);
iterator_t b;
b = std::move(*a);
}
/** Tests a single node tree */
void test_single_node_tree() {
tree_t stree(box);
node_t* sroot = stree.root();
iterator_t it(sroot);
assert(it.operator->() == sroot);
assert(it._is_end == false);
assert(it._is_rend == false);
++it;
assert(it._is_end == true);
assert(it._is_rend == false);
--it;
assert(it.operator->() == sroot);
--it;
assert(it._is_end == false);
assert(it._is_rend == true);
++it;
assert(it.operator->() == sroot);
assert(it._is_end == false);
assert(it._is_rend == false);
}
/** Walks the tree, checking each step */
void test_prefix_increment() {
iterator_t it(root);
assert(root == &(*it));
++it;
assert(root->getChild(0) == &(*it));
++it;
assert(root->getChild(1) == &(*it));
++it;
assert(root->getChild(1)->getChild(0) == &(*it));
++it;
assert(root->getChild(1)->getChild(1) == &(*it));
++it;
assert(root->getChild(1)->getChild(2) == &(*it));
++it;
assert(root->getChild(1)->getChild(3) == &(*it));
++it;
assert(root->getChild(1)->getChild(4) == &(*it));
++it;
assert(root->getChild(1)->getChild(5) == &(*it));
++it;
assert(root->getChild(1)->getChild(6) == &(*it));
++it;
assert(root->getChild(1)->getChild(7) == &(*it));
++it;
assert(root->getChild(2) == &(*it));
++it;
assert(root->getChild(3) == &(*it));
++it;
assert(root->getChild(4) == &(*it));
++it;
assert(root->getChild(5) == &(*it));
++it;
assert(root->getChild(6) == &(*it));
++it;
assert(root->getChild(7) == &(*it));
iterator_t it2(++it);
++it;
assert(it2 == it);
assert(it2._is_end == true);
assert(it2._is_rend == false);
}
/** Moves iterator past the end and plays back the walk */
void test_prefix_decrement() {
iterator_t it(root);
for(int i = 0; i < 17; ++i) {
++it;
}
assert(it._is_end == true);
--it;
assert(it._is_end == false);
assert(root->getChild(7) == &(*it));
--it;
assert(root->getChild(6) == &(*it));
--it;
assert(root->getChild(5) == &(*it));
--it;
assert(root->getChild(4) == &(*it));
--it;
assert(root->getChild(3) == &(*it));
--it;
assert(root->getChild(2) == &(*it));
--it;
assert(root->getChild(1)->getChild(7) == &(*it));
--it;
assert(root->getChild(1)->getChild(6) == &(*it));
--it;
assert(root->getChild(1)->getChild(5) == &(*it));
--it;
assert(root->getChild(1)->getChild(4) == &(*it));
--it;
assert(root->getChild(1)->getChild(3) == &(*it));
--it;
assert(root->getChild(1)->getChild(2) == &(*it));
--it;
assert(root->getChild(1)->getChild(1) == &(*it));
--it;
assert(root->getChild(1)->getChild(0) == &(*it));
--it;
assert(root->getChild(1) == &(*it));
--it;
assert(root->getChild(0) == &(*it));
--it;
assert(root == &(*it));
--it;
assert(it._is_rend == true);
}
void print(iterator_t it) {
int i = 0;
while(! it._is_end) {
std::cout << i++ << " " << (it++)._cur << std::endl;
}
}
void test_incr_inverse_decr() {
iterator_t it(root);
while(! (it)._is_end) {
auto cur = it._cur;
++it;
auto cur2 = it._cur;
--it;
assert(cur == it._cur);
++it;
assert(cur2 == it._cur);
}