[ox] Add StringView, Writer system, Preloader system

This commit is contained in:
2022-11-30 01:45:11 -06:00
parent 98f35140fe
commit cbb496c59f
64 changed files with 2343 additions and 417 deletions

287
deps/ox/src/ox/preloader/preloader.hpp vendored Normal file
View File

@@ -0,0 +1,287 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/array.hpp>
#include <ox/std/buffer.hpp>
#include <ox/std/byteswap.hpp>
#include <ox/std/error.hpp>
#include <ox/std/memops.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/types.hpp>
#include <ox/std/typetraits.hpp>
#include <ox/std/units.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include "preloader.hpp"
#include "platspecs.hpp"
namespace ox {
template<typename PlatSpec>
class Preloader: public ModelHandlerBase<Preloader<PlatSpec>> {
private:
class UnionIdxTracker {
private:
int m_unionIdx = -1;
int m_it = 0;
public:
constexpr UnionIdxTracker() noexcept = default;
constexpr explicit UnionIdxTracker(int idx) noexcept: m_unionIdx(idx) {}
constexpr auto checkAndIterate() noexcept {
return m_unionIdx == -1 || m_it++ == m_unionIdx;
}
};
ox::Buffer m_buff;
ox::BufferWriter m_writer;
// list of all the places where ptrs were written to buffer
struct PtrPair {
std::size_t loc = 0;
typename PlatSpec::PtrType value = 0;
constexpr PtrPair() noexcept = default;
constexpr PtrPair(std::size_t pLoc, typename PlatSpec::PtrType pValue) noexcept:
loc(pLoc), value(pValue) {}
};
ox::Vector<PtrPair> m_ptrs;
ox::Vector<UnionIdxTracker, 8> m_unionIdx = {{}};
constexpr Preloader() noexcept: m_writer(&m_buff) {}
Preloader(const Preloader &src) = delete;
Preloader(Preloader &&src) = delete;
const Preloader &operator=(const Preloader &src) = delete;
const Preloader &operator=(Preloader &&src) = delete;
public:
constexpr static ox::Result<ox::UniquePtr<Preloader>> make(ox::ios_base::seekdir anchor = ox::ios_base::cur,
std::size_t sz = 0) noexcept;
constexpr void setTypeInfo(CRStringView, int, const ox::Vector<String>& = {}, int = 0) noexcept {}
template<typename U, bool force>
constexpr ox::Error field(CRStringView, const ox::UnionView<U, force> val) noexcept;
template<typename T>
constexpr ox::Error field(CRStringView, const T *val) noexcept;
template<std::size_t SmallStringSize>
constexpr ox::Error field(CRStringView, const ox::BasicString<SmallStringSize> *val) noexcept;
template<typename T, std::size_t sz>
constexpr ox::Error field(CRStringView, const ox::Array<T, sz> *valArray) noexcept;
template<typename T>
constexpr ox::Error field(CRStringView, const T **val, std::size_t cnt) noexcept;
constexpr ox::Error offsetPtrs(std::size_t offset) noexcept;
[[nodiscard]]
constexpr auto &buff() const noexcept {
return m_buff;
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return ox::OpType::Write;
}
private:
constexpr ox::Error fieldVector(CRStringView name, const ox::ModelValueVector *val) noexcept;
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr ox::Error fieldVector(CRStringView, const ox::Vector<T, SmallVectorSize, Allocator> *val) noexcept;
constexpr ox::Error fieldVector(CRStringView, const auto *val, ox::VectorMemMap<PlatSpec> vecVal) noexcept;
constexpr ox::Error pad(const auto *val) noexcept;
constexpr bool unionCheckAndIt() noexcept;
};
template<typename PlatSpec>
constexpr ox::Result<ox::UniquePtr<Preloader<PlatSpec>>>
Preloader<PlatSpec>::make(ox::ios_base::seekdir anchor, std::size_t sz) noexcept {
auto p = ox::UniquePtr<Preloader>(new Preloader);
if (const auto err = p->m_writer.seekp(0, anchor)) {
return {std::move(p), err};
}
if (const auto err = p->m_writer.write(nullptr, sz)) {
return {std::move(p), err};
}
if (const auto err = p->m_writer.seekp(p->m_writer.tellp() - sz)) {
return {std::move(p), err};
}
return p;
}
template<typename PlatSpec>
template<typename U, bool force>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView, const ox::UnionView<U, force> val) noexcept {
if (!unionCheckAndIt()) {
return {};
}
oxReturnError(pad(val.get()));
m_unionIdx.emplace_back(val.idx());
const auto err = model(this->interface(), val.get());
m_unionIdx.pop_back();
return err;
}
template<typename PlatSpec>
template<typename T>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView name, const T *val) noexcept {
if (!unionCheckAndIt()) {
return {};
}
oxReturnError(pad(val));
if constexpr(ox::is_integral_v<T>) {
return ox::serialize(&m_writer, PlatSpec::correctEndianness(*val));
} else if constexpr(ox::is_pointer_v<T>) {
return {};
} else if constexpr(ox::isVector_v<T> || ox::is_same_v<T, ox::ModelValueVector>) {
return fieldVector(name, val);
} else {
m_unionIdx.emplace_back(-1);
const auto out = model(this->interface(), val);
m_unionIdx.pop_back();
return out;
}
}
template<typename PlatSpec>
template<std::size_t SmallStringSize>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView, const ox::BasicString<SmallStringSize> *val) noexcept {
if (!unionCheckAndIt()) {
return {};
}
using VecMap = ox::VectorMemMap<PlatSpec>;
const auto sz = val->bytes();
oxRequire(a, ox::allocate(&m_writer, sz));
const VecMap vecVal{
.smallVecSize = SmallStringSize,
.size = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(sz)),
.cap = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(sz)),
.items = sz ? PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(a) + PlatSpec::RomStart) : 0,
};
oxReturnError(pad(&vecVal));
const auto restore = m_writer.tellp();
oxReturnError(m_writer.seekp(a));
oxReturnError(m_writer.write(val->data(), sz));
oxReturnError(m_writer.seekp(restore));
oxReturnError(serialize(&m_writer, vecVal));
m_ptrs.emplace_back(restore + offsetof(VecMap, items), vecVal.items);
return {};
}
template<typename PlatSpec>
template<typename T, std::size_t sz>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView name, const ox::Array<T, sz> *val) noexcept {
if (!unionCheckAndIt()) {
return {};
}
// serialize the Array elements
if constexpr(sz) {
m_unionIdx.emplace_back(-1);
for (std::size_t i = 0; i < val->size(); ++i) {
oxReturnError(this->interface()->field(name, &(*val)[i]));
}
m_unionIdx.pop_back();
}
return {};
}
template<typename PlatSpec>
template<typename T>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView, const T **val, std::size_t cnt) noexcept {
if (!unionCheckAndIt()) {
return {};
}
// serialize the array
m_unionIdx.emplace_back(-1);
for (std::size_t i = 0; i < cnt; ++i) {
oxReturnError(this->interface()->field(nullptr, &val[i]));
}
m_unionIdx.pop_back();
return {};
}
template<typename PlatSpec>
constexpr ox::Error Preloader<PlatSpec>::offsetPtrs(std::size_t offset) noexcept {
for (const auto &p : m_ptrs) {
oxReturnError(m_writer.seekp(p.loc));
oxReturnError(ox::serialize(&m_writer, PlatSpec::correctEndianness(p.value + offset)));
}
return {};
}
template<typename PlatSpec>
constexpr ox::Error Preloader<PlatSpec>::fieldVector(CRStringView name, const ox::ModelValueVector *val) noexcept {
// serialize the Vector
ox::VectorMemMap<PlatSpec> vecVal{
.size = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(val->size())),
.cap = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(val->size())),
};
return fieldVector(name, val, vecVal);
}
template<typename PlatSpec>
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr ox::Error Preloader<PlatSpec>::fieldVector(CRStringView name, const ox::Vector<T, SmallVectorSize, Allocator> *val) noexcept {
// serialize the Vector
ox::VectorMemMap<PlatSpec> vecVal{
.smallVecSize = SmallVectorSize * sizeOf<PlatSpec>(static_cast<T*>(nullptr)),
.size = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(val->size())),
.cap = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(val->size())),
};
return fieldVector(name, val, vecVal);
}
template<typename PlatSpec>
constexpr ox::Error Preloader<PlatSpec>::fieldVector(CRStringView, const auto *val, ox::VectorMemMap<PlatSpec> vecVal) noexcept {
oxReturnError(pad(&vecVal));
const auto vecValPt = m_writer.tellp();
// serialize the Vector elements
if (val->size()) {
const auto sz = sizeOf<PlatSpec>(&(*val)[0]) * val->size();
oxRequire(p, ox::allocate(&m_writer, sz));
oxReturnError(m_writer.seekp(p));
m_unionIdx.emplace_back(-1);
for (std::size_t i = 0; i < val->size(); ++i) {
oxReturnError(this->interface()->field(nullptr, &val->operator[](i)));
}
m_unionIdx.pop_back();
vecVal.items = PlatSpec::correctEndianness(p + PlatSpec::RomStart);
oxReturnError(m_writer.seekp(vecValPt));
} else {
vecVal.items = 0;
}
// serialize the Vector
oxReturnError(serialize(&m_writer, vecVal));
m_ptrs.emplace_back(vecValPt + offsetof(ox::VectorMemMap<PlatSpec>, items), vecVal.items);
return {};
}
template<typename PlatSpec>
constexpr ox::Error Preloader<PlatSpec>::pad(const auto *val) noexcept {
constexpr auto a = alignOf_v<PlatSpec, decltype(val)>;
const auto padding = a - m_writer.tellp() % a;
return m_writer.write(nullptr, padding);
}
template<typename PlatSpec>
constexpr bool Preloader<PlatSpec>::unionCheckAndIt() noexcept {
auto &u = m_unionIdx.back().unwrap();
return u.checkAndIterate();
}
template<typename PlatSpec>
constexpr ox::Result<ox::Buffer> preload(const auto *obj) noexcept {
using Pl = Preloader<PlatSpec>;
oxRequireM(preloader, Pl::make(ox::ios_base::end));
oxReturnError(model(preloader->interface(), obj));
return preloader->buff();
}
}