#ifndef MNODE_H #define MNODE_H ///////////////////////////////////////////////////////////////// // MNode.h - Node helper for M-ary Tree data structure // // // // Application: Help for CSE687 Pr#2, Spring 2015 // // Platform: Dell XPS 2720, Win 8.1 Pro, Visual Studio 2013 // // Author: Jim Fawcett, CST 4-187, 443-3948 // // jfawcett@twcny.rr.com // ///////////////////////////////////////////////////////////////// /* * Package Operations: * ------------------- * This package contains classes MTree and MNode. * MTree is an M-ary tree, e.g., each MNode has zero or more * children. Note that this is not a balanced binary tree. No * order is imposed on the children of any node. They simply appear * in the order they were added. * * M-ary trees are often used to represent parse trees where the * ordering of nodes depends on the structure of the entity being * represented, e.g., source code, XML, or HTML. * * MTree's nodes are members of class MNode. each MNode * holds a vector of std::shared_prt's to it's children, if any. * the value of the template parameter T represents what each node * of the tree holds, e.g., a string representing a grammatical * constructor, or XML or HTML element. * * Required Files: * --------------- * - MTree.h and MTree.cpp * * Build Process: * -------------- * devenv MTree.sln /debug rebuild * * Maintenance History: * -------------------- * This is a complete redesign of an earlier MTree class that uses * C++11 constructs, most noteably std::shared_ptr. * * Ver 1 : 4 Feb 15 * - first release * */ #include #include #include #include #include "../Utilities/Utilities.h" ///////////////////////////////////////////////////////////////////////////// // MNode class template class MNode { public: using sPtr = std::shared_ptr < MNode > ; using Children = std::vector ; using iterator = typename Children::iterator; MNode(); MNode(const T& t); MNode(const MNode& node); MNode(MNode&& node); MNode& operator=(const MNode& node); MNode& operator=(MNode&& node); sPtr clone() const; virtual ~MNode(); T& value(); T value() const; std::string& id(); std::string id() const; bool addChild(sPtr pChild); // fails if already has parent void addChild(const T& t); // makes new node so has no parent std::vector nodeChildren(); size_t size() const; // note iterator points to std::shared_ptr>, e.g., a pointer to a pointer iterator begin(); iterator end(); // note indexers return std::shared_ptr> sPtr& operator[](size_t n); const sPtr& operator[](size_t n) const; sPtr findById(const std::string& id); std::vector findByValue(const T& t); private: void MNode::cloneHelper(const MNode& src, sPtr& dst) const; void MNode::findByValueHelper(sPtr ptr, const T& t); void MNode::findByIdHelper(sPtr ptr, const std::string& id); Children children_; T value_; std::string id_; // MTree expects all its nodes to have unique ids or empty ids bool hasParent = false; // set to true when added to a node's children_ collection std::vector foundValues_; sPtr foundId_; }; //----< default constructor >------------------------------------------------ template MNode::MNode() : value_("default"), hasParent(false) { mtLog << std::string("\n constructing default MNode"); } //----< promotion constructor taking value >--------------------------------- template MNode::MNode(const T& t) : value_(t), hasParent(false) { mtLog << std::string("\n constructing MNode(T)"); } //----< copy constructor >--------------------------------------------------- template MNode::MNode(const MNode& node) : value_(node.value_), hasParent(false) { mtLog << std::string("copy construction from ") << node.value_; for (auto pChild : node.children_) children_.push_back(pChild->clone()); } //----< move constructor >--------------------------------------------------- template MNode::MNode(MNode&& node) : value_(node.value_), hasParent(false) { mtLog << std::string("\n move construction from ") << value_; children_ = std::move(node.children_); // causes children_.swap() node.value_ = T(); } //----< destructor just used to enunciate >---------------------------------- template MNode::~MNode() { mtLog << std::string("\n deleting ") << value(); } //----< access children collection >----------------------------------------- template std::vector>> MNode::nodeChildren() { return children_; } //----< copy assignment operator >------------------------------------------- template MNode& MNode::operator=(const MNode& node) { mtLog << std::string("\n copy assignment from ") << node.value_; if (this == &node) return *this; // don't change hasParent value_ = node.value_; children_ = node.children_; return *this; } //----< move assignment operator >------------------------------------------- template MNode& MNode::operator=(MNode&& node) { mtLog << std::string("\n move assignment from ") << node.value_; if (this == &node) return *this; // don't change hasParent value_ = node.value_; children_ = std::move(node.children_); return *this; } //----< get iterator pointing to std::shared_ptr to first child >------------ template typename MNode::iterator MNode::begin() { return children_.begin(); } //----< get iterator pointing to std::shared_ptr to one past last child >---- template typename MNode::iterator MNode::end() { return children_.end(); } //----< index through std::shared_ptrs to children >------------------------- template std::shared_ptr>& MNode::operator[](size_t n) { if (size() <= n) throw(std::invalid_argument("index out of range")); return children_[n]; } //----< index through std::shared_ptrs to children >------------------------- template const std::shared_ptr>& MNode::operator[](size_t n) const { if (size() <= n) throw(std::invalid_argument("index out of range")); return children_[n]; } //----< retrieve or set id >------------------------------------------------- template std::string& MNode::id() { return id_; } //----< retrieve id >-------------------------------------------------------- template std::string MNode::id() const { return id_; } //----< retrieve or set value >---------------------------------------------- template T& MNode::value() { return value_; } //----< retrieve value >----------------------------------------------------- template T MNode::value() const { return value_; } //----< private helper function for clone >---------------------------------- template void MNode::cloneHelper(const MNode& src, sPtr& dst) const { for (auto& pChild : src.children_) { sPtr pdstChild(new MNode(pChild->value())); dst->addChild(pdstChild); cloneHelper(*pChild, pdstChild); } } //----< return clone of self >----------------------------------------------- template std::shared_ptr> MNode::clone() const { mtLog << std::string("\n cloning ") << value_; auto pReplica = sPtr(new MNode(this->value())); cloneHelper(*this, pReplica); return pReplica; } //----< add child std::shared_ptr to existing node >------------------------- /* * Each node of tree must have only one parent (otherwise not a tree), * so add child only if child has no other parent. */ template bool MNode::addChild(sPtr pChild) { mtLog << std::string("\n adding existing child ") << pChild->value_ << std::string(" to ") << value_; if (!pChild->hasParent) { pChild->hasParent = true; children_.push_back(pChild); return true; } return false; } //----< add child std::shared_ptr to new node with specified value >--------- template void MNode::addChild(const T& t) { mtLog << std::string("\n adding new child ") << t << std::string(" to ") << value_; std::shared_ptr> pToAdd(new MNode(t)); pToAdd->hasParent = true; children_.push_back(pToAdd); } //----< return number of children >------------------------------------------ template size_t MNode::size() const { return children_.size(); } //----< make new MNode with specified value >----------------------------- template std::shared_ptr> makeNode(const T& t) { return std::shared_ptr>(new MNode(t)); } //----< global function to display contents of MNode >-------------------- template void show(MNode& node) { std::cout << "\n " << node.value(); for (auto& pChild : node) show(*pChild); } //----< Depth First Search with pluggable operation >------------------------ /* * apply callable object f on every node of tree during depth first search */ template void DFS(MNode& node, std::function&)>& f) { f(node); for (auto& pChild : node) DFS(*pChild, f); } //----< search children for id >--------------------------------------------- template void MNode::findByIdHelper(sPtr ptr, const std::string& id) { if(foundId_ != nullptr) return; if (ptr->id() == id) foundId_ = ptr; else { for (auto pChild : ptr->children_) findByIdHelper(pChild, id); } } //----< search children for id >--------------------------------------------- template std::shared_ptr> MNode::findById(const std::string& id) { foundId_ = nullptr; for (auto pChild : children_) { findByIdHelper(pChild, id); } return foundId_; // will be nullptr if not found } //----< search children for value >------------------------------------------ template void MNode::findByValueHelper(sPtr ptr, const T& value) { if (ptr->value() == value) foundValues_.push_back(ptr); for (auto pChild : ptr->children_) findByValueHelper(pChild, value); } //----< search children for value >------------------------------------------ template std::vector>> MNode::findByValue(const T& value) { for(auto pChild : children_) findByValueHelper(pChild, value); std::vector>> temp = std::move(foundValues_); return temp; } #endif