summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/persistence.cpp56
-rw-r--r--lib/persistence.h66
-rw-r--r--test/test-persistence.cpp33
3 files changed, 105 insertions, 50 deletions
diff --git a/lib/persistence.cpp b/lib/persistence.cpp
index 4f1be8f..b85bff2 100644
--- a/lib/persistence.cpp
+++ b/lib/persistence.cpp
@@ -1,5 +1,6 @@
#include "persistence.h"
#include <map>
+#include <sstream>
namespace Persistence {
using Factories
@@ -26,6 +27,61 @@ namespace Persistence {
return namedTypeFactories.at(t).second();
}
+ [[nodiscard]] std::string
+ Persistable::getId() const
+ {
+ std::stringstream ss;
+ ss << std::hex << this;
+ return ss.str();
+ }
+
+ PersistenceSelect::PersistenceSelect(const std::string & n) : name {n} { }
+
+ PersistenceStore::NameAction
+ PersistenceSelect::setName(const std::string_view key)
+ {
+ return (key == name) ? NameAction::Push : NameAction::Ignore;
+ }
+
+ void
+ PersistenceSelect::setType(const std::string_view, const Persistable *)
+ {
+ }
+
+ PersistenceWrite::PersistenceWrite(const Writer & o, bool sh) : out {o}, shared {sh} { }
+
+ PersistenceStore::NameAction
+ PersistenceWrite::setName(const std::string_view key)
+ {
+ if (!first) {
+ out.nextValue();
+ }
+ else {
+ first = false;
+ }
+ out.pushKey(key);
+ return NameAction::HandleAndContinue;
+ }
+
+ void
+ PersistenceWrite::selHandler()
+ {
+ this->sel->write(out);
+ };
+
+ void
+ PersistenceWrite::setType(const std::string_view tn, const Persistable * p)
+ {
+ out.pushKey("@typeid");
+ out.pushValue(tn);
+ first = false;
+ if (shared) {
+ out.nextValue();
+ out.pushKey("@id");
+ out.pushValue(p->getId());
+ }
+ }
+
void
Selection::setValue(float)
{
diff --git a/lib/persistence.h b/lib/persistence.h
index 9a143c4..0eba1ab 100644
--- a/lib/persistence.h
+++ b/lib/persistence.h
@@ -99,6 +99,7 @@ namespace Persistence {
}
};
+ struct Persistable;
struct PersistenceStore {
template<typename T> [[nodiscard]] inline bool persistType(const T * const, const std::type_info & ti);
@@ -119,60 +120,33 @@ namespace Persistence {
virtual NameAction setName(const std::string_view key) = 0;
virtual void selHandler() {};
- virtual void setType(const std::string_view) = 0;
+ virtual void setType(const std::string_view, const Persistable *) = 0;
SelectionPtr sel {};
};
struct PersistenceSelect : public PersistenceStore {
- explicit PersistenceSelect(const std::string & n) : name {n} { }
+ explicit PersistenceSelect(const std::string & n);
- NameAction
- setName(const std::string_view key) override
- {
- return (key == name) ? NameAction::Push : NameAction::Ignore;
- }
+ NameAction setName(const std::string_view key) override;
- void
- setType(const std::string_view) override
- {
- }
+ void setType(const std::string_view, const Persistable *) override;
const std::string & name;
};
struct PersistenceWrite : public PersistenceStore {
- explicit PersistenceWrite(const Writer & o) : out {o} { }
+ explicit PersistenceWrite(const Writer & o, bool sh);
- NameAction
- setName(const std::string_view key) override
- {
- if (!first) {
- out.nextValue();
- }
- else {
- first = false;
- }
- out.pushKey(key);
- return NameAction::HandleAndContinue;
- }
+ NameAction setName(const std::string_view key) override;
- void
- selHandler() override
- {
- this->sel->write(out);
- };
+ void selHandler() override;
- void
- setType(const std::string_view tn) override
- {
- out.pushKey("@typeid");
- out.pushValue(tn);
- first = false;
- }
+ void setType(const std::string_view tn, const Persistable * p) override;
bool first {true};
const Writer & out;
+ bool shared;
};
template<glm::length_t L, typename T, glm::qualifier Q>
@@ -267,6 +241,8 @@ namespace Persistence {
virtual bool persist(PersistenceStore & store) = 0;
+ [[nodiscard]] virtual std::string getId() const;
+
template<typename T>
[[nodiscard]] constexpr static auto
typeName()
@@ -292,20 +268,22 @@ namespace Persistence {
template<typename T>
inline bool
- PersistenceStore::persistType(const T * const, const std::type_info & ti)
+ PersistenceStore::persistType(const T * const v, const std::type_info & ti)
{
if constexpr (!std::is_abstract_v<T>) {
[[maybe_unused]] constexpr auto f = &Persistable::addFactory<T>;
}
if (typeid(std::decay_t<T>) == ti) {
- setType(Persistable::typeName<T>());
+ setType(Persistable::typeName<T>(), v);
}
return true;
}
- // TODO Move this
+ // TODO Move these
using SharedObjects = std::map<std::string, std::shared_ptr<Persistable>>;
inline SharedObjects sharedObjects;
+ using SeenSharedObjects = std::map<void *, std::string>;
+ inline SeenSharedObjects seenSharedObjects;
template<typename Ptr, bool shared> struct SelectionPtrBase : public SelectionV<Ptr> {
using T = typename Ptr::element_type;
@@ -380,7 +358,7 @@ namespace Persistence {
write(const Writer & out) const override
{
out.beginObject();
- PersistenceWrite pw {out};
+ PersistenceWrite pw {out, shared};
this->v->persist(pw);
out.endObject();
}
@@ -425,6 +403,14 @@ namespace Persistence {
write(const Writer & out) const override
{
if (this->v) {
+ if constexpr (shared) {
+ if (const auto existing = seenSharedObjects.find(std::to_address(this->v));
+ existing != seenSharedObjects.end()) {
+ out.pushValue(existing->second);
+ return;
+ }
+ seenSharedObjects.emplace(std::to_address(this->v), this->v->getId());
+ }
SelectionObj {this->v}.write(out);
}
else {
diff --git a/test/test-persistence.cpp b/test/test-persistence.cpp
index ab16166..e13cb7a 100644
--- a/test/test-persistence.cpp
+++ b/test/test-persistence.cpp
@@ -39,6 +39,12 @@ struct SubObject : public AbsObject {
dummy() const override
{
}
+
+ [[nodiscard]] std::string
+ getId() const override
+ {
+ return "someid";
+ }
};
struct SubObject2 : public AbsObject {
@@ -313,9 +319,8 @@ BOOST_AUTO_TEST_CASE(write_test_dfl)
auto to = std::make_unique<TestObject>();
std::stringstream ss;
Persistence::JsonWritePersistence {ss}.saveState(to);
- // TODO We can omit writing explicit nulls
BOOST_CHECK_EQUAL(ss.str(),
- R"({"@typeid":"TestObject","flt":0,"str":"","bl":false,"pos":[0,0,0],"flts":[],"poss":[],"nest":[],"ptr":null,"aptr":null,"vptr":[]})");
+ R"({"@typeid":"TestObject","flt":0,"str":"","bl":false,"pos":[0,0,0],"flts":[],"poss":[],"nest":[],"vptr":[]})");
}
BOOST_FIXTURE_TEST_CASE(write_test_loaded, JPP)
@@ -323,9 +328,8 @@ BOOST_FIXTURE_TEST_CASE(write_test_loaded, JPP)
auto to = load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/load_object.json");
std::stringstream ss;
Persistence::JsonWritePersistence {ss}.saveState(to);
- // TODO We can omit writing explicit nulls
BOOST_CHECK_EQUAL(ss.str(),
- R"({"@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],"poss":[[3.14,6.28,1.57],[0,-1,-3.14]],"nest":[[["a","b"],["c","d","e"]],[["f"]],[]],"ptr":{"@typeid":"TestObject","flt":3.14,"str":"Lovely string","bl":false,"pos":[0,0,0],"flts":[],"poss":[],"nest":[],"ptr":null,"aptr":null,"vptr":[]},"aptr":null,"vptr":[]})");
+ R"({"@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],"poss":[[3.14,6.28,1.57],[0,-1,-3.14]],"nest":[[["a","b"],["c","d","e"]],[["f"]],[]],"ptr":{"@typeid":"TestObject","flt":3.14,"str":"Lovely string","bl":false,"pos":[0,0,0],"flts":[],"poss":[],"nest":[],"vptr":[]},"vptr":[]})");
}
BOOST_FIXTURE_TEST_CASE(write_test_loaded_abs, JPP)
@@ -333,20 +337,19 @@ BOOST_FIXTURE_TEST_CASE(write_test_loaded_abs, JPP)
auto to = load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/abs.json");
std::stringstream ss;
Persistence::JsonWritePersistence {ss}.saveState(to);
- // TODO We can omit writing explicit nulls
BOOST_CHECK_EQUAL(ss.str(),
- R"({"@typeid":"TestObject","flt":0,"str":"","bl":false,"pos":[0,0,0],"flts":[],"poss":[],"nest":[],"ptr":null,"aptr":{"@typeid":"SubObject","base":"set base","sub":"set sub"},"vptr":[]})");
+ R"({"@typeid":"TestObject","flt":0,"str":"","bl":false,"pos":[0,0,0],"flts":[],"poss":[],"nest":[],"aptr":{"@typeid":"SubObject","base":"set base","sub":"set sub"},"vptr":[]})");
}
BOOST_FIXTURE_TEST_CASE(write_test_loaded_shared, JPP)
{
auto to = load_json<std::unique_ptr<SharedTestObject>>(FIXTURESDIR "json/shared_ptr_same.json");
std::stringstream ss;
+ Persistence::seenSharedObjects.clear();
Persistence::JsonWritePersistence {ss}.saveState(to);
- // TODO We can omit writing explicit nulls
- // TODO Also not really implemented, but it runs :)
- // BOOST_CHECK_EQUAL(ss.str(),
- // R"({"@typeid":"SharedTestObject","sptr":{"@typeid":"SubObject","@id":"someid"},"ssptr":"someid"})");
+ BOOST_CHECK_EQUAL(Persistence::seenSharedObjects.size(), 1);
+ BOOST_CHECK_EQUAL(ss.str(),
+ R"({"@typeid":"SharedTestObject","sptr":{"@typeid":"SubObject","@id":"someid","base":"","sub":""},"ssptr":"someid"})");
}
BOOST_DATA_TEST_CASE(write_special_strings, TEST_STRINGS, exp, in)
@@ -356,3 +359,13 @@ BOOST_DATA_TEST_CASE(write_special_strings, TEST_STRINGS, exp, in)
Persistence::JsonWritePersistence {ss}.saveState(copy);
BOOST_CHECK_EQUAL(ss.str(), exp);
}
+
+BOOST_AUTO_TEST_CASE(get_default_id)
+{
+ SubObject2 so;
+ const auto id {so.getId()};
+ BOOST_TEST_CONTEXT(id) {
+ auto ptr = std::stoul(id, nullptr, 16);
+ BOOST_CHECK_EQUAL(ptr, reinterpret_cast<decltype(ptr)>(&so));
+ }
+}