From 45be1fe12769291437b7b08e65a2d578660587b8 Mon Sep 17 00:00:00 2001 From: heck Date: Thu, 8 Jul 2021 02:44:40 +0200 Subject: [PATCH] Test: PityTree - RValue refs, copy constructor, addRef/addCopy/addNew Tree can now own or reference nodes, mixed. --- src/PityTree.hh | 28 +++++++++++++++---- src/PityTree.hxx | 71 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/PityTree.hh b/src/PityTree.hh index 380bf59..9478c7f 100644 --- a/src/PityTree.hh +++ b/src/PityTree.hh @@ -17,17 +17,32 @@ namespace pEp { template class PityTree { // TODO: NEEEEED THIS -// static_assert(std::is_base_of, T>::value, "PityTree must be a base of T"); + // static_assert(std::is_base_of, T>::value, "PityTree must be a base of T"); public: - using Children = std::map; + using ChildObj = std::shared_ptr; + using ChildObjs = std::vector; + using ChildRef = std::pair; + using ChildRefs = std::map; + // Constructors explicit PityTree(T& self, const std::string& name); explicit PityTree(T& self, const std::string& name, T& parent); + explicit PityTree(const PityTree& rhs, T& owner); - T& add(T& node); + virtual PityTree* clone() = 0; + // Append + T& addRef(T& node); + + template + T& addNew(Args&&... args); + + template + T& addCopy(const CT&& t, const std::string& new_name = ""); + + // Query T* getParent() const; - Children getChildren() const; + ChildRefs getChildRefs() const; T& getChild(const std::string& name); T& getRoot(); @@ -50,8 +65,9 @@ namespace pEp { // Fields std::string _nodename; T& _self; - T* _parent = nullptr; //nullptr if RootUnit - Children _children; // map to guarantee uniqueness of sibling-names + T* _parent; //nullptr if RootUnit + ChildRefs _childrefs; // map to guarantee uniqueness of sibling-names + ChildObjs _childobjs; }; }; // namespace PityTest11 }; // namespace pEp diff --git a/src/PityTree.hxx b/src/PityTree.hxx index 464e60a..fdef8f4 100644 --- a/src/PityTree.hxx +++ b/src/PityTree.hxx @@ -15,32 +15,77 @@ #include #include #include +#include "PityTree.hh" namespace pEp { namespace PityTest11 { + // RootNode template PityTree::PityTree(T& self, const std::string& name) : - _self{ self }, _nodename{ _normalizeName(name) } + _self{ self }, _parent{ nullptr }, _nodename{ _normalizeName(name) }, _childrefs{}, + _childobjs{} { } + // LeafNode template PityTree::PityTree(T& self, const std::string& name, T& parent) : - _self(self), _nodename{ _normalizeName(name) } + _self(self), _parent{ nullptr }, _nodename{ _normalizeName(name) }, _childrefs{}, + _childobjs{} { - parent.add(_self); + parent.addRef(_self); } + // Copy template - T& PityTree::add(T& node) + PityTree::PityTree(const PityTree& rhs, T& owner) : _self{ owner } + { + _nodename = rhs._nodename; + _parent = nullptr; + + for (const ChildRef& cr : rhs.getChildRefs()) { + _childobjs.push_back(ChildObj(cr.second.clone())); + T& ret = *_childobjs.back().get(); + addRef(ret); + } + } + + template + T& PityTree::addRef(T& node) { node.setParent(&_self); - _children.insert(std::pair(node.getName(), node)); + _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) { @@ -99,9 +144,9 @@ namespace pEp { ret = builder.str(); if (recursive) { - if (!getChildren().empty()) { + if (!getChildRefs().empty()) { indent++; - for (auto child : getChildren()) { + for (ChildRef child : getChildRefs()) { ret += child.second.to_string(true, indent); } indent--; @@ -121,15 +166,21 @@ namespace pEp { } template - typename PityTree::Children PityTree::getChildren() const + typename PityTree::ChildRefs PityTree::getChildRefs() const { - return _children; + return _childrefs; } template T& PityTree::getChild(const std::string& name) { - return _children.at(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)