From b46b8615fa1b3d1a37d28e6f5ee58ddd242c797f Mon Sep 17 00:00:00 2001 From: Xeno Snow Fox Date: Sat, 29 Aug 2026 12:11:42 +1000 Subject: [PATCH 1/5] Refactor XML nodes; add NodeContainer Rename and reorganize XML node classes and add a container node type. - Rename XmlDeclarationTag -> DeclarationNode and XmlTextContent -> TextNode. - Remove legacy XmlTagNode and add TagNode (now inherits NodeContainer). - Introduce NodeContainer (new) to own children, serialize them, and prevent cycles when appending. - Extend INode with parent tracking (getParent/setParent) and make NodeContainer a friend. - Add NodeType::CONTAINER. - Provide operator<< overloads for appending/serialization and keep XML escaping/validation logic. These changes centralize child-management, simplify cycle detection, and standardize naming. --- ...DeclarationTag.hpp => DeclarationNode.hpp} | 4 +- include/xtrpg/xml/node/INode.hpp | 24 +++- include/xtrpg/xml/node/NodeContainer.hpp | 92 +++++++++++++ include/xtrpg/xml/node/NodeType.hpp | 2 +- include/xtrpg/xml/node/TagNode.hpp | 79 +++++++++++ .../node/{XmlTextContent.hpp => TextNode.hpp} | 11 +- include/xtrpg/xml/node/XmlTagNode.hpp | 130 ------------------ 7 files changed, 202 insertions(+), 140 deletions(-) rename include/xtrpg/xml/node/{XmlDeclarationTag.hpp => DeclarationNode.hpp} (95%) create mode 100644 include/xtrpg/xml/node/NodeContainer.hpp create mode 100644 include/xtrpg/xml/node/TagNode.hpp rename include/xtrpg/xml/node/{XmlTextContent.hpp => TextNode.hpp} (87%) delete mode 100644 include/xtrpg/xml/node/XmlTagNode.hpp diff --git a/include/xtrpg/xml/node/XmlDeclarationTag.hpp b/include/xtrpg/xml/node/DeclarationNode.hpp similarity index 95% rename from include/xtrpg/xml/node/XmlDeclarationTag.hpp rename to include/xtrpg/xml/node/DeclarationNode.hpp index ca8f4d0..60dad55 100644 --- a/include/xtrpg/xml/node/XmlDeclarationTag.hpp +++ b/include/xtrpg/xml/node/DeclarationNode.hpp @@ -13,12 +13,12 @@ namespace xtrpg::xml::node { /** * Represents an XML declaration node with a tag name and attributes. */ -class XmlDeclarationTag : public INode, public ITagname, public IAttributes { +class DeclarationNode : public INode, public ITagname, public IAttributes { public: /** * Constructs an XML declaration. */ - explicit XmlDeclarationTag(std::string tagname) + explicit DeclarationNode(std::string tagname) : INode(NodeType::DECLARATION), ITagname(std::move(tagname)), IAttributes() { if (this->getTagname() != "xml") { diff --git a/include/xtrpg/xml/node/INode.hpp b/include/xtrpg/xml/node/INode.hpp index 6016f69..4166d98 100644 --- a/include/xtrpg/xml/node/INode.hpp +++ b/include/xtrpg/xml/node/INode.hpp @@ -5,10 +5,15 @@ namespace xtrpg::xml::node { +// Forward declaration +class NodeContainer; + /** * Defines the common interface and node type metadata for XML nodes. */ class INode { + friend class NodeContainer; + public: /** * Constructor that takes in a node type. @@ -30,10 +35,27 @@ class INode { */ NodeType getNodeType() const { return this->_type; }; + /** + * Checks if this node is of the specified type. + */ bool isType(NodeType type) const { return this->_type == type; } + /** + * Returns the parent NodeContainer of this node, or nullptr if this is a + * root node. + */ + class NodeContainer *getParent() const { return this->_parent; } + +protected: + /** + * Sets the parent NodeContainer for this node. + * Called by NodeContainer when appending children. + */ + void setParent(class NodeContainer *parent) { this->_parent = parent; } + private: NodeType _type; + class NodeContainer *_parent = nullptr; }; /** @@ -44,4 +66,4 @@ inline std::ostream &operator<<(std::ostream &os, const INode &node) { return os; } -} // namespace xtrpg::xml \ No newline at end of file +} // namespace xtrpg::xml::node \ No newline at end of file diff --git a/include/xtrpg/xml/node/NodeContainer.hpp b/include/xtrpg/xml/node/NodeContainer.hpp new file mode 100644 index 0000000..66bfd3a --- /dev/null +++ b/include/xtrpg/xml/node/NodeContainer.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include +#include + +#include "xtrpg/xml/node/INode.hpp" +#include "xtrpg/xml/node/NodeType.hpp" +#include "xtrpg/xml/node/TextNode.hpp" + +namespace xtrpg::xml::node { + +/** + * A node design to be a container of other nodes. + */ +class NodeContainer : public INode { +public: + NodeContainer() : INode(NodeType::CONTAINER) {}; + + explicit NodeContainer(NodeType type) : INode(type) {}; + + ~NodeContainer() {} + + /** + * Appends a given child node. + * + * @throws std::invalid_argument if appending would create a cycle. + */ + void append(std::shared_ptr child) { + if (child) { + // Check if this node is already an ancestor of child by walking up + // the parent chain. This is O(depth) instead of O(n). + for (NodeContainer *ancestor = child->getParent(); ancestor != nullptr; + ancestor = ancestor->getParent()) { + if (ancestor == this) { + throw std::invalid_argument("Cannot create a cycle in XML nodes"); + } + } + // Set this node as the child's parent and append + child->setParent(this); + this->_children.push_back(std::move(child)); + } + } + + /** + * Returns a vector of child nodes. + */ + const std::vector> &children() const { + return this->_children; + } + + /** + * Checks whether this node has any child nodes. + * + * @return true if this node contains at least one child, false otherwise. + */ + [[nodiscard]] constexpr bool hasChildren() const noexcept { + return !this->_children.empty(); + } + + /** + * Serializes all child nodes into the provided output stream. + */ + void serialize(std::ostream &os) const override { + for (const auto &child : this->_children) { + child->serialize(os); + } + } + +private: + std::vector> _children; +}; + +/** + * Stream operator overload for easy serialization + */ +inline NodeContainer &operator<<(NodeContainer &node, + std::shared_ptr child) { + node.append(std::move(child)); + return node; +} + +/** + * Stream operator overload for easy serialization, appends a new Text Node + * child containing the provided text. + */ +inline NodeContainer &operator<<(NodeContainer &node, + const std::string &withText) { + auto textNode = std::make_shared(withText); + node.append(textNode); + return node; +} +} // namespace xtrpg::xml::node \ No newline at end of file diff --git a/include/xtrpg/xml/node/NodeType.hpp b/include/xtrpg/xml/node/NodeType.hpp index 00755c7..8c139ca 100644 --- a/include/xtrpg/xml/node/NodeType.hpp +++ b/include/xtrpg/xml/node/NodeType.hpp @@ -5,6 +5,6 @@ namespace xtrpg::xml::node { /** * Identifies the supported XML node categories. */ -enum class NodeType { TAG, DECLARATION, TEXT_CONTENT }; +enum class NodeType { TAG, DECLARATION, TEXT_CONTENT, CONTAINER }; } // namespace xtrpg::xml::node \ No newline at end of file diff --git a/include/xtrpg/xml/node/TagNode.hpp b/include/xtrpg/xml/node/TagNode.hpp new file mode 100644 index 0000000..3af6583 --- /dev/null +++ b/include/xtrpg/xml/node/TagNode.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xtrpg/xml/node/IAttributes.hpp" +#include "xtrpg/xml/node/INode.hpp" +#include "xtrpg/xml/node/ITagname.hpp" +#include "xtrpg/xml/node/NodeContainer.hpp" +#include "xtrpg/xml/node/NodeType.hpp" +#include "xtrpg/xml/node/TextNode.hpp" + +namespace xtrpg::xml::node { + +/** + * Represents an XML element with a tag name, attributes, and child nodes. + */ +class TagNode : public INode, + public ITagname, + public IAttributes, + public NodeContainer { +public: + /** + * Inline constructor that accepts a tag name. + */ + explicit TagNode(std::string name) + : INode(NodeType::TAG), ITagname(name), IAttributes(), NodeContainer() {} + + /** + * Returns a reference to the name of the tag. + */ + const std::string_view name() const { return this->getTagname(); } + + /** + * Serializes the node into an XML formatted string. + */ + void serialize(std::ostream &os) const override { + os << "<" << this->getTagname(); + + IAttributes::serialize(os); + + if (!this->hasChildren()) { + os << "/>"; + return; + } + + os << ">"; + NodeContainer::serialize(os); + os << "getTagname() << ">"; + } + +private: +}; +/** + * Stream operator overload for easy serialization + */ +inline TagNode &operator<<(TagNode &node, std::shared_ptr child) { + node.append(std::move(child)); + return node; +} + +/** + * Stream operator overload for easy serialization, appends a new Text Node + * child containing the provided text. + */ +inline TagNode &operator<<(TagNode &node, const std::string &withText) { + auto textNode = std::make_shared(withText); + node.append(textNode); + return node; +} +} // namespace xtrpg::xml::node \ No newline at end of file diff --git a/include/xtrpg/xml/node/XmlTextContent.hpp b/include/xtrpg/xml/node/TextNode.hpp similarity index 87% rename from include/xtrpg/xml/node/XmlTextContent.hpp rename to include/xtrpg/xml/node/TextNode.hpp index d5dc6dc..5d459e3 100644 --- a/include/xtrpg/xml/node/XmlTextContent.hpp +++ b/include/xtrpg/xml/node/TextNode.hpp @@ -13,18 +13,18 @@ namespace xtrpg::xml::node { /** * Represents text content within an XML document and escapes it on output. */ -class XmlTextContent : public INode { +class TextNode : public INode { public: /** * Default constructor that generate a blank text node. */ - XmlTextContent() : INode(NodeType::TEXT_CONTENT) {} + TextNode() : INode(NodeType::TEXT_CONTENT) {} /** * Constructor that takes in a copy of the text content to store within this * node. */ - explicit XmlTextContent(std::string content) + explicit TextNode(std::string content) : INode(NodeType::TEXT_CONTENT), _content(std::move(content)) { if (!isValidXmlCharacterData(this->_content)) { throw std::invalid_argument("Invalid character in XML text content"); @@ -86,8 +86,7 @@ class XmlTextContent : public INode { /** * Stream insertion overload. (node << text). */ -inline XmlTextContent &operator<<(XmlTextContent &node, - const std::string &withText) { +inline TextNode &operator<<(TextNode &node, const std::string &withText) { node.append(withText); return node; } @@ -96,7 +95,7 @@ inline XmlTextContent &operator<<(XmlTextContent &node, * Stream extraction overload: reads one line and appends the characters read * to the content of the node without adding a delimiter. */ -inline std::istream &operator>>(std::istream &is, XmlTextContent &node) { +inline std::istream &operator>>(std::istream &is, TextNode &node) { std::string temp; if (std::getline(is, temp)) { node.append(temp); diff --git a/include/xtrpg/xml/node/XmlTagNode.hpp b/include/xtrpg/xml/node/XmlTagNode.hpp deleted file mode 100644 index 6d50a96..0000000 --- a/include/xtrpg/xml/node/XmlTagNode.hpp +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xtrpg/xml/node/IAttributes.hpp" -#include "xtrpg/xml/node/INode.hpp" -#include "xtrpg/xml/node/ITagname.hpp" -#include "xtrpg/xml/node/NodeType.hpp" -#include "xtrpg/xml/node/XmlTextContent.hpp" - -namespace xtrpg::xml::node { - -/** - * Represents an XML element with a tag name, attributes, and child nodes. - */ -class XmlTagNode : public INode, public ITagname, public IAttributes { -public: - /** - * Inline constructor that accepts a tag name. - */ - explicit XmlTagNode(std::string name) - : INode(NodeType::TAG), ITagname(name), IAttributes() {} - - /** - * Returns a reference to the name of the tag. - */ - const std::string_view name() const { return this->getTagname(); } - - /** - * Appends a given child node. - * - * @throws std::invalid_argument if the child already contains this node. - */ - void append(std::shared_ptr child) { - if (child) { - if (containsNode(child.get(), this)) { - throw std::invalid_argument("Cannot create a cycle in XML nodes"); - } - this->_children.push_back(std::move(child)); - } - } - - /** - * Returns a vector of child nodes. - */ - const std::vector> &children() const { - return this->_children; - } - - /** - * Serializes the node into an XML formatted string. - */ - void serialize(std::ostream &os) const override { - os << "<" << this->getTagname(); - - IAttributes::serialize(os); - - if (this->_children.empty()) { - os << "/>"; - return; - } - - os << ">"; - for (const auto &child : this->_children) { - child->serialize(os); - } - os << "getTagname() << ">"; - } - -private: - /** - * Checks whether target is reachable through an XML tag node subtree. - */ - static bool containsNode(const INode *root, const INode *target) { - std::vector pending{root}; - std::unordered_set visited; - - while (!pending.empty()) { - const INode *current = pending.back(); - pending.pop_back(); - - if (!current || !visited.insert(current).second) { - continue; - } - if (current == target) { - return true; - } - - const auto *tag = dynamic_cast(current); - if (!tag) { - continue; - } - for (const auto &child : tag->_children) { - pending.push_back(child.get()); - } - } - return false; - } - - std::vector> _children; -}; - -/** - * Stream operator overload for easy serialization - */ -inline XmlTagNode &operator<<(XmlTagNode &node, std::shared_ptr child) { - node.append(std::move(child)); - return node; -} - -/** - * Stream operator overload for easy serialization, appends a new Text Node - * child containing the provided text. - */ -inline XmlTagNode &operator<<(XmlTagNode &node, const std::string &withText) { - auto textNode = std::make_shared(withText); - node.append(textNode); - return node; -} - -} // namespace xtrpg::xml::node \ No newline at end of file From d5b668e8e40d227b8c9160bd36f52213f921c75f Mon Sep 17 00:00:00 2001 From: Xeno Snow Fox Date: Sat, 29 Aug 2026 12:12:27 +1000 Subject: [PATCH 2/5] Make setAttribute virtual; validate declaration IAttributes::setAttribute was made virtual so nodes can override attribute assignment. DeclarationNode now overrides setAttribute to restrict attributes to 'version', 'encoding', and 'standalone', validating allowed values and throwing std::invalid_argument on errors. serialize() was simplified to assume a validated state and requires a 'version' attribute. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- include/xtrpg/xml/node/DeclarationNode.hpp | 58 ++++++++++++++-------- include/xtrpg/xml/node/IAttributes.hpp | 2 +- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/include/xtrpg/xml/node/DeclarationNode.hpp b/include/xtrpg/xml/node/DeclarationNode.hpp index 60dad55..8a0798f 100644 --- a/include/xtrpg/xml/node/DeclarationNode.hpp +++ b/include/xtrpg/xml/node/DeclarationNode.hpp @@ -27,35 +27,49 @@ class DeclarationNode : public INode, public ITagname, public IAttributes { } /** - * Serializes the node into an XML formatted string. + * Sets an attribute key/value pair with XML declaration-specific validation. + * Only allows 'version', 'encoding', and 'standalone' attributes. + * Version must be '1.0' or '1.1', encoding must be a valid encoding name, + * and standalone must be 'yes' or 'no'. + * + * @throws std::invalid_argument if the attribute is invalid for XML + * declarations */ - void serialize(std::ostream &os) const override { - const auto version = this->getAttribute("version"); - if (!version || (*version != "1.0" && *version != "1.1")) { - throw std::invalid_argument( - "XML declaration requires version 1.0 or 1.1"); - } - - bool hasInvalidAttribute = false; - this->forEachAttribute([&](std::string_view key, std::string_view) { - if (key != "version" && key != "encoding" && key != "standalone") { - hasInvalidAttribute = true; + void setAttribute(std::string_view key, std::string_view value) override { + // Validate XML declaration-specific attributes + if (key == "version") { + if (value != "1.0" && value != "1.1") { + throw std::invalid_argument( + "XML declaration version must be '1.0' or '1.1'"); } - }); - if (hasInvalidAttribute) { - throw std::invalid_argument("Invalid XML declaration attribute"); - } - - if (const auto encoding = this->getAttribute("encoding")) { - if (!isValidEncodingName(*encoding)) { + } else if (key == "encoding") { + if (!isValidEncodingName(value)) { throw std::invalid_argument("Invalid XML declaration encoding"); } - } - if (const auto standalone = this->getAttribute("standalone")) { - if (*standalone != "yes" && *standalone != "no") { + } else if (key == "standalone") { + if (value != "yes" && value != "no") { throw std::invalid_argument( "XML declaration standalone must be 'yes' or 'no'"); } + } else { + throw std::invalid_argument( + "XML declaration does not support attribute: " + std::string(key)); + } + + // Call parent implementation + IAttributes::setAttribute(key, value); + } + + /** + * Serializes the node into an XML formatted string. + * Note: All attribute validation occurs in setAttribute(), so this method + * assumes a valid state. + */ + void serialize(std::ostream &os) const override { + const auto version = this->getAttribute("version"); + if (!version) { + throw std::invalid_argument( + "XML declaration requires a 'version' attribute"); } os << " Date: Sat, 29 Aug 2026 12:13:08 +1000 Subject: [PATCH 3/5] Rename TextNode::content to setContent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the TextNode method `content(std::string)` to `setContent(std::string)` in include/xtrpg/xml/node/TextNode.hpp to improve naming consistency. Behavior and validation are unchanged (still throws std::invalid_argument for invalid XML characters). Note: this is an API change — update any callers that used the old method name. --- include/xtrpg/xml/node/TextNode.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xtrpg/xml/node/TextNode.hpp b/include/xtrpg/xml/node/TextNode.hpp index 5d459e3..8014c8c 100644 --- a/include/xtrpg/xml/node/TextNode.hpp +++ b/include/xtrpg/xml/node/TextNode.hpp @@ -39,7 +39,7 @@ class TextNode : public INode { /** * Sets the text content stored on this node, overriding any previous content. */ - void content(std::string withContent) { + void setContent(std::string withContent) { if (!isValidXmlCharacterData(withContent)) { throw std::invalid_argument("Invalid character in XML text content"); } From b0843e5280c77c41ea363873590a145cc491cd61 Mon Sep 17 00:00:00 2001 From: Xeno Snow Fox Date: Sat, 29 Aug 2026 12:13:49 +1000 Subject: [PATCH 4/5] forEachAttribute: callback can abort iteration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change forEachAttribute to use a boolean-returning callback so callers can control iteration. The callback signature was updated from void(std::string_view key, std::string_view value) to bool(std::string_view key, std::string_view value); returning true continues iteration, false breaks early. Implementation and doc comment updated accordingly. Note: this is a small API change — update existing callbacks to return a bool. --- include/xtrpg/xml/node/IAttributes.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/xtrpg/xml/node/IAttributes.hpp b/include/xtrpg/xml/node/IAttributes.hpp index 97c32f7..5788f37 100644 --- a/include/xtrpg/xml/node/IAttributes.hpp +++ b/include/xtrpg/xml/node/IAttributes.hpp @@ -62,12 +62,17 @@ class IAttributes { /** * Executes a callback function for each key/value attribute pair. + * The callback can control iteration by returning a boolean value: + * - Return true to continue iterating to the next attribute + * - Return false to break early and stop iteration * - * Callback signature: void(std::string_view key, std::string_view value) + * Callback signature: bool(std::string_view key, std::string_view value) */ template void forEachAttribute(Func &&callback) const { for (const auto &[key, value] : this->_attributes) { - callback(std::string_view{key}, std::string_view{value}); + if (!callback(std::string_view{key}, std::string_view{value})) { + break; + } } } From 51bb49e40506fc704df9fe588eecbf12809a8689 Mon Sep 17 00:00:00 2001 From: Xeno Snow Fox Date: Sat, 29 Aug 2026 12:16:56 +1000 Subject: [PATCH 5/5] Default special-members for XML nodes Defaulted copy/move constructors and copy/move assignment operators for DeclarationNode, TagNode, and TextNode to restore implicit copy/move behavior and reduce boilerplate. Added a default constructor for IAttributes. Cleaned up NodeContainer constructors' formatting and defaulted its destructor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- include/xtrpg/xml/node/DeclarationNode.hpp | 20 ++++++++++++++++++++ include/xtrpg/xml/node/IAttributes.hpp | 5 +++++ include/xtrpg/xml/node/NodeContainer.hpp | 6 +++--- include/xtrpg/xml/node/TagNode.hpp | 20 ++++++++++++++++++++ include/xtrpg/xml/node/TextNode.hpp | 20 ++++++++++++++++++++ 5 files changed, 68 insertions(+), 3 deletions(-) diff --git a/include/xtrpg/xml/node/DeclarationNode.hpp b/include/xtrpg/xml/node/DeclarationNode.hpp index 8a0798f..23038d9 100644 --- a/include/xtrpg/xml/node/DeclarationNode.hpp +++ b/include/xtrpg/xml/node/DeclarationNode.hpp @@ -26,6 +26,26 @@ class DeclarationNode : public INode, public ITagname, public IAttributes { } } + /** + * Explicitly defaulted copy constructor. + */ + DeclarationNode(const DeclarationNode &) = default; + + /** + * Explicitly defaulted move constructor. + */ + DeclarationNode(DeclarationNode &&) = default; + + /** + * Explicitly defaulted copy assignment operator. + */ + DeclarationNode &operator=(const DeclarationNode &) = default; + + /** + * Explicitly defaulted move assignment operator. + */ + DeclarationNode &operator=(DeclarationNode &&) = default; + /** * Sets an attribute key/value pair with XML declaration-specific validation. * Only allows 'version', 'encoding', and 'standalone' attributes. diff --git a/include/xtrpg/xml/node/IAttributes.hpp b/include/xtrpg/xml/node/IAttributes.hpp index 5788f37..2c183bb 100644 --- a/include/xtrpg/xml/node/IAttributes.hpp +++ b/include/xtrpg/xml/node/IAttributes.hpp @@ -19,6 +19,11 @@ namespace xtrpg::xml::node { */ class IAttributes { public: + /** + * Default constructor. + */ + IAttributes() {} + /** * Virtual destructor. */ diff --git a/include/xtrpg/xml/node/NodeContainer.hpp b/include/xtrpg/xml/node/NodeContainer.hpp index 66bfd3a..599e276 100644 --- a/include/xtrpg/xml/node/NodeContainer.hpp +++ b/include/xtrpg/xml/node/NodeContainer.hpp @@ -14,11 +14,11 @@ namespace xtrpg::xml::node { */ class NodeContainer : public INode { public: - NodeContainer() : INode(NodeType::CONTAINER) {}; + NodeContainer() : INode(NodeType::CONTAINER) {} - explicit NodeContainer(NodeType type) : INode(type) {}; + explicit NodeContainer(NodeType type) : INode(type) {} - ~NodeContainer() {} + ~NodeContainer() = default; /** * Appends a given child node. diff --git a/include/xtrpg/xml/node/TagNode.hpp b/include/xtrpg/xml/node/TagNode.hpp index 3af6583..01a9bcf 100644 --- a/include/xtrpg/xml/node/TagNode.hpp +++ b/include/xtrpg/xml/node/TagNode.hpp @@ -34,6 +34,26 @@ class TagNode : public INode, explicit TagNode(std::string name) : INode(NodeType::TAG), ITagname(name), IAttributes(), NodeContainer() {} + /** + * Explicitly defaulted copy constructor. + */ + TagNode(const TagNode &) = default; + + /** + * Explicitly defaulted move constructor. + */ + TagNode(TagNode &&) = default; + + /** + * Explicitly defaulted copy assignment operator. + */ + TagNode &operator=(const TagNode &) = default; + + /** + * Explicitly defaulted move assignment operator. + */ + TagNode &operator=(TagNode &&) = default; + /** * Returns a reference to the name of the tag. */ diff --git a/include/xtrpg/xml/node/TextNode.hpp b/include/xtrpg/xml/node/TextNode.hpp index 8014c8c..413fe9f 100644 --- a/include/xtrpg/xml/node/TextNode.hpp +++ b/include/xtrpg/xml/node/TextNode.hpp @@ -31,6 +31,26 @@ class TextNode : public INode { } } + /** + * Explicitly defaulted copy constructor. + */ + TextNode(const TextNode &) = default; + + /** + * Explicitly defaulted move constructor. + */ + TextNode(TextNode &&) = default; + + /** + * Explicitly defaulted copy assignment operator. + */ + TextNode &operator=(const TextNode &) = default; + + /** + * Explicitly defaulted move assignment operator. + */ + TextNode &operator=(TextNode &&) = default; + /** * Returns a reference to the text content stored on this node. */