ADD: initial source commit

This commit is contained in:
Dominik Meyer 2019-04-03 21:21:22 +02:00
parent 1059be2ab2
commit 30ccb2e695
No known key found for this signature in database
GPG Key ID: B4C312B600606B64
6 changed files with 707 additions and 0 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
build build
release release
debug debug
src/config.hpp

75
CMakeLists.txt Normal file
View File

@ -0,0 +1,75 @@
cmake_minimum_required (VERSION 3.1 FATAL_ERROR)
project (libtree++ VERSION 0.1.0 LANGUAGES CXX)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)
include(GNUInstallDirs)
enable_testing()
#cmake options for the project
option(DOXYGEN "Also build the doxygen documentation" OFF)
# set the required c++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(CTest)
find_package(Git)
INCLUDE(ProcessDOXYGEN)
INCLUDE(ProcessGIT)
INCLUDE(add_my_test)
IF(CMAKE_BUILD_TYPE MATCHES DEBUG)
set(DEBUG 1)
ENDIF(CMAKE_BUILD_TYPE MATCHES DEBUG)
configure_file(${PROJECT_SOURCE_DIR}/src/config.hpp.in ${PROJECT_SOURCE_DIR}/src/config.hpp @ONLY)
set(generated "${PROJECT_SOURCE_DIR}/src/config.hpp")
add_custom_target(clean-generated COMMAND rm -f ${generated})
add_library(tree STATIC
src/config.hpp
include/Tree/tree.hpp
src/Tree/tree.cpp
)
target_include_directories(tree PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE src
)
IF(CMAKE_BUILD_TYPE MATCHES DEBUG)
target_compile_options(tree PUBLIC -Wall -g -O0 )
ELSE()
target_compile_options(tree PUBLIC -O4)
target_compile_options(tree PUBLIC -O4)
ENDIF()
#
# Everything TEST related
#
add_my_test(TEST test_base
SOURCES tests/test_base.cpp
LIBS tree
)
add_my_test(TEST test_add_child
SOURCES tests/test_add_child.cpp
LIBS tree
)
get_property(_mytests GLOBAL PROPERTY _mytests)
FOREACH( _test ${_mytests})
IF(CMAKE_BUILD_TYPE MATCHES DEBUG)
target_compile_options(${_test} PUBLIC -Wall -g -O0)
ELSE()
target_compile_options(${_test} PUBLIC -O4)
ENDIF()
ENDFOREACH()

352
include/Tree/tree.hpp Normal file
View File

@ -0,0 +1,352 @@
#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>
/**
* @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;
public:
/**
* @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>>::iterator getChildrenBegin() {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>>::iterator getChildrenEnd() {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 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<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) {c->setParent(shared_from_this()); children.push_back(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 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<Tree::BaseNode> findNext(const std::string &t);
/**
* @brief finds all nodes of a given type
*
* @param type - 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 &type, Container &c);
/**
* @brief finds all nodes of a given base
*
* @param base - 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 <typename Container>
void findAllBase(const std::string &base, Container &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
{
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
{
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

117
src/Tree/tree.cpp Normal file
View File

@ -0,0 +1,117 @@
/*
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 <iostream>
#include <iomanip>
#include <Tree/tree.hpp>
std::shared_ptr<Tree::BaseNode> Tree::BaseNode::findNext(const std::string &t)
{
std::list<std::shared_ptr<Tree::BaseNode>>::iterator childIT;
std::shared_ptr<Tree::BaseNode> temp;
if (type() == t )
{
return shared_from_this();
}
for(childIT=children.begin(); childIT != children.end(); ++childIT)
{
temp=(*childIT)->findNext(t);
if (temp != nullptr)
{
return temp;
}
}
return nullptr;
}
/*
* return the number of children
*/
const unsigned int Tree::BaseNode::getNrChildren() const
{
std::list<std::shared_ptr<Tree::BaseNode>>::const_iterator childIT;
unsigned int nr=children.size();
for(childIT=children.begin(); childIT != children.end(); ++childIT)
{
nr += (*childIT)->getNrChildren();
}
return nr;
}
/*
* print the tree and indent according to depth
*/
void Tree::BaseNode::printTree(const uint32_t depth)
{
for (uint32_t i=0; i< depth; i++)
{
std::cout << " ";
}
std::cout << toString() << std::endl;
std::list<std::shared_ptr<Tree::BaseNode>>::iterator childIT;
for(childIT=getChildrenBegin(); childIT != getChildrenEnd(); ++childIT)
{
(*childIT)->printTree(depth+1);
}
}
void Tree::BaseNode::removeChild(const std::shared_ptr<Tree::BaseNode> &c)
{
std::list<std::shared_ptr<Tree::BaseNode>>::iterator it;
it=std::find(children.begin(), children.end(),c);
children.erase(it);
}
void Tree::BaseNode::deleteChild(const std::shared_ptr<Tree::BaseNode> &c)
{
std::list<std::shared_ptr<Tree::BaseNode>>::iterator it;
it=std::find(children.begin(), children.end(),c);
children.erase(it);
c->setParent(nullptr);
}
/*
* delete all children
*/
void Tree::BaseNode::deleteChildren()
{
std::list<std::shared_ptr<Tree::BaseNode>>::iterator it;
for(it=children.begin(); it!=children.end(); ++it)
{
if ((*it) != nullptr )
{
deleteChild((*it));
}
}
}

114
tests/test_add_child.cpp Normal file
View File

@ -0,0 +1,114 @@
/*
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 <iostream>
#include <memory>
#include <string>
#include <vector>
#include <Tree/tree.hpp>
#include <cstdint>
int main()
{
bool error=false;
std::vector<std::shared_ptr<Tree::TempNode>> nodes;
// create a root node of the tree
std::shared_ptr<Tree::TreeRoot> t=std::make_shared<Tree::TreeRoot>();
// create one child
std::shared_ptr<Tree::TempNode> temp0=std::make_shared<Tree::TempNode>();
// add child to tree
t->addChild(temp0);
if (t->getNrDirectChildren() != 1 || t->getNrChildren()!=1)
{
error=true;
std::cerr << std::string(__FILE__) + ":" + std::to_string(__LINE__) + " NR of children do not match added children" << std::endl;
}
// create another child
std::shared_ptr<Tree::TempNode> temp1=std::make_shared<Tree::TempNode>();
// add child to tree
temp0->addChild(temp1);
if (t->getNrDirectChildren() != 1 || t->getNrChildren()!=2 || temp0->getNrDirectChildren()!=1 || temp0->getNrChildren() != 1)
{
error=true;
std::cerr << std::string(__FILE__) + ":" + std::to_string(__LINE__) + " NR of children do not match added children" << std::endl;
}
// remove a node from the list of children of root node
t->removeChild(temp0);
if (t->getNrDirectChildren() != 0 || t->getNrChildren()!= 0 || temp0->getNrDirectChildren()!=1 || temp0->getNrChildren() != 1)
{
error=true;
std::cerr << std::string(__FILE__) + ":" + std::to_string(__LINE__) + " NR of children do not match added children" << std::endl;
}
// readd the removed node
t->addChild(temp0);
if (t->getNrDirectChildren() != 1 || t->getNrChildren()!=2 || temp0->getNrDirectChildren()!=1 || temp0->getNrChildren() != 1)
{
error=true;
std::cerr << std::string(__FILE__) + ":" + std::to_string(__LINE__) + " NR of children do not match added children" << std::endl;
}
// delete Child
temp0->getParent()->deleteChild(temp0);
if (t->getNrDirectChildren() != 0 || t->getNrChildren()!=0 )
{
error=true;
std::cerr << std::string(__FILE__) + ":" + std::to_string(__LINE__) + " NR of children do not match added children" << std::endl;
}
// add a bunch of children
for(int i=0; i<20; i++)
{
std::shared_ptr<Tree::TempNode> temp0=std::make_shared<Tree::TempNode>();
nodes.push_back(temp0);
}
t->addChildren(nodes.begin(), nodes.end());
if (t->getNrDirectChildren() != 20 || t->getNrChildren()!=20 )
{
error=true;
std::cerr << std::string(__FILE__) + ":" + std::to_string(__LINE__) + " NR of children do not match added children" << std::endl;
}
std::cout << "--------------" << std::endl;
t->printTree();
std::cout << "--------------" << std::endl;
if (error)
{
std::cerr << "Test failed" << std::endl;
return -1;
}
std::cerr << "Test OK" << std::endl;
return 0;
}

48
tests/test_base.cpp Normal file
View File

@ -0,0 +1,48 @@
#include <iostream>
#include <memory>
#include <Tree/tree.hpp>
int main()
{
bool error=false;
std::shared_ptr<Tree::TreeRoot> t=std::make_shared<Tree::TreeRoot>();
// first test if the parent node is a nullptr for root node
if ( t->getParent() != nullptr )
{
std::cerr << "Failed Test: Root node parent is not null" << std::endl;
error=true;
}
/*
* create a temp node and add to root
*/
std::shared_ptr<Tree::TempNode> temp0=std::make_shared<Tree::TempNode>();
t->addChild(temp0);
// check if the parent node of temp0 has been set correctly
if (temp0->getParent() != t)
{
std::cerr << "Failed Test: temp0 node parent is null" << std::endl;
error=true;
}
// check if the number of direct children of t is 1
if (t->getNrDirectChildren() != 1)
{
std::cerr << "Failed Test: nr of direct children is not 1" << std::endl;
error=true;
}
if (error)
{
return -1;
}
std::cerr << "Test OK" << std::endl;
return 0;
}