From 788f2790125af40e4ffab75cc3963f4442524e2e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 30 Apr 2021 00:58:47 +0100 Subject: Implement shared_ptr support Uses somewhat dirty global map for keeping shared_ptr objects by key, needs fix --- lib/persistance.h | 108 +++++++++++++++++++++++++++++++++++- test/fixtures/json/shared_ptr1.json | 11 ++++ test/fixtures/json/shared_ptr2.json | 8 +++ test/test-persistance.cpp | 34 ++++++++++++ 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/json/shared_ptr1.json create mode 100644 test/fixtures/json/shared_ptr2.json diff --git a/lib/persistance.h b/lib/persistance.h index 6e23272..c64d4ec 100644 --- a/lib/persistance.h +++ b/lib/persistance.h @@ -4,13 +4,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include @@ -259,6 +259,112 @@ namespace Persistanace { stk.pop(); } }; + + // TODO Move this + using SharedObjects = std::map>; + inline SharedObjects sharedObjects; + + template struct SelectionT> : public SelectionV> { + using Ptr = std::shared_ptr; + struct SelectionObj : public SelectionV { + struct MakeObjectByTypeName : public SelectionV { + using SelectionV::SelectionV; + + void + setValue(std::string & type) override + { + auto no = Persistable::callSharedFactory(type); + if (auto tno = std::dynamic_pointer_cast(no)) { + this->v = std::move(tno); + } + } + }; + + struct RememberObjectById : public SelectionV { + using SelectionV::SelectionV; + + void + setValue(std::string & id) override + { + sharedObjects.emplace(id, this->v); + } + }; + + using SelectionV::SelectionV; + + SelectionPtr + select(const std::string & mbr) override + { + using namespace std::literals; + if (mbr == "@typeid"sv) { + if (this->v) { + throw std::runtime_error("cannot set object type after creation"); + } + return this->template make_s(this->v); + } + else if (mbr == "@id"sv) { + return this->template make_s(this->v); + } + else { + if (!this->v) { + if constexpr (std::is_abstract_v) { + throw std::runtime_error("cannot select member of null object"); + } + else { + this->v = std::make_shared(); + } + } + PersistanceStore ps {mbr}; + if (this->v->persist(ps)) { + throw std::runtime_error("cannot find member: " + mbr); + } + return std::move(ps.sel); + } + } + + void + endObject(Stack & stk) override + { + if (!this->v) { + if constexpr (std::is_abstract_v) { + throw std::runtime_error("cannot default create abstract object"); + } + else { + this->v = std::make_shared(); + } + } + stk.pop(); + } + }; + + using SelectionV::SelectionV; + + void + setValue(const std::nullptr_t &) override + { + this->v.reset(); + } + + void + setValue(std::string & id) override + { + if (auto teo = std::dynamic_pointer_cast(sharedObjects.at(id))) { + this->v = std::move(teo); + } + } + + void + beginObject(Stack & stk) override + { + stk.push(this->template make_s(this->v)); + } + + void + endObject(Stack & stk) override + { + stk.pop(); + } + }; } #define STORE_TYPE store.persistType>() diff --git a/test/fixtures/json/shared_ptr1.json b/test/fixtures/json/shared_ptr1.json new file mode 100644 index 0000000..bb18e33 --- /dev/null +++ b/test/fixtures/json/shared_ptr1.json @@ -0,0 +1,11 @@ +{ + "@typeid": "SharedTestObject", + "sptr": { + "@typeid": "SubObject", + "@id": "someid" + }, + "ssptr": { + "@typeid": "SubObject", + "@id": "some other id" + } +} diff --git a/test/fixtures/json/shared_ptr2.json b/test/fixtures/json/shared_ptr2.json new file mode 100644 index 0000000..4115493 --- /dev/null +++ b/test/fixtures/json/shared_ptr2.json @@ -0,0 +1,8 @@ +{ + "@typeid": "SharedTestObject", + "sptr": { + "@typeid": "SubObject", + "@id": "someid" + }, + "ssptr": "someid" +} diff --git a/test/test-persistance.cpp b/test/test-persistance.cpp index a4fda31..2c06c48 100644 --- a/test/test-persistance.cpp +++ b/test/test-persistance.cpp @@ -68,6 +68,7 @@ struct JPP : public Persistanace::JsonParsePersistance { BOOST_TEST_CONTEXT(path) { std::ifstream ss {path}; auto to = loadState(ss); + Persistanace::sharedObjects.clear(); BOOST_CHECK(stk.empty()); BOOST_REQUIRE(to); return to; @@ -177,3 +178,36 @@ BOOST_FIXTURE_TEST_CASE(load_vector_ptr, JPP) BOOST_CHECK(!to->vptr.at(2)); BOOST_CHECK(to->vptr.at(3)->str.empty()); } + +struct SharedTestObject : public Persistanace::Persistable { + SharedTestObject() = default; + + std::shared_ptr sptr; + std::shared_ptr ssptr; + + bool + persist(Persistanace::PersistanceStore & store) override + { + return STORE_TYPE && STORE_MEMBER(sptr) && STORE_MEMBER(ssptr); + } +}; + +BOOST_FIXTURE_TEST_CASE(load_shared_object1, JPP) +{ + auto to = load_json>(FIXTURESDIR "json/shared_ptr1.json"); + BOOST_CHECK(to->sptr); + BOOST_CHECK(to->ssptr); + BOOST_CHECK_NE(to->sptr, to->ssptr); + BOOST_CHECK_EQUAL(to->sptr.use_count(), 1); + BOOST_CHECK_EQUAL(to->ssptr.use_count(), 1); +} + +BOOST_FIXTURE_TEST_CASE(load_shared_object2, JPP) +{ + auto to = load_json>(FIXTURESDIR "json/shared_ptr2.json"); + BOOST_CHECK(to->sptr); + BOOST_CHECK(to->ssptr); + BOOST_CHECK_EQUAL(to->sptr, to->ssptr); + BOOST_CHECK_EQUAL(to->sptr.use_count(), 2); + BOOST_CHECK_EQUAL(to->ssptr.use_count(), 2); +} -- cgit v1.2.3