From 3cd4ff83a253e098e6524df5be3a686727e4f50b Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 28 Mar 2021 17:17:11 +0100 Subject: Initial commit of basis persistence JSON parser lifted almost verbatim for libjsonpp running into some custom code for populating ilt objects. Pretty minimal per object code requirements. --- test/Jamfile.jam | 1 + test/test-persistance.cpp | 281 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 test/test-persistance.cpp (limited to 'test') diff --git a/test/Jamfile.jam b/test/Jamfile.jam index f1fda72..c065dd8 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -18,3 +18,4 @@ run test-collection.cpp ; run test-obj.cpp ; run test-maths.cpp ; run test-network.cpp ; +run test-persistance.cpp ; diff --git a/test/test-persistance.cpp b/test/test-persistance.cpp new file mode 100644 index 0000000..7d66675 --- /dev/null +++ b/test/test-persistance.cpp @@ -0,0 +1,281 @@ +#define BOOST_TEST_MODULE test_persistance + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct PersistanceStore; +struct Selection; +using SelectionPtr = std::unique_ptr; +struct Selection { + virtual ~Selection() = default; + virtual void + operator()(float &) + { + throw std::runtime_error("Unexpected float"); + } + virtual void + operator()(bool &) + { + throw std::runtime_error("Unexpected bool"); + } + virtual void + operator()(const std::nullptr_t &) + { + throw std::runtime_error("Unexpected null"); + } + virtual void + operator()(std::string &) + { + throw std::runtime_error("Unexpected string"); + } + virtual void + BeginArray() + { + throw std::runtime_error("Unexpected array"); + } + virtual SelectionPtr + BeginObject() + { + throw std::runtime_error("Unexpected object"); + } + virtual SelectionPtr select(std::string) + { + throw std::runtime_error("Unexpected persist"); + } +}; + +template struct SelectionT : public Selection { + SelectionT(T & value) : v {value} { } + void + operator()(T & evalue) override + { + std::swap(v, evalue); + } + T & v; +}; + +template struct SelectionT> : public Selection { + SelectionT(glm::vec3 & value) : v {value} + { + CLOG(__PRETTY_FUNCTION__); + } + void + operator()(float & value) override + { + v[idx++] = value; + } + void + BeginArray() override + { + } + glm::vec3 & v; + glm::vec3::length_type idx {0}; +}; + +template struct SelectionT> : public Selection { + SelectionT(std::vector & value) : v {value} { } + void + operator()(T & value) override + { + v.push_back(value); + } + void + BeginArray() + { + } + std::vector & v; +}; + +struct TestObject; + +template struct MakeObjectByTypeName : public Selection { + MakeObjectByTypeName(Ptr & o) : o {o} { } + virtual void + operator()(std::string &) + { + o = std::make_unique(); // TODO shared_ptr + } + Ptr & o; +}; + +struct PersistanceStore { + // virtual bool persistType(const std::type_info &) = 0; + template + bool + persistValue(const std::string_view & key, T & value) + { + if (key == name) { + sel = std::make_unique>(std::ref(value)); + return false; + } + return true; + } + const std::string & name; + std::unique_ptr sel {}; +}; + +template struct SelectionObj : public Selection { + SelectionObj(Ptr & o) : v {o} { } + + SelectionPtr + select(std::string mbr) override + { + if (mbr == "@typeid") { + return std::make_unique>(std::ref(v)); + } + else if (v) { + CLOG(mbr); + PersistanceStore ps {mbr}; + v->persist(ps); + return std::move(ps.sel); + } + throw std::runtime_error("cannot select member of null object"); + } + + Ptr & v; +}; + +template struct SelectionT> : public Selection { + SelectionT(std::unique_ptr & o) : v {o} { } + SelectionPtr + BeginObject() override + { + CLOG(__PRETTY_FUNCTION__); + return std::make_unique>>(v); + } + std::unique_ptr & v; +}; + +struct Persistable { + virtual void persist(PersistanceStore & store) = 0; +}; + +struct JsonLoadPersistanceStore : public json::jsonParser { + JsonLoadPersistanceStore(std::istream & in) : json::jsonParser {&in} { } + + std::stack> stk; + std::unique_ptr selection; + + template + void + loadState(std::unique_ptr & t) + { + yy_push_state(0); + stk.push(std::make_unique>>(std::ref(t))); + yylex(); + } + void + BeginObject() override + { + CLOG(__FUNCTION__); + stk.push(stk.top()->BeginObject()); + } + void + BeginArray() override + { + CLOG(__FUNCTION__); + selection->BeginArray(); + } + void + PushBoolean(bool value) override + { + CLOG(__FUNCTION__); + (*selection)(value); + } + void + PushNumber(float value) override + { + CLOG(__FUNCTION__); + (*selection)(value); + } + void + PushNull() override + { + CLOG(__FUNCTION__); + (*selection)(nullptr); + } + void + PushText(std::string && value) override + { + CLOG(__FUNCTION__); + (*selection)(value); + } + void + PushKey(std::string && k) override + { + CLOG(__FUNCTION__); + selection = stk.top()->select(std::move(k)); + } + void + EndArray() override + { + CLOG(__FUNCTION__); + } + void + EndObject() override + { + CLOG(__FUNCTION__); + stk.pop(); + } +}; + +#define STORE_TYPE store.persistType(typeid(*this)) +#define STORE_MEMBER(mbr) store.persistValue(#mbr##sv, mbr) + +struct TestObject : public Persistable { + TestObject() = default; + + float flt {}; + std::string str {}; + bool bl {}; + glm::vec3 pos {}; + std::vector flts; + + void + persist(PersistanceStore & store) override + { + using namespace std::literals; + STORE_MEMBER(flt) && STORE_MEMBER(str) && STORE_MEMBER(bl) && STORE_MEMBER(pos) && STORE_MEMBER(flts); + } +}; + +const std::string input(R"J({ + "@typeid": "TestObject", + "flt": 3.14, + "str": "Lovely string", + "bl": true, + "pos": [3.14, 6.28, 1.57], + "flts": [3.14, 6.28, 1.57, 0, -1, -3.14], +})J"); + +BOOST_AUTO_TEST_CASE(load_object) +{ + std::stringstream ss {input}; + JsonLoadPersistanceStore jlps {ss}; + std::unique_ptr to; + jlps.loadState(to); + + BOOST_CHECK_CLOSE(to->flt, 3.14, 0.01); + BOOST_CHECK_EQUAL(to->str, "Lovely string"); + BOOST_CHECK_EQUAL(to->bl, true); + BOOST_CHECK_CLOSE(to->pos[0], 3.14, 0.01); + BOOST_CHECK_CLOSE(to->pos[1], 6.28, 0.01); + BOOST_CHECK_CLOSE(to->pos[2], 1.57, 0.01); + BOOST_REQUIRE_EQUAL(to->flts.size(), 6); + BOOST_CHECK_CLOSE(to->flts[0], 3.14, 0.01); + BOOST_CHECK_CLOSE(to->flts[1], 6.28, 0.01); + BOOST_CHECK_CLOSE(to->flts[2], 1.57, 0.01); + BOOST_CHECK_CLOSE(to->flts[3], 0, 0.01); + BOOST_CHECK_CLOSE(to->flts[4], -1, 0.01); + BOOST_CHECK_CLOSE(to->flts[5], -3.14, 0.01); +} -- cgit v1.2.3