// This file is under GNU General Public License 3.0 // see LICENSE.txt #ifndef PITYTEST_PITYTREE_HXX #define PITYTEST_PITYTREE_HXX #include #include #include #include #include #include #include #include #include #include #include #include "PityTree.hh" namespace pEp { namespace PityTest11 { // RootNode template PityTree::PityTree(T& self, const std::string& name) : _self{ self }, _parent{ nullptr }, _nodename{ _normalizeName(name) }, _childrefs{}, _childobjs{} { } // LeafNode template PityTree::PityTree(T& self, const std::string& name, T& parent) : _self(self), _parent{ nullptr }, _nodename{ _normalizeName(name) }, _childrefs{}, _childobjs{} { parent.addRef(_self); } // Copy template PityTree::PityTree(const PityTree& rhs, T& owner) : _self{ owner } { _nodename = rhs._nodename; _parent = nullptr; _cloneChildRefs(rhs); } template PityTree& PityTree::operator=(const PityTree& rhs) { _nodename = rhs._nodename; _parent = nullptr; _cloneChildRefs(rhs); return *this; } template T& PityTree::addRef(T& node) { node.setParent(&_self); _childrefs.insert(ChildRef(node.getName(), node)); return node; } template template T& PityTree::addNew(Args&&... args) { _childobjs.push_back(ChildObj(new T(std::forward(args)...))); T& ret = *_childobjs.back().get(); addRef(ret); return ret; } template template T& PityTree::addCopy(const CT&& t, const std::string& new_name) { static_assert(std::is_base_of::value, "PityTree must be a base of T"); _childobjs.push_back(ChildObj(new CT(t))); T& ret = *_childobjs.back().get(); if (new_name != "") { ret.setName(new_name); } addRef(ret); return ret; } template void PityTree::setParent(T* parent) { _parent = parent; } template T* PityTree::getParent() const { return _parent; } template bool PityTree::isRoot() const { if (_parent == nullptr) { return true; } else { return false; } } template void PityTree::setName(const std::string& name) { _nodename = name; } template std::string PityTree::getName() const { return _nodename; } template std::string PityTree::getPath() const { std::string ret; if (!isRoot()) { ret = _parent->getPath() + "/" + getName(); } else { ret = getName(); } return ret; } template std::string PityTree::to_string(bool recursive, int indent) { std::string ret; std::stringstream builder; builder << std::string(indent * 4, ' '); builder << getName(); builder << std::endl; ret = builder.str(); if (recursive) { if (!getChildRefs().empty()) { indent++; for (ChildRef child : getChildRefs()) { ret += child.second.to_string(true, indent); } indent--; } } return ret; } template T& PityTree::getRoot() { if (!isRoot()) { return _parent->getRoot(); } else { return _self; } } template typename PityTree::ChildRefs PityTree::getChildRefs() const { return _childrefs; } template T& PityTree::getChild(const std::string& name) { T* ret = nullptr; try { ret = &getChildRefs().at(name); } catch (const std::exception& e) { throw std::invalid_argument("PityNode not found: '" + name + "'"); } return *ret; } // name is alphanumeric only (everything else will be replaced by an underscore) // static template std::string PityTree::_normalizeName(std::string name) { replace_if( name.begin(), name.end(), [](char c) -> bool { return !isalnum(c); }, '_'); return name; } // When you copy a treenode, you need to create a copy of all children // and take ownership template void PityTree::_cloneChildRefs(const PityTree& rhs) { for (const ChildRef& cr : rhs.getChildRefs()) { _childobjs.push_back(ChildObj(cr.second.clone())); T& ret = *_childobjs.back().get(); addRef(ret); } } } // namespace PityTest11 } // namespace pEp #endif