::StackType otherStackCopy(parOther.m_stack);
+ std::vector localCopy;
+ localCopy.reserve(parOther.m_stack.size());
+ while (not otherStackCopy.empty()) {
+ P convertedItem = otherStackCopy.top();
+ localCopy.push_back(convertedItem);
+ otherStackCopy.pop();
+ }
+ m_stack.reserve(parOther.m_stack.capacity());
+ for (typename std::vector
::reverse_iterator itRev = localCopy.rbegin(), itRevEnd = localCopy.rend(); itRev != itRevEnd; ++itRev) {
+ assert(m_stack.capacity() > m_stack.size());
+ m_stack.push(*itRev);
+ }
+ }
+
+ ///---------------------------------------------------------------------
+ ///---------------------------------------------------------------------
+ template
+ typename TreeIterator_const_layer::reference TreeIterator_const_layer::operator* () {
+ assert(not this->Exhausted());
+ return this->m_stack.top()->content;
+ }
+
+ ///---------------------------------------------------------------------
+ ///---------------------------------------------------------------------
+ template
+ typename TreeIterator_const_layer::const_reference TreeIterator_const_layer::operator* () const {
+ assert(not this->Exhausted());
+ return this->m_stack.top()->content;
+ }
+
+ ///---------------------------------------------------------------------
+ ///---------------------------------------------------------------------
+ template
+ typename TreeIterator_const_layer::pointer TreeIterator_const_layer::operator-> () {
+ assert(not this->Exhausted());
+ return &this->m_stack.top()->content;
+ }
+
+ ///---------------------------------------------------------------------
+ ///---------------------------------------------------------------------
+ template
+ typename TreeIterator_const_layer::const_pointer TreeIterator_const_layer::operator-> () const {
+ assert(not this->Exhausted());
+ return &this->m_stack.top()->content;
+ }
+
+ ///---------------------------------------------------------------------
+ ///---------------------------------------------------------------------
+ template
+ N* TreeIterator_const_layer::GetPointer() {
+ assert(not this->Exhausted());
+ return this->m_stack.top();
+ }
+
+ ///---------------------------------------------------------------------
+ ///---------------------------------------------------------------------
+ template
+ const N* TreeIterator_const_layer::GetPointer() const {
+ assert(not this->Exhausted());
+ return this->m_stack.top();
+ }
+
+ ///---------------------------------------------------------------------
+ ///---------------------------------------------------------------------
+ template
+ typename TreeIterator_const_layer::const_reference TreeIterator_const_layer::operator* () const {
+ assert(not this->Exhausted());
+ return this->m_stack.top()->content;
+ }
+
+ ///---------------------------------------------------------------------
+ ///---------------------------------------------------------------------
+ template
+ typename TreeIterator_const_layer::const_pointer TreeIterator_const_layer::operator-> () const {
+ assert(not this->Exhausted());
+ return &this->m_stack.top()->content;
+ }
+
+ ///---------------------------------------------------------------------
+ ///---------------------------------------------------------------------
+ template
+ const N* TreeIterator_const_layer::GetPointer() const {
+ assert(not this->Exhausted());
+ return this->m_stack.top();
+ }
+ } //namespace implem
+
+ ///-------------------------------------------------------------------------
+ ///-------------------------------------------------------------------------
+ template
+ TreeIterator::TreeIterator() {
+ }
+
+ ///-------------------------------------------------------------------------
+ ///-------------------------------------------------------------------------
+ template
+ TreeIterator::TreeIterator (const TreeIterator& parOther) :
+ parent_type(parOther)
+ {
+ }
+
+ ///-------------------------------------------------------------------------
+ ///-------------------------------------------------------------------------
+ template
+ template
+ TreeIterator::TreeIterator (const TreeIterator& parOther) :
+ parent_type(parOther)
+ {
+ }
+
+ ///-------------------------------------------------------------------------
+ ///-------------------------------------------------------------------------
+ template
+ template
+ TreeIterator::TreeIterator (S parCopyStackBottomUp, size_type parStackLen, size_type parMaxDepthHint) {
+ assert(parStackLen > 0);
+ this->m_stack.reserve(std::max(parStackLen, parMaxDepthHint));
+ typename StackType::value_type prevNode = *parCopyStackBottomUp;
+ ++parCopyStackBottomUp;
+ this->m_stack.push(prevNode);
+
+ for (size_type z = 1; z < parStackLen; ++z) {
+ typename StackType::value_type currNode = *parCopyStackBottomUp;
+ if (prevNode->left == currNode) {
+ assert(this->m_stack.capacity() > this->m_stack.size());
+ this->m_stack.push(currNode);
+ }
+ else {
+ //If you get this assertion make sure the iterator you are
+ //passing in is reversed (ie: from leaf to root)
+ assert(currNode == prevNode->right);
+ }
+
+ prevNode = currNode;
+ ++parCopyStackBottomUp;
+ }
+ assert(not this->Exhausted());
+ }
+
+ ///-------------------------------------------------------------------------
+ ///-------------------------------------------------------------------------
+ template
+ TreeIterator::TreeIterator (NodeTypePointer parRoot, size_type parMaxDepthHint) {
+ if (parMaxDepthHint > 0)
+ this->m_stack.reserve(parMaxDepthHint);
+ RecurseLeft(parRoot);
+ }
+
+ ///-------------------------------------------------------------------------
+ ///-------------------------------------------------------------------------
+ template
+ TreeIterator::~TreeIterator() {
+ }
+
+ ///-------------------------------------------------------------------------
+ ///Post-increment
+ ///-------------------------------------------------------------------------
+ template
+ TreeIterator TreeIterator::operator++ (int) {
+ assert(not this->Exhausted());
+ TreeIterator retVal = *this;
+ ++(*this);
+ return retVal;
+ }
+
+ ///-------------------------------------------------------------------------
+ ///Pre-increment
+ ///-------------------------------------------------------------------------
+ template
+ TreeIterator& TreeIterator::operator++() {
+ assert(not this->Exhausted());
+ NodeTypePointer currNode = this->m_stack.top();
+#if defined(ASSERTIONSENABLED)
+ const size_type stackCapacity = this->m_stack.capacity();
+#endif
+ this->m_stack.pop();
+#if defined(ASSERTIONSENABLED)
+ //It shouldn't normally happen, but it's just to make sure
+ assert(stackCapacity == this->m_stack.capacity());
+#endif
+ RecurseLeft(currNode->right);
+ return *this;
+ }
+
+ ///-------------------------------------------------------------------------
+ ///-------------------------------------------------------------------------
+ template
+ const TreeIterator& TreeIterator::operator= (const TreeIterator& parOther) {
+ this->m_stack = parOther.m_stack;
+ assert(this->m_stack.capacity() >= parOther.m_stack.capacity());
+ return *this;
+ }
+
+ ///-------------------------------------------------------------------------
+ ///-------------------------------------------------------------------------
+ template
+ bool TreeIterator::operator== (const TreeIterator& parOther) const {
+ return this->m_stack.size() == parOther.m_stack.size() and (this->m_stack.empty() or parOther.m_stack.top() == this->m_stack.top());
+ }
+
+ ///-------------------------------------------------------------------------
+ ///-------------------------------------------------------------------------
+ template
+ void TreeIterator::RecurseLeft (NodeTypePointer parFrom) {
+ NodeTypePointer currNode = parFrom;
+ while (NULL != currNode) {
+ assert(this->m_stack.capacity() > this->m_stack.size());
+ this->m_stack.push(currNode);
+ currNode = currNode->left;
+ }
+ }
+} //namespace dhandy
diff --git a/include/duckhandy/tree_iterator.hpp b/include/duckhandy/tree_iterator.hpp
new file mode 100644
index 0000000..40b3e41
--- /dev/null
+++ b/include/duckhandy/tree_iterator.hpp
@@ -0,0 +1,152 @@
+/* Copyright 2016-2024 Michele Santullo
+ * This file is part of "duckhandy".
+ *
+ * "duckhandy" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "duckhandy" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "duckhandy". If not, see .
+ */
+
+#ifndef id6109D5EDE99D43C4909F084A231BF2C2
+#define id6109D5EDE99D43C4909F084A231BF2C2
+
+#include
+#include
+#include
+#include
+#include
+
+namespace dhandy {
+ namespace implem {
+ template
+ class TreeIteratorStack : public std::stack> {
+ public:
+ void reserve (std::size_t size) {
+ std::stack
>::c.reserve(size);
+ }
+
+ std::size_t capacity() const {
+ return std::stack
>::c.capacity();
+ }
+ private:
+ };
+
+ template
+ class TreeIterator_base {
+ template friend class TreeIterator_base;
+ public:
+ explicit TreeIterator_base ( void ) {}
+ TreeIterator_base ( const TreeIterator_base& parOther );
+ template
+ explicit TreeIterator_base ( const TreeIterator_base& parOther );
+ ~TreeIterator_base ( void ) {}
+ protected:
+ typedef TreeIteratorStack StackType;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ bool Exhausted ( void ) const;
+ StackType m_stack;
+ };
+
+ template
+ class TreeIterator_const_layer;
+ template
+ class TreeIterator_const_layer : protected TreeIterator_base {
+ template friend class TreeIterator_const_layer;
+ typedef TreeIterator_base parent_type;
+ public:
+ typedef const T* pointer;
+ typedef const T* const_pointer;
+ typedef const T& reference;
+ typedef const T& const_reference;
+ typedef typename parent_type::size_type size_type;
+ typedef typename parent_type::difference_type difference_type;
+ typedef N NodeType;
+ typedef const N* NodeTypePointer;
+ enum { IS_CONST = 1 };
+ TreeIterator_const_layer ( void ) {}
+ TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {}
+ template
+ explicit TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {}
+ const_reference operator* ( void ) const;
+ const_pointer operator-> ( void ) const;
+ const N* GetPointer ( void ) const;
+ protected:
+ typedef typename parent_type::StackType StackType;
+ };
+ template
+ class TreeIterator_const_layer : protected TreeIterator_base {
+ template friend class TreeIterator_const_layer;
+ typedef TreeIterator_base parent_type;
+ public:
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef typename parent_type::size_type size_type;
+ typedef typename parent_type::difference_type difference_type;
+ typedef N NodeType;
+ typedef N* NodeTypePointer;
+ enum { IS_CONST = 0 };
+ TreeIterator_const_layer ( void ) {}
+ TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {}
+ template
+ explicit TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {}
+ reference operator* ( void );
+ const_reference operator* ( void ) const;
+ pointer operator-> ( void );
+ const_pointer operator-> ( void ) const;
+ const N* GetPointer ( void ) const;
+ N* GetPointer ( void );
+ protected:
+ typedef typename parent_type::StackType StackType;
+ };
+ } //namespace implem
+
+ template
+ class TreeIterator : public implem::TreeIterator_const_layer::value> {
+ typedef implem::TreeIterator_const_layer::value> parent_type;
+ typedef typename parent_type::NodeTypePointer NodeTypePointer;
+ typedef typename parent_type::NodeType NodeType;
+ typedef typename parent_type::StackType StackType;
+ public:
+ typedef T value_type;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef typename parent_type::difference_type difference_type;
+ typedef typename parent_type::size_type size_type;
+ typedef typename parent_type::pointer pointer;
+ typedef typename parent_type::const_pointer const_pointer;
+ typedef typename parent_type::reference reference;
+ typedef typename parent_type::const_reference const_reference;
+
+ TreeIterator ( void );
+ TreeIterator ( const TreeIterator& parOther );
+ TreeIterator ( NodeTypePointer parRoot, size_type parMaxDepthHint );
+ template
+ TreeIterator ( S parCopyStackBottomUp, size_type parStackLen, size_type parMaxDepthHint );
+ template
+ TreeIterator ( const TreeIterator& parOther );
+ ~TreeIterator ( void );
+
+ const TreeIterator& operator= ( const TreeIterator& parOther );
+ bool operator== ( const TreeIterator& parOther ) const;
+ bool operator!= ( const TreeIterator& parOther ) const { return not (*this == parOther); }
+ TreeIterator& operator++ ( void ); //pre
+ TreeIterator operator++ ( int ); //post
+
+ private:
+ void RecurseLeft ( NodeTypePointer parFrom );
+ };
+} //namespace dhandy
+
+#include "implem/tree_iterator.inl"
+
+#endif
diff --git a/test/unit/meson.build b/test/unit/meson.build
index 5ec1bd0..2373f86 100644
--- a/test/unit/meson.build
+++ b/test/unit/meson.build
@@ -10,6 +10,7 @@ unit_test_prog = executable(meson.project_name(),
'version_test.cpp',
'tiger_test.cpp',
'infix_iterator.cpp',
+ 'tree_iterator_test.cpp',
install: false,
dependencies: [sprout_dep, catch2_dep],
include_directories: [public_incl],
diff --git a/test/unit/tree_iterator_test.cpp b/test/unit/tree_iterator_test.cpp
new file mode 100644
index 0000000..b0533a4
--- /dev/null
+++ b/test/unit/tree_iterator_test.cpp
@@ -0,0 +1,136 @@
+/* Copyright 2016-2024 Michele Santullo
+ * This file is part of "duckhandy".
+ *
+ * "duckhandy" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "duckhandy" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "duckhandy". If not, see .
+ */
+
+#include "catch2/catch_test_macros.hpp"
+#include "duckhandy/tree_iterator.hpp"
+
+namespace {
+
+enum Letters : unsigned int {
+ A = 'a', B, C, D, E, F, G, H, I
+};
+
+struct TestNode {
+ TestNode (unsigned int val) : content(val) {}
+ TestNode* left{nullptr}, *right{nullptr};
+ unsigned int content{0};
+};
+} //unnamed namespace
+
+TEST_CASE("Check TreeIterator", "[TreeIterator][containers][iterator]") {
+ typedef dhandy::TreeIterator TestIterator;
+
+ TestIterator empty;
+
+ {
+ TestNode root{0xDEADBEEFu};
+ TestIterator it{&root, 1};
+ CHECK(*it == 0xDEADBEEFu);
+
+ ++it;
+ CHECK(it == empty);
+ }
+
+ {
+ TestNode root{A};
+ TestNode l{B}, ll{C}, lr{D};
+ TestNode r{E}, rl{F}, rr{G}, rll{H}, rrr{I};
+
+ root.left = &l;
+ root.right = &r;
+ l.left = ≪
+ l.right = &lr;
+ r.left = &rl;
+ r.right = &rr;
+ rl.left = &rll;
+ rr.right = &rrr;
+
+ TestIterator it{&root, 4};
+ CHECK(*it == C); //ll
+ ++it;
+ CHECK(*it == B); //l
+ it++;
+ CHECK(*it == D); //lr
+ it++;
+ CHECK(*it == A); //root
+ ++it;
+ CHECK(*it == H); //rll
+ it++;
+ CHECK(*it == F); //rl
+ it++;
+ CHECK(*it == E); //r
+ ++it;
+ CHECK(*it == G); //rr
+ ++it;
+ CHECK(*it == I); //rrr
+ CHECK(it != empty);
+ it++;
+ CHECK(it == empty);
+ }
+
+ {
+ TestNode root{A};
+ TestNode l{B}, ll{C}, lll{D}, llll{E}, lllll{F};
+ root.left = &l;
+ l.left = ≪
+ ll.left = &lll;
+ lll.left = &llll;
+ llll.left = &lllll;
+
+ TestIterator it{&root, 6};
+ CHECK(it != empty);
+ CHECK(*it == F);
+ ++it;
+ CHECK(*it == E);
+ ++it;
+ CHECK(*it == D);
+ ++it;
+ CHECK(*it == C);
+ ++it;
+ CHECK(*it == B);
+ ++it;
+ CHECK(*it == A);
+ ++it;
+ CHECK(it == empty);
+ }
+
+ {
+ TestNode root{A};
+ TestNode r{B}, rr{C}, rrr{D}, rrrr{E}, rrrrr{F};
+ root.right = &r;
+ r.right = &rr;
+ rr.right = &rrr;
+ rrr.right = &rrrr;
+ rrrr.right = &rrrrr;
+
+ TestIterator it{&root, 6};
+ CHECK(it != empty);
+ CHECK(*it == A);
+ ++it;
+ CHECK(*it == B);
+ ++it;
+ CHECK(*it == C);
+ ++it;
+ CHECK(*it == D);
+ ++it;
+ CHECK(*it == E);
+ ++it;
+ CHECK(*it == F);
+ ++it;
+ CHECK(it == empty);
+ }
+}