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