summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2021-04-30 00:58:47 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2021-11-07 16:41:37 +0000
commit788f2790125af40e4ffab75cc3963f4442524e2e (patch)
tree86d93860dd04265b7e511a1da4ab1c9a55f6cc27
parentExtend factory map to include make_shared (diff)
downloadilt-788f2790125af40e4ffab75cc3963f4442524e2e.tar.bz2
ilt-788f2790125af40e4ffab75cc3963f4442524e2e.tar.xz
ilt-788f2790125af40e4ffab75cc3963f4442524e2e.zip
Implement shared_ptr support
Uses somewhat dirty global map for keeping shared_ptr objects by key, needs fix
-rw-r--r--lib/persistance.h108
-rw-r--r--test/fixtures/json/shared_ptr1.json11
-rw-r--r--test/fixtures/json/shared_ptr2.json8
-rw-r--r--test/test-persistance.cpp34
4 files changed, 160 insertions, 1 deletions
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 <functional>
#include <glm/glm.hpp>
#include <iosfwd>
+#include <map>
#include <memory>
#include <special_members.hpp>
#include <stack>
#include <stdexcept>
#include <string>
#include <string_view>
-#include <type_traits>
#include <utility>
#include <vector>
@@ -259,6 +259,112 @@ namespace Persistanace {
stk.pop();
}
};
+
+ // TODO Move this
+ using SharedObjects = std::map<std::string, std::shared_ptr<Persistable>>;
+ inline SharedObjects sharedObjects;
+
+ template<typename T> struct SelectionT<std::shared_ptr<T>> : public SelectionV<std::shared_ptr<T>> {
+ using Ptr = std::shared_ptr<T>;
+ struct SelectionObj : public SelectionV<Ptr> {
+ struct MakeObjectByTypeName : public SelectionV<Ptr> {
+ using SelectionV<Ptr>::SelectionV;
+
+ void
+ setValue(std::string & type) override
+ {
+ auto no = Persistable::callSharedFactory(type);
+ if (auto tno = std::dynamic_pointer_cast<T>(no)) {
+ this->v = std::move(tno);
+ }
+ }
+ };
+
+ struct RememberObjectById : public SelectionV<Ptr> {
+ using SelectionV<Ptr>::SelectionV;
+
+ void
+ setValue(std::string & id) override
+ {
+ sharedObjects.emplace(id, this->v);
+ }
+ };
+
+ using SelectionV<Ptr>::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<MakeObjectByTypeName>(this->v);
+ }
+ else if (mbr == "@id"sv) {
+ return this->template make_s<RememberObjectById>(this->v);
+ }
+ else {
+ if (!this->v) {
+ if constexpr (std::is_abstract_v<T>) {
+ throw std::runtime_error("cannot select member of null object");
+ }
+ else {
+ this->v = std::make_shared<T>();
+ }
+ }
+ 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<T>) {
+ throw std::runtime_error("cannot default create abstract object");
+ }
+ else {
+ this->v = std::make_shared<T>();
+ }
+ }
+ stk.pop();
+ }
+ };
+
+ using SelectionV<Ptr>::SelectionV;
+
+ void
+ setValue(const std::nullptr_t &) override
+ {
+ this->v.reset();
+ }
+
+ void
+ setValue(std::string & id) override
+ {
+ if (auto teo = std::dynamic_pointer_cast<T>(sharedObjects.at(id))) {
+ this->v = std::move(teo);
+ }
+ }
+
+ void
+ beginObject(Stack & stk) override
+ {
+ stk.push(this->template make_s<SelectionObj>(this->v));
+ }
+
+ void
+ endObject(Stack & stk) override
+ {
+ stk.pop();
+ }
+ };
}
#define STORE_TYPE store.persistType<std::decay_t<decltype(*this)>>()
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<T>(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<AbsObject> sptr;
+ std::shared_ptr<SubObject> 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<std::unique_ptr<SharedTestObject>>(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<std::unique_ptr<SharedTestObject>>(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);
+}