// This file is under GNU General Public License 3.0 // see LICENSE.txt #ifndef PITYTEST_PITYTREE_HXX #define PITYTEST_PITYTREE_HXX #include "PityTree.hh" #include #include 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; _copyChildRefs(rhs); } template PityTree& PityTree::operator=(const PityTree& rhs) { _nodename = rhs._nodename; _parent = nullptr; _copyChildRefs(rhs); return *this; } template template CT& PityTree::addNew(Args&&... args) { static_assert(std::is_base_of::value, "T must be base of CT"); std::shared_ptr tmp = std::make_shared(std::forward(args)...); _childobjs.push_back(tmp); addRef(*tmp.get()); return *tmp.get(); } template template CT& PityTree::addCopy(const CT&& child, const std::string& new_name) { static_assert(std::is_base_of::value, "PityTree must be a base of T"); CT* tmpraw = new CT(child); _childobjs.push_back(ChildObj(tmpraw)); if (new_name != "") { tmpraw->setName(new_name); } addRef(*tmpraw); return *tmpraw; } template T& PityTree::addRef(T& child) { child.setParent(&_self); _childrefs.insert(ChildRef(child.getName(), child)); return child; } 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::_copyChildRefs(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