X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fstlplus%2Fcontainers%2Fntree.tpp;h=1467aa8c72331ef4ffbda13a357ad7dc71b6ef9f;hp=6fd019d9f30b7eee6fe71ebd682e9667172060c4;hb=5846afb00833cc72fe72422ca896d2387c712cb4;hpb=a97500609dc3c1b11f9786d32bc458eb00de4c36 diff --git a/src/stlplus/containers/ntree.tpp b/src/stlplus/containers/ntree.tpp index 6fd019d..1467aa8 100644 --- a/src/stlplus/containers/ntree.tpp +++ b/src/stlplus/containers/ntree.tpp @@ -1,913 +1,913 @@ -//////////////////////////////////////////////////////////////////////////////// - -// Author: Andy Rushton -// Copyright: (c) Southampton University 1999-2004 -// (c) Andy Rushton 2004-2009 -// License: BSD License, see ../docs/license.html - -//////////////////////////////////////////////////////////////////////////////// -#include -#include - -namespace stlplus -{ - - //////////////////////////////////////////////////////////////////////////////// - // ntree_node - - template - class ntree_node - { - public: - master_iterator, ntree_node > m_master; - T m_data; - ntree_node* m_parent; - std::vector*> m_children; - - public: - ntree_node(const ntree* owner, const T& data = T()) : - m_master(owner,this), m_data(data), m_parent(0) - { - } - - void change_owner(const ntree* owner) - { - m_master.change_owner(owner); - for (TYPENAME std::vector*>::iterator i = m_children.begin(); i != m_children.end(); i++) - (*i)->change_owner(owner); - } - - ~ntree_node(void) - { - m_parent = 0; - for (TYPENAME std::vector*>::iterator i = m_children.begin(); i != m_children.end(); i++) - delete *i; - } - - }; - - template - static ntree_node* ntree_copy(const ntree* new_owner, ntree_node* root) - { - if (!root) return 0; - ntree_node* new_tree = new ntree_node(new_owner, root->m_data); - for (TYPENAME std::vector*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++) - { - ntree_node* new_child = ntree_copy(new_owner, *i); - new_tree->m_children.push_back(new_child); - new_child->m_parent = new_tree; - } - return new_tree; - } - - template - static unsigned ntree_size(ntree_node* root) - { - if (!root) return 0; - unsigned result = 1; - for (TYPENAME std::vector*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++) - result += ntree_size(*i); - return result; - } - - template - static unsigned ntree_depth(ntree_node* root) - { - unsigned depth = 0; - for (ntree_node* i = root; i; i = i->m_parent) - depth++; - return depth; - } - - //////////////////////////////////////////////////////////////////////////////// - // ntree_iterator - - // constructor to create a null iterator - you must assign a valid value to this iterator before using it - template - ntree_iterator::ntree_iterator(void) - { - } - - // used to create an alias of an iterator - template - ntree_iterator::ntree_iterator(const safe_iterator, ntree_node >& iterator) : - safe_iterator,ntree_node >(iterator) - { - } - - // constructor used by ntree to create a non-null iterator - template - ntree_iterator::ntree_iterator(ntree_node* node) : - safe_iterator,ntree_node >(node->m_master) - { - } - - // constructor used by ntree to create an end iterator - template - ntree_iterator::ntree_iterator(const ntree* owner) : - safe_iterator,ntree_node >(owner) - { - } - - // destructor - template - ntree_iterator::~ntree_iterator(void) - { - } - - template - TYPENAME ntree_iterator::const_iterator ntree_iterator::constify(void) const - { - return ntree_iterator(*this); - } - - template - TYPENAME ntree_iterator::iterator ntree_iterator::deconstify(void) const - { - return ntree_iterator(*this); - } - - template - bool ntree_iterator::operator == (const TYPENAME ntree_iterator::this_iterator& r) const - { - return equal(r); - } - - template - bool ntree_iterator::operator != (const TYPENAME ntree_iterator::this_iterator& r) const - { - return !operator==(r); - } - - template - bool ntree_iterator::operator < (const TYPENAME ntree_iterator::this_iterator& r) const - { - return compare(r) < 0; - } - - template - TYPENAME ntree_iterator::reference ntree_iterator::operator*(void) const - throw(null_dereference,end_dereference) - { - this->assert_valid(); - return this->node()->m_data; - } - - template - TYPENAME ntree_iterator::pointer ntree_iterator::operator->(void) const - throw(null_dereference,end_dereference) - { - return &(operator*()); - } - - //////////////////////////////////////////////////////////////////////////////// - // ntree_prefix_iterator - - template - ntree_prefix_iterator::ntree_prefix_iterator(void) - { - } - - template - ntree_prefix_iterator::~ntree_prefix_iterator(void) - { - } - - template - ntree_prefix_iterator::ntree_prefix_iterator(const ntree_iterator& i) : - m_iterator(i) - { - // this is initialised with the root node - // which is also the first node in prefix traversal order - } - - template - bool ntree_prefix_iterator::null(void) const - { - return m_iterator.null(); - } - - template - bool ntree_prefix_iterator::end(void) const - { - return m_iterator.end(); - } - - template - bool ntree_prefix_iterator::valid(void) const - { - return m_iterator.valid(); - } - - template - TYPENAME ntree_prefix_iterator::const_iterator ntree_prefix_iterator::constify(void) const - { - return ntree_prefix_iterator(m_iterator); - } - - template - TYPENAME ntree_prefix_iterator::iterator ntree_prefix_iterator::deconstify(void) const - { - return ntree_prefix_iterator(m_iterator); - } - - template - ntree_iterator ntree_prefix_iterator::simplify(void) const - { - return m_iterator; - } - - template - bool ntree_prefix_iterator::operator == (const TYPENAME ntree_prefix_iterator::this_iterator& r) const - { - return m_iterator == r.m_iterator; - } - - template - bool ntree_prefix_iterator::operator != (const TYPENAME ntree_prefix_iterator::this_iterator& r) const - { - return m_iterator != r.m_iterator; - } - - template - bool ntree_prefix_iterator::operator < (const TYPENAME ntree_prefix_iterator::this_iterator& r) const - { - return m_iterator < r.m_iterator; - } - - template - TYPENAME ntree_prefix_iterator::this_iterator& ntree_prefix_iterator::operator ++ (void) - throw(null_dereference,end_dereference) - { - // pre-increment operator - // algorithm: if there are any children, visit child 0, otherwise, go to - // parent and deduce which child the start node was of that parent - if - // there are further children, go into the next one. Otherwise, go up the - // tree and test again for further children. Return null if there are no - // further nodes - m_iterator.assert_valid(); - ntree_node* old_node = m_iterator.node(); - if (!old_node->m_children.empty()) - { - // simply take the first child of this node - m_iterator.set(old_node->m_children[0]->m_master); - } - else - { - // this loop walks up the parent pointers - // either it will walk off the top and exit or a new node will be found and the loop will exit - for (;;) - { - // go up a level - ntree_node* parent = old_node->m_parent; - if (!parent) - { - // we've walked off the top of the tree, so return end - m_iterator.set_end(); - break; - } - else - { - // otherwise walk down the next child - if there is one - // find which index the old node was relative to this node - TYPENAME std::vector*>::iterator found = - std::find(parent->m_children.begin(), parent->m_children.end(), old_node); - // if this was found, then see if there is another and if so return that - found++; - if (found != parent->m_children.end()) - { - // visit the next child - m_iterator.set((*found)->m_master); - break; - } - else - { - // keep going up - old_node = parent; - } - } - } - } - return *this; - } - - template - TYPENAME ntree_prefix_iterator::this_iterator ntree_prefix_iterator::operator ++ (int) - throw(null_dereference,end_dereference) - { - // post-increment is defined in terms of the pre-increment - ntree_prefix_iterator result(*this); - ++(*this); - return result; - } - - template - TYPENAME ntree_prefix_iterator::reference ntree_prefix_iterator::operator*(void) const - throw(null_dereference,end_dereference) - { - return m_iterator.operator*(); - } - - template - TYPENAME ntree_prefix_iterator::pointer ntree_prefix_iterator::operator->(void) const - throw(null_dereference,end_dereference) - { - return m_iterator.operator->(); - } - - template - const ntree_iterator& ntree_prefix_iterator::get_iterator(void) const - { - return m_iterator; - } - - template - ntree_iterator& ntree_prefix_iterator::get_iterator(void) - { - return m_iterator; - } - - //////////////////////////////////////////////////////////////////////////////// - // ntree_postfix_iterator - - template - ntree_postfix_iterator::ntree_postfix_iterator(void) - { - } - - template - ntree_postfix_iterator::~ntree_postfix_iterator(void) - { - } - - template - ntree_postfix_iterator::ntree_postfix_iterator(const ntree_iterator& i) : - m_iterator(i) - { - // this is initialised with the root node - // initially traverse to the first node to be visited - if (m_iterator.valid()) - { - ntree_node* node = m_iterator.node(); - while (!node->m_children.empty()) - node = node->m_children[0]; - m_iterator.set(node->m_master); - } - } - - template - bool ntree_postfix_iterator::null(void) const - { - return m_iterator.null(); - } - - template - bool ntree_postfix_iterator::end(void) const - { - return m_iterator.end(); - } - - template - bool ntree_postfix_iterator::valid(void) const - { - return m_iterator.valid(); - } - - template - TYPENAME ntree_postfix_iterator::const_iterator ntree_postfix_iterator::constify(void) const - { - return ntree_postfix_iterator(m_iterator); - } - - template - TYPENAME ntree_postfix_iterator::iterator ntree_postfix_iterator::deconstify(void) const - { - return ntree_postfix_iterator(m_iterator); - } - - template - ntree_iterator ntree_postfix_iterator::simplify(void) const - { - return m_iterator; - } - - template - bool ntree_postfix_iterator::operator == (const TYPENAME ntree_postfix_iterator::this_iterator& r) const - { - return m_iterator == r.m_iterator; - } - - template - bool ntree_postfix_iterator::operator != (const TYPENAME ntree_postfix_iterator::this_iterator& r) const - { - return m_iterator != r.m_iterator; - } - - template - bool ntree_postfix_iterator::operator < (const TYPENAME ntree_postfix_iterator::this_iterator& r) const - { - return m_iterator < r.m_iterator; - } - - template - TYPENAME ntree_postfix_iterator::this_iterator& ntree_postfix_iterator::operator ++ (void) - throw(null_dereference,end_dereference) - { - // pre-increment operator - // algorithm: this node has been visited, therefore all children must have - // already been visited. So go to parent. Return null if the parent is null. - // Otherwise deduce which child the start node was of that parent - if there - // are further children, go into the next one and then walk down any - // subsequent first-child pointers to the bottom. Otherwise, if there are no - // children then the parent node is the next in the traversal. - m_iterator.assert_valid(); - // go up a level - ntree_node* old_node = m_iterator.node(); - ntree_node* parent = old_node->m_parent; - if (!parent) - { - // we've walked off the top of the tree, so return end - m_iterator.set_end(); - } - else - { - // otherwise find which index the old node was relative to this node - TYPENAME std::vector*>::iterator found = - std::find(parent->m_children.begin(), parent->m_children.end(), old_node); - // if this was found, then see if there is another - found++; - if (found != parent->m_children.end()) - { - // if so traverse to it and walk down the leftmost child pointers to the bottom of the new sub-tree - ntree_node* new_node = *found; - while (!new_node->m_children.empty()) - new_node = new_node->m_children[0]; - m_iterator.set(new_node->m_master); - } - else - { - // the parent's children have all been visited - so the parent is visited - m_iterator.set(parent->m_master); - } - } - return *this; - } - - template - TYPENAME ntree_postfix_iterator::this_iterator ntree_postfix_iterator::operator ++ (int) - throw(null_dereference,end_dereference) - { - // post-increment is defined in terms of the pre-increment - ntree_postfix_iterator result(*this); - ++(*this); - return result; - } - - template - TYPENAME ntree_postfix_iterator::reference ntree_postfix_iterator::operator*(void) const - throw(null_dereference,end_dereference) - { - return m_iterator.operator*(); - } - - template - TYPENAME ntree_postfix_iterator::pointer ntree_postfix_iterator::operator->(void) const - throw(null_dereference,end_dereference) - { - return m_iterator.operator->(); - } - - template - const ntree_iterator& ntree_postfix_iterator::get_iterator(void) const - { - return m_iterator; - } - - template - ntree_iterator& ntree_postfix_iterator::get_iterator(void) - { - return m_iterator; - } - - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - // ntree - //////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - - template - ntree::ntree(void) : m_root(0) - { - } - - template - ntree::~ntree(void) - { - if (m_root) delete m_root; - } - - template - ntree::ntree(const ntree& r) : m_root(0) - { - *this = r; - } - - template - ntree& ntree::operator=(const ntree& r) - { - if (m_root) delete m_root; - m_root = ntree_copy(this, r.m_root); - return *this; - } - - template - bool ntree::empty(void) const - { - return m_root == 0; - } - - template - unsigned ntree::size(void) const - { - return ntree_size(m_root); - } - - template - unsigned ntree::size(const TYPENAME ntree::const_iterator& i) const - throw(wrong_object,null_dereference,end_dereference) - { - i.assert_valid(this); - return ntree_size(i.node()); - } - - template - unsigned ntree::size(const TYPENAME ntree::iterator& i) - throw(wrong_object,null_dereference,end_dereference) - { - i.assert_valid(this); - return ntree_size(i.node()); - } - - template - unsigned ntree::depth(const TYPENAME ntree::const_iterator& i) const - throw(wrong_object,null_dereference,end_dereference) - { - i.assert_valid(this); - return ntree_depth(i.node()); - } - - template - unsigned ntree::depth(const TYPENAME ntree::iterator& i) - throw(wrong_object,null_dereference,end_dereference) - { - i.assert_valid(this); - return ntree_depth(i.node()); - } - - template - TYPENAME ntree::const_iterator ntree::root(void) const - { - if (!m_root) return ntree_iterator(this); - return ntree_iterator(m_root); - } - - template - TYPENAME ntree::iterator ntree::root(void) - { - if (!m_root) return ntree_iterator(this); - return ntree_iterator(m_root); - } - - template - unsigned ntree::children(const TYPENAME ntree::const_iterator& i) const - throw(wrong_object,null_dereference,end_dereference) - { - i.assert_valid(this); - return i.node()->m_children.size(); - } - - template - unsigned ntree::children(const ntree_iterator& i) - throw(wrong_object,null_dereference,end_dereference) - { - i.assert_valid(this); - return i.node()->m_children.size(); - } - - template - TYPENAME ntree::const_iterator ntree::child(const TYPENAME ntree::const_iterator& i, unsigned child) const - throw(wrong_object,null_dereference,end_dereference,std::out_of_range) - { - i.assert_valid(this); - if (child >= children(i)) throw std::out_of_range("stlplus::ntree"); - return ntree_iterator(i.node()->m_children[child]); - } - - template - TYPENAME ntree::iterator ntree::child(const TYPENAME ntree::iterator& i, unsigned child) - throw(wrong_object,null_dereference,end_dereference,std::out_of_range) - { - i.assert_valid(this); - if (child >= children(i)) throw std::out_of_range("stlplus::ntree"); - return ntree_iterator(i.node()->m_children[child]); - } - - template - TYPENAME ntree::const_iterator ntree::parent(const TYPENAME ntree::const_iterator& i) const - throw(wrong_object,null_dereference,end_dereference) - { - i.assert_valid(this); - ntree_node* parent = i.node()->m_parent; - if (!parent) return ntree_iterator(this); - return ntree_iterator(parent); - } - - template - TYPENAME ntree::iterator ntree::parent(const TYPENAME ntree::iterator& i) - throw(wrong_object,null_dereference,end_dereference) - { - i.assert_valid(this); - ntree_node* parent = i.node()->m_parent; - if (!parent) return ntree_iterator(this); - return ntree_iterator(parent); - } - - template - TYPENAME ntree::const_prefix_iterator ntree::prefix_begin(void) const - { - return ntree_prefix_iterator(root()); - } - - template - TYPENAME ntree::prefix_iterator ntree::prefix_begin(void) - { - return ntree_prefix_iterator(root()); - } - - template - TYPENAME ntree::const_prefix_iterator ntree::prefix_end(void) const - { - return ntree_prefix_iterator(ntree_iterator(this)); - } - - template - TYPENAME ntree::prefix_iterator ntree::prefix_end(void) - { - return ntree_prefix_iterator(ntree_iterator(this)); - } - - template - TYPENAME ntree::const_postfix_iterator ntree::postfix_begin(void) const - { - return ntree_postfix_iterator(root()); - } - - template - TYPENAME ntree::postfix_iterator ntree::postfix_begin(void) - { - return ntree_postfix_iterator(root()); - } - - template - TYPENAME ntree::const_postfix_iterator ntree::postfix_end(void) const - { - return ntree_postfix_iterator(ntree_iterator(this)); - } - - template - TYPENAME ntree::postfix_iterator ntree::postfix_end(void) - { - return ntree_postfix_iterator(ntree_iterator(this)); - } - - template - TYPENAME ntree::iterator ntree::insert(const T& data) - { - // insert a new node as the root - return insert(ntree_iterator(this), 0, data); - } - - template - TYPENAME ntree::iterator ntree::insert(const TYPENAME ntree::iterator& i, unsigned offset, const T& data) - throw(wrong_object,null_dereference,end_dereference,std::out_of_range) - { - // if i is the end iterator, this means insert a new root - if (i.end()) - erase(); - else - { - i.assert_valid(this); - if (offset > children(i)) throw std::out_of_range("stlplus::ntree"); - } - ntree_node* new_node = new ntree_node(this,data); - if (i.end()) - { - m_root = new_node; - } - else - { - i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node); - new_node->m_parent = i.node(); - } - return ntree_iterator(new_node); - } - - template - TYPENAME ntree::iterator ntree::append(const TYPENAME ntree::iterator& i, const T& data) - throw(wrong_object,null_dereference,end_dereference) - { - return insert(i, i.node()->m_children.size(), data); - } - - template - TYPENAME ntree::iterator ntree::insert(const TYPENAME ntree::iterator& i, unsigned offset, const ntree& tree) - throw(wrong_object,null_dereference,end_dereference,std::out_of_range) - { - // insert a whole tree as a child of i - i.assert_valid(this); - if (offset > children(i)) throw std::out_of_range("stlplus::ntree"); - ntree_node* new_node = ntree_copy(this, tree.m_root); - i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node); - new_node->m_parent = i.node(); - return ntree_iterator(new_node); - } - - template - TYPENAME ntree::iterator ntree::append(const TYPENAME ntree::iterator& i, const ntree& tree) - throw(wrong_object,null_dereference,end_dereference) - { - return insert(i, children(i), tree); - } - - template - TYPENAME ntree::iterator ntree::push(const TYPENAME ntree::iterator& node, const T& data) - throw(wrong_object,null_dereference,end_dereference) - { - // insert a new node to replace the existing node in the tree - // making the original node the child of the new node - // i.e. (node) becomes (new)->(node) - // afterwards, the iterator still points to the old node, now the child - // returns the iterator to the new node - node.assert_valid(this); - ntree_node* new_node = new ntree_node(this,data); - if (node.node() == m_root) - { - // pushing the root node - m_root = new_node; - new_node->m_parent = 0; - } - else - { - // pushing a sub-node - *(std::find(node.node()->m_parent->m_children.begin(), node.node()->m_parent->m_children.end(), node.node())) = new_node; - new_node->m_parent = node.node()->m_parent; - } - // link up the old node as the child of the new node - new_node->m_children.insert(new_node->m_children.begin(),node.node()); - node.node()->m_parent = new_node; - return ntree_iterator(new_node); - } - - template - void ntree::pop(const TYPENAME ntree::iterator& parent, unsigned offset) - throw(wrong_object,null_dereference,end_dereference) - { - // inverse of push - // removes the specified child of the parent node, adding its children to the parent node at the same offset - parent.assert_valid(this); - ntree_node* node = parent.node(); - if (offset >= node->m_children.size()) throw std::out_of_range("stlplus::ntree"); - // move the grandchildren first - ntree_node* child = parent.node()->m_children[offset]; - while (!child->m_children.empty()) - { - // remove the last grandchild and insert into node just after the child to be removed - ntree_node* grandchild = child->m_children[child->m_children.size()-1]; - child->m_children.pop_back(); - node->m_children.insert(node->m_children.begin()+offset+1, grandchild); - grandchild->m_parent = node; - } - // now remove the child - node->m_children.erase(node->m_children.begin()+offset); - delete child; - } - - template - void ntree::erase(void) - { - // erase the whole tree - erase(root()); - } - - template - void ntree::erase(const TYPENAME ntree::iterator& i) - throw(wrong_object,null_dereference,end_dereference) - { - if (!i.end()) - { - // erase this node and its subtree - // do this by erasing this child of its parent - // handle the case of erasing the root - i.assert_valid(this); - ntree_node* node = i.node(); - if (node == m_root) - { - delete m_root; - m_root = 0; - } - else - { - ntree_node* parent = node->m_parent; - // impossible for parent to be null - should assert this - TYPENAME std::vector*>::iterator found = - std::find(parent->m_children.begin(), parent->m_children.end(), node); - // impossible for find to fail - should assert this - parent->m_children.erase(found); - delete node; - } - } - } - - template - void ntree::erase(const TYPENAME ntree::iterator& i, unsigned offset) - throw(wrong_object,null_dereference,end_dereference,std::out_of_range) - { - erase(child(i, offset)); - } - - template - ntree ntree::subtree(void) - { - return subtree(root()); - } - - template - ntree ntree::subtree(const TYPENAME ntree::iterator& i) - throw(wrong_object,null_dereference,end_dereference) - { - ntree result; - if (!i.end()) - { - i.assert_valid(this); - result.m_root = ntree_copy(&result, i.node()); - } - return result; - } - - template - ntree ntree::subtree(const TYPENAME ntree::iterator& i, unsigned offset) - throw(wrong_object,null_dereference,end_dereference,std::out_of_range) - { - return subtree(child(i, offset)); - } - - template - ntree ntree::cut(void) - { - return cut(root()); - } - - template - ntree ntree::cut(const TYPENAME ntree::iterator& i) - throw(wrong_object,null_dereference,end_dereference) - { - ntree result; - if (!i.end()) - { - i.assert_valid(this); - ntree_node* node = i.node(); - if (node == m_root) - { - result.m_root = m_root; - m_root = 0; - } - else - { - ntree_node* parent = node->m_parent; - // impossible for parent to be null - should assert this - TYPENAME std::vector*>::iterator found = - std::find(parent->m_children.begin(), parent->m_children.end(), node); - // impossible for find to fail - should assert this - result.m_root = *found; - parent->m_children.erase(found); - } - if (result.m_root) - { - result.m_root->m_parent = 0; - result.m_root->set_new_owner(&result); - } - } - return result; - } - - template - ntree ntree::cut(const TYPENAME ntree::iterator& i, unsigned offset) - throw(wrong_object,null_dereference,end_dereference,std::out_of_range) - { - return cut(child(i, offset)); - } - - //////////////////////////////////////////////////////////////////////////////// - -} // end namespace stlplus - +//////////////////////////////////////////////////////////////////////////////// + +// Author: Andy Rushton +// Copyright: (c) Southampton University 1999-2004 +// (c) Andy Rushton 2004-2009 +// License: BSD License, see ../docs/license.html + +//////////////////////////////////////////////////////////////////////////////// +#include +#include + +namespace stlplus +{ + + //////////////////////////////////////////////////////////////////////////////// + // ntree_node + + template + class ntree_node + { + public: + master_iterator, ntree_node > m_master; + T m_data; + ntree_node* m_parent; + std::vector*> m_children; + + public: + ntree_node(const ntree* owner, const T& data = T()) : + m_master(owner,this), m_data(data), m_parent(0) + { + } + + void change_owner(const ntree* owner) + { + m_master.change_owner(owner); + for (TYPENAME std::vector*>::iterator i = m_children.begin(); i != m_children.end(); i++) + (*i)->change_owner(owner); + } + + ~ntree_node(void) + { + m_parent = 0; + for (TYPENAME std::vector*>::iterator i = m_children.begin(); i != m_children.end(); i++) + delete *i; + } + + }; + + template + static ntree_node* ntree_copy(const ntree* new_owner, ntree_node* root) + { + if (!root) return 0; + ntree_node* new_tree = new ntree_node(new_owner, root->m_data); + for (TYPENAME std::vector*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++) + { + ntree_node* new_child = ntree_copy(new_owner, *i); + new_tree->m_children.push_back(new_child); + new_child->m_parent = new_tree; + } + return new_tree; + } + + template + static unsigned ntree_size(ntree_node* root) + { + if (!root) return 0; + unsigned result = 1; + for (TYPENAME std::vector*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++) + result += ntree_size(*i); + return result; + } + + template + static unsigned ntree_depth(ntree_node* root) + { + unsigned depth = 0; + for (ntree_node* i = root; i; i = i->m_parent) + depth++; + return depth; + } + + //////////////////////////////////////////////////////////////////////////////// + // ntree_iterator + + // constructor to create a null iterator - you must assign a valid value to this iterator before using it + template + ntree_iterator::ntree_iterator(void) + { + } + + // used to create an alias of an iterator + template + ntree_iterator::ntree_iterator(const safe_iterator, ntree_node >& iterator) : + safe_iterator,ntree_node >(iterator) + { + } + + // constructor used by ntree to create a non-null iterator + template + ntree_iterator::ntree_iterator(ntree_node* node) : + safe_iterator,ntree_node >(node->m_master) + { + } + + // constructor used by ntree to create an end iterator + template + ntree_iterator::ntree_iterator(const ntree* owner) : + safe_iterator,ntree_node >(owner) + { + } + + // destructor + template + ntree_iterator::~ntree_iterator(void) + { + } + + template + TYPENAME ntree_iterator::const_iterator ntree_iterator::constify(void) const + { + return ntree_iterator(*this); + } + + template + TYPENAME ntree_iterator::iterator ntree_iterator::deconstify(void) const + { + return ntree_iterator(*this); + } + + template + bool ntree_iterator::operator == (const TYPENAME ntree_iterator::this_iterator& r) const + { + return equal(r); + } + + template + bool ntree_iterator::operator != (const TYPENAME ntree_iterator::this_iterator& r) const + { + return !operator==(r); + } + + template + bool ntree_iterator::operator < (const TYPENAME ntree_iterator::this_iterator& r) const + { + return compare(r) < 0; + } + + template + TYPENAME ntree_iterator::reference ntree_iterator::operator*(void) const + throw(null_dereference,end_dereference) + { + this->assert_valid(); + return this->node()->m_data; + } + + template + TYPENAME ntree_iterator::pointer ntree_iterator::operator->(void) const + throw(null_dereference,end_dereference) + { + return &(operator*()); + } + + //////////////////////////////////////////////////////////////////////////////// + // ntree_prefix_iterator + + template + ntree_prefix_iterator::ntree_prefix_iterator(void) + { + } + + template + ntree_prefix_iterator::~ntree_prefix_iterator(void) + { + } + + template + ntree_prefix_iterator::ntree_prefix_iterator(const ntree_iterator& i) : + m_iterator(i) + { + // this is initialised with the root node + // which is also the first node in prefix traversal order + } + + template + bool ntree_prefix_iterator::null(void) const + { + return m_iterator.null(); + } + + template + bool ntree_prefix_iterator::end(void) const + { + return m_iterator.end(); + } + + template + bool ntree_prefix_iterator::valid(void) const + { + return m_iterator.valid(); + } + + template + TYPENAME ntree_prefix_iterator::const_iterator ntree_prefix_iterator::constify(void) const + { + return ntree_prefix_iterator(m_iterator); + } + + template + TYPENAME ntree_prefix_iterator::iterator ntree_prefix_iterator::deconstify(void) const + { + return ntree_prefix_iterator(m_iterator); + } + + template + ntree_iterator ntree_prefix_iterator::simplify(void) const + { + return m_iterator; + } + + template + bool ntree_prefix_iterator::operator == (const TYPENAME ntree_prefix_iterator::this_iterator& r) const + { + return m_iterator == r.m_iterator; + } + + template + bool ntree_prefix_iterator::operator != (const TYPENAME ntree_prefix_iterator::this_iterator& r) const + { + return m_iterator != r.m_iterator; + } + + template + bool ntree_prefix_iterator::operator < (const TYPENAME ntree_prefix_iterator::this_iterator& r) const + { + return m_iterator < r.m_iterator; + } + + template + TYPENAME ntree_prefix_iterator::this_iterator& ntree_prefix_iterator::operator ++ (void) + throw(null_dereference,end_dereference) + { + // pre-increment operator + // algorithm: if there are any children, visit child 0, otherwise, go to + // parent and deduce which child the start node was of that parent - if + // there are further children, go into the next one. Otherwise, go up the + // tree and test again for further children. Return null if there are no + // further nodes + m_iterator.assert_valid(); + ntree_node* old_node = m_iterator.node(); + if (!old_node->m_children.empty()) + { + // simply take the first child of this node + m_iterator.set(old_node->m_children[0]->m_master); + } + else + { + // this loop walks up the parent pointers + // either it will walk off the top and exit or a new node will be found and the loop will exit + for (;;) + { + // go up a level + ntree_node* parent = old_node->m_parent; + if (!parent) + { + // we've walked off the top of the tree, so return end + m_iterator.set_end(); + break; + } + else + { + // otherwise walk down the next child - if there is one + // find which index the old node was relative to this node + TYPENAME std::vector*>::iterator found = + std::find(parent->m_children.begin(), parent->m_children.end(), old_node); + // if this was found, then see if there is another and if so return that + found++; + if (found != parent->m_children.end()) + { + // visit the next child + m_iterator.set((*found)->m_master); + break; + } + else + { + // keep going up + old_node = parent; + } + } + } + } + return *this; + } + + template + TYPENAME ntree_prefix_iterator::this_iterator ntree_prefix_iterator::operator ++ (int) + throw(null_dereference,end_dereference) + { + // post-increment is defined in terms of the pre-increment + ntree_prefix_iterator result(*this); + ++(*this); + return result; + } + + template + TYPENAME ntree_prefix_iterator::reference ntree_prefix_iterator::operator*(void) const + throw(null_dereference,end_dereference) + { + return m_iterator.operator*(); + } + + template + TYPENAME ntree_prefix_iterator::pointer ntree_prefix_iterator::operator->(void) const + throw(null_dereference,end_dereference) + { + return m_iterator.operator->(); + } + + template + const ntree_iterator& ntree_prefix_iterator::get_iterator(void) const + { + return m_iterator; + } + + template + ntree_iterator& ntree_prefix_iterator::get_iterator(void) + { + return m_iterator; + } + + //////////////////////////////////////////////////////////////////////////////// + // ntree_postfix_iterator + + template + ntree_postfix_iterator::ntree_postfix_iterator(void) + { + } + + template + ntree_postfix_iterator::~ntree_postfix_iterator(void) + { + } + + template + ntree_postfix_iterator::ntree_postfix_iterator(const ntree_iterator& i) : + m_iterator(i) + { + // this is initialised with the root node + // initially traverse to the first node to be visited + if (m_iterator.valid()) + { + ntree_node* node = m_iterator.node(); + while (!node->m_children.empty()) + node = node->m_children[0]; + m_iterator.set(node->m_master); + } + } + + template + bool ntree_postfix_iterator::null(void) const + { + return m_iterator.null(); + } + + template + bool ntree_postfix_iterator::end(void) const + { + return m_iterator.end(); + } + + template + bool ntree_postfix_iterator::valid(void) const + { + return m_iterator.valid(); + } + + template + TYPENAME ntree_postfix_iterator::const_iterator ntree_postfix_iterator::constify(void) const + { + return ntree_postfix_iterator(m_iterator); + } + + template + TYPENAME ntree_postfix_iterator::iterator ntree_postfix_iterator::deconstify(void) const + { + return ntree_postfix_iterator(m_iterator); + } + + template + ntree_iterator ntree_postfix_iterator::simplify(void) const + { + return m_iterator; + } + + template + bool ntree_postfix_iterator::operator == (const TYPENAME ntree_postfix_iterator::this_iterator& r) const + { + return m_iterator == r.m_iterator; + } + + template + bool ntree_postfix_iterator::operator != (const TYPENAME ntree_postfix_iterator::this_iterator& r) const + { + return m_iterator != r.m_iterator; + } + + template + bool ntree_postfix_iterator::operator < (const TYPENAME ntree_postfix_iterator::this_iterator& r) const + { + return m_iterator < r.m_iterator; + } + + template + TYPENAME ntree_postfix_iterator::this_iterator& ntree_postfix_iterator::operator ++ (void) + throw(null_dereference,end_dereference) + { + // pre-increment operator + // algorithm: this node has been visited, therefore all children must have + // already been visited. So go to parent. Return null if the parent is null. + // Otherwise deduce which child the start node was of that parent - if there + // are further children, go into the next one and then walk down any + // subsequent first-child pointers to the bottom. Otherwise, if there are no + // children then the parent node is the next in the traversal. + m_iterator.assert_valid(); + // go up a level + ntree_node* old_node = m_iterator.node(); + ntree_node* parent = old_node->m_parent; + if (!parent) + { + // we've walked off the top of the tree, so return end + m_iterator.set_end(); + } + else + { + // otherwise find which index the old node was relative to this node + TYPENAME std::vector*>::iterator found = + std::find(parent->m_children.begin(), parent->m_children.end(), old_node); + // if this was found, then see if there is another + found++; + if (found != parent->m_children.end()) + { + // if so traverse to it and walk down the leftmost child pointers to the bottom of the new sub-tree + ntree_node* new_node = *found; + while (!new_node->m_children.empty()) + new_node = new_node->m_children[0]; + m_iterator.set(new_node->m_master); + } + else + { + // the parent's children have all been visited - so the parent is visited + m_iterator.set(parent->m_master); + } + } + return *this; + } + + template + TYPENAME ntree_postfix_iterator::this_iterator ntree_postfix_iterator::operator ++ (int) + throw(null_dereference,end_dereference) + { + // post-increment is defined in terms of the pre-increment + ntree_postfix_iterator result(*this); + ++(*this); + return result; + } + + template + TYPENAME ntree_postfix_iterator::reference ntree_postfix_iterator::operator*(void) const + throw(null_dereference,end_dereference) + { + return m_iterator.operator*(); + } + + template + TYPENAME ntree_postfix_iterator::pointer ntree_postfix_iterator::operator->(void) const + throw(null_dereference,end_dereference) + { + return m_iterator.operator->(); + } + + template + const ntree_iterator& ntree_postfix_iterator::get_iterator(void) const + { + return m_iterator; + } + + template + ntree_iterator& ntree_postfix_iterator::get_iterator(void) + { + return m_iterator; + } + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // ntree + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + template + ntree::ntree(void) : m_root(0) + { + } + + template + ntree::~ntree(void) + { + if (m_root) delete m_root; + } + + template + ntree::ntree(const ntree& r) : m_root(0) + { + *this = r; + } + + template + ntree& ntree::operator=(const ntree& r) + { + if (m_root) delete m_root; + m_root = ntree_copy(this, r.m_root); + return *this; + } + + template + bool ntree::empty(void) const + { + return m_root == 0; + } + + template + unsigned ntree::size(void) const + { + return ntree_size(m_root); + } + + template + unsigned ntree::size(const TYPENAME ntree::const_iterator& i) const + throw(wrong_object,null_dereference,end_dereference) + { + i.assert_valid(this); + return ntree_size(i.node()); + } + + template + unsigned ntree::size(const TYPENAME ntree::iterator& i) + throw(wrong_object,null_dereference,end_dereference) + { + i.assert_valid(this); + return ntree_size(i.node()); + } + + template + unsigned ntree::depth(const TYPENAME ntree::const_iterator& i) const + throw(wrong_object,null_dereference,end_dereference) + { + i.assert_valid(this); + return ntree_depth(i.node()); + } + + template + unsigned ntree::depth(const TYPENAME ntree::iterator& i) + throw(wrong_object,null_dereference,end_dereference) + { + i.assert_valid(this); + return ntree_depth(i.node()); + } + + template + TYPENAME ntree::const_iterator ntree::root(void) const + { + if (!m_root) return ntree_iterator(this); + return ntree_iterator(m_root); + } + + template + TYPENAME ntree::iterator ntree::root(void) + { + if (!m_root) return ntree_iterator(this); + return ntree_iterator(m_root); + } + + template + unsigned ntree::children(const TYPENAME ntree::const_iterator& i) const + throw(wrong_object,null_dereference,end_dereference) + { + i.assert_valid(this); + return i.node()->m_children.size(); + } + + template + unsigned ntree::children(const ntree_iterator& i) + throw(wrong_object,null_dereference,end_dereference) + { + i.assert_valid(this); + return i.node()->m_children.size(); + } + + template + TYPENAME ntree::const_iterator ntree::child(const TYPENAME ntree::const_iterator& i, unsigned child) const + throw(wrong_object,null_dereference,end_dereference,std::out_of_range) + { + i.assert_valid(this); + if (child >= children(i)) throw std::out_of_range("stlplus::ntree"); + return ntree_iterator(i.node()->m_children[child]); + } + + template + TYPENAME ntree::iterator ntree::child(const TYPENAME ntree::iterator& i, unsigned child) + throw(wrong_object,null_dereference,end_dereference,std::out_of_range) + { + i.assert_valid(this); + if (child >= children(i)) throw std::out_of_range("stlplus::ntree"); + return ntree_iterator(i.node()->m_children[child]); + } + + template + TYPENAME ntree::const_iterator ntree::parent(const TYPENAME ntree::const_iterator& i) const + throw(wrong_object,null_dereference,end_dereference) + { + i.assert_valid(this); + ntree_node* parent = i.node()->m_parent; + if (!parent) return ntree_iterator(this); + return ntree_iterator(parent); + } + + template + TYPENAME ntree::iterator ntree::parent(const TYPENAME ntree::iterator& i) + throw(wrong_object,null_dereference,end_dereference) + { + i.assert_valid(this); + ntree_node* parent = i.node()->m_parent; + if (!parent) return ntree_iterator(this); + return ntree_iterator(parent); + } + + template + TYPENAME ntree::const_prefix_iterator ntree::prefix_begin(void) const + { + return ntree_prefix_iterator(root()); + } + + template + TYPENAME ntree::prefix_iterator ntree::prefix_begin(void) + { + return ntree_prefix_iterator(root()); + } + + template + TYPENAME ntree::const_prefix_iterator ntree::prefix_end(void) const + { + return ntree_prefix_iterator(ntree_iterator(this)); + } + + template + TYPENAME ntree::prefix_iterator ntree::prefix_end(void) + { + return ntree_prefix_iterator(ntree_iterator(this)); + } + + template + TYPENAME ntree::const_postfix_iterator ntree::postfix_begin(void) const + { + return ntree_postfix_iterator(root()); + } + + template + TYPENAME ntree::postfix_iterator ntree::postfix_begin(void) + { + return ntree_postfix_iterator(root()); + } + + template + TYPENAME ntree::const_postfix_iterator ntree::postfix_end(void) const + { + return ntree_postfix_iterator(ntree_iterator(this)); + } + + template + TYPENAME ntree::postfix_iterator ntree::postfix_end(void) + { + return ntree_postfix_iterator(ntree_iterator(this)); + } + + template + TYPENAME ntree::iterator ntree::insert(const T& data) + { + // insert a new node as the root + return insert(ntree_iterator(this), 0, data); + } + + template + TYPENAME ntree::iterator ntree::insert(const TYPENAME ntree::iterator& i, unsigned offset, const T& data) + throw(wrong_object,null_dereference,end_dereference,std::out_of_range) + { + // if i is the end iterator, this means insert a new root + if (i.end()) + erase(); + else + { + i.assert_valid(this); + if (offset > children(i)) throw std::out_of_range("stlplus::ntree"); + } + ntree_node* new_node = new ntree_node(this,data); + if (i.end()) + { + m_root = new_node; + } + else + { + i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node); + new_node->m_parent = i.node(); + } + return ntree_iterator(new_node); + } + + template + TYPENAME ntree::iterator ntree::append(const TYPENAME ntree::iterator& i, const T& data) + throw(wrong_object,null_dereference,end_dereference) + { + return insert(i, i.node()->m_children.size(), data); + } + + template + TYPENAME ntree::iterator ntree::insert(const TYPENAME ntree::iterator& i, unsigned offset, const ntree& tree) + throw(wrong_object,null_dereference,end_dereference,std::out_of_range) + { + // insert a whole tree as a child of i + i.assert_valid(this); + if (offset > children(i)) throw std::out_of_range("stlplus::ntree"); + ntree_node* new_node = ntree_copy(this, tree.m_root); + i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node); + new_node->m_parent = i.node(); + return ntree_iterator(new_node); + } + + template + TYPENAME ntree::iterator ntree::append(const TYPENAME ntree::iterator& i, const ntree& tree) + throw(wrong_object,null_dereference,end_dereference) + { + return insert(i, children(i), tree); + } + + template + TYPENAME ntree::iterator ntree::push(const TYPENAME ntree::iterator& node, const T& data) + throw(wrong_object,null_dereference,end_dereference) + { + // insert a new node to replace the existing node in the tree + // making the original node the child of the new node + // i.e. (node) becomes (new)->(node) + // afterwards, the iterator still points to the old node, now the child + // returns the iterator to the new node + node.assert_valid(this); + ntree_node* new_node = new ntree_node(this,data); + if (node.node() == m_root) + { + // pushing the root node + m_root = new_node; + new_node->m_parent = 0; + } + else + { + // pushing a sub-node + *(std::find(node.node()->m_parent->m_children.begin(), node.node()->m_parent->m_children.end(), node.node())) = new_node; + new_node->m_parent = node.node()->m_parent; + } + // link up the old node as the child of the new node + new_node->m_children.insert(new_node->m_children.begin(),node.node()); + node.node()->m_parent = new_node; + return ntree_iterator(new_node); + } + + template + void ntree::pop(const TYPENAME ntree::iterator& parent, unsigned offset) + throw(wrong_object,null_dereference,end_dereference) + { + // inverse of push + // removes the specified child of the parent node, adding its children to the parent node at the same offset + parent.assert_valid(this); + ntree_node* node = parent.node(); + if (offset >= node->m_children.size()) throw std::out_of_range("stlplus::ntree"); + // move the grandchildren first + ntree_node* child = parent.node()->m_children[offset]; + while (!child->m_children.empty()) + { + // remove the last grandchild and insert into node just after the child to be removed + ntree_node* grandchild = child->m_children[child->m_children.size()-1]; + child->m_children.pop_back(); + node->m_children.insert(node->m_children.begin()+offset+1, grandchild); + grandchild->m_parent = node; + } + // now remove the child + node->m_children.erase(node->m_children.begin()+offset); + delete child; + } + + template + void ntree::erase(void) + { + // erase the whole tree + erase(root()); + } + + template + void ntree::erase(const TYPENAME ntree::iterator& i) + throw(wrong_object,null_dereference,end_dereference) + { + if (!i.end()) + { + // erase this node and its subtree + // do this by erasing this child of its parent + // handle the case of erasing the root + i.assert_valid(this); + ntree_node* node = i.node(); + if (node == m_root) + { + delete m_root; + m_root = 0; + } + else + { + ntree_node* parent = node->m_parent; + // impossible for parent to be null - should assert this + TYPENAME std::vector*>::iterator found = + std::find(parent->m_children.begin(), parent->m_children.end(), node); + // impossible for find to fail - should assert this + parent->m_children.erase(found); + delete node; + } + } + } + + template + void ntree::erase(const TYPENAME ntree::iterator& i, unsigned offset) + throw(wrong_object,null_dereference,end_dereference,std::out_of_range) + { + erase(child(i, offset)); + } + + template + ntree ntree::subtree(void) + { + return subtree(root()); + } + + template + ntree ntree::subtree(const TYPENAME ntree::iterator& i) + throw(wrong_object,null_dereference,end_dereference) + { + ntree result; + if (!i.end()) + { + i.assert_valid(this); + result.m_root = ntree_copy(&result, i.node()); + } + return result; + } + + template + ntree ntree::subtree(const TYPENAME ntree::iterator& i, unsigned offset) + throw(wrong_object,null_dereference,end_dereference,std::out_of_range) + { + return subtree(child(i, offset)); + } + + template + ntree ntree::cut(void) + { + return cut(root()); + } + + template + ntree ntree::cut(const TYPENAME ntree::iterator& i) + throw(wrong_object,null_dereference,end_dereference) + { + ntree result; + if (!i.end()) + { + i.assert_valid(this); + ntree_node* node = i.node(); + if (node == m_root) + { + result.m_root = m_root; + m_root = 0; + } + else + { + ntree_node* parent = node->m_parent; + // impossible for parent to be null - should assert this + TYPENAME std::vector*>::iterator found = + std::find(parent->m_children.begin(), parent->m_children.end(), node); + // impossible for find to fail - should assert this + result.m_root = *found; + parent->m_children.erase(found); + } + if (result.m_root) + { + result.m_root->m_parent = 0; + result.m_root->set_new_owner(&result); + } + } + return result; + } + + template + ntree ntree::cut(const TYPENAME ntree::iterator& i, unsigned offset) + throw(wrong_object,null_dereference,end_dereference,std::out_of_range) + { + return cut(child(i, offset)); + } + + //////////////////////////////////////////////////////////////////////////////// + +} // end namespace stlplus +