Skip to content

Instantly share code, notes, and snippets.

@tomolatoon
Last active December 30, 2023 06:51
Show Gist options
  • Save tomolatoon/db219d078b9cd83a51ab14d4c2358312 to your computer and use it in GitHub Desktop.
Save tomolatoon/db219d078b9cd83a51ab14d4c2358312 to your computer and use it in GitHub Desktop.
OpenSiv3D v0.8 世代を見据えた新たな JSON クラスの研究
namespace tomolatoon
{
#define ARGS std::map, std::vector, std::string, bool, int64_t, uint64_t, double, std::allocator, nlohmann::adl_serializer, std::vector<uint8_t>
struct JSON
{
JSON() = default;
JSON(std::shared_ptr<void>&& data)
: m_data(std::move(data))
{}
JSON& operator[](StringView sv);
template <class T>
T get();
static JSON Parse(StringView sv);
friend struct JSONConstructor;
private:
std::shared_ptr<void> m_data;
};
using NJSON = nlohmann::basic_json<ARGS, JSON>;
struct JSONConstructor
{
static JSON FromNJSON(NJSON&& njson)
{
return JSON(std::shared_ptr<void>(new NJSON(std::move(njson))));
}
};
#define EXPAND(x) x
#define to_NJSONPtr(...) ((NJSON*)(__VA_ARGS__))
#define to_NJSONRef(...) (*to_NJSONPtr(__VA_ARGS__))
#define ptrRaw (m_data.get())
JSON JSON::Parse(StringView sv)
{
return JSONConstructor::FromNJSON(NJSON::parse(Unicode::ToUTF8(sv)));
}
JSON& JSON::operator[](StringView sv)
{
if (to_NJSONPtr(ptrRaw))
{
return to_NJSONRef(ptrRaw)[Unicode::ToUTF8(sv)];
}
else
{
return to_NJSONRef(this)[Unicode::ToUTF8(sv)];
}
}
template <class T>
T JSON::get()
{
if constexpr (std::convertible_to<T, String>)
{
if (to_NJSONPtr(ptrRaw))
{
return Unicode::FromUTF8(to_NJSONRef(ptrRaw).get<std::string>());
}
else
{
return Unicode::FromUTF8(to_NJSONRef(this).get<std::string>());
}
}
else
{
if (to_NJSONPtr(ptrRaw))
{
return to_NJSONRef(ptrRaw).get<T>();
}
else
{
return to_NJSONRef(this).get<T>();
}
}
}
#undef ptrRaw
#undef to_NJSONRef
#undef to_NJSONPtr
} // namespace tomolatoon
void Main()
{
tomolatoon::JSON json = tomolatoon::JSON::Parse(UR"({"a":"a"})");
auto&& r = json[U"a"];
auto&& s = r.get<String>();
while (System::Update())
{
}
}
// コンパイル通らないが、type1 ではだいたいこんなことをしたい。
namespace tomolatoon
{
// clang-format off
#define ARGS std::map, std::vector, std::string, bool, int64_t, uint64_t, double, std::allocator, nlohmann::adl_serializer, std::vector<uint8_t>
// clang-format on
struct JSON
{
// JSON を継承した nlohmann_json を NJSON としている
using NJSON = nlohmann::basic_json<ARGS, JSON>;
JSON() = default;
JSON(const JSON& json);
JSON(std::shared_ptr<NJSON>&& data)
: m_data(std::move(data)) {}
JSON& operator[](StringView sv);
const JSON& operator[](StringView sv) const;
template <class T>
T get() const;
String format(char32 space = U' ', size_t spaceCount = 2) const;
static JSON Parse(StringView sv);
friend struct JSONHelper;
private:
// これは shared_ptr<NJSON> のようなもの
// 持っている: 一番根っこのノード。NJSON 根っこを維持するために必要
// 持っていない: 葉のノード。
std::shared_ptr<NJSON> m_data = nullptr;
};
#define EXPAND(x) x
#define to_NJSONPtr(...) ((JSON::NJSON*)(__VA_ARGS__))
#define to_NJSONRef(...) (*to_NJSONPtr(__VA_ARGS__))
#define ptrRaw (m_data.get())
struct JSONHelper
{
static JSON FromNJSON(JSON::NJSON&& njson) {
return JSON(std::make_shared<JSON::NJSON>(std::move(njson)));
}
// const 性を伝搬しつつ、NJSON への参照を返す
template <class T>
requires std::same_as<std::remove_cv_t<T>, JSON>
static auto ToRefNJSON(T& json) -> std::add_lvalue_reference_t<
std::conditional_t<std::is_const_v<JSON>, std::add_const_t<JSON::NJSON>, JSON::NJSON>> {
// return to_NJSONRef(std::addressof(json));
if (json.m_data.get()) { return *((JSON::NJSON*)(json.m_data.get())); }
else { return *((JSON::NJSON*)(std::addressof(json))); }
}
};
// ここ、今のところ色々とガバ
JSON::JSON(const JSON& json)
: m_data(
json.m_data.get() ? std::make_shared<JSON::NJSON>(JSONHelper::ToRefNJSON(json))
: std::shared_ptr<JSON::NJSON>((JSON::NJSON*)(this))
) {}
JSON& JSON::operator[](StringView sv) {
return JSONHelper::ToRefNJSON(*this)[Unicode::ToUTF8(sv)];
}
const JSON& JSON::operator[](StringView sv) const {
return JSONHelper::ToRefNJSON(*this)[Unicode::ToUTF8(sv)];
}
template <class T>
T JSON::get() const {
if constexpr (std::convertible_to<T, String>)
{ return Unicode::FromUTF8(JSONHelper::ToRefNJSON(*this).get<std::string>()); }
else { return JSONHelper::ToRefNJSON(*this).get<T>(); }
}
String JSON::format(char32 space, size_t spaceCount) const {
return Unicode::FromUTF8(JSONHelper::ToRefNJSON(*this).dump(spaceCount, space));
}
JSON JSON::Parse(StringView sv) {
return JSONHelper::FromNJSON(NJSON::parse(Unicode::ToUTF8(sv)));
}
#undef ptrRaw
#undef to_NJSONRef
#undef to_NJSONPtr
} // namespace tomolatoon
tomolatoon::JSON f() {
tomolatoon::JSON json = tomolatoon::JSON::Parse(UR"({"a":{"b":[0,1,2,3]}, "c":"d"})");
return json[U"a"][U"b"];
}
void Main() {
using tomolatoon::JSON;
JSON json = JSON::Parse(UR"({"a":{"b":[0,1,2,3]}, "c":"d"})");
{
auto&& r = json[U"c"];
auto&& s = r.get<String>();
Print << r.format();
static_assert(std::same_as<decltype(r), JSON&>);
}
{
JSON r = f();
Print << r.format();
}
while (System::Update()) {}
}
namespace tomolatoon
{
struct JSONBase
{
using PJSON = nlohmann::basic_json<
std::map,
std::vector,
std::string,
bool,
int64_t,
uint64_t,
double,
std::allocator,
nlohmann::adl_serializer,
std::vector<uint8_t>,
JSONBase>;
// オーバーライドされてしまうので定義しても意味ない...
/*PJSON& operator[](const String& key) {
return pjson()[key.narrow()];
}
const PJSON& operator[](const String& key) const {
return pjson()[key.narrow()];
}*/
String format(char32 space = U' ', size_t spaceCount = 2) const {
return Unicode::FromUTF8(pjson().dump(spaceCount, space));
}
static PJSON Parse(StringView sv) {
return PJSON::parse(sv.narrow());
}
private:
PJSON& pjson() {
return static_cast<PJSON&>(*this);
}
const PJSON& pjson() const {
return static_cast<const PJSON&>(*this);
}
};
using JSON = JSONBase::PJSON;
} // namespace tomolatoon
// nlohmann/json のエコシステムに乗せれば良い
namespace s3d
{
void to_json(tomolatoon::JSON& j, const String& p) {
j = p.narrow();
}
void from_json(const tomolatoon::JSON& j, String& p) {
p = Unicode::FromUTF8(j.get<std::string>());
}
} // namespace s3d
void Main() {
using tomolatoon::JSON;
JSON j = JSON::Parse(UR"({"a":{"b":[0,1,2,3]}, "c":"d"})");
{
auto&& r = j["c"];
auto&& s = r.get<String>();
Print << j.format();
Print << s;
static_assert(std::same_as<decltype(r), JSON&>);
}
while (System::Update()) {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment