//////////////////////////////////////////////////////////////////////////////// // 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