diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-03-05 01:59:16 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-03-05 01:59:16 +0000 |
commit | d4c073a18adaed73973f34c6c39fc15664d9211d (patch) | |
tree | 44536af3af0284ab75eae79ef81a5e4452019269 /lib | |
parent | Add helper operator to perform vec3*mat4 and perspective divide (diff) | |
parent | Remove old hard coded asset factory test, run entirely from XML load and rend... (diff) | |
download | ilt-d4c073a18adaed73973f34c6c39fc15664d9211d.tar.bz2 ilt-d4c073a18adaed73973f34c6c39fc15664d9211d.tar.xz ilt-d4c073a18adaed73973f34c6c39fc15664d9211d.zip |
Merge branch 'model-factory'
Diffstat (limited to 'lib')
-rw-r--r-- | lib/collections.hpp | 41 | ||||
-rw-r--r-- | lib/filesystem.cpp | 9 | ||||
-rw-r--r-- | lib/filesystem.h | 5 | ||||
-rw-r--r-- | lib/jsonParse-persistence.h | 4 | ||||
-rw-r--r-- | lib/persistence.cpp | 9 | ||||
-rw-r--r-- | lib/persistence.h | 158 | ||||
-rw-r--r-- | lib/saxParse-persistence.cpp | 50 | ||||
-rw-r--r-- | lib/saxParse-persistence.h | 40 | ||||
-rw-r--r-- | lib/saxParse.cpp | 41 | ||||
-rw-r--r-- | lib/saxParse.h | 21 |
10 files changed, 340 insertions, 38 deletions
diff --git a/lib/collections.hpp b/lib/collections.hpp index 47967b2..16870be 100644 --- a/lib/collections.hpp +++ b/lib/collections.hpp @@ -15,9 +15,11 @@ concept SequentialCollection = requires(T c) { c.data() } -> std::same_as<const E *>; }; +template<typename T> +concept IterableCollection = std::is_same_v<decltype(std::declval<T>().begin()), decltype(std::declval<T>().end())>; template<typename T, std::size_t first, std::size_t second> -constexpr std::array<T, first + second> +[[nodiscard]] constexpr std::array<T, first + second> operator+(const std::array<T, first> & a, const std::array<T, second> & b) { std::array<T, first + second> r; @@ -28,7 +30,7 @@ operator+(const std::array<T, first> & a, const std::array<T, second> & b) } template<typename T, typename V, std::size_t first, std::size_t second> -constexpr std::array<std::pair<T, V>, first * second> +[[nodiscard]] constexpr std::array<std::pair<T, V>, first * second> operator*(const std::array<T, first> & a, const std::array<V, second> & b) { std::array<std::pair<T, V>, first * second> r; @@ -42,7 +44,7 @@ operator*(const std::array<T, first> & a, const std::array<V, second> & b) } template<typename T, std::size_t N> -constexpr auto +[[nodiscard]] constexpr auto operator*(const std::array<T, N> & in, auto && f) { std::array<decltype(f(in[0])), N> out; @@ -53,9 +55,8 @@ operator*(const std::array<T, N> & in, auto && f) return out; } -template<typename T> constexpr auto & -operator*=(std::span<T> & in, auto && f) +operator*=(IterableCollection auto & in, auto && f) { for (auto & v : in) { f(v); @@ -64,7 +65,7 @@ operator*=(std::span<T> & in, auto && f) } template<template<typename...> typename C, typename... T> -constexpr auto +[[nodiscard]] constexpr auto operator*(const C<T...> & in, auto && f) { C<decltype(f(in[0]))> out; @@ -82,17 +83,17 @@ operator+=(std::vector<T...> & in, std::vector<T...> && src) return in; } -template<typename... T> -constexpr auto -operator+(std::vector<T...> && in, std::vector<T...> && src) +template<typename... T, typename Vn> +[[nodiscard]] constexpr auto +operator+(const std::vector<T...> & in, Vn && vn) { - in.reserve(in.size() + src.size()); - std::move(src.begin(), src.end(), std::back_inserter(in)); - return in; + auto out(in); + out.emplace_back(std::forward<Vn>(vn)); + return out; } template<template<typename> typename Direction = std::plus> -static auto +[[nodiscard]] static auto vectorOfN(std::integral auto N, unsigned int start = {}, unsigned int step = 1) { std::vector<unsigned int> v; @@ -102,3 +103,17 @@ vectorOfN(std::integral auto N, unsigned int start = {}, unsigned int step = 1) }); return v; } + +template<template<typename...> typename Rtn = std::vector, IterableCollection In> +[[nodiscard]] auto +materializeRange(In && in) +{ + return Rtn(in.begin(), in.end()); +} + +template<template<typename...> typename Rtn = std::vector, typename In> +[[nodiscard]] auto +materializeRange(const std::pair<In, In> & in) +{ + return Rtn(in.first, in.second); +} diff --git a/lib/filesystem.cpp b/lib/filesystem.cpp index 0e19e8d..7e8ab9c 100644 --- a/lib/filesystem.cpp +++ b/lib/filesystem.cpp @@ -62,4 +62,13 @@ namespace filesystem { { return memmap {length, prot, flags, h, static_cast<off_t>(offset)}; } + + FILE * + checked_fopen(const char * pathname, const char * mode) + { + if (auto file = fopen(pathname, mode)) { + return file; + } + throw_filesystem_error("fopen", errno, pathname); + } } diff --git a/lib/filesystem.h b/lib/filesystem.h index 0c44236..5315183 100644 --- a/lib/filesystem.h +++ b/lib/filesystem.h @@ -1,7 +1,9 @@ #pragma once +#include "ptr.hpp" #include "special_members.hpp" #include <cstddef> +#include <cstdio> #include <sys/types.h> namespace filesystem { @@ -39,4 +41,7 @@ namespace filesystem { private: int h; }; + + FILE * checked_fopen(const char * pathname, const char * mode); + using FileStar = wrapped_ptrt<FILE, &checked_fopen, &fclose>; } diff --git a/lib/jsonParse-persistence.h b/lib/jsonParse-persistence.h index fa5e772..a676282 100644 --- a/lib/jsonParse-persistence.h +++ b/lib/jsonParse-persistence.h @@ -9,7 +9,7 @@ #include <string_view> namespace Persistence { - class JsonParsePersistence : public json::jsonParser { + class JsonParsePersistence : public json::jsonParser, ParseBase { public: template<typename T> inline T @@ -34,8 +34,6 @@ namespace Persistence { void endArray() override; void endObject() override; - Stack stk; - template<typename T> inline void pushValue(T && value); inline SelectionPtr & current(); }; diff --git a/lib/persistence.cpp b/lib/persistence.cpp index 239e425..8c7c6a4 100644 --- a/lib/persistence.cpp +++ b/lib/persistence.cpp @@ -81,12 +81,12 @@ namespace Persistence { void PersistenceWrite::setType(const std::string_view tn, const Persistable * p) { - out.pushKey("@typeid"); + out.pushKey("p.typeid"); out.pushValue(tn); first = false; if (shared) { out.nextValue(); - out.pushKey("@id"); + out.pushKey("p.id"); out.pushValue(p->getId()); } } @@ -157,4 +157,9 @@ namespace Persistence { throw std::logic_error("Default write op shouldn't ever get called"); } /// LCOV_EXCL_STOP + + ParseBase::ParseBase() : sharedObjectsInstance {std::make_shared<SharedObjects>()} + { + sharedObjects = sharedObjectsInstance; + } } diff --git a/lib/persistence.h b/lib/persistence.h index 4fbff4c..05cb49b 100644 --- a/lib/persistence.h +++ b/lib/persistence.h @@ -1,11 +1,13 @@ #pragma once +#include <charconv> #include <functional> #include <glm/glm.hpp> #include <iosfwd> #include <map> #include <memory> #include <special_members.hpp> +#include <sstream> #include <stack> #include <stdexcept> #include <string> @@ -86,13 +88,53 @@ namespace Persistence { T & v; }; - template<typename T> struct SelectionT : public SelectionV<T> { + template<typename T> + concept Scalar = std::is_scalar_v<T>; + template<typename T> + concept NotScalar = (!Scalar<T>); + + template<Scalar T> struct SelectionT<T> : public SelectionV<T> { + using SelectionV<T>::SelectionV; + using Selection::setValue; + + void + setValue(T evalue) override + { + std::swap(this->v, evalue); + } + + void + setValue(std::string && evalue) override + { + if constexpr (std::same_as<T, bool>) { + using namespace std::literals; + if (!(this->v = evalue == "true"sv)) { + if (evalue != "false"sv) { + throw std::runtime_error("Value conversion failure"); + } + } + } + else { + if (auto res = std::from_chars(evalue.c_str(), evalue.c_str() + evalue.length(), this->v).ec; + res != std::errc {}) { + throw std::runtime_error("Value conversion failure"); + } + } + } + + void + write(const Writer & out) const override + { + out.pushValue(this->v); + } + }; + + template<NotScalar T> struct SelectionT<T> : public SelectionV<T> { using SelectionV<T>::SelectionV; using Selection::setValue; - using P = std::conditional_t<std::is_scalar_v<T>, T, T &&>; void - setValue(P evalue) override + setValue(T && evalue) override { std::swap(this->v, evalue); } @@ -113,14 +155,14 @@ namespace Persistence { template<typename T> [[nodiscard]] inline bool persistType(const T * const, const std::type_info & ti); enum class NameAction { Push, HandleAndContinue, Ignore }; - template<typename T> + template<typename Helper, typename T> [[nodiscard]] inline bool persistValue(const std::string_view key, T & value) { - SelectionT<T> s {value}; - const auto act {setName(key, s)}; + auto s = std::make_unique<Helper>(value); + const auto act {setName(key, *s)}; if (act != NameAction::Ignore) { - sel = std::make_unique<decltype(s)>(std::move(s)); + sel = std::move(s); if (act == NameAction::HandleAndContinue) { selHandler(); } @@ -187,6 +229,17 @@ namespace Persistence { }; using SelectionV<V>::SelectionV; + using SelectionV<V>::setValue; + + void + setValue(std::string && s) override + { + std::stringstream ss {std::move(s)}; + for (glm::length_t n = 0; n < L; n += 1) { + ss >> this->v[n]; + ss.get(); + } + } void beginArray(Stack & stk) override @@ -244,6 +297,39 @@ namespace Persistence { } }; + template<typename Map, typename Type = typename Map::mapped_type, auto Key = &Type::element_type::id> + struct MapByMember : public Persistence::SelectionT<Type> { + MapByMember(Map & m) : Persistence::SelectionT<Type> {s}, map {m} { } + + using Persistence::SelectionT<Type>::SelectionT; + void + endObject(Persistence::Stack & stk) override + { + map.emplace(std::invoke(Key, s), std::move(s)); + stk.pop(); + } + + private: + Type s; + Map & map; + }; + + template<typename Container, typename Type = typename Container::value_type> + struct Appender : public Persistence::SelectionT<Type> { + Appender(Container & c) : Persistence::SelectionT<Type> {s}, container {c} { } + using Persistence::SelectionT<Type>::SelectionT; + void + endObject(Persistence::Stack & stk) override + { + container.emplace_back(std::move(s)); + stk.pop(); + } + + private: + Type s; + Container & container; + }; + struct Persistable { Persistable() = default; virtual ~Persistable() = default; @@ -289,13 +375,41 @@ namespace Persistence { return true; } + class ParseBase { + public: + using SharedObjects = std::map<std::string, std::shared_ptr<Persistable>>; + using SharedObjectsWPtr = std::weak_ptr<SharedObjects>; + using SharedObjectsPtr = std::shared_ptr<SharedObjects>; + + ParseBase(); + DEFAULT_MOVE_NO_COPY(ParseBase); + + template<typename T> + static auto + getShared(auto && k) + { + return std::dynamic_pointer_cast<T>(Persistence::ParseBase::sharedObjects.lock()->at(k)); + } + template<typename... T> + static auto + emplaceShared(T &&... v) + { + return sharedObjects.lock()->emplace(std::forward<T>(v)...); + } + + protected: + Stack stk; + + private: + inline static thread_local SharedObjectsWPtr sharedObjects; + SharedObjectsPtr sharedObjectsInstance; + }; // 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> { + template<typename Ptr> struct SelectionPtrBase : public SelectionV<Ptr> { + static constexpr auto shared = std::is_copy_assignable_v<Ptr>; using T = typename Ptr::element_type; struct SelectionObj : public SelectionV<Ptr> { struct MakeObjectByTypeName : public SelectionV<Ptr> { @@ -330,7 +444,7 @@ namespace Persistence { void setValue(std::string && id) override { - sharedObjects.emplace(id, this->v); + ParseBase::emplaceShared(id, this->v); } }; @@ -340,14 +454,15 @@ namespace Persistence { select(const std::string & mbr) override { using namespace std::literals; - if (mbr == "@typeid"sv) { + if (mbr == "p.typeid"sv) { if (this->v) { throw std::runtime_error("cannot set object type after creation"); } return this->template make_s<MakeObjectByTypeName>(this->v); } if constexpr (shared) { - if (mbr == "@id"sv) { + if (mbr == "p.id"sv) { + make_default_as_needed(this->v); return this->template make_s<RememberObjectById>(this->v); } } @@ -439,18 +554,18 @@ namespace Persistence { } }; - template<typename T> struct SelectionT<std::unique_ptr<T>> : public SelectionPtrBase<std::unique_ptr<T>, false> { - using SelectionPtrBase<std::unique_ptr<T>, false>::SelectionPtrBase; + template<typename T> struct SelectionT<std::unique_ptr<T>> : public SelectionPtrBase<std::unique_ptr<T>> { + using SelectionPtrBase<std::unique_ptr<T>>::SelectionPtrBase; }; - template<typename T> struct SelectionT<std::shared_ptr<T>> : public SelectionPtrBase<std::shared_ptr<T>, true> { - using SelectionPtrBase<std::shared_ptr<T>, true>::SelectionPtrBase; - using SelectionPtrBase<std::shared_ptr<T>, true>::setValue; + template<typename T> struct SelectionT<std::shared_ptr<T>> : public SelectionPtrBase<std::shared_ptr<T>> { + using SelectionPtrBase<std::shared_ptr<T>>::SelectionPtrBase; + using SelectionPtrBase<std::shared_ptr<T>>::setValue; void setValue(std::string && id) override { - if (auto teo = std::dynamic_pointer_cast<T>(sharedObjects.at(id))) { + if (auto teo = ParseBase::getShared<T>(id)) { this->v = std::move(teo); } else { @@ -461,4 +576,7 @@ namespace Persistence { } #define STORE_TYPE store.persistType(this, typeid(*this)) -#define STORE_MEMBER(mbr) store.persistValue(#mbr, mbr) +#define STORE_MEMBER(mbr) STORE_NAME_MEMBER(#mbr, mbr) +#define STORE_NAME_MEMBER(name, mbr) store.persistValue<Persistence::SelectionT<decltype(mbr)>>(name, mbr) +#define STORE_HELPER(mbr, Helper) STORE_NAME_HELPER(#mbr, mbr, Helper) +#define STORE_NAME_HELPER(name, mbr, Helper) store.persistValue<Helper>(name, mbr) diff --git a/lib/saxParse-persistence.cpp b/lib/saxParse-persistence.cpp new file mode 100644 index 0000000..a6a0d23 --- /dev/null +++ b/lib/saxParse-persistence.cpp @@ -0,0 +1,50 @@ +#include "saxParse-persistence.h" + +namespace Persistence { + + void + SAXParsePersistence::loadStateInternal(FILE * in) + { + stk.top()->beforeValue(stk); + stk.top()->beginObject(stk); + parseFile(in); + stk.pop(); + stk.pop(); + } + + void + SAXParsePersistence::elementOpen(mxml_node_t * n) + { + stk.push(stk.top()->select(mxmlGetElement(n))); + stk.top()->beforeValue(stk); + stk.top()->beginObject(stk); + for (int attrCount = mxmlElementGetAttrCount(n), attrIdx {0}; attrIdx < attrCount; ++attrIdx) { + const char *name, *value = mxmlElementGetAttrByIndex(n, attrIdx, &name); + auto sel = stk.top()->select(name); + sel->beforeValue(stk); + sel->setValue(std::string {value}); + } + } + + void + SAXParsePersistence::elementClose(mxml_node_t *) + { + stk.top()->endObject(stk); + stk.top()->endObject(stk); + } + + void + SAXParsePersistence::data(mxml_node_t *) + { + } + + void + SAXParsePersistence::directive(mxml_node_t *) + { + } + + void + SAXParsePersistence::cdata(mxml_node_t *) + { + } +} diff --git a/lib/saxParse-persistence.h b/lib/saxParse-persistence.h new file mode 100644 index 0000000..6043b25 --- /dev/null +++ b/lib/saxParse-persistence.h @@ -0,0 +1,40 @@ +#pragma once + +#include "persistence.h" +#include "saxParse.h" +#include <cstdio> +#include <mxml.h> + +namespace Persistence { + class SAXParsePersistence : public SAXParse, ParseBase { + private: + template<typename T> struct Root : public Persistable { + T t {}; + bool + persist(PersistenceStore & store) + { + return STORE_TYPE && STORE_NAME_MEMBER("ilt", t); + } + }; + + void loadStateInternal(FILE * in); + + public: + template<typename T> + auto + loadState(FILE * in) + { + std::unique_ptr<Root<T>> root; + stk.push(std::make_unique<SelectionT<decltype(root)>>(std::ref(root))); + loadStateInternal(in); + return std::move(root->t); + } + + protected: + void elementOpen(mxml_node_t * n) override; + void elementClose(mxml_node_t *) override; + void data(mxml_node_t *) override; + void directive(mxml_node_t *) override; + void cdata(mxml_node_t *) override; + }; +} diff --git a/lib/saxParse.cpp b/lib/saxParse.cpp new file mode 100644 index 0000000..5c597aa --- /dev/null +++ b/lib/saxParse.cpp @@ -0,0 +1,41 @@ +#include "saxParse.h" +#include "mxml.h" + +namespace Persistence { + void + SAXParse::comment(mxml_node_t *) + { + // Default to just ignore comments + } + + void + SAXParse::parseFile(FILE * file) + { + mxmlRelease(mxmlSAXLoadFile( + nullptr, file, MXML_TEXT_CALLBACK, + [](mxml_node_t * n, mxml_sax_event_t e, void * data) { + SAXParse * self = static_cast<SAXParse *>(data); + switch (e) { + case MXML_SAX_ELEMENT_OPEN: + return self->elementOpen(n); + break; + case MXML_SAX_ELEMENT_CLOSE: + return self->elementClose(n); + break; + case MXML_SAX_COMMENT: + return self->comment(n); + break; + case MXML_SAX_DATA: + return self->data(n); + break; + case MXML_SAX_DIRECTIVE: + return self->directive(n); + break; + case MXML_SAX_CDATA:; + return self->cdata(n); + break; + } + }, + this)); + } +} diff --git a/lib/saxParse.h b/lib/saxParse.h new file mode 100644 index 0000000..d5baaca --- /dev/null +++ b/lib/saxParse.h @@ -0,0 +1,21 @@ +#pragma once + +#include <cstdio> + +typedef struct _mxml_node_s mxml_node_t; + +namespace Persistence { + class SAXParse { + public: + virtual ~SAXParse() = default; + + virtual void elementOpen(mxml_node_t *) = 0; + virtual void elementClose(mxml_node_t *) = 0; + virtual void comment(mxml_node_t *); + virtual void data(mxml_node_t *) = 0; + virtual void directive(mxml_node_t *) = 0; + virtual void cdata(mxml_node_t *) = 0; + + void parseFile(FILE * file); + }; +} |