From ce5c689a5f9e544d724b2a41fda2f752ccc4a4ae Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 7 May 2021 20:50:48 +0100 Subject: Initial commit where writing objects back out to JSON It's not perfect, writes explicit nulls, doesn't do shared @id --- lib/persistence.h | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 150 insertions(+), 8 deletions(-) (limited to 'lib/persistence.h') diff --git a/lib/persistence.h b/lib/persistence.h index 519cb0e..4b72eb3 100644 --- a/lib/persistence.h +++ b/lib/persistence.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,19 @@ namespace Persistence { using SelectionPtr = std::unique_ptr; using Stack = std::stack; + struct Writer { + virtual void beginObject() const = 0; + virtual void beginArray() const = 0; + virtual void pushValue(bool value) const = 0; + virtual void pushValue(float value) const = 0; + virtual void pushValue(std::nullptr_t) const = 0; + virtual void pushValue(std::string_view value) const = 0; + virtual void nextValue() const = 0; + virtual void pushKey(std::string_view k) const = 0; + virtual void endArray() const = 0; + virtual void endObject() const = 0; + }; + struct Selection { Selection() = default; virtual ~Selection() = default; @@ -38,6 +52,8 @@ namespace Persistence { virtual void endObject(Stack &); virtual void beforeValue(Stack &); [[nodiscard]] virtual SelectionPtr select(const std::string &); + + virtual void write(const Writer &) const; }; template struct SelectionT; @@ -75,25 +91,90 @@ namespace Persistence { { std::swap(this->v, evalue); } + + void + write(const Writer & out) const override + { + out.pushValue(this->v); + } }; struct PersistenceStore { - template [[nodiscard]] inline bool persistType() const; + template [[nodiscard]] inline bool persistType(const T * const, const std::type_info & ti); + enum class NameAction { Push, HandleAndContinue, Ignore }; template [[nodiscard]] inline bool persistValue(const std::string_view key, T & value) { - if (key == name) { + const auto act {setName(key)}; + if (act != NameAction::Ignore) { sel = SelectionV::make(value); - return false; + if (act == NameAction::HandleAndContinue) { + selHandler(); + } } - return true; + return (act != NameAction::Push); } - const std::string & name; + + virtual NameAction setName(const std::string_view key) = 0; + virtual void selHandler() {}; + virtual void setType(const std::string_view) = 0; + SelectionPtr sel {}; }; + struct PersistenceSelect : public PersistenceStore { + explicit PersistenceSelect(const std::string & n) : name {n} { } + + NameAction + setName(const std::string_view key) override + { + return (key == name) ? NameAction::Push : NameAction::Ignore; + } + + void + setType(const std::string_view) override + { + } + + const std::string & name; + }; + + struct PersistenceWrite : public PersistenceStore { + explicit PersistenceWrite(const Writer & o) : out {o} { } + + NameAction + setName(const std::string_view key) override + { + if (!first) { + out.nextValue(); + } + else { + first = false; + } + out.pushKey(key); + return NameAction::HandleAndContinue; + } + + void + selHandler() override + { + this->sel->write(out); + }; + + void + setType(const std::string_view tn) override + { + out.pushKey("@typeid"); + out.pushValue(tn); + first = false; + } + + bool first {true}; + const Writer & out; + }; + template struct SelectionT> : public SelectionV> { using V = glm::vec; @@ -108,6 +189,17 @@ namespace Persistence { } glm::length_t idx {0}; + + void + write(const Writer & out) const override + { + for (glm::length_t idx = 0; idx < L; idx += 1) { + if (idx) { + out.nextValue(); + } + SelectionT {this->v[idx]}.write(out); + } + } }; using SelectionV::SelectionV; @@ -117,6 +209,14 @@ namespace Persistence { { stk.push(this->template make_s(this->v)); } + + void + write(const Writer & out) const override + { + out.beginArray(); + Members {this->v}.write(out); + out.endArray(); + } }; template struct SelectionT> : public SelectionV> { @@ -130,6 +230,17 @@ namespace Persistence { { stk.push(SelectionV::make(this->v.emplace_back())); } + + void + write(const Writer & out) const override + { + for (std::size_t idx = 0; idx < this->v.size(); idx += 1) { + if (idx) { + out.nextValue(); + } + SelectionT {this->v[idx]}.write(out); + } + } }; using SelectionV::SelectionV; @@ -139,6 +250,14 @@ namespace Persistence { { stk.push(this->template make_s(this->v)); } + + void + write(const Writer & out) const override + { + out.beginArray(); + Members {this->v}.write(out); + out.endArray(); + } }; struct Persistable { @@ -173,11 +292,14 @@ namespace Persistence { template inline bool - PersistenceStore::persistType() const + PersistenceStore::persistType(const T * const, const std::type_info & ti) { if constexpr (!std::is_abstract_v) { [[maybe_unused]] constexpr auto f = &Persistable::addFactory; } + if (typeid(std::decay_t) == ti) { + setType(Persistable::typeName()); + } return true; } @@ -240,7 +362,7 @@ namespace Persistence { } } make_default_as_needed(this->v); - PersistenceStore ps {mbr}; + PersistenceSelect ps {mbr}; if (this->v->persist(ps)) { throw std::runtime_error("cannot find member: " + mbr); } @@ -253,6 +375,15 @@ namespace Persistence { make_default_as_needed(this->v); stk.pop(); } + + void + write(const Writer & out) const override + { + out.beginObject(); + PersistenceWrite pw {out}; + this->v->persist(pw); + out.endObject(); + } }; static inline void @@ -289,6 +420,17 @@ namespace Persistence { { stk.pop(); } + + void + write(const Writer & out) const override + { + if (this->v) { + SelectionObj {this->v}.write(out); + } + else { + out.pushValue(nullptr); + } + } }; template struct SelectionT> : public SelectionPtrBase, false> { @@ -311,7 +453,7 @@ namespace Persistence { }; } -#define STORE_TYPE store.persistType>() +#define STORE_TYPE store.persistType(this, typeid(*this)) #define STORE_MEMBER(mbr) store.persistValue(#mbr, mbr) #endif -- cgit v1.2.3