-
-
Save tomolatoon/db219d078b9cd83a51ab14d4c2358312 to your computer and use it in GitHub Desktop.
OpenSiv3D v0.8 世代を見据えた新たな JSON クラスの研究
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) | |
{ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// コンパイル通らないが、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()) {} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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