Jump to content

JSON C++ implementation


Josh
 Share

Recommended Posts

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"]));

 

  • Like 1

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

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;
}

 

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

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...