#ifndef PERSISTANCE_H #define PERSISTANCE_H #include #include #include #include #include #include #include #include #include #include #include #include namespace glm { template struct vec; } namespace Persistence { struct Selection; using SelectionPtr = std::unique_ptr; using Stack = std::stack; struct Selection { Selection() = default; virtual ~Selection() = default; DEFAULT_MOVE_COPY(Selection); virtual void setValue(float &); virtual void setValue(bool &); virtual void setValue(const std::nullptr_t &); virtual void setValue(std::string &); virtual void beginArray(Stack &); virtual void beginObject(Stack &); virtual void endObject(Stack &); virtual void beforeValue(Stack &); virtual SelectionPtr select(const std::string &); }; template struct SelectionT; template struct SelectionV : public Selection { explicit SelectionV(T & value) : v {value} { } void beforeValue(Stack &) override { } static SelectionPtr make(T & value) { return make_s>(value); } template static SelectionPtr make_s(T & value) { return std::make_unique(value); } T & v; }; template struct SelectionT : public SelectionV { using SelectionV::SelectionV; void setValue(T & evalue) override { std::swap(this->v, evalue); } }; struct PersistenceStore { template inline bool persistType() const; template inline bool persistValue(const std::string_view key, T & value) { if (key == name) { sel = SelectionV::make(value); return false; } return true; } const std::string & name; SelectionPtr sel {}; }; template struct SelectionT> : public SelectionV> { using V = glm::vec; struct Members : public SelectionV { using SelectionV::SelectionV; void beforeValue(Stack & stk) override { stk.push(SelectionV::make(this->v[idx++])); } glm::length_t idx {0}; }; using SelectionV::SelectionV; void beginArray(Stack & stk) override { stk.push(this->template make_s(this->v)); } }; template struct SelectionT> : public SelectionV> { using V = std::vector; struct Members : public SelectionV { using SelectionV::SelectionV; void beforeValue(Stack & stk) override { stk.push(SelectionV::make(this->v.emplace_back())); } }; using SelectionV::SelectionV; void beginArray(Stack & stk) override { stk.push(this->template make_s(this->v)); } }; struct Persistable { Persistable() = default; virtual ~Persistable() = default; DEFAULT_MOVE_COPY(Persistable); virtual bool persist(PersistenceStore & store) = 0; template constexpr static auto typeName() { constexpr std::string_view name {__PRETTY_FUNCTION__}; constexpr auto s {name.find("T = ") + 4}, e {name.rfind(']')}; return name.substr(s, e - s); } template static void addFactory() __attribute__((constructor)); static void addFactory(const std::string_view, std::function()>, std::function()>); static std::unique_ptr callFactory(const std::string_view); static std::shared_ptr callSharedFactory(const std::string_view); }; template void Persistable::addFactory() { addFactory(typeName(), std::make_unique, std::make_shared); } template inline bool PersistenceStore::persistType() const { if constexpr (!std::is_abstract_v) { [[maybe_unused]] constexpr auto f = &Persistable::addFactory; } return true; } // TODO Move this using SharedObjects = std::map>; inline SharedObjects sharedObjects; template struct SelectionPtrBase : public SelectionV { using T = typename Ptr::element_type; struct SelectionObj : public SelectionV { struct MakeObjectByTypeName : public SelectionV { using SelectionV::SelectionV; void setValue(std::string & type) override { if constexpr (shared) { auto no = Persistable::callSharedFactory(type); if (auto tno = std::dynamic_pointer_cast(no)) { this->v = std::move(tno); return; } } else { auto no = Persistable::callFactory(type); if (dynamic_cast(no.get())) { this->v.reset(static_cast(no.release())); return; } } throw std::runtime_error("Named type doesn't cast to target type"); } }; 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); } if constexpr (shared) { if (mbr == "@id"sv) { return this->template make_s(this->v); } } make_default_as_needed(this->v); PersistenceStore 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 { make_default_as_needed(this->v); stk.pop(); } }; static inline void make_default_as_needed(Ptr & v) { if (!v) { if constexpr (std::is_abstract_v) { throw std::runtime_error("cannot select member of null abstract object"); } else if constexpr (shared) { v = std::make_shared(); } else { v = std::make_unique(); } } } using SelectionV::SelectionV; void setValue(const std::nullptr_t &) override { this->v.reset(); } void beginObject(Stack & stk) override { stk.push(this->template make_s(this->v)); } void endObject(Stack & stk) override { stk.pop(); } }; template struct SelectionT> : public SelectionPtrBase, false> { using SelectionPtrBase, false>::SelectionPtrBase; }; template struct SelectionT> : public SelectionPtrBase, true> { using SelectionPtrBase, true>::SelectionPtrBase; void setValue(std::string & id) override { if (auto teo = std::dynamic_pointer_cast(sharedObjects.at(id))) { this->v = std::move(teo); } else { throw std::runtime_error("Named type doesn't cast to target type"); } } }; } #define STORE_TYPE store.persistType>() #define STORE_MEMBER(mbr) store.persistValue(#mbr, mbr) #endif