summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/collections.hpp41
-rw-r--r--lib/filesystem.cpp9
-rw-r--r--lib/filesystem.h5
-rw-r--r--lib/jsonParse-persistence.h4
-rw-r--r--lib/persistence.cpp9
-rw-r--r--lib/persistence.h158
-rw-r--r--lib/saxParse-persistence.cpp50
-rw-r--r--lib/saxParse-persistence.h40
-rw-r--r--lib/saxParse.cpp41
-rw-r--r--lib/saxParse.h21
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);
+ };
+}