From e7c92b5658a0829885a729039356fbad1bf939bb Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 9 Dec 2021 15:25:20 -0800 Subject: [PATCH] Move ValueWriter out, add DeepCompareIsEqual Signed-off-by: Nicholas Van Sickle --- Code/Framework/AzCore/AzCore/DOM/DomValue.cpp | 405 +++++++++--------- Code/Framework/AzCore/AzCore/DOM/DomValue.h | 81 ++-- .../AzCore/AzCore/DOM/DomValueWriter.cpp | 218 ++++++++++ .../AzCore/AzCore/DOM/DomValueWriter.h | 58 +++ .../AzCore/AzCore/azcore_files.cmake | 2 + 5 files changed, 504 insertions(+), 260 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomValueWriter.cpp create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomValueWriter.h diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp b/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp index 032e5795da..68a88ed35a 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp @@ -9,7 +9,7 @@ #pragma once #include - +#include #include namespace AZ::Dom @@ -26,6 +26,11 @@ namespace AZ::Dom return refCountedPointer; } + Node::Node(AZ::Name name) + : m_name(name) + { + } + AZ::Name Node::GetName() const { return m_name; @@ -36,31 +41,24 @@ namespace AZ::Dom m_name = name; } - ObjectPtr Node::GetMutableProperties() + Object::ContainerType& Node::GetProperties() { - CheckCopyOnWrite(m_object); - return m_object; + return m_properties; } - ConstObjectPtr Node::GetProperties() const + const Object::ContainerType& Node::GetProperties() const { - return m_object; + return m_properties; } - ArrayPtr Node::GetMutableChildren() + Array::ContainerType& Node::GetChildren() { - CheckCopyOnWrite(m_array); - return m_array; + return m_children; } - ConstArrayPtr Node::GetChildren() const + const Array::ContainerType& Node::GetChildren() const { - return m_array; - } - - bool Node::operator==(const Node& rhs) const - { - return m_name == rhs.m_name && m_array == rhs.m_array && m_object == rhs.m_object; + return m_children; } Value::Value() @@ -187,7 +185,7 @@ namespace AZ::Dom return Type::ObjectType; case 8: // ArrayPtr return Type::ArrayType; - case 9: // Node + case 9: // NodePtr return Type::NodeType; case 10: // AZStd::any* return Type::OpaqueType; @@ -267,18 +265,31 @@ namespace AZ::Dom return *this; } + const Node& Value::GetNodeInternal() const + { + AZ_Assert(GetType() == Type::NodeType, "AZ::Dom::Value: attempted to retrieve a node from a non-node value"); + return *AZStd::get(m_value); + } + + Node& Value::GetNodeInternal() + { + AZ_Assert(GetType() == Type::NodeType, "AZ::Dom::Value: attempted to retrieve a node from a non-node value"); + return *CheckCopyOnWrite(AZStd::get(m_value)); + } + const Object::ContainerType& Value::GetObjectInternal() const { const Type type = GetType(); AZ_Assert( - type == Type::ObjectType || type == Type::NodeType, "AZ::Dom::Value: attempted to retrieve an object from a non-object value"); + type == Type::ObjectType || type == Type::NodeType, + "AZ::Dom::Value: attempted to retrieve an object from a value that isn't an object or a node"); if (type == Type::ObjectType) { return AZStd::get(m_value)->m_values; } else { - return AZStd::get(m_value).GetProperties()->m_values; + return AZStd::get(m_value)->GetProperties(); } } @@ -286,14 +297,15 @@ namespace AZ::Dom { const Type type = GetType(); AZ_Assert( - type == Type::ObjectType || type == Type::NodeType, "AZ::Dom::Value: attempted to retrieve an object from a non-object value"); + type == Type::ObjectType || type == Type::NodeType, + "AZ::Dom::Value: attempted to retrieve an object from a value that isn't an object or a node"); if (type == Type::ObjectType) { return CheckCopyOnWrite(AZStd::get(m_value))->m_values; } else { - return AZStd::get(m_value).GetMutableProperties()->m_values; + return CheckCopyOnWrite(AZStd::get(m_value))->GetProperties(); } } @@ -301,14 +313,15 @@ namespace AZ::Dom { const Type type = GetType(); AZ_Assert( - type == Type::ArrayType || type == Type::NodeType, "AZ::Dom::Value: attempted to retrieve an array from a non-array value"); + type == Type::ArrayType || type == Type::NodeType, + "AZ::Dom::Value: attempted to retrieve an array from a value that isn't an array or a node"); if (type == Type::ObjectType) { return AZStd::get(m_value)->m_values; } else { - return AZStd::get(m_value).GetChildren()->m_values; + return AZStd::get(m_value)->GetChildren(); } } @@ -316,14 +329,15 @@ namespace AZ::Dom { const Type type = GetType(); AZ_Assert( - type == Type::ArrayType || type == Type::NodeType, "AZ::Dom::Value: attempted to retrieve an array from a non-array value"); + type == Type::ArrayType || type == Type::NodeType, + "AZ::Dom::Value: attempted to retrieve an array from a value that isn't an array or node"); if (type == Type::ObjectType) { return CheckCopyOnWrite(AZStd::get(m_value))->m_values; } else { - return AZStd::get(m_value).GetMutableChildren()->m_values; + return CheckCopyOnWrite(AZStd::get(m_value))->GetChildren(); } } @@ -627,6 +641,67 @@ namespace AZ::Dom return GetArrayInternal(); } + void Value::SetNode(AZ::Name name) + { + m_value = AZStd::make_shared(name); + } + + void Value::SetNode(AZStd::string_view name) + { + SetNode(AZ::Name(name)); + } + + AZ::Name Value::GetNodeName() const + { + return GetNodeInternal().GetName(); + } + + void Value::SetNodeName(AZ::Name name) + { + GetNodeInternal().SetName(name); + } + + void Value::SetNodeName(AZStd::string_view name) + { + SetNodeName(AZ::Name(name)); + } + + void Value::SetNodeValue(Value value) + { + AZ_Assert(GetType() == Type::NodeType, "AZ::Dom::Value: Attempted to set value for non-node type"); + Array::ContainerType& nodeChildren = GetArrayInternal(); + + // Set the first non-node child, if one is found + for (Value& entry : nodeChildren) + { + if (entry.GetType() != Type::NodeType) + { + entry = AZStd::move(value); + return; + } + } + + // Otherwise, append the value entry + nodeChildren.push_back(AZStd::move(value)); + } + + Value Value::GetNodeValue() const + { + AZ_Assert(GetType() == Type::NodeType, "AZ::Dom::Value: Attempted to get value for non-node type"); + const Array::ContainerType& nodeChildren = GetArrayInternal(); + + // Get the first non-node child, if one is found + for (const Value& entry : nodeChildren) + { + if (entry.GetType() != Type::NodeType) + { + return entry; + } + } + + return Value(); + } + int64_t Value::GetInt() const { switch (m_value.index()) @@ -812,9 +887,9 @@ namespace AZ::Dom result = visitor.EndArray(arrayContainer.size()); } } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { - const Node& node = AZStd::get(m_value); + const Node& node = *AZStd::get(m_value); result = visitor.StartNode(node.GetName()); if (result.IsSuccess()) { @@ -850,204 +925,124 @@ namespace AZ::Dom return result; } - ValueWriter::ValueWriter(Value& outputValue) - : m_result(outputValue) + AZStd::unique_ptr Value::GetWriteHandler() { + return AZStd::make_unique(*this); } - VisitorFlags ValueWriter::GetVisitorFlags() const + bool Value::DeepCompareIsEqual(const Value& other) const { - return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects | VisitorFlags::SupportsNodes; - } - - ValueWriter::ValueInfo::ValueInfo(Value& container) - : m_container(container) - { - } - - Visitor::Result ValueWriter::Null() - { - CurrentValue().SetNull(); - return FinishWrite(); - } - - Visitor::Result ValueWriter::Bool(bool value) - { - CurrentValue().SetBool(value); - return FinishWrite(); - } - - Visitor::Result ValueWriter::Int64(AZ::s64 value) - { - CurrentValue().SetInt(value); - return FinishWrite(); - } - - Visitor::Result ValueWriter::Uint64(AZ::u64 value) - { - CurrentValue().SetUint(value); - return FinishWrite(); - } - - Visitor::Result ValueWriter::Double(double value) - { - CurrentValue().SetDouble(value); - return FinishWrite(); - } - - Visitor::Result ValueWriter::String(AZStd::string_view value, Lifetime lifetime) - { - if (lifetime == Lifetime::Persistent) + if (m_value.index() != other.m_value.index()) { - CurrentValue().SetString(value); - } - else - { - CurrentValue().CopyFromString(value); - } - return FinishWrite(); - } - - Visitor::Result ValueWriter::StartObject() - { - CurrentValue().SetObject(); - - m_entryStack.emplace(CurrentValue()); - return VisitorSuccess(); - } - - Visitor::Result ValueWriter::EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount) - { - const char* endMethodName; - switch (containerType) - { - case Type::ObjectType: - endMethodName = "EndObject"; - break; - case Type::ArrayType: - endMethodName = "EndArray"; - break; - case Type::NodeType: - endMethodName = "EndNode"; - break; - default: - AZ_Assert(false, "Invalid container type specified"); - return VisitorFailure(VisitorErrorCode::InternalError, "AZ::Dom::ValueWriter: EndContainer called with invalid container type"); + return false; } - if (m_entryStack.empty()) - { - return VisitorFailure( - VisitorErrorCode::InternalError, - AZStd::string::format("AZ::Dom::ValueWriter: %s called without a matching call", endMethodName)); - } + return AZStd::visit( + [&](auto&& ourValue) -> bool + { + using Alternative = AZStd::decay_t; + auto&& theirValue = AZStd::get>(other.m_value); - const ValueInfo& topEntry = m_entryStack.top(); - if (topEntry.m_container.GetType() != containerType) - { - return VisitorFailure( - VisitorErrorCode::InternalError, - AZStd::string::format("AZ::Dom::ValueWriter: %s called from within a different container type", endMethodName)); - } + if constexpr (AZStd::is_same_v) + { + return true; + } + else if constexpr (AZStd::is_same_v) + { + if (ourValue == theirValue) + { + return true; + } - if (topEntry.m_attributeCount != attributeCount) - { - return VisitorFailure( - VisitorErrorCode::InternalError, - AZStd::string::format( - "AZ::Dom::ValueWriter: %s expected %llu attributes but received %llu attributes instead", endMethodName, attributeCount, - topEntry.m_attributeCount)); - } + if (ourValue->m_values.size() != theirValue->m_values.size()) + { + return false; + } - if (topEntry.m_elementCount != elementCount) - { - return VisitorFailure( - VisitorErrorCode::InternalError, - AZStd::string::format( - "AZ::Dom::ValueWriter: %s expected %llu elements but received %llu elements instead", endMethodName, elementCount, - topEntry.m_elementCount)); - } + for (size_t i = 0; i < ourValue->m_values.size(); ++i) + { + const Object::EntryType& lhs = ourValue->m_values[i]; + const Object::EntryType& rhs = theirValue->m_values[i]; + if (lhs.first != rhs.first || !lhs.second.DeepCompareIsEqual(rhs.second)) + { + return false; + } + } - m_entryStack.pop(); - return FinishWrite(); - } + return true; + } + else if constexpr (AZStd::is_same_v) + { + if (ourValue == theirValue) + { + return true; + } - Visitor::Result ValueWriter::EndObject(AZ::u64 attributeCount) - { - return EndContainer(Type::ObjectType, attributeCount, 0); - } + if (ourValue->m_values.size() != theirValue->m_values.size()) + { + return false; + } - Visitor::Result ValueWriter::Key(AZ::Name key) - { - AZ_Assert(!m_entryStack.empty(), "Attempmted to push a key with no object"); - AZ_Assert(!m_entryStack.top().m_container.IsArray(), "Attempted to push a key to an array"); - m_entryStack.top().m_key = key; - return VisitorSuccess(); - } + for (size_t i = 0; i < ourValue->m_values.size(); ++i) + { + const Value& lhs = ourValue->m_values[i]; + const Value& rhs = theirValue->m_values[i]; + if (!lhs.DeepCompareIsEqual(rhs)) + { + return false; + } + } - Visitor::Result ValueWriter::RawKey(AZStd::string_view key, [[maybe_unused]] Lifetime lifetime) - { - return Key(AZ::Name(key)); - } + return true; + } + else if constexpr (AZStd::is_same_v) + { + if (ourValue == theirValue) + { + return true; + } - Visitor::Result ValueWriter::StartArray() - { - CurrentValue().SetArray(); + const Node& ourNode = *ourValue; + const Node& theirNode = *theirValue; - m_entryStack.emplace(CurrentValue()); - return VisitorSuccess(); - } + const Object::ContainerType& ourProperties = ourNode.GetProperties(); + const Object::ContainerType& theirProperties = theirNode.GetProperties(); - Visitor::Result ValueWriter::EndArray(AZ::u64 elementCount) - { - return EndContainer(Type::ArrayType, 0, elementCount); - } + if (ourProperties.size() != theirProperties.size()) + { + return false; + } - Visitor::Result ValueWriter::StartNode(AZ::Name name) - { - CurrentValue().SetNode(name); + for (size_t i = 0; i < ourProperties.size(); ++i) + { + const Object::EntryType& lhs = ourProperties[i]; + const Object::EntryType& rhs = theirProperties[i]; + if (lhs.first != rhs.first || !lhs.second.DeepCompareIsEqual(rhs.second)) + { + return false; + } + } - m_entryStack.emplace(CurrentValue()); - return VisitorSuccess(); - } + const Array::ContainerType& ourChildren = ourNode.GetChildren(); + const Array::ContainerType& theirChildren = theirNode.GetChildren(); - Visitor::Result ValueWriter::EndNode(AZ::u64 attributeCount, AZ::u64 elementCount) - { - return EndContainer(Type::NodeType, attributeCount, elementCount); - } + for (size_t i = 0; i < ourChildren.size(); ++i) + { + const Value& lhs = ourChildren[i]; + const Value& rhs = theirChildren[i]; + if (!lhs.DeepCompareIsEqual(rhs)) + { + return false; + } + } - Visitor::Result ValueWriter::FinishWrite() - { - if (m_entryStack.empty()) - { - return VisitorSuccess(); - } - - Value value; - m_entryStack.top().m_value.Swap(value); - ValueInfo& newEntry = m_entryStack.top(); - - if (!newEntry.m_key.IsEmpty()) - { - newEntry.m_container.AddMember(newEntry.m_key, AZStd::move(value)); - newEntry.m_key = AZ::Name(); - ++newEntry.m_attributeCount; - } - else - { - newEntry.m_container.PushBack(AZStd::move(value)); - ++newEntry.m_elementCount; - } - - return VisitorSuccess(); - } - - Value& ValueWriter::CurrentValue() - { - if (m_entryStack.empty()) - { - return m_result; - } - return m_entryStack.top().m_value; + return true; + } + else + { + return ourValue == theirValue; + } + }, + m_value); } } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValue.h b/Code/Framework/AzCore/AzCore/DOM/DomValue.h index 439971a5a0..a460274602 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomValue.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomValue.h @@ -8,13 +8,13 @@ #pragma once +#include #include - #include +#include #include #include #include -#include #include namespace AZ::Dom @@ -72,25 +72,34 @@ namespace AZ::Dom class Node { public: + Node() = default; + Node(AZ::Name name); + Node(const Node&) = default; + Node(Node&&) = default; + + Node& operator=(const Node&) = default; + Node& operator=(Node&&) = default; + AZ::Name GetName() const; void SetName(AZ::Name name); - ObjectPtr GetMutableProperties(); - ConstObjectPtr GetProperties() const; + Object::ContainerType& GetProperties(); + const Object::ContainerType& GetProperties() const; - ArrayPtr GetMutableChildren(); - ConstArrayPtr GetChildren() const; - - bool operator==(const Node& rhs) const; + Array::ContainerType& GetChildren(); + const Array::ContainerType& GetChildren() const; private: AZ::Name m_name; - ArrayPtr m_array; - ObjectPtr m_object; + Object::ContainerType m_properties; + Array::ContainerType m_children; friend class Value; }; + using NodePtr = AZStd::shared_ptr; + using ConstNodePtr = AZStd::shared_ptr; + class Value { public: @@ -252,8 +261,13 @@ namespace AZ::Dom // Visitor API Visitor::Result Accept(Visitor& visitor, bool copyStrings) const; + AZStd::unique_ptr GetWriteHandler(); + + bool DeepCompareIsEqual(const Value& other) const; private: + const Node& GetNodeInternal() const; + Node& GetNodeInternal(); const Object::ContainerType& GetObjectInternal() const; Object::ContainerType& GetObjectInternal(); const Array::ContainerType& GetArrayInternal() const; @@ -284,53 +298,10 @@ namespace AZ::Dom // ArrayType ArrayPtr, // NodeType - Node, + NodePtr, // OpaqueType AZStd::any*>; ValueType m_value; }; - - class ValueWriter : public Visitor - { - public: - ValueWriter(Value& outputValue); - - VisitorFlags GetVisitorFlags() const override; - Result Null() override; - Result Bool(bool value) override; - Result Int64(AZ::s64 value) override; - Result Uint64(AZ::u64 value) override; - Result Double(double value) override; - - Result String(AZStd::string_view value, Lifetime lifetime) override; - Result StartObject() override; - Result EndObject(AZ::u64 attributeCount) override; - Result Key(AZ::Name key) override; - Result RawKey(AZStd::string_view key, Lifetime lifetime) override; - Result StartArray() override; - Result EndArray(AZ::u64 elementCount) override; - Result StartNode(AZ::Name name) override; - Result RawStartNode(AZStd::string_view name, Lifetime lifetime) override; - Result EndNode(AZ::u64 attributeCount, AZ::u64 elementCount) override; - - private: - Result FinishWrite(); - Value& CurrentValue(); - Visitor::Result EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount); - - struct ValueInfo - { - ValueInfo(Value& container); - - KeyType m_key; - Value m_value; - Value& m_container; - AZ::u64 m_attributeCount = 0; - AZ::u64 m_elementCount = 0; - }; - - Value& m_result; - AZStd::stack m_entryStack; - }; - } // namespace AZ::Dom +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.cpp b/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.cpp new file mode 100644 index 0000000000..71710f543b --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +namespace AZ::Dom +{ + ValueWriter::ValueWriter(Value& outputValue) + : m_result(outputValue) + { + } + + VisitorFlags ValueWriter::GetVisitorFlags() const + { + return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects | VisitorFlags::SupportsNodes; + } + + ValueWriter::ValueInfo::ValueInfo(Value& container) + : m_container(container) + { + } + + Visitor::Result ValueWriter::Null() + { + CurrentValue().SetNull(); + return FinishWrite(); + } + + Visitor::Result ValueWriter::Bool(bool value) + { + CurrentValue().SetBool(value); + return FinishWrite(); + } + + Visitor::Result ValueWriter::Int64(AZ::s64 value) + { + CurrentValue().SetInt(value); + return FinishWrite(); + } + + Visitor::Result ValueWriter::Uint64(AZ::u64 value) + { + CurrentValue().SetUint(value); + return FinishWrite(); + } + + Visitor::Result ValueWriter::Double(double value) + { + CurrentValue().SetDouble(value); + return FinishWrite(); + } + + Visitor::Result ValueWriter::String(AZStd::string_view value, Lifetime lifetime) + { + if (lifetime == Lifetime::Persistent) + { + CurrentValue().SetString(value); + } + else + { + CurrentValue().CopyFromString(value); + } + return FinishWrite(); + } + + Visitor::Result ValueWriter::StartObject() + { + CurrentValue().SetObject(); + + m_entryStack.emplace(CurrentValue()); + return VisitorSuccess(); + } + + Visitor::Result ValueWriter::EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount) + { + const char* endMethodName; + switch (containerType) + { + case Type::ObjectType: + endMethodName = "EndObject"; + break; + case Type::ArrayType: + endMethodName = "EndArray"; + break; + case Type::NodeType: + endMethodName = "EndNode"; + break; + default: + AZ_Assert(false, "Invalid container type specified"); + return VisitorFailure(VisitorErrorCode::InternalError, "AZ::Dom::ValueWriter: EndContainer called with invalid container type"); + } + + if (m_entryStack.empty()) + { + return VisitorFailure( + VisitorErrorCode::InternalError, + AZStd::string::format("AZ::Dom::ValueWriter: %s called without a matching call", endMethodName)); + } + + const ValueInfo& topEntry = m_entryStack.top(); + if (topEntry.m_container.GetType() != containerType) + { + return VisitorFailure( + VisitorErrorCode::InternalError, + AZStd::string::format("AZ::Dom::ValueWriter: %s called from within a different container type", endMethodName)); + } + + if (topEntry.m_attributeCount != attributeCount) + { + return VisitorFailure( + VisitorErrorCode::InternalError, + AZStd::string::format( + "AZ::Dom::ValueWriter: %s expected %llu attributes but received %llu attributes instead", endMethodName, attributeCount, + topEntry.m_attributeCount)); + } + + if (topEntry.m_elementCount != elementCount) + { + return VisitorFailure( + VisitorErrorCode::InternalError, + AZStd::string::format( + "AZ::Dom::ValueWriter: %s expected %llu elements but received %llu elements instead", endMethodName, elementCount, + topEntry.m_elementCount)); + } + + m_entryStack.pop(); + return FinishWrite(); + } + + Visitor::Result ValueWriter::EndObject(AZ::u64 attributeCount) + { + return EndContainer(Type::ObjectType, attributeCount, 0); + } + + Visitor::Result ValueWriter::Key(AZ::Name key) + { + AZ_Assert(!m_entryStack.empty(), "Attempmted to push a key with no object"); + AZ_Assert(!m_entryStack.top().m_container.IsArray(), "Attempted to push a key to an array"); + m_entryStack.top().m_key = key; + return VisitorSuccess(); + } + + Visitor::Result ValueWriter::RawKey(AZStd::string_view key, [[maybe_unused]] Lifetime lifetime) + { + return Key(AZ::Name(key)); + } + + Visitor::Result ValueWriter::StartArray() + { + CurrentValue().SetArray(); + + m_entryStack.emplace(CurrentValue()); + return VisitorSuccess(); + } + + Visitor::Result ValueWriter::EndArray(AZ::u64 elementCount) + { + return EndContainer(Type::ArrayType, 0, elementCount); + } + + Visitor::Result ValueWriter::StartNode(AZ::Name name) + { + CurrentValue().SetNode(name); + + m_entryStack.emplace(CurrentValue()); + return VisitorSuccess(); + } + + Visitor::Result ValueWriter::RawStartNode(AZStd::string_view name, [[maybe_unused]] Lifetime lifetime) + { + return StartNode(AZ::Name(name)); + } + + Visitor::Result ValueWriter::EndNode(AZ::u64 attributeCount, AZ::u64 elementCount) + { + return EndContainer(Type::NodeType, attributeCount, elementCount); + } + + Visitor::Result ValueWriter::FinishWrite() + { + if (m_entryStack.empty()) + { + return VisitorSuccess(); + } + + Value value; + m_entryStack.top().m_value.Swap(value); + ValueInfo& newEntry = m_entryStack.top(); + + if (!newEntry.m_key.IsEmpty()) + { + newEntry.m_container.AddMember(newEntry.m_key, AZStd::move(value)); + newEntry.m_key = AZ::Name(); + ++newEntry.m_attributeCount; + } + else + { + newEntry.m_container.PushBack(AZStd::move(value)); + ++newEntry.m_elementCount; + } + + return VisitorSuccess(); + } + + Value& ValueWriter::CurrentValue() + { + if (m_entryStack.empty()) + { + return m_result; + } + return m_entryStack.top().m_value; + } +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.h b/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.h new file mode 100644 index 0000000000..fb5f4324a6 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomValueWriter.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AZ::Dom +{ + class ValueWriter : public Visitor + { + public: + ValueWriter(Value& outputValue); + + VisitorFlags GetVisitorFlags() const override; + Result Null() override; + Result Bool(bool value) override; + Result Int64(AZ::s64 value) override; + Result Uint64(AZ::u64 value) override; + Result Double(double value) override; + + Result String(AZStd::string_view value, Lifetime lifetime) override; + Result StartObject() override; + Result EndObject(AZ::u64 attributeCount) override; + Result Key(AZ::Name key) override; + Result RawKey(AZStd::string_view key, Lifetime lifetime) override; + Result StartArray() override; + Result EndArray(AZ::u64 elementCount) override; + Result StartNode(AZ::Name name) override; + Result RawStartNode(AZStd::string_view name, Lifetime lifetime) override; + Result EndNode(AZ::u64 attributeCount, AZ::u64 elementCount) override; + + private: + Result FinishWrite(); + Value& CurrentValue(); + Visitor::Result EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount); + + struct ValueInfo + { + ValueInfo(Value& container); + + KeyType m_key; + Value m_value; + Value& m_container; + AZ::u64 m_attributeCount = 0; + AZ::u64 m_elementCount = 0; + }; + + Value& m_result; + AZStd::stack m_entryStack; + }; +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index fa9f94505f..e17fb941b8 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -133,6 +133,8 @@ set(FILES DOM/DomUtils.h DOM/DomValue.cpp DOM/DomValue.h + DOM/DomValueWriter.cpp + DOM/DomValueWriter.h DOM/DomVisitor.cpp DOM/DomVisitor.h DOM/Backends/JSON/JsonBackend.h