libtree/include/Tree/tree.hpp

466 lines
13 KiB
C++

#ifndef __TREE_BASENODE_HPP__
#define __TREE_BASENODE_HPP__
/**
* @file
* @brief header file for the libtree++ library
* @author Dominik Meyer <dmeyer@hsu-hh.de>
* @date 2019-03-03
* @copyright 2019 GPLv2 by Dominik Meyer
*/
/*
Copyright (C) 2019 Dominik Meyer
This program 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.
This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <memory>
#include <string>
#include <list>
#include <algorithm>
#include <iostream>
/**
* @brief main namespace for the libtree++ library
*/
namespace Tree
{
/**
* @brief base node for all nodes within the tree, implementing base tree methods
*/
class BaseNode : public std::enable_shared_from_this<Tree::BaseNode>
{
private:
/// the parent node of a node ;)
std::shared_ptr<Tree::BaseNode> parent;
/// all child nodes of a node
std::list<std::shared_ptr<Tree::BaseNode>> children;
virtual std::shared_ptr<Tree::BaseNode> clone_() const = 0;
public:
/**
* @brief clear the node of parent and children, but do not delete the children, required for cloning
*
*/
void clear() {
children.clear();
parent=nullptr;
};
/**
* @brief get the root of the tree
*
*/
std::shared_ptr<Tree::BaseNode> getRoot() const
{
if (parent==nullptr)
{
return std::const_pointer_cast<Tree::BaseNode>(shared_from_this());
}
return parent->getRoot();
}
/**
* @brief method to deep clone this node
*
* @return pointer to the cloned object
*/
std::shared_ptr<Tree::BaseNode> clone() const
{
std::shared_ptr<Tree::BaseNode> node = clone_();
node->clear();
std::list<std::shared_ptr<Tree::BaseNode>>::const_iterator it;
for(it = children.begin(); it != children.end(); ++it)
{
node->addChild((*it)->clone());
}
return node;
}
/**
* @brief print the tree starting with the current node to stdout
*
* @param depth - used for indenting the tree
*/
void printTree(const uint32_t depth);
/**
* @brief print the tree starting with the current node to stdout
*
* just calls printTree(0)
*/
void printTree() { printTree(0); }
/**
* @brief returns a string representing this node
*
* this method has to be implemented by all nodes extending this class
*
* @return std::string representing this node
*/
virtual const std::string toString() const = 0;
/**
* @brief returns the type of this node as a string
*
* this method has to be implemented by all nodes extending this class
*
* @return std::string representing the type of this node
*/
virtual const std::string type() const = 0;
/**
* @brief returns the base of this node as a string
*
* this method has to be implemented by all nodes extending this class
*
* a base is some kind of way to group nodes belonging to a certain topic
*
* @return std::string representing the type of this node
*/
virtual const std::string base() const = 0;
/**
* @brief return the parent node of the node
*
* @return nullptr - no parent is set, therefore, it should be a root node
* @return a std::shared_ptr to the the parent node
*/
const std::shared_ptr<Tree::BaseNode> getParent() const { return parent;}
/**
* @brief set the parent node of this node
*
* @param p - the parent node as a shared_ptr
*/
void setParent(const std::shared_ptr<Tree::BaseNode> &p) {parent=p;}
/**
* @brief returns an iterator to the beginning of the list of children
*
* @return iterator to the beginning of the list of children
*/
std::list<std::shared_ptr<Tree::BaseNode>>::const_iterator getChildrenBegin() const {return children.begin();}
/**
* @brief returns an iterator to the end of the list of children
*
* @return iterator to the end of the list of children
*/
std::list<std::shared_ptr<Tree::BaseNode>>::const_iterator getChildrenEnd() const {return children.end();}
/**
* @brief returns the nr of direct children
*
* @return the nr of direct children
*/
const unsigned int getNrDirectChildren() const { return children.size(); }
/**
* @brief returns the nr of all children
*
* @return the nr of all children
*/
const unsigned int getNrChildren() const;
/**
* @brief get the iterator of the given child
*
* @param child - the childnode to find the iterator for
* @return - the const iterator for the given child
*/
std::list<std::shared_ptr<Tree::BaseNode>>::const_iterator getChildIterator(const std::shared_ptr<const Tree::BaseNode> child) const;
/**
* @brief deletes all the children and their children and ... from the tree
*/
void deleteChildren();
/**
* @brief deletes the given node and all its children
*
* @param c - the node to delete
*
*/
void deleteChild(const std::shared_ptr<Tree::BaseNode> &c);
/**
* @brief remove the given node from the children of the node
*
* remove is not delete. The node gets just disconnected from the tree
*
* @param c - the node to remove from the nodes list of children
*
*/
void removeChild(const std::shared_ptr<const Tree::BaseNode> &c);
/**
* @brief adds a child to the node which is already a shared_ptr
*
* @param c - a shared_ptr to a BaseNode
*/
void addChild(const std::shared_ptr<Tree::BaseNode> &c) {
if (c!=nullptr)
{
c->setParent(shared_from_this());
children.push_back(c);
}
}
/**
* @brief prepends a child to the node which is already a shared_ptr
*
* @param c - a shared_ptr to a BaseNode
*/
void prependChild(const std::shared_ptr<Tree::BaseNode> &c) {c->setParent(shared_from_this()); children.push_front(c); }
/**
* @brief adds a container of nodes to the list of children
*
* @param begin - iterator to the beginning of the container of objects of type std::shared_ptr<Tree::BaseNode>
* @param end - iterator to the end of the container of objects of type std::shared_ptr<Tree::BaseNode>
*/
template <typename Iter>
void addChildren(Iter begin, Iter end) { std::copy( begin, end, std::back_inserter( children ) );}
/**
* @brief prepends a container of nodes to the list of children
*
* @param begin - iterator to the beginning of the container of objects of type std::shared_ptr<Tree::BaseNode>
* @param end - iterator to the end of the container of objects of type std::shared_ptr<Tree::BaseNode>
*/
template <typename Iter>
void prependChildren(Iter begin, Iter end) { std::copy( begin, end, std::front_inserter( children ) );}
/**
* @brief inserts a child before the given iterator which is already a shared_ptr
*
* @param c - a shared_ptr to a BaseNode
* @param it - the iterator before which to insert the node
*/
void insertChild(const std::shared_ptr<Tree::BaseNode> &c, std::list<std::shared_ptr<Tree::BaseNode>>::const_iterator it) {c->setParent(shared_from_this());children.insert(it,c);}
/**
* @brief finds the next node in the tree of a given type
*
* @param t - the type of the node as a string
*
* @return nullptr - a node of that type could not be found
* @return the found node as a shared_ptr
*/
std::shared_ptr<const Tree::BaseNode> findNext(const std::string &t) const;
/**
* @brief finds all nodes of a given type
*
* @param t - the type of the node as a string
* @param c - a container for holding all found nodes, has to be holding objects of type std::shared_ptr<Tree::BaseNode>
*/
template <typename Container>
void findAll(const std::string &t, Container &c) const
{
std::list<std::shared_ptr<Tree::BaseNode>>::const_iterator it;
if (type() == t)
{
c.push_back(std::const_pointer_cast<Tree::BaseNode>(shared_from_this()));
}
for(it = children.begin(); it != children.end(); ++it)
{
(*it)->findAll(t,c);
}
}
/**
* @brief finds all nodes of a given base
*
* @param b - the base type of the node as a string
* @param c - a container for holding all found nodes, has to be holding objects of type std::shared_ptr<Tree::BaseNode>
*/
template <class Container>
void findAllBase(const std::string &b, Container &c) const
{
std::list<std::shared_ptr<Tree::BaseNode>>::const_iterator it;
if (base() == b)
{
c.push_back(std::const_pointer_cast<Tree::BaseNode>(shared_from_this()));
}
for(it = children.begin(); it != children.end(); ++it)
{
(*it)->findAllBase(b,c);
}
}
/**
* @brief checks if the given node is a direct child of this node
*
* @param n - shared_ptr of the node to check
*
* @return true - the node is a direct child
* @return false - the node is not a direct child
*/
const bool isDirectChild(std::shared_ptr<Tree::BaseNode> &n) const;
/**
* @brief checks if the given node is a child of this node
*
* @param n - shared_ptr of the node to check
*
* @return true - the node is a child
* @return false - the node is not a child
*/
const bool isChild(std::shared_ptr<Tree::BaseNode> &n) const;
/**
* @brief replaces this node within the tree with the given one
*
* this means moving all children to the given node and setting all of their parents
* to the new node
*
* @param n - the new node to replace the current one with
*/
void replace(std::shared_ptr<Tree::BaseNode> n);
/**
* @brief overriding the to string operator
*
* used to convert the object on the fly to a string
*
* @return a string representing this object
*/
operator std::string() const { return toString(); }
};
/**
* @brief stream operator override
*
* make it possible to use nodes within output streams
*
* @param Str - the output stream to stream to ;)
* @param v - the node which should be streamed to Str
*
* @return the outstream returned
*/
inline std::ostream & operator<<(std::ostream & Str, const Tree::BaseNode &v) {
Str << v.toString();
return Str;
}
/*
* Some basic Node Types
*/
/**
* @brief class representing the Root of a Tree
*/
class TreeRoot : public Tree::BaseNode
{
private:
virtual std::shared_ptr<Tree::BaseNode> clone_() const {return std::make_shared<Tree::TreeRoot>();};
public:
/**
* @brief returns the type of this node as a string
*
* this method has to be implemented by all nodes extending this class
*
* @return std::string representing the type of this node
*/
const std::string type() const { return "Tree::TreeRoot";}
/**
* @brief returns the base of this node as a string
*
* this method has to be implemented by all nodes extending this class
*
* a base is some kind of way to group nodes belonging to a certain topic
*
* @return std::string representing the type of this node
*/
const std::string base() const { return "Tree::Base";}
/**
* @brief returns a string representing this node
*
* this method has to be implemented by all nodes extending this class
*
* @return std::string representing this node
*/
virtual const std::string toString() const { return type();};
};
/**
* @brief class representing a temporary node within the tree
*/
class TempNode : public Tree::BaseNode
{
private:
virtual std::shared_ptr<Tree::BaseNode> clone_() const {return std::make_shared<Tree::TempNode>();};
public:
/**
* @brief returns the type of this node as a string
*
* this method has to be implemented by all nodes extending this class
*
* @return std::string representing the type of this node
*/
const std::string type() const { return "Tree::TempNode";}
/**
* @brief returns the base of this node as a string
*
* this method has to be implemented by all nodes extending this class
*
* a base is some kind of way to group nodes belonging to a certain topic
*
* @return std::string representing the type of this node
*/
const std::string base() const { return "Tree::Base";}
/**
* @brief returns a string representing this node
*
* this method has to be implemented by all nodes extending this class
*
* @return std::string representing this node
*/
virtual const std::string toString() const { return type();};
};
}; // namespace Tree
#endif