From d519d4cb030bda67b4023c9677116801c858330c Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Wed, 1 Dec 2021 16:22:48 -0800 Subject: [PATCH] Improve performance for both in-place and copy parsing (faster than `AZ::JsonSerializationUtils::ReadJsonString` now!) Signed-off-by: Nicholas Van Sickle --- .../Backends/JSON/JsonSerializationUtils.cpp | 51 ------------ .../Backends/JSON/JsonSerializationUtils.h | 77 ++++++++++++++++--- 2 files changed, 66 insertions(+), 62 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 84f663f97c..104082ce54 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -413,57 +413,6 @@ namespace AZ::Dom::Json return true; } - // - // struct AzStringStream - // - // rapidjson stream wrapper for AZStd::string suitable for in-situ parsing - AzStringStream::AzStringStream(AZStd::string& buffer) - { - m_cursor = buffer.data(); - m_begin = m_cursor; - } - - char AzStringStream::Peek() const - { - return *m_cursor; - } - - char AzStringStream::Take() - { - return *m_cursor++; - } - - size_t AzStringStream::Tell() const - { - return static_cast(m_cursor - m_begin); - } - - char* AzStringStream::PutBegin() - { - m_write = m_cursor; - return m_cursor; - } - - void AzStringStream::Put(char c) - { - (*m_write++) = c; - } - - void AzStringStream::Flush() - { - } - - size_t AzStringStream::PutEnd(char* begin) - { - return m_write - begin; - } - - const char* AzStringStream::Peek4() const - { - AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); - return m_cursor; - } - // // Serialized JSON util functions // diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index 4197209b8e..5e7976568b 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -113,19 +113,65 @@ namespace AZ::Dom::Json }; //! rapidjson stream wrapper for AZStd::string suitable for in-situ parsing + //! Faster than rapidjson::MemoryStream for reading from AZStd::string / AZStd::string_view (because it requires a null terminator) + //! \note This needs to be inlined for performance reasons. struct AzStringStream { using Ch = char; //(buffer.data()); + m_begin = m_cursor; + } + + AZ_FORCE_INLINE char Peek() const + { + return *m_cursor; + } + + AZ_FORCE_INLINE char Take() + { + return *m_cursor++; + } + + AZ_FORCE_INLINE size_t Tell() const + { + return static_cast(m_cursor - m_begin); + } + + AZ_FORCE_INLINE char* PutBegin() + { + m_write = m_cursor; + return m_cursor; + } + + AZ_FORCE_INLINE void Put(char c) + { + (*m_write++) = c; + } + + AZ_FORCE_INLINE void Flush() + { + } + + AZ_FORCE_INLINE size_t PutEnd(char* begin) + { + return m_write - begin; + } + + AZ_FORCE_INLINE const char* Peek4() const + { + AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); + return m_cursor; + } char* m_cursor; //!< Current read position. char* m_write; //!< Current write position. @@ -180,10 +226,19 @@ namespace AZ::Dom::Json Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) { rapidjson::Reader reader; - rapidjson::MemoryStream stream(buffer.data(), buffer.size()); RapidJsonReadHandler handler(&visitor, lifetime); - reader.Parse(parseFlags)>(stream, handler); + // If the string is null terminated, we can use the faster AzStringStream path - otherwise we fall back on rapidjson::MemoryStream + if (buffer.data()[buffer.size()] == '\0') + { + AzStringStream stream(buffer); + reader.Parse(parseFlags)>(stream, handler); + } + else + { + rapidjson::MemoryStream stream(buffer.data(), buffer.size()); + reader.Parse(parseFlags)>(stream, handler); + } return handler.TakeOutcome(); }