diff --git a/src/util/json/fromjson.h b/src/util/json/fromjson.h new file mode 100644 index 0000000..048faf2 --- /dev/null +++ b/src/util/json/fromjson.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#ifndef JSON_FROM_JSON_H +#define JSON_FROM_JSON_H + +#include // transform +#include // assert +#include // nullptr_t +#include +#include +#include +#include + +#include "util/json/array.h" +#include "util/json/object.h" + +namespace Json { + +namespace Detail { + +// Required for containers with Json::Value type +template +void fromJson(const Json& json, Json& value) +{ + value = json; +} + +template +void fromJson(const Json& json, std::nullptr_t& null) +{ + assert(json.type() == Json::Type::Null); + null = nullptr; +} + +template +void fromJson(const Json& json, bool& boolean) +{ + assert(json.type() == Json::Type::Bool); + boolean = json.asBool(); +} + +template +void fromJson(const Json& json, int& number) +{ + assert(json.type() == Json::Type::Number); + number = (int)json.asDouble(); +} + +template +void fromJson(const Json& json, double& number) +{ + assert(json.type() == Json::Type::Number); + number = json.asDouble(); +} + +template +void fromJson(const Json& json, std::string& string) +{ + assert(json.type() == Json::Type::String); + string = json.asString(); +} + +template +void fromJson(const Json& json, std::vector& array) +{ + assert(json.type() == Json::Type::Array); + array.resize(json.size()); + std::transform( + json.asArray().values().begin(), + json.asArray().values().end(), + array.begin(), + [](const Json& json) { + return json.template get(); // (missing-dependent-template-keyword) + }); +} + +struct fromJsonFunction { + template + auto operator()(const Json& json, T&& value) const + { + return fromJson(json, std::forward(value)); + } +}; + +// Avoid ODR (One Definition Rule) violations +template +constexpr T staticConst {}; + +} // namespace Detail + +// Anonymous namespace prevents multiple definition of the reference +namespace { +// Function object +constexpr const auto& fromJson = Detail::staticConst; // NOLINT (misc-definitions-in-headers) +} // namespace + +} // namespace Json + +#endif // JSON_FROM_JSON_H + +// Customization Points +// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html + +// Json::fromJson is a function object, the type of which is +// Json::Detail::fromJsonFunction. In the Json::Detail namespace are the +// fromJson free functions. The function call operator of fromJsonFunction makes +// an unqualified call to fromJson which, since it shares the Detail namespace +// with the fromJson free functions, will consider those in addition to any +// overloads that are found by argument-dependent lookup. + +// Variable templates are linked externally, therefor every translation unit +// will see the same address for Detail::staticConst. +// Since Json::fromJson is a reference to the variable template, it too will +// have the same address in all translation units. diff --git a/src/util/json/value.cpp b/src/util/json/value.cpp index 8b5d9fa..4167bc1 100644 --- a/src/util/json/value.cpp +++ b/src/util/json/value.cpp @@ -7,8 +7,7 @@ #include // all_of #include // assert #include // uint32_t -#include -#include // make_shared, shared_ptr +#include // istream, ostream #include #include // move diff --git a/src/util/json/value.h b/src/util/json/value.h index 93481b2..7ac9e4d 100644 --- a/src/util/json/value.h +++ b/src/util/json/value.h @@ -13,6 +13,8 @@ #include // istream, ostream #include +#include "util/json/fromjson.h" + namespace Json { class Array; @@ -73,6 +75,22 @@ public: // -------------------------------------- + template + T get() const + { + T type; + fromJson(*this, type); + return type; + } + + template + void getTo(T& type) const + { + fromJson(*this, type); + } + + // -------------------------------------- + Type type() const { return m_type; } size_t size() const;