From 88af15d5132e047ff44b5ffbb8952c9f0f00e30d Mon Sep 17 00:00:00 2001 From: Dan Klishch Date: Wed, 15 Nov 2023 03:03:07 -0500 Subject: [PATCH] AK: Store JsonValue's value in AK::Variant --- AK/JsonObject.h | 50 ++++--------- AK/JsonValue.cpp | 156 ++++++++++++++++------------------------ AK/JsonValue.h | 180 +++++++++++++++++------------------------------ 3 files changed, 137 insertions(+), 249 deletions(-) diff --git a/AK/JsonObject.h b/AK/JsonObject.h index a985ab4dbf7..e6df653cb84 100644 --- a/AK/JsonObject.h +++ b/AK/JsonObject.h @@ -138,44 +138,18 @@ inline typename Builder::OutputType JsonObject::serialized() const template inline void JsonValue::serialize(Builder& builder) const { - switch (m_type) { - case Type::String: { - builder.append('\"'); - builder.append_escaped_for_json({ m_value.as_string->characters(), m_value.as_string->length() }); - builder.append('\"'); - } break; - case Type::Array: - m_value.as_array->serialize(builder); - break; - case Type::Object: - m_value.as_object->serialize(builder); - break; - case Type::Bool: - builder.append(m_value.as_bool ? "true"sv : "false"sv); - break; -#if !defined(KERNEL) - case Type::Double: - builder.appendff("{}", m_value.as_double); - break; -#endif - case Type::Int32: - builder.appendff("{}", m_value.as_i32); - break; - case Type::Int64: - builder.appendff("{}", m_value.as_i64); - break; - case Type::UnsignedInt32: - builder.appendff("{}", m_value.as_u32); - break; - case Type::UnsignedInt64: - builder.appendff("{}", m_value.as_u64); - break; - case Type::Null: - builder.append("null"sv); - break; - default: - VERIFY_NOT_REACHED(); - } + m_value.visit( + [&](Empty const&) { builder.append("null"sv); }, + [&](bool const& value) { builder.append(value ? "true"sv : "false"sv); }, + [&](Arithmetic auto const& value) { builder.appendff("{}", value); }, + [&](ByteString const& value) { + builder.append('\"'); + builder.append_escaped_for_json(value.bytes()); + builder.append('\"'); + }, + [&](auto const& array_or_object) { + array_or_object->serialize(builder); + }); } template diff --git a/AK/JsonValue.cpp b/AK/JsonValue.cpp index b1699fb716e..9b4db020ba8 100644 --- a/AK/JsonValue.cpp +++ b/AK/JsonValue.cpp @@ -1,69 +1,77 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2024, Dan Klishch * * SPDX-License-Identifier: BSD-2-Clause */ #include #include +#include #include #include -#ifndef KERNEL -# include -#endif - namespace AK { -JsonValue::JsonValue(JsonValue const& other) +namespace { +using JsonValueStorage = Variant< + Empty, + bool, + i64, + u64, + double, + ByteString, + NonnullOwnPtr, + NonnullOwnPtr>; + +static ErrorOr clone(JsonValueStorage const& other) +{ + return other.visit( + [](NonnullOwnPtr const& value) -> ErrorOr { + return TRY(try_make(*value)); + }, + [](NonnullOwnPtr const& value) -> ErrorOr { + return TRY(try_make(*value)); + }, + [](auto const& value) -> ErrorOr { return JsonValueStorage(value); }); +} +} + +JsonValue::JsonValue() = default; +JsonValue::~JsonValue() = default; +JsonValue::JsonValue(JsonValue&&) = default; +JsonValue& JsonValue::operator=(JsonValue&&) = default; + +JsonValue::JsonValue(JsonValue const& other) + : m_value(MUST(clone(other.m_value))) { - copy_from(other); } JsonValue& JsonValue::operator=(JsonValue const& other) { - if (this != &other) { - clear(); - copy_from(other); - } + if (this != &other) + m_value = MUST(clone(other.m_value)); return *this; } -void JsonValue::copy_from(JsonValue const& other) +JsonValue& JsonValue::operator=(JsonArray const& other) { - m_type = other.m_type; - switch (m_type) { - case Type::String: - VERIFY(!m_value.as_string); - m_value.as_string = other.m_value.as_string; - m_value.as_string->ref(); - break; - case Type::Object: - m_value.as_object = new JsonObject(*other.m_value.as_object); - break; - case Type::Array: - m_value.as_array = new JsonArray(*other.m_value.as_array); - break; - default: - m_value.as_u64 = other.m_value.as_u64; - break; - } + return *this = JsonValue(other); } -JsonValue::JsonValue(JsonValue&& other) +JsonValue& JsonValue::operator=(JsonArray&& other) { - m_type = exchange(other.m_type, Type::Null); - m_value.as_u64 = exchange(other.m_value.as_u64, 0); + return *this = JsonValue(other); } -JsonValue& JsonValue::operator=(JsonValue&& other) +JsonValue& JsonValue::operator=(JsonObject const& other) { - if (this != &other) { - clear(); - m_type = exchange(other.m_type, Type::Null); - m_value.as_u64 = exchange(other.m_value.as_u64, 0); - } - return *this; + return *this = JsonValue(other); +} + +JsonValue& JsonValue::operator=(JsonObject&& other) +{ + return *this = JsonValue(other); } bool JsonValue::equals(JsonValue const& other) const @@ -127,122 +135,78 @@ bool JsonValue::equals(JsonValue const& other) const } JsonValue::JsonValue(int value) - : m_type(Type::Int32) + : m_value(i64 { value }) { - m_value.as_i32 = value; } JsonValue::JsonValue(unsigned value) - : m_type(Type::UnsignedInt32) + : m_value(i64 { value }) { - m_value.as_u32 = value; } JsonValue::JsonValue(long value) - : m_type(sizeof(long) == 8 ? Type::Int64 : Type::Int32) + : m_value(i64 { value }) { - if constexpr (sizeof(long) == 8) - m_value.as_i64 = value; - else - m_value.as_i32 = value; } JsonValue::JsonValue(unsigned long value) - : m_type(sizeof(long) == 8 ? Type::UnsignedInt64 : Type::UnsignedInt32) + : m_value(u64 { value }) { - if constexpr (sizeof(long) == 8) - m_value.as_u64 = value; - else - m_value.as_u32 = value; } JsonValue::JsonValue(long long value) - : m_type(Type::Int64) + : m_value(i64 { value }) { - static_assert(sizeof(long long unsigned) == 8); - m_value.as_i64 = value; } JsonValue::JsonValue(long long unsigned value) - : m_type(Type::UnsignedInt64) + : m_value(u64 { value }) { - static_assert(sizeof(long long unsigned) == 8); - m_value.as_u64 = value; } JsonValue::JsonValue(char const* cstring) - : JsonValue(ByteString(cstring)) + : m_value(ByteString { cstring }) { } -#if !defined(KERNEL) JsonValue::JsonValue(double value) - : m_type(Type::Double) + : m_value(double { value }) { - m_value.as_double = value; } -#endif JsonValue::JsonValue(ByteString const& value) + : m_value(value) { - m_type = Type::String; - m_value.as_string = const_cast(value.impl()); - m_value.as_string->ref(); } JsonValue::JsonValue(StringView value) - : JsonValue(value.to_byte_string()) + : m_value(ByteString { value }) { } JsonValue::JsonValue(JsonObject const& value) - : m_type(Type::Object) + : m_value(make(value)) { - m_value.as_object = new JsonObject(value); } JsonValue::JsonValue(JsonArray const& value) - : m_type(Type::Array) + : m_value(make(value)) { - m_value.as_array = new JsonArray(value); } JsonValue::JsonValue(JsonObject&& value) - : m_type(Type::Object) + : m_value(make(value)) { - m_value.as_object = new JsonObject(move(value)); } JsonValue::JsonValue(JsonArray&& value) - : m_type(Type::Array) + : m_value(make(value)) { - m_value.as_array = new JsonArray(move(value)); } -void JsonValue::clear() -{ - switch (m_type) { - case Type::String: - m_value.as_string->unref(); - break; - case Type::Object: - delete m_value.as_object; - break; - case Type::Array: - delete m_value.as_array; - break; - default: - break; - } - m_type = Type::Null; - m_value.as_string = nullptr; -} - -#ifndef KERNEL ErrorOr JsonValue::from_string(StringView input) { return JsonParser(input).parse(); } -#endif } diff --git a/AK/JsonValue.h b/AK/JsonValue.h index b8e7419fe95..7faf48d3c61 100644 --- a/AK/JsonValue.h +++ b/AK/JsonValue.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2024, Dan Klishch * * SPDX-License-Identifier: BSD-2-Clause */ @@ -13,6 +14,7 @@ #include #include #include +#include #include namespace AK { @@ -21,12 +23,8 @@ class JsonValue { public: enum class Type { Null, - Int32, - UnsignedInt32, - Int64, - UnsignedInt64, - Double, Bool, + Number, String, Array, Object, @@ -34,8 +32,8 @@ public: static ErrorOr from_string(StringView); - JsonValue() = default; - ~JsonValue() { clear(); } + JsonValue(); + ~JsonValue(); JsonValue(JsonValue const&); JsonValue(JsonValue&&); @@ -58,8 +56,7 @@ public: template requires(SameAs, bool>) JsonValue(T value) - : m_type(Type::Bool) - , m_value { .as_bool = value } + : m_value { static_cast(value) } { } @@ -69,9 +66,11 @@ public: JsonValue(JsonArray&&); JsonValue(JsonObject&&); - // FIXME: Implement these - JsonValue& operator=(JsonArray&&) = delete; - JsonValue& operator=(JsonObject&&) = delete; + JsonValue& operator=(JsonArray const&); + JsonValue& operator=(JsonObject const&); + + JsonValue& operator=(JsonArray&&); + JsonValue& operator=(JsonObject&&); template typename Builder::OutputType serialized() const; @@ -126,166 +125,117 @@ public: bool as_bool() const { - VERIFY(is_bool()); - return m_value.as_bool; + return m_value.get(); } ByteString as_string() const { - VERIFY(is_string()); - return *m_value.as_string; + return m_value.get(); } JsonObject& as_object() { - VERIFY(is_object()); - return *m_value.as_object; + return *m_value.get>(); } JsonObject const& as_object() const { - VERIFY(is_object()); - return *m_value.as_object; + return *m_value.get>(); } JsonArray& as_array() { - VERIFY(is_array()); - return *m_value.as_array; + return *m_value.get>(); } JsonArray const& as_array() const { - VERIFY(is_array()); - return *m_value.as_array; + return *m_value.get>(); } Variant as_number() const { - VERIFY(is_number()); - - switch (m_type) { - case Type::Int32: - return static_cast(m_value.as_i32); - case Type::UnsignedInt32: - return static_cast(m_value.as_u32); - case Type::Int64: - return m_value.as_i64; - case Type::UnsignedInt64: - return m_value.as_u64; - case Type::Double: - return m_value.as_double; - default: - VERIFY_NOT_REACHED(); - } + return m_value.downcast(); } Type type() const { - return m_type; + return m_value.visit( + [](Empty const&) { return Type::Null; }, + [](bool const&) { return Type::Bool; }, + [](Arithmetic auto const&) { return Type::Number; }, + [](ByteString const&) { return Type::String; }, + [](NonnullOwnPtr const&) { return Type::Array; }, + [](NonnullOwnPtr const&) { return Type::Object; }); } - bool is_null() const { return m_type == Type::Null; } - bool is_bool() const { return m_type == Type::Bool; } - bool is_string() const { return m_type == Type::String; } - bool is_array() const { return m_type == Type::Array; } - bool is_object() const { return m_type == Type::Object; } + bool is_null() const { return m_value.has(); } + bool is_bool() const { return m_value.has(); } + bool is_string() const { return m_value.has(); } + bool is_array() const { return m_value.has>(); } + bool is_object() const { return m_value.has>(); } bool is_number() const { - switch (m_type) { - case Type::Int32: - case Type::UnsignedInt32: - case Type::Int64: - case Type::UnsignedInt64: - case Type::Double: - return true; - default: - return false; - } + return m_value.visit( + [](bool const&) { return false; }, + [](U const&) { return true; }, + [](auto const&) { return false; }); } template Optional get_number_with_precision_loss() const { - switch (m_type) { - case Type::Double: - return static_cast(m_value.as_double); - case Type::Int32: - return static_cast(m_value.as_i32); - case Type::UnsignedInt32: - return static_cast(m_value.as_u32); - case Type::Int64: - return static_cast(m_value.as_i64); - case Type::UnsignedInt64: - return static_cast(m_value.as_u64); - default: - return {}; - } + return m_value.visit( + [](bool const&) { return Optional {}; }, + [](U const& value) { return Optional { static_cast(value) }; }, + [](auto const&) { return Optional {}; }); } template bool is_integer() const { - switch (m_type) { - case Type::Int32: - return is_within_range(m_value.as_i32); - case Type::UnsignedInt32: - return is_within_range(m_value.as_u32); - case Type::Int64: - return is_within_range(m_value.as_i64); - case Type::UnsignedInt64: - return is_within_range(m_value.as_u64); - default: - return false; - } + return get_integer().has_value(); } template T as_integer() const { - VERIFY(is_integer()); - - switch (m_type) { - case Type::Int32: - return static_cast(m_value.as_i32); - case Type::UnsignedInt32: - return static_cast(m_value.as_u32); - case Type::Int64: - return static_cast(m_value.as_i64); - case Type::UnsignedInt64: - return static_cast(m_value.as_u64); - default: - VERIFY_NOT_REACHED(); - } + return get_integer().value(); } template Optional get_integer() const { - if (!is_integer()) - return {}; - return as_integer(); + return m_value.visit( + [](bool const&) { return Optional {}; }, + [](U const& value) -> Optional { + if constexpr (Integral) { + if (!is_within_range(value)) + return {}; + return static_cast(value); + } else { + // FIXME: Make is_within_range work with floating point numbers. + if (static_cast(static_cast(value)) != value) + return {}; + return static_cast(value); + } + }, + [](auto const&) { return Optional {}; }); } bool equals(JsonValue const& other) const; private: - void clear(); - void copy_from(JsonValue const&); - - Type m_type { Type::Null }; - - union { - StringImpl* as_string { nullptr }; - JsonArray* as_array; - JsonObject* as_object; - double as_double; - i32 as_i32; - u32 as_u32; - i64 as_i64; - u64 as_u64; - bool as_bool; - } m_value; + Variant< + Empty, + bool, + i64, + u64, + double, + ByteString, + NonnullOwnPtr, + NonnullOwnPtr> + m_value; }; template<>