From d00bb90a38cd5cf5f7b1e938fdff7088fe6ab92f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=9C=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D0=BD=D0=BA=D0=B5=D0=B2=D0=B8=D1=87?= Date: Tue, 5 Aug 2025 19:30:21 +0700 Subject: [PATCH] blah --- include/ifaces/ILinkMixin.h | 2 + include/links/BaseLink.h | 2 +- include/links/NotImplementedLink.h | 2 +- include/mixins/BaseLinkMixin.h | 20 ++++++++- include/mixins/FabricMixin.h | 11 +++++ include/mixins/HierarchicalLinkMixin.h | 6 +-- include/mixins/LazyLinkMixin.h | 5 +-- include/nodes/BaseNode.h | 5 +-- include/nodes/ComplexNode.h | 13 +++--- include/nodes/SimpleNode.h | 11 +++-- src/main.cpp | 62 +++++++++++++++++--------- 11 files changed, 96 insertions(+), 43 deletions(-) create mode 100644 include/mixins/FabricMixin.h diff --git a/include/ifaces/ILinkMixin.h b/include/ifaces/ILinkMixin.h index db07e52..9396d44 100644 --- a/include/ifaces/ILinkMixin.h +++ b/include/ifaces/ILinkMixin.h @@ -11,6 +11,8 @@ public: using ElemPtr = std::shared_ptr; virtual ~ILinkMixin() = default; + virtual operator std::shared_ptr() = 0; + virtual operator TElem&() = 0; virtual void linkChild(const ElemPtr& child) = 0; virtual void unlinkParent() = 0; virtual const std::vector& children() = 0; diff --git a/include/links/BaseLink.h b/include/links/BaseLink.h index 2f9bfce..d6c04f5 100644 --- a/include/links/BaseLink.h +++ b/include/links/BaseLink.h @@ -34,7 +34,7 @@ public: } ~BaseLink() override { - Logger::get("Link").dbg("--- Destructor called for: BaseLink"); + Logger::get("ConDes").dbg("--- Destructor called for: BaseLink"); } protected: std::vector children_; diff --git a/include/links/NotImplementedLink.h b/include/links/NotImplementedLink.h index f7d9549..43b848a 100644 --- a/include/links/NotImplementedLink.h +++ b/include/links/NotImplementedLink.h @@ -20,7 +20,7 @@ public: void removeChild(const ElemPtr& child) override { } ~NotImplementedLink() override { - Logger::get("Link").dbg("--- Destructor called for: NotImplementedLink"); + Logger::get("ConDes").dbg("--- Destructor called for: NotImplementedLink"); } private: std::vector empty_; diff --git a/include/mixins/BaseLinkMixin.h b/include/mixins/BaseLinkMixin.h index 8abc174..5f6f50c 100644 --- a/include/mixins/BaseLinkMixin.h +++ b/include/mixins/BaseLinkMixin.h @@ -14,7 +14,15 @@ class BaseLinkMixin : public virtual ILinkMixin, public: ~BaseLinkMixin() override { - Logger::get("Mixin").dbg("--- Destructor called for: BaseLinkMixin"); + Logger::get("ConDes").dbg("--- Destructor called for: BaseLinkMixin"); + } + + operator std::shared_ptr() override { + return this->getNode(); + } + + operator INode&() override { + return static_cast(*this); } void linkChild(const ElemPtr& child) override { @@ -33,7 +41,15 @@ public: auto parentLink = parent->getLink(); - parentLink->removeChild(getNode()); + /* NOTE: + * + * Keep a reference to the node we gonna to unlink. + * Otherwise, we'll disappear between `removeChild` and + * `setParent`. Do not rearrange these calls, because + * we want to modify the tree top down. + */ + auto node = getNode(); + parentLink->removeChild(node); getLink()->setParent(nullptr); } diff --git a/include/mixins/FabricMixin.h b/include/mixins/FabricMixin.h new file mode 100644 index 0000000..4dc078d --- /dev/null +++ b/include/mixins/FabricMixin.h @@ -0,0 +1,11 @@ +#pragma once +#include + +template +class FabricMixin { +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr(new T(std::forward(args)...)); + } +}; diff --git a/include/mixins/HierarchicalLinkMixin.h b/include/mixins/HierarchicalLinkMixin.h index 07c84a1..e2b3c9a 100644 --- a/include/mixins/HierarchicalLinkMixin.h +++ b/include/mixins/HierarchicalLinkMixin.h @@ -16,7 +16,7 @@ class HierarchicalLinkMixin : public LazyLinkMixin> { public: ~HierarchicalLinkMixin() override { - Logger::get("Mixin").dbg("--- Destructor called for: HierarchicalLinkMixin"); + Logger::get("ConDes").dbg("--- Destructor called for: HierarchicalLinkMixin"); } void linkChild(const ElemPtr& child) override { @@ -34,10 +34,10 @@ protected: if (typeid(*child) == typeid(*this)) { Logger::get("Mixin").dbg("--- Mutate to OneToMany"); - newLink = std::make_shared>(this->getNode()); + newLink = std::make_shared>(*this); } else { Logger::get("Mixin").dbg("--- Mutate to OneToOne"); - newLink = std::make_shared>(this->getNode()); + newLink = std::make_shared>(*this); } if (newLink && this->link_) diff --git a/include/mixins/LazyLinkMixin.h b/include/mixins/LazyLinkMixin.h index 3186da5..e58e3da 100644 --- a/include/mixins/LazyLinkMixin.h +++ b/include/mixins/LazyLinkMixin.h @@ -25,14 +25,13 @@ public: LazyLinkMixin() {} ~LazyLinkMixin() override { - Logger::get("Mixin").dbg("--- Destructor called for: LazyLinkMixin"); + Logger::get("ConDes").info("--- Destructor called for: LazyLinkMixin"); } protected: void lazyInit() { if (!link_) { - link_ = std::make_shared( - BaseLinkMixin::getNode()); + link_ = std::make_shared(*this); } } LinkPtr link_; diff --git a/include/nodes/BaseNode.h b/include/nodes/BaseNode.h index 0eae52d..1882ff9 100644 --- a/include/nodes/BaseNode.h +++ b/include/nodes/BaseNode.h @@ -1,5 +1,4 @@ #pragma once -#include #include "ifaces/INode.h" #include "Logger.h" @@ -9,12 +8,12 @@ class BaseNode : public virtual INode { public: BaseNode(std::string name) : name_(std::move(name)) { - Logger::get("Node").dbg(std::string("--- Base constructor called for: ") + name_); + Logger::get("ConDes").dbg(std::string("--- Base constructor called for: ") + name_); } const std::string& name() const override { return name_; } const std::string& kind() const override { return kind_; } ~BaseNode() { - Logger::get("Node").dbg(std::string("--- Base destructor called for: ") + name_); + Logger::get("ConDes").info(std::string("--- Base destructor called for: ") + name_); } protected: std::string name_; diff --git a/include/nodes/ComplexNode.h b/include/nodes/ComplexNode.h index f611332..f36f3c9 100644 --- a/include/nodes/ComplexNode.h +++ b/include/nodes/ComplexNode.h @@ -1,19 +1,22 @@ #pragma once -#include #include "nodes/BaseNode.h" #include "mixins/HierarchicalLinkMixin.h" +#include "mixins/FabricMixin.h" #include "Logger.h" /// \brief Класс сложного (составного) узла дерева. -/// Может содержать несколько дочерних ComplexNode и один SimpleNode. +/// Может содержать несколько дочерних ComplexNode или один SimpleNode. class ComplexNode : public BaseNode, - virtual public HierarchicalLinkMixin { + virtual public HierarchicalLinkMixin, + public FabricMixin { public: ~ComplexNode() { - Logger::get("Node").dbg(std::string("--- Complex destructor called for: ") + name_); + Logger::get("ConDes").dbg(std::string("--- Complex destructor called for: ") + name_); } +private: + friend class FabricMixin; ComplexNode(std::string name) : BaseNode(std::move(name)) { - Logger::get("Node").dbg(std::string("--- Complex constructor called for: ") + name_); + Logger::get("ConDes").dbg(std::string("--- Complex constructor called for: ") + name_); } }; diff --git a/include/nodes/SimpleNode.h b/include/nodes/SimpleNode.h index 8f920b0..221d9a0 100644 --- a/include/nodes/SimpleNode.h +++ b/include/nodes/SimpleNode.h @@ -1,20 +1,23 @@ #pragma once -#include #include "nodes/BaseNode.h" #include "mixins/LazyLinkMixin.h" +#include "mixins/FabricMixin.h" #include "links/OneToOneLink.h" #include "Logger.h" /// \brief Класс простого (листового) узла дерева. /// Может содержать только одного дочернего ComplexNode. class SimpleNode : public BaseNode, - virtual public LazyLinkMixin> { + virtual public LazyLinkMixin>, + public FabricMixin { public: ~SimpleNode() { - Logger::get("Node").dbg(std::string("--- Simple destructor called for: ") + name_); + Logger::get("ConDes").dbg(std::string("--- Simple destructor called for: ") + name_); } +private: + friend class FabricMixin; SimpleNode(std::string name) : BaseNode(std::move(name)) { - Logger::get("Node").dbg(std::string("--- Simple constructor called for: ") + name_); + Logger::get("ConDes").dbg(std::string("--- Simple constructor called for: ") + name_); } }; diff --git a/src/main.cpp b/src/main.cpp index b8c12ec..2feb4e3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,12 +31,16 @@ int main() { Logger::suppressCategory("Node"); Logger::suppressCategory("Link"); Logger::suppressCategory("Mixin"); + + Logger::suppressCategory("ConDes"); + Logger::setMinSeverity("ConDes", Logger::Severity::Info); + auto& logger = Logger::get("MAIN"); logger.info("Entering main scope..."); { - auto root = std::make_shared("ComplexRoot"); - auto child1 = std::make_shared("ComplexChild1"); + auto root = ComplexNode::create("ComplexRoot"); + auto child1 = ComplexNode::create("ComplexChild1"); root->linkChild(child1); @@ -45,23 +49,21 @@ int main() { std::cout << "\n"; { - auto child2 = std::make_shared("ComplexChild2"); + auto child2 = ComplexNode::create("ComplexChild2"); root->linkChild(child2); - auto subchild2 = std::make_shared("SimpleSubChild2"); + auto subchild2 = SimpleNode::create("SimpleSubChild2"); child2->linkChild(subchild2); - auto child3 = std::make_shared("ComplexChild3"); + auto child3 = ComplexNode::create("ComplexChild3"); root->linkChild(child3); - auto subchild3 = std::make_shared("SimpleSubChild3"); - child3->linkChild(subchild3); + child3->linkChild(SimpleNode::create("SimpleSubChild3")); { // Негативный сценарий 1: попытка добавить второй SimpleNode к ComplexNode try { - auto anotherSimple = std::make_shared("ShouldFail"); - child2->linkChild(anotherSimple); + child2->linkChild(SimpleNode::create("ShouldFail")); logger.err("[ERROR] Не должно было получиться добавить второй SimpleNode к ComplexNode!"); } catch (const std::logic_error& e) { logger.warn(std::string("[Ожидаемое исключение] ") + e.what()); @@ -69,14 +71,12 @@ int main() { // Негативный сценарий 2: попытка добавить ComplexNode к SimpleNode // Это допустимо: SimpleNode может иметь ComplexNode в качестве единственного ребёнка - auto goodComplex = std::make_shared("GoodComplex"); - subchild2->linkChild(goodComplex); + subchild2->linkChild(ComplexNode::create("GoodComplex")); logger.info("[OK] ComplexNode успешно добавлен к SimpleNode как единственный ребёнок."); // Негативный сценарий: попытка добавить второго ребёнка к SimpleNode try { - auto anotherSimple = std::make_shared("ShouldFail2"); - subchild2->linkChild(anotherSimple); + subchild2->linkChild(SimpleNode::create("ShouldFail2")); logger.err("[ERROR] Не должно было получиться добавить второго ребёнка к SimpleNode!"); } catch (const std::logic_error& e) { logger.warn(std::string("[Ожидаемое исключение] ") + e.what()); @@ -84,8 +84,7 @@ int main() { // Негативный сценарий: попытка добавить SimpleNode в ComplexNode, который уже содержит несколько ComplexNode-дочерних try { - auto badSimple = std::make_shared("BadSimple"); - root->linkChild(badSimple); + root->linkChild(SimpleNode::create("BadSimple")); logger.err("[ERROR] Не должно было получиться добавить SimpleNode в ComplexNode с несколькими ComplexNode-дочерними!"); } catch (const std::logic_error& e) { logger.warn(std::string("[Ожидаемое исключение] ") + e.what()); @@ -120,16 +119,36 @@ int main() { logger.info("Unlinking ComplexChild1 and ComplexChild3...\n"); child1->unlinkParent(); - for (auto child : root->getLink()->getChildren()) { - NodePtr childNode = std::dynamic_pointer_cast(child); - if (childNode->name() == "ComplexChild3") { - childNode->unlinkParent(); + for (auto child : traversal::BFS(root)) { + if (child->name() == "ComplexChild3") { + /* Avoid of disconnecting a node of the tree + * we're traversing. Method holds reference + * to it's object itself. But iterator ignores + * smart pointers, feeling free to dereference + * the destroyed object. + */ +#if 1 + /* Keep in mind to keep your reference until + * the cycle ends, if you want more than just + * remove subtree. + */ + NodePtr node = *child; + node->unlinkParent(); + std::cout << "Unlinked: " + << node->name() << std::endl; break; +#else + /* Otherwise, just break immediately you + * unlinked a node. The current pointer is not + * a valid pointer anymore. + */ + child->unlinkParent(); + break; +#endif } } - auto child4 = std::make_shared("SimpleChild4"); - root->linkChild(child4); + root->linkChild(SimpleNode::create("SimpleChild4")); std::cout << "\nTree flush and link SimpleChild4:\n"; printTreeLadder(*root); @@ -137,6 +156,7 @@ int main() { } logger.info("Exited main scope. All smart pointers destroyed."); + logger.info("(It don't? Check ConDes logger)"); return 0; }