1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 08:24:58 +00:00

AK: Store JsonValue's value in AK::Variant

This commit is contained in:
Dan Klishch 2023-11-15 03:03:07 -05:00 committed by Andrew Kaster
parent 05e53b5fd3
commit 88af15d513
3 changed files with 137 additions and 249 deletions

View file

@ -138,44 +138,18 @@ inline typename Builder::OutputType JsonObject::serialized() const
template<typename Builder> template<typename Builder>
inline void JsonValue::serialize(Builder& builder) const inline void JsonValue::serialize(Builder& builder) const
{ {
switch (m_type) { m_value.visit(
case Type::String: { [&](Empty const&) { builder.append("null"sv); },
builder.append('\"'); [&](bool const& value) { builder.append(value ? "true"sv : "false"sv); },
builder.append_escaped_for_json({ m_value.as_string->characters(), m_value.as_string->length() }); [&](Arithmetic auto const& value) { builder.appendff("{}", value); },
builder.append('\"'); [&](ByteString const& value) {
} break; builder.append('\"');
case Type::Array: builder.append_escaped_for_json(value.bytes());
m_value.as_array->serialize(builder); builder.append('\"');
break; },
case Type::Object: [&](auto const& array_or_object) {
m_value.as_object->serialize(builder); array_or_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();
}
} }
template<typename Builder> template<typename Builder>

View file

@ -1,69 +1,77 @@
/* /*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2024, Dan Klishch <danilklishch@gmail.com>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/JsonArray.h> #include <AK/JsonArray.h>
#include <AK/JsonObject.h> #include <AK/JsonObject.h>
#include <AK/JsonParser.h>
#include <AK/JsonValue.h> #include <AK/JsonValue.h>
#include <AK/StringView.h> #include <AK/StringView.h>
#ifndef KERNEL
# include <AK/JsonParser.h>
#endif
namespace AK { namespace AK {
JsonValue::JsonValue(JsonValue const& other) namespace {
using JsonValueStorage = Variant<
Empty,
bool,
i64,
u64,
double,
ByteString,
NonnullOwnPtr<JsonArray>,
NonnullOwnPtr<JsonObject>>;
static ErrorOr<JsonValueStorage> clone(JsonValueStorage const& other)
{
return other.visit(
[](NonnullOwnPtr<JsonArray> const& value) -> ErrorOr<JsonValueStorage> {
return TRY(try_make<JsonArray>(*value));
},
[](NonnullOwnPtr<JsonObject> const& value) -> ErrorOr<JsonValueStorage> {
return TRY(try_make<JsonObject>(*value));
},
[](auto const& value) -> ErrorOr<JsonValueStorage> { 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) JsonValue& JsonValue::operator=(JsonValue const& other)
{ {
if (this != &other) { if (this != &other)
clear(); m_value = MUST(clone(other.m_value));
copy_from(other);
}
return *this; return *this;
} }
void JsonValue::copy_from(JsonValue const& other) JsonValue& JsonValue::operator=(JsonArray const& other)
{ {
m_type = other.m_type; return *this = JsonValue(other);
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;
}
} }
JsonValue::JsonValue(JsonValue&& other) JsonValue& JsonValue::operator=(JsonArray&& other)
{ {
m_type = exchange(other.m_type, Type::Null); return *this = JsonValue(other);
m_value.as_u64 = exchange(other.m_value.as_u64, 0);
} }
JsonValue& JsonValue::operator=(JsonValue&& other) JsonValue& JsonValue::operator=(JsonObject const& other)
{ {
if (this != &other) { return *this = JsonValue(other);
clear(); }
m_type = exchange(other.m_type, Type::Null);
m_value.as_u64 = exchange(other.m_value.as_u64, 0); JsonValue& JsonValue::operator=(JsonObject&& other)
} {
return *this; return *this = JsonValue(other);
} }
bool JsonValue::equals(JsonValue const& other) const bool JsonValue::equals(JsonValue const& other) const
@ -127,122 +135,78 @@ bool JsonValue::equals(JsonValue const& other) const
} }
JsonValue::JsonValue(int value) JsonValue::JsonValue(int value)
: m_type(Type::Int32) : m_value(i64 { value })
{ {
m_value.as_i32 = value;
} }
JsonValue::JsonValue(unsigned value) JsonValue::JsonValue(unsigned value)
: m_type(Type::UnsignedInt32) : m_value(i64 { value })
{ {
m_value.as_u32 = value;
} }
JsonValue::JsonValue(long 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) 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) 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) 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::JsonValue(char const* cstring)
: JsonValue(ByteString(cstring)) : m_value(ByteString { cstring })
{ {
} }
#if !defined(KERNEL)
JsonValue::JsonValue(double value) JsonValue::JsonValue(double value)
: m_type(Type::Double) : m_value(double { value })
{ {
m_value.as_double = value;
} }
#endif
JsonValue::JsonValue(ByteString const& value) JsonValue::JsonValue(ByteString const& value)
: m_value(value)
{ {
m_type = Type::String;
m_value.as_string = const_cast<StringImpl*>(value.impl());
m_value.as_string->ref();
} }
JsonValue::JsonValue(StringView value) JsonValue::JsonValue(StringView value)
: JsonValue(value.to_byte_string()) : m_value(ByteString { value })
{ {
} }
JsonValue::JsonValue(JsonObject const& value) JsonValue::JsonValue(JsonObject const& value)
: m_type(Type::Object) : m_value(make<JsonObject>(value))
{ {
m_value.as_object = new JsonObject(value);
} }
JsonValue::JsonValue(JsonArray const& value) JsonValue::JsonValue(JsonArray const& value)
: m_type(Type::Array) : m_value(make<JsonArray>(value))
{ {
m_value.as_array = new JsonArray(value);
} }
JsonValue::JsonValue(JsonObject&& value) JsonValue::JsonValue(JsonObject&& value)
: m_type(Type::Object) : m_value(make<JsonObject>(value))
{ {
m_value.as_object = new JsonObject(move(value));
} }
JsonValue::JsonValue(JsonArray&& value) JsonValue::JsonValue(JsonArray&& value)
: m_type(Type::Array) : m_value(make<JsonArray>(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> JsonValue::from_string(StringView input) ErrorOr<JsonValue> JsonValue::from_string(StringView input)
{ {
return JsonParser(input).parse(); return JsonParser(input).parse();
} }
#endif
} }

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2024, Dan Klishch <danilklishch@gmail.com>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -13,6 +14,7 @@
#include <AK/ByteString.h> #include <AK/ByteString.h>
#include <AK/Forward.h> #include <AK/Forward.h>
#include <AK/Optional.h> #include <AK/Optional.h>
#include <AK/OwnPtr.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
namespace AK { namespace AK {
@ -21,12 +23,8 @@ class JsonValue {
public: public:
enum class Type { enum class Type {
Null, Null,
Int32,
UnsignedInt32,
Int64,
UnsignedInt64,
Double,
Bool, Bool,
Number,
String, String,
Array, Array,
Object, Object,
@ -34,8 +32,8 @@ public:
static ErrorOr<JsonValue> from_string(StringView); static ErrorOr<JsonValue> from_string(StringView);
JsonValue() = default; JsonValue();
~JsonValue() { clear(); } ~JsonValue();
JsonValue(JsonValue const&); JsonValue(JsonValue const&);
JsonValue(JsonValue&&); JsonValue(JsonValue&&);
@ -58,8 +56,7 @@ public:
template<typename T> template<typename T>
requires(SameAs<RemoveCVReference<T>, bool>) requires(SameAs<RemoveCVReference<T>, bool>)
JsonValue(T value) JsonValue(T value)
: m_type(Type::Bool) : m_value { static_cast<bool>(value) }
, m_value { .as_bool = value }
{ {
} }
@ -69,9 +66,11 @@ public:
JsonValue(JsonArray&&); JsonValue(JsonArray&&);
JsonValue(JsonObject&&); JsonValue(JsonObject&&);
// FIXME: Implement these JsonValue& operator=(JsonArray const&);
JsonValue& operator=(JsonArray&&) = delete; JsonValue& operator=(JsonObject const&);
JsonValue& operator=(JsonObject&&) = delete;
JsonValue& operator=(JsonArray&&);
JsonValue& operator=(JsonObject&&);
template<typename Builder> template<typename Builder>
typename Builder::OutputType serialized() const; typename Builder::OutputType serialized() const;
@ -126,166 +125,117 @@ public:
bool as_bool() const bool as_bool() const
{ {
VERIFY(is_bool()); return m_value.get<bool>();
return m_value.as_bool;
} }
ByteString as_string() const ByteString as_string() const
{ {
VERIFY(is_string()); return m_value.get<ByteString>();
return *m_value.as_string;
} }
JsonObject& as_object() JsonObject& as_object()
{ {
VERIFY(is_object()); return *m_value.get<NonnullOwnPtr<JsonObject>>();
return *m_value.as_object;
} }
JsonObject const& as_object() const JsonObject const& as_object() const
{ {
VERIFY(is_object()); return *m_value.get<NonnullOwnPtr<JsonObject>>();
return *m_value.as_object;
} }
JsonArray& as_array() JsonArray& as_array()
{ {
VERIFY(is_array()); return *m_value.get<NonnullOwnPtr<JsonArray>>();
return *m_value.as_array;
} }
JsonArray const& as_array() const JsonArray const& as_array() const
{ {
VERIFY(is_array()); return *m_value.get<NonnullOwnPtr<JsonArray>>();
return *m_value.as_array;
} }
Variant<u64, i64, double> as_number() const Variant<u64, i64, double> as_number() const
{ {
VERIFY(is_number()); return m_value.downcast<u64, i64, double>();
switch (m_type) {
case Type::Int32:
return static_cast<i64>(m_value.as_i32);
case Type::UnsignedInt32:
return static_cast<i64>(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();
}
} }
Type type() const 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<JsonArray> const&) { return Type::Array; },
[](NonnullOwnPtr<JsonObject> const&) { return Type::Object; });
} }
bool is_null() const { return m_type == Type::Null; } bool is_null() const { return m_value.has<Empty>(); }
bool is_bool() const { return m_type == Type::Bool; } bool is_bool() const { return m_value.has<bool>(); }
bool is_string() const { return m_type == Type::String; } bool is_string() const { return m_value.has<ByteString>(); }
bool is_array() const { return m_type == Type::Array; } bool is_array() const { return m_value.has<NonnullOwnPtr<JsonArray>>(); }
bool is_object() const { return m_type == Type::Object; } bool is_object() const { return m_value.has<NonnullOwnPtr<JsonObject>>(); }
bool is_number() const bool is_number() const
{ {
switch (m_type) { return m_value.visit(
case Type::Int32: [](bool const&) { return false; },
case Type::UnsignedInt32: []<Arithmetic U>(U const&) { return true; },
case Type::Int64: [](auto const&) { return false; });
case Type::UnsignedInt64:
case Type::Double:
return true;
default:
return false;
}
} }
template<typename T> template<typename T>
Optional<T> get_number_with_precision_loss() const Optional<T> get_number_with_precision_loss() const
{ {
switch (m_type) { return m_value.visit(
case Type::Double: [](bool const&) { return Optional<T> {}; },
return static_cast<T>(m_value.as_double); []<Arithmetic U>(U const& value) { return Optional<T> { static_cast<T>(value) }; },
case Type::Int32: [](auto const&) { return Optional<T> {}; });
return static_cast<T>(m_value.as_i32);
case Type::UnsignedInt32:
return static_cast<T>(m_value.as_u32);
case Type::Int64:
return static_cast<T>(m_value.as_i64);
case Type::UnsignedInt64:
return static_cast<T>(m_value.as_u64);
default:
return {};
}
} }
template<Integral T> template<Integral T>
bool is_integer() const bool is_integer() const
{ {
switch (m_type) { return get_integer<T>().has_value();
case Type::Int32:
return is_within_range<T>(m_value.as_i32);
case Type::UnsignedInt32:
return is_within_range<T>(m_value.as_u32);
case Type::Int64:
return is_within_range<T>(m_value.as_i64);
case Type::UnsignedInt64:
return is_within_range<T>(m_value.as_u64);
default:
return false;
}
} }
template<Integral T> template<Integral T>
T as_integer() const T as_integer() const
{ {
VERIFY(is_integer<T>()); return get_integer<T>().value();
switch (m_type) {
case Type::Int32:
return static_cast<T>(m_value.as_i32);
case Type::UnsignedInt32:
return static_cast<T>(m_value.as_u32);
case Type::Int64:
return static_cast<T>(m_value.as_i64);
case Type::UnsignedInt64:
return static_cast<T>(m_value.as_u64);
default:
VERIFY_NOT_REACHED();
}
} }
template<Integral T> template<Integral T>
Optional<T> get_integer() const Optional<T> get_integer() const
{ {
if (!is_integer<T>()) return m_value.visit(
return {}; [](bool const&) { return Optional<T> {}; },
return as_integer<T>(); []<Arithmetic U>(U const& value) -> Optional<T> {
if constexpr (Integral<U>) {
if (!is_within_range<T>(value))
return {};
return static_cast<T>(value);
} else {
// FIXME: Make is_within_range work with floating point numbers.
if (static_cast<U>(static_cast<T>(value)) != value)
return {};
return static_cast<T>(value);
}
},
[](auto const&) { return Optional<T> {}; });
} }
bool equals(JsonValue const& other) const; bool equals(JsonValue const& other) const;
private: private:
void clear(); Variant<
void copy_from(JsonValue const&); Empty,
bool,
Type m_type { Type::Null }; i64,
u64,
union { double,
StringImpl* as_string { nullptr }; ByteString,
JsonArray* as_array; NonnullOwnPtr<JsonArray>,
JsonObject* as_object; NonnullOwnPtr<JsonObject>>
double as_double; m_value;
i32 as_i32;
u32 as_u32;
i64 as_i64;
u64 as_u64;
bool as_bool;
} m_value;
}; };
template<> template<>