Mise à jour terminée. Pour connaître les apports de la version 13.8.4 par rapport à notre ancienne version vous pouvez lire les "Release Notes" suivantes :
https://about.gitlab.com/releases/2021/02/11/security-release-gitlab-13-8-4-released/
https://about.gitlab.com/releases/2021/02/05/gitlab-13-8-3-released/

Commit a01d0d40 authored by Quentin Khan's avatar Quentin Khan

Add FNode in order iterator implementation

parent 8f4ca7e1
#ifndef _SCALFMM_IN_ORDER_NODE_ITERATOR_HPP_
#define _SCALFMM_IN_ORDER_NODE_ITERATOR_HPP_
#include "FNodeIterator.hpp"
namespace scalfmm {
namespace tests {
struct test_InOrderNodeIterator;
}
}
template<class Node>
class FInOrderNodeIterator : public FNodeIterator<FInOrderNodeIterator<Node>, Node> {
using base_t = FNodeIterator<FInOrderNodeIterator<Node>, Node>;
using Direction = typename base_t::Direction;
friend scalfmm::tests::test_InOrderNodeIterator;
friend base_t;
public:
using base_t::base_t;
using base_t::operator++;
using base_t::operator--;
FInOrderNodeIterator& operator++() {
return move_iterator<Direction::forwards>();
}
FInOrderNodeIterator& operator--() {
return move_iterator<Direction::backwards>();
}
private:
/** Indicates the index of the middle child */
template<Direction dir>
typename base_t::index_t mid_idx() const {
if(dir == Direction::forwards) { // Compile time optimisation will remove unused branch
return (base_t::child_count/2)-1;
} else {
return (base_t::child_count/2);
}
}
/** Moves the cursor to the first node
*
* Resets the iterator to a valid state.
*/
template<Direction dir>
FInOrderNodeIterator& move_to_boundary() {
base_t::template goto_root<dir>();
while(! this->_cur->is_leaf()) {
base_t::template move_down<dir>();
}
return *this;
}
template<Direction dir>
FInOrderNodeIterator& leaf_next() {
// Leave current leaf
if(!this->_cur_state.empty()) {
base_t::move_up();
}
// If we visited half the parent's children, stay on the parent
if (!this->_cur_state.empty() && mid_idx<dir>() == this->_cur_state.back()) {
return *this;
}
// 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 leaf
while(! this->_cur->is_leaf()) {
base_t::template move_down<dir>();
}
return *this;
}
template<Direction dir>
FInOrderNodeIterator& node_next() {
// If we are on an internal node, we move down to the children
if(dir == Direction::forwards) { // Compile time optimisation will remove unused branch
this->_cur_state.back() = static_cast<char>(mid_idx<dir>()+1);
} else {
this->_cur_state.back() = static_cast<char>(mid_idx<dir>()-1);
}
this->_cur = this->_cur->getChild((std::size_t)this->_cur_state.back());
this->_cur_state.push_back(base_t::template first_idx<dir>());
while(! this->_cur->is_leaf()) {
base_t::template move_down<dir>();
}
return *this;
}
template<Direction dir>
FInOrderNodeIterator& move_iterator() {
// If before the beginning, move to the first node
if(base_t::template is_other_end<dir>()) {
return move_to_boundary<dir>();
}
// Don't move if already past the end
if(base_t::template is_end<dir>()) {
return *this;
}
if(this->_cur->is_leaf()) {
return leaf_next<dir>();
} else {
return node_next<dir>();
}
}
};
#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/FInOrderNodeIterator.hpp"
#include "Utils/make_unique.hpp"
namespace scalfmm {
namespace tests {
struct test_InOrderNodeIterator : public test_Abstract<test_InOrderNodeIterator> {
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 = FInOrderNodeIterator<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;
root = 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) ({0,-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) == &(*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 == &(*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 == &(*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) == &(*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 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_InOrderNodeIterator().run_all();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment