diff --git a/tree.cc b/tree.cc index c3b3c05..974e297 100644 --- a/tree.cc +++ b/tree.cc @@ -5,285 +5,176 @@ #include #include +// Forward declarations 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 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; + virtual LinkPtr getLink() = 0; }; -class INode { +class INode : public ILinkMixin { public: - virtual ~INode() = default; - virtual LinkPtr getLink() const = 0; - virtual LinkMixinPtr getLinkMixin() const = 0; + ~INode() override = default; + virtual const std::string& name() const = 0; + // УБРАНО: const. Этот метод используется для получения указателя, + // который может участвовать в не-константных операциях. + virtual NodePtr getSelf() = 0; }; -class LeafLink : public ILink { +class 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 {} - - std::mutex& getLock() override { return lock_; } - LinkMixinPtr getLinkMixin() const override { return node_->getLinkMixin(); } - -private: - NodePtr node_; - LinkPtr parent_; - mutable std::mutex lock_; + virtual ~ILink() = default; + virtual NodePtr getNode() const = 0; + virtual LinkPtr getParent() const = 0; + virtual void setParent(const LinkPtr& parent) = 0; + virtual const std::vector& getChildren() const = 0; + virtual void addChild(const LinkPtr& child) = 0; + virtual void removeChild(const LinkPtr& child) = 0; }; -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); } +// --- РЕАЛИЗАЦИИ LINK --- +class BaseLink : public ILink { +public: + explicit BaseLink(NodePtr node) : owner_node_(node) {} + NodePtr getNode() const override { return owner_node_.lock(); } + LinkPtr getParent() const override { return parent_.lock(); } + void setParent(const LinkPtr& parent) override { parent_ = 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 { + void removeChild(const LinkPtr& child) override { children_.erase(std::remove(children_.begin(), children_.end(), child), children_.end()); } - - std::mutex& getLock() override { return lock_; } - LinkMixinPtr getLinkMixin() const override { return node_->getLinkMixin(); } - -private: - NodePtr node_; - LinkPtr parent_; +protected: std::vector children_; - mutable std::mutex lock_; + std::weak_ptr owner_node_; + std::weak_ptr parent_; }; -class OneToOneLink : public ILink { +class LeafLink : public BaseLink { 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(); - } - } - - 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_; + using BaseLink::BaseLink; + void addChild(const LinkPtr&) override { throw std::logic_error("LeafLink cannot have children"); } }; -// Note: TypedOneToManyLink ensures type-safety on child linkage - -template -class TypedOneToManyLink : public OneToManyLink { +class OneToManyLink : public BaseLink { public: - explicit TypedOneToManyLink(NodePtr node) : OneToManyLink(std::move(node)) {} - - void addChild(LinkPtr child) override { - NodePtr n = child->getLinkMixin()->getNode(); - if (!std::dynamic_pointer_cast(n)) { - throw std::invalid_argument("TypedOneToManyLink: child is not of expected type"); - } - OneToManyLink::addChild(std::move(child)); - } + using BaseLink::BaseLink; + void addChild(const LinkPtr& child) override { children_.push_back(child); } }; -// Note: BaseLinkMixin is used for direct eager link composition (non-lazy) +// --- CRTP МИКСИН-РЕАЛИЗАЦИЯ --- -class BaseLinkMixin : public ILinkMixin { +template +class LazyLinkMixin : public INode { public: - explicit BaseLinkMixin(NodePtr self) { - link_ = std::make_shared(self); - } - - void linkChild(const NodePtr& child) override { - LinkPtr childLink = child->getLink(); + void linkChild(const NodePtr& childNode) override { + lazyInit(); + upgradeLinkIfNeeded(); + LinkPtr childLink = childNode->getLink(); childLink->setParent(link_); link_->addChild(childLink); } void unlinkParent() override { - if (!link_ || !link_->getParent()) return; - auto parent = link_->getParent(); - parent->getLinkMixin()->unlinkChild(getNode()); + lazyInit(); + LinkPtr parentLink = link_->getParent(); + if (!parentLink) return; + parentLink->removeChild(this->getLink()); link_->setParent(nullptr); + downgradeLinkIfPossible(); } - void unlinkChild(const NodePtr& child) override { - LinkPtr childLink = child->getLink(); - link_->removeChild(childLink); - childLink->setParent(nullptr); + LinkPtr getLink() override { + lazyInit(); + return link_; } - LinkPtr getLink() const override { return link_; } - NodePtr getNode() const override { return self_; } - -private: - LinkPtr link_; - NodePtr self_; -}; - -// Note: LazyLinkMixin starts with LeafLink and upgrades dynamically +protected: + // УБРАНО: const. Возвращаем неконстантный указатель. + virtual std::shared_ptr getShared() = 0; -template -class LazyLinkMixin : public ILinkMixin { -public: - explicit LazyLinkMixin(NodePtr self) : self_(self) { - link_ = std::make_shared(self); - } - - void linkChild(const NodePtr& child) override { - ensureInitialized(child); - - LinkPtr childLink = child->getLink(); - childLink->setParent(link_); - link_->addChild(childLink); + // УБРАНО: const. Соответствует базовому классу. + NodePtr getSelf() override { + return getShared(); } - void unlinkParent() override { - if (!link_ || !link_->getParent()) return; - auto parent = link_->getParent(); - parent->getLinkMixin()->unlinkChild(getNode()); - link_->setParent(nullptr); - - if (link_->getChildren().empty()) { - link_ = std::make_shared(getNode()); +private: + void lazyInit() { + if (!link_) { + link_ = std::make_shared(getSelf()); } } - - void unlinkChild(const NodePtr& child) override { - if (!link_) return; - LinkPtr childLink = child->getLink(); - link_->removeChild(childLink); - childLink->setParent(nullptr); - + void upgradeLinkIfNeeded() { + if (!std::dynamic_pointer_cast(link_)) return; + auto oldParent = link_->getParent(); + link_ = std::make_shared(getSelf()); + link_->setParent(oldParent); + } + void downgradeLinkIfPossible() { if (link_->getChildren().empty()) { - link_ = std::make_shared(getNode()); + auto oldParent = link_->getParent(); + link_ = std::make_shared(getSelf()); + link_->setParent(oldParent); } } - - LinkPtr getLink() const override { return link_; } - NodePtr getNode() const override { return self_; } - -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>(getNode()); - } else { - newLink = std::make_shared(getNode()); - } - - newLink->setParent(oldLink->getParent()); - link_ = newLink; - } - LinkPtr link_; - NodePtr self_; }; -class SimpleNode : public INode, public std::enable_shared_from_this { +// --- КОНКРЕТНЫЙ УЗЕЛ --- + +// УБРАНО: final. Теперь от класса можно наследоваться. +class SimpleNode : public LazyLinkMixin, + public std::enable_shared_from_this +{ public: - static std::shared_ptr create(std::string name) { + static NodePtr create(std::string name) { + // Теперь эта структура может легально наследоваться от SimpleNode struct EnableMakeShared : public SimpleNode { EnableMakeShared(std::string n) : SimpleNode(std::move(n)) {} }; - auto ptr = std::make_shared(std::move(name)); - ptr->initMixin(); - return ptr; + return std::make_shared(std::move(name)); } - const std::string& name() const { return name_; } - LinkPtr getLink() const override { return mixin_->getLink(); } - LinkMixinPtr getLinkMixin() const override { return mixin_; } + const std::string& name() const override { return name_; } - void linkChild(const std::shared_ptr& child) { mixin_->linkChild(child); } - void unlinkParent() { mixin_->unlinkParent(); } +protected: + // УБРАНО: const. Теперь возвращается неконстантный shared_ptr, как и ожидается. + std::shared_ptr getShared() override { + return shared_from_this(); + } private: + friend struct std::enable_shared_from_this; + friend class LazyLinkMixin; 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) { +// --- УТИЛИТА ДЛЯ ВЫВОДА --- + +void printTree(const NodePtr& startNode, int indent = 0) { + if (!startNode) return; for (int i = 0; i < indent; ++i) std::cout << " "; - auto node = link->getLinkMixin()->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); + std::cout << startNode->name() << "\n"; + LinkPtr nodeLink = startNode->getLink(); + for (const auto& childLink : nodeLink->getChildren()) { + printTree(childLink->getNode(), indent + 1); } } +// --- MAIN --- + int main() { auto root = SimpleNode::create("Root"); auto child1 = SimpleNode::create("Child1"); @@ -295,12 +186,12 @@ int main() { auto subchild = SimpleNode::create("SubChild"); child1->linkChild(subchild); - printTree(root->getLink()); + printTree(root); - std::cout << "\nUnlinking Child2...\n"; - child2->unlinkParent(); + std::cout << "\nUnlinking Child1...\n"; + child1->unlinkParent(); - printTree(root->getLink()); + printTree(root); return 0; }