/* * Copyright (C) 2022 Riyyi * * SPDX-License-Identifier: MIT */ #ifndef JSON_TO_JSON_H #define JSON_TO_JSON_H #include // assert #include // nullptr_t #include #include #include #include // forward #include "util/json/array.h" #include "util/json/object.h" #include "util/meta/odr.h" namespace Json { namespace Detail { struct jsonConstructor { template static void construct(Json& json, bool boolean) { json.destroy(); json.m_type = Json::Type::Bool; json.m_value.boolean = boolean; } template static void construct(Json& json, int number) { json.destroy(); json.m_type = Json::Type::Number; json.m_value.number = (double)number; } template static void construct(Json& json, double number) { json.destroy(); json.m_type = Json::Type::Number; json.m_value.number = number; } template static void construct(Json& json, const char* string) { json.destroy(); json.m_type = Json::Type::String; json.m_value.string = new std::string(string); } template static void construct(Json& json, const std::string& string) { json.destroy(); json.m_type = Json::Type::String; json.m_value.string = new std::string(string); } template static void construct(Json& json, const Array& array) { json.destroy(); json.m_type = Json::Type::Array; json.m_value.array = new Array(array); } template static void construct(Json& json, const std::vector& array) { json.destroy(); json.m_type = Json::Type::Array; json.m_value.array = new Array; json.m_value.array->reserve(array.size()); for (const T& value : array) { json.m_value.array->emplace_back(value); } } template static void construct(Json& json, const Object& object) { json.destroy(); json.m_type = Json::Type::Object; json.m_value.object = new Object(object); } template static void construct(Json& json, const std::map& object) { json.destroy(); json.m_type = Json::Type::Object; json.m_value.object = new Object; for (const auto& [name, value] : object) { json.m_value.object->emplace(name, value); } } template static void construct(Json& json, const std::unordered_map& object) { json.destroy(); json.m_type = Json::Type::Object; json.m_value.object = new Object; for (const auto& [name, value] : object) { json.m_value.object->emplace(name, value); } } }; template void toJson(Json& json, const T& value) { jsonConstructor::construct(json, value); } struct toJsonFunction { template auto operator()(Json& json, T&& value) const { return toJson(json, std::forward(value)); } }; } // namespace Detail // Anonymous namespace prevents multiple definition of the reference namespace { // Function object constexpr const auto& toJson = Util::Detail::staticConst; // NOLINT(misc-definitions-in-headers,clang-diagnostic-unused-variable) } // namespace } // namespace Json #endif // JSON_TO_JSON_H // Customization Points // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html // Json::toJson is a function object, the type of which is // Json::Detail::toJsonFunction. In the Json::Detail namespace are the toJson // free functions. The function call operator of toJsonFunction makes an // unqualified call to toJson which, since it shares the Detail namespace with // the toJson 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::toJson is a reference to the variable template, it too will have // the same address in all translation units.