From b9cf6623d1703ea5f5084d11d88e1095ed8fed71 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: Mon, 21 Jul 2025 15:52:36 +0700 Subject: [PATCH] init --- tree.cc | 308 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 tree.cc diff --git a/tree.cc b/tree.cc new file mode 100644 index 0000000..7a198f2 --- /dev/null +++ b/tree.cc @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +#include +#include + +class INode; +class ILink; +class ILinkMixin; + +using NodePtr = std::shared_ptr; +using LinkPtr = std::shared_ptr; +using LinkMixinPtr = std::shared_ptr; + +class ILink { +public: + virtual ~ILink() = default; + + virtual LinkPtr getParent() const = 0; + virtual void setParent(LinkPtr parent) = 0; + + virtual const std::vector& getChildren() const = 0; + virtual void addChild(LinkPtr child) = 0; + virtual void removeChild(LinkPtr child) = 0; + + virtual NodePtr getNode() const = 0; + virtual std::mutex& getLock() = 0; + virtual LinkMixinPtr getLinkMixin() const = 0; +}; + +class ILinkMixin { +public: + virtual ~ILinkMixin() = default; + virtual void linkChild(const NodePtr& child) = 0; + virtual void unlinkParent() = 0; + virtual void unlinkChild(const NodePtr& child) = 0; + virtual LinkPtr getLink() const = 0; + virtual NodePtr getNode() const = 0; +}; + +class INode { +public: + virtual ~INode() = default; + virtual LinkPtr getLink() const = 0; + virtual LinkMixinPtr getLinkMixin() const = 0; +}; + +class LeafLink : public ILink { +public: + explicit LeafLink(NodePtr node) : node_(std::move(node)) {} + + LinkPtr getParent() const override { return parent_; } + void setParent(LinkPtr parent) override { parent_ = std::move(parent); } + + const std::vector& getChildren() const override { + static std::vector empty; + return empty; + } + + void addChild(LinkPtr) override { + throw std::logic_error("LeafLink cannot have children"); + } + + void removeChild(LinkPtr) override {} + + NodePtr getNode() const override { return node_; } + std::mutex& getLock() override { return lock_; } + LinkMixinPtr getLinkMixin() const override { return node_->getLinkMixin(); } + +private: + NodePtr node_; + LinkPtr parent_; + mutable std::mutex lock_; +}; + +class OneToManyLink : public ILink { +public: + explicit OneToManyLink(NodePtr node) : node_(std::move(node)) {} + + LinkPtr getParent() const override { return parent_; } + void setParent(LinkPtr parent) override { parent_ = std::move(parent); } + + const std::vector& getChildren() const override { return children_; } + + void addChild(LinkPtr child) override { children_.push_back(std::move(child)); } + + void removeChild(LinkPtr child) override { + children_.erase(std::remove(children_.begin(), children_.end(), child), children_.end()); + } + + NodePtr getNode() const override { return node_; } + std::mutex& getLock() override { return lock_; } + LinkMixinPtr getLinkMixin() const override { return node_->getLinkMixin(); } + +private: + NodePtr node_; + LinkPtr parent_; + std::vector children_; + mutable std::mutex lock_; +}; + +class OneToOneLink : public ILink { +public: + explicit OneToOneLink(NodePtr node) : node_(std::move(node)) {} + + LinkPtr getParent() const override { return parent_; } + void setParent(LinkPtr parent) override { parent_ = std::move(parent); } + + const std::vector& getChildren() const override { return singleChildVec_; } + + void addChild(LinkPtr child) override { + if (!singleChildVec_.empty()) { + throw std::logic_error("OneToOneLink already has a child"); + } + singleChildVec_.push_back(std::move(child)); + } + + void removeChild(LinkPtr child) override { + if (!singleChildVec_.empty() && singleChildVec_.front() == child) { + singleChildVec_.clear(); + } + } + + NodePtr getNode() const override { return node_; } + std::mutex& getLock() override { return lock_; } + LinkMixinPtr getLinkMixin() const override { return node_->getLinkMixin(); } + +private: + NodePtr node_; + LinkPtr parent_; + std::vector singleChildVec_; + mutable std::mutex lock_; +}; + +// Типизированная связь один ко многим +template +class TypedOneToManyLink : public OneToManyLink { +public: + explicit TypedOneToManyLink(NodePtr node) : OneToManyLink(std::move(node)) {} + + void addChild(LinkPtr child) override { + NodePtr n = child->getNode(); + if (!std::dynamic_pointer_cast(n)) { + throw std::invalid_argument("TypedOneToManyLink: child is not of expected type"); + } + OneToManyLink::addChild(std::move(child)); + } +}; + +// Базовая реализация LinkMixin +class BaseLinkMixin : public ILinkMixin { +public: + explicit BaseLinkMixin(NodePtr self) { + link_ = std::make_shared(self); + } + + void linkChild(const NodePtr& child) override { + LinkPtr childLink = child->getLink(); + childLink->setParent(link_); + link_->addChild(childLink); + } + + void unlinkParent() override { + if (!link_ || !link_->getParent()) return; + auto parent = link_->getParent(); + parent->getLinkMixin()->unlinkChild(link_->getNode()); + link_->setParent(nullptr); + } + + void unlinkChild(const NodePtr& child) override { + LinkPtr childLink = child->getLink(); + link_->removeChild(childLink); + childLink->setParent(nullptr); + } + + LinkPtr getLink() const override { return link_; } + NodePtr getNode() const override { return link_->getNode(); } + +protected: + LinkPtr link_; +}; + +// Ленивый LinkMixin с выбором стратегии по типу +template +class LazyLinkMixin : public ILinkMixin { +public: + explicit LazyLinkMixin(NodePtr self) { + link_ = std::make_shared(self); + } + + void linkChild(const NodePtr& child) override { + ensureInitialized(child); + + LinkPtr childLink = child->getLink(); + childLink->setParent(link_); + link_->addChild(childLink); + } + + void unlinkParent() override { + if (!link_ || !link_->getParent()) return; + auto parent = link_->getParent(); + parent->getLinkMixin()->unlinkChild(link_->getNode()); + link_->setParent(nullptr); + + if (link_->getChildren().empty()) { + link_ = std::make_shared(link_->getNode()); + } + } + + void unlinkChild(const NodePtr& child) override { + if (!link_) return; + LinkPtr childLink = child->getLink(); + link_->removeChild(childLink); + childLink->setParent(nullptr); + + if (link_->getChildren().empty()) { + link_ = std::make_shared(link_->getNode()); + } + } + + LinkPtr getLink() const override { return link_; } + NodePtr getNode() const override { return link_->getNode(); } + +private: + void ensureInitialized(const NodePtr& child) { + if (link_ && !std::dynamic_pointer_cast(link_)) return; + + LinkPtr oldLink = link_; + LinkPtr newLink; + + if (std::dynamic_pointer_cast(child)) { + newLink = std::make_shared>(oldLink->getNode()); + } else { + newLink = std::make_shared(oldLink->getNode()); + } + + newLink->setParent(oldLink->getParent()); + link_ = newLink; + } + + LinkPtr link_; +}; + +// Пример узла +class SimpleNode : public INode, public std::enable_shared_from_this { +public: + static std::shared_ptr create(std::string name) { + struct EnableMakeShared : public SimpleNode { + EnableMakeShared(std::string n) : SimpleNode(std::move(n)) {} + }; + auto ptr = std::make_shared(std::move(name)); + ptr->initMixin(); + return ptr; + } + + const std::string& name() const { return name_; } + LinkPtr getLink() const override { return mixin_->getLink(); } + LinkMixinPtr getLinkMixin() const override { return mixin_; } + + void linkChild(const std::shared_ptr& child) { mixin_->linkChild(child); } + void unlinkParent() { mixin_->unlinkParent(); } + +private: + explicit SimpleNode(std::string name) : name_(std::move(name)) {} + + void initMixin() { + mixin_ = std::make_shared>(shared_from_this()); + } + + std::string name_; + LinkMixinPtr mixin_; +}; + +// Пример использования +void printTree(const LinkPtr& link, int indent = 0) { + for (int i = 0; i < indent; ++i) std::cout << " "; + auto node = link->getNode(); + auto simpleNode = std::dynamic_pointer_cast(node); + if (simpleNode) { + std::cout << simpleNode->name() << "\n"; + } + for (const auto& child : link->getChildren()) { + printTree(child, indent + 1); + } +} + +int main() { + auto root = SimpleNode::create("Root"); + auto child1 = SimpleNode::create("Child1"); + auto child2 = SimpleNode::create("Child2"); + + root->linkChild(child1); + root->linkChild(child2); + + auto subchild = SimpleNode::create("SubChild"); + child1->linkChild(subchild); + + printTree(root->getLink()); + + std::cout << "\nUnlinking Child2...\n"; + child2->unlinkParent(); + + printTree(root->getLink()); + + return 0; +}