Josh Posted April 16, 2023 Share Posted April 16, 2023 It's clear after working with this for a while that what is needed is a table-like class in C++ that is mostly interchangeable with JSON and can be quickly accessed by both C++ and Lua. The problem with JSON is that nodes can behave like STL maps or vectors, and when you try to derive from both those types there's a lot of problems binding it with sol. So I will paste this here before I go tearing it apart. enum JsonType { JSON_NULL, JSON_INTEGER, JSON_FLOAT, JSON_BOOLEAN, JSON_STRING, JSON_OBJECT, JSON_ARRAY }; class Json : private std::map<std::string, Json>, std::vector<Json> { typedef std::map<std::string, Json> JsonObject; typedef std::vector<Json> JsonArray; float f; int i; bool b; std::string s; JsonType t; friend JsonObject; friend JsonArray; public: Json() { f = 0; i = 0; b = false; t = JSON_NULL; } JsonObject::iterator begin() { return JsonObject::begin(); } JsonObject::iterator end() { return JsonObject::end(); } static Json Object() { Json j; j.t = JSON_OBJECT; return j; } static Json Array() { Json j; j.t = JSON_ARRAY; return j; } JsonType GetType() { return t; } operator int() { if (t == JSON_INTEGER) return i; if (t == JSON_FLOAT) return f; if (t == JSON_BOOLEAN) return b; return 0; } operator float() { if (t == JSON_FLOAT) return f; if (t == JSON_INTEGER) return i; if (t == JSON_BOOLEAN) return b; return 0.0f; } operator std::string() { if (t == JSON_STRING) return s; if (t == JSON_FLOAT) return String(f); if (t == JSON_INTEGER) return String(i); if (t == JSON_BOOLEAN) return String(b); return ""; } void clear() { i = 0; f = 0; b = false; s.clear(); JsonArray::clear(); JsonObject::clear(); } Json(const int i_) { clear(); i = i_; t = JSON_INTEGER; } Json(const bool b_) { clear(); b = b_; t = JSON_BOOLEAN; } Json(const float f_) { clear(); f = f_; t = JSON_FLOAT; } Json(const std::string& s_) { clear(); s = s_; t = JSON_STRING; } Json(const JsonObject& j3) { clear(); t = JSON_OBJECT; for (const auto& pair : j3) { JsonObject::insert(pair); } //JsonObject::insert(JsonObject::end(), j3.begin(), j3.end()); } Json(const JsonArray& j3) { clear(); t = JSON_ARRAY; JsonArray::insert(JsonArray::end(), j3.begin(), j3.end()); } Json& operator[](const std::string& key) { if (t != JSON_OBJECT) RuntimeError("JSON value is not an object"); auto it = JsonObject::find(key); if (it == JsonObject::end()) { auto pair = std::pair<std::string, Json>(key, {}); JsonObject::insert(pair); it = JsonObject::find(key); Assert(it != JsonObject::end()); } return it->second; } Json& operator[](const int index) { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); return JsonArray::at(index); } void resize(const size_t sz) { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); JsonArray::resize(sz); } void reserve(const size_t sz) { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); JsonArray::reserve(sz); } size_t capacity() { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); return JsonArray::capacity(); } size_t size() { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); return JsonArray::size(); } void push_back(const Json& j3) { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); JsonArray::push_back(j3); } }; Example usage: auto j3 = Json::Object(); j3["health"] = 100; j3["windowsettings"] = Json::Object(); j3["windowsettings"]["position"] = 3; int g = j3["health"]; for (auto a : j3) { Print(a.first); Print(std::string(a.second)); } auto arr = Json::Array(); arr.push_back(1); arr.push_back(2); arr.push_back(3); arr.push_back(4); arr.push_back(5); for (int n = 0; n < arr.size(); ++n) { Print(std::string(arr[n])); } Print(std::string(j3["health"])); 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Josh Posted April 17, 2023 Author Share Posted April 17, 2023 My current implementation, working in Lua with indexes and keys. This is very very touchy: #include "UltraEngine.h" using namespace UltraEngine; enum JsonType { JSON_NULL, JSON_INTEGER, JSON_FLOAT, JSON_BOOLEAN, JSON_STRING, JSON_OBJECT, JSON_ARRAY }; class Json : public std::map<std::string, Json> { typedef std::map<std::string, Json> JsonObject; std::vector<Json> v; double f; int64_t i; bool b; std::string s; JsonType t; public: Json() { f = 0; i = 0; b = false; t = JSON_NULL; } Json::iterator begin() { return JsonObject::begin(); } Json::iterator end() { return JsonObject::end(); } //Json::iterator erase(Json::iterator it) //{ // if (t != JSON_OBJECT) RuntimeError("JSON value is not an object"); // return JsonObject::erase(it); //} Json::iterator find(const std::string& s) { return JsonObject::find(s); } std::pair<Json::iterator, bool> insert(std::pair<std::string, Json> pair) { return JsonObject::insert(pair); } static Json Object() { Json j; j.t = JSON_OBJECT; return j; } static Json Array() { Json j; j.t = JSON_ARRAY; return j; } JsonType GetType() const { return t; } operator bool() const { if (t == JSON_BOOLEAN) return b; return false; } operator int() const { if (t == JSON_INTEGER) return i; if (t == JSON_FLOAT) return f; if (t == JSON_BOOLEAN) return b; return 0; } operator int64_t() const { if (t == JSON_INTEGER) return i; if (t == JSON_FLOAT) return f; if (t == JSON_BOOLEAN) return b; return 0; } operator float() const { if (t == JSON_FLOAT) return f; if (t == JSON_INTEGER) return i; if (t == JSON_BOOLEAN) return b; return 0.0f; } operator double() const { if (t == JSON_FLOAT) return f; if (t == JSON_INTEGER) return i; if (t == JSON_BOOLEAN) return b; return 0.0f; } operator std::string() const { if (t == JSON_STRING) return s; if (t == JSON_FLOAT) return String(f); if (t == JSON_INTEGER) return String(i); if (t == JSON_BOOLEAN) return String(b); return ""; } void clear() { i = 0; f = 0; b = false; s.clear(); JsonObject::clear(); v.clear(); } Json(const int i_) { clear(); i = i_; t = JSON_INTEGER; } Json(const int64_t i_) { clear(); i = i_; t = JSON_INTEGER; } Json(const bool b_) { clear(); b = b_; t = JSON_BOOLEAN; } Json(const float f_) { clear(); f = f_; t = JSON_FLOAT; } Json(const double f_) { clear(); f = f_; t = JSON_FLOAT; } Json(const std::string& s_) { clear(); s = s_; t = JSON_STRING; } Json(const JsonObject& j3) { clear(); t = JSON_OBJECT; for (const auto& pair : j3) { JsonObject::insert(pair); } //JsonObject::insert(JsonObject::end(), j3.begin(), j3.end()); } Json& operator[](const char* c) { return (*this)[std::string(c)]; } Json& operator[](const std::string& key) { if (t != JSON_OBJECT) RuntimeError("JSON value is not an object"); auto it = find(key); if (it == end()) { auto pair = std::pair<std::string, Json>(key, {}); JsonObject::insert(pair); it = JsonObject::find(key); Assert(it != JsonObject::end()); } return it->second; } Json& operator[](const size_t index) { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); if (index >= size()) RuntimeError("Index out of bounds"); return v[index]; } size_t size() { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); return v.size(); } void push_back(const Json& j3) { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); v.push_back(j3); } void resize(const size_t sz) { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); v.resize(sz); } void reserve(const size_t sz) { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); v.reserve(sz); } size_t capacity() { if (t != JSON_ARRAY) RuntimeError("JSON value is not an array"); return v.capacity(); } }; /*namespace sol { template <> struct is_container<Json> : std::true_type {}; }*/ /*namespace sol { template <> struct is_container<Json> : std::true_type {}; template <> struct usertype_container<Json> { ... // see below for implemetation details }; }*/ int main(int argc, const char* argv[]) { auto L = GetLuaState(); L->new_usertype<Json>("MYJSON", sol::meta_function::to_string, [](const Json& v) { std::string s = v; return s; }, sol::meta_function::index, sol::overload( [](Json& v, std::string key) { auto L = GetLuaState()->lua_state(); auto val = v[key]; switch (val.GetType()) { case JSON_INTEGER: return sol::make_object(L, int64_t(val)); case JSON_FLOAT: return sol::make_object(L, double(val)); case JSON_BOOLEAN: return sol::make_object(L, bool(val)); case JSON_STRING: return sol::make_object(L, std::string(val)); case JSON_ARRAY: case JSON_OBJECT: return sol::make_object(L, val); } }, [](Json& v, int64_t index) { auto L = GetLuaState()->lua_state(); if (index < 0 or index >= v.size()) sol::make_object(L, sol::lua_nil); --index; auto val = v[index]; switch (val.GetType()) { case JSON_INTEGER: return sol::make_object(L, int64_t(val)); case JSON_FLOAT: return sol::make_object(L, double(val)); case JSON_BOOLEAN: return sol::make_object(L, bool(val)); case JSON_STRING: return sol::make_object(L, std::string(val)); case JSON_ARRAY: case JSON_OBJECT: return sol::make_object(L, val); } } ), sol::meta_function::new_index, sol::overload( [](Json& v, int64_t index, double x) { --index; if (index < 0) return; if (index >= v.size()) v.resize(index + 1); v[index] = x; }, [](Json& v, std::string key, double x) { v[key] = x; }, [](Json& v, int64_t index, std::string x) { --index; if (index < 0) return; if (index >= v.size()) v.resize(index + 1); v[index] = x; }, [](Json& v, std::string key, std::string x) { v[key] = x; }, [](Json& v, int64_t index, bool x) { --index; if (index < 0) return; if (index >= v.size()) v.resize(index + 1); v[index] = x; }, [](Json& v, std::string key, bool x) { v[key] = x; }, [](Json& v, int64_t index, const Json& x) { --index; if (index < 0) return; if (index >= v.size()) v.resize(index + 1); v[index] = x; }, [](Json& v, std::string key, const Json& x) { v[key] = x; } ) ); L->set_function("JsonObject", Json::Object); L->set_function("JsonArray", Json::Array); auto j3 = Json::Object(); /*j3["health"] = 100; j3["windowsettings"] = Json::Object(); j3["windowsettings"]["position"] = 3; int gf = j3["windowsettings"]["position"]; int g = j3["health"]; for (auto a : j3) { Print(a.first); std::string s = a.second; Print(s); } auto arr = Json::Array(); arr.push_back(1); arr.push_back(2); arr.push_back(3); arr.push_back(4); arr.push_back(5); for (int n = 0; n < arr.size(); ++n) { Print(std::string(arr[n])); } Print(std::string(j3["health"])); */ //Get commandline settings auto settings = ParseCommandLine(argc, argv); //Enable the debugger if needed shared_ptr<Timer> debugtimer; if (settings["debug"].is_boolean() and settings["debug"] == true) { RunScript("Scripts/System/Debugger.lua"); debugtimer = CreateTimer(510); ListenEvent(EVENT_TIMERTICK, debugtimer, std::bind(PollDebugger, 500)); } //Run main script RunScript("Scripts/Main.lua"); return 0; } Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Josh Posted April 17, 2023 Author Share Posted April 17, 2023 I got everything working except ipairs() in Lua. Further work will go here: https://github.com/UltraEngine/tableplusplus 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.