From cbb496c59ff830004b9fac1d27aacc92683f87e9 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Wed, 30 Nov 2022 01:45:11 -0600 Subject: [PATCH] [ox] Add StringView, Writer system, Preloader system --- deps/ox/src/ox/CMakeLists.txt | 1 + deps/ox/src/ox/claw/read.cpp | 9 +- deps/ox/src/ox/claw/read.hpp | 1 + deps/ox/src/ox/claw/test/tests.cpp | 2 +- deps/ox/src/ox/claw/write.hpp | 13 +- deps/ox/src/ox/fs/filesystem/filelocation.cpp | 6 +- deps/ox/src/ox/fs/filesystem/filelocation.hpp | 15 +- deps/ox/src/ox/fs/tool.cpp | 4 +- deps/ox/src/ox/mc/read.hpp | 10 +- deps/ox/src/ox/mc/test/tests.cpp | 14 +- deps/ox/src/ox/mc/write.hpp | 16 +- deps/ox/src/ox/model/CMakeLists.txt | 5 + deps/ox/src/ox/model/desctypes.hpp | 118 +++++-- deps/ox/src/ox/model/descwrite.hpp | 153 ++++++---- deps/ox/src/ox/model/fieldcounter.hpp | 11 +- deps/ox/src/ox/model/metadata.hpp | 18 +- deps/ox/src/ox/model/modelhandleradaptor.hpp | 45 ++- deps/ox/src/ox/model/modelops.hpp | 9 +- deps/ox/src/ox/model/modelvalue.cpp | 14 + deps/ox/src/ox/model/modelvalue.hpp | 195 +++++++++++- deps/ox/src/ox/model/optype.hpp | 17 +- deps/ox/src/ox/model/test/CMakeLists.txt | 11 + deps/ox/src/ox/model/test/tests.cpp | 41 +++ deps/ox/src/ox/model/typenamecatcher.hpp | 10 +- deps/ox/src/ox/model/types.hpp | 102 +++++-- deps/ox/src/ox/model/typestore.hpp | 54 ++-- deps/ox/src/ox/model/walk.hpp | 5 +- deps/ox/src/ox/oc/read.hpp | 4 +- deps/ox/src/ox/oc/test/tests.cpp | 2 +- deps/ox/src/ox/oc/write.hpp | 3 +- deps/ox/src/ox/preloader/CMakeLists.txt | 24 ++ deps/ox/src/ox/preloader/alignmentcatcher.hpp | 62 ++++ deps/ox/src/ox/preloader/platspecs.hpp | 126 ++++++++ deps/ox/src/ox/preloader/preload.cpp | 33 ++ deps/ox/src/ox/preloader/preload.hpp | 21 ++ deps/ox/src/ox/preloader/preloader.cpp | 33 ++ deps/ox/src/ox/preloader/preloader.hpp | 287 ++++++++++++++++++ deps/ox/src/ox/preloader/sizecatcher.hpp | 109 +++++++ deps/ox/src/ox/preloader/unionsizecatcher.hpp | 97 ++++++ deps/ox/src/ox/std/CMakeLists.txt | 3 + deps/ox/src/ox/std/algorithm.hpp | 10 + deps/ox/src/ox/std/assert.hpp | 20 +- deps/ox/src/ox/std/bit.hpp | 3 +- deps/ox/src/ox/std/bstring.hpp | 16 + deps/ox/src/ox/std/buffer.cpp | 3 + deps/ox/src/ox/std/buffer.hpp | 152 ++++++++++ deps/ox/src/ox/std/concepts.hpp | 36 +++ deps/ox/src/ox/std/def.hpp | 1 + deps/ox/src/ox/std/error.hpp | 15 + deps/ox/src/ox/std/fmt.hpp | 69 +++-- deps/ox/src/ox/std/memops.hpp | 6 +- deps/ox/src/ox/std/memory.hpp | 2 +- deps/ox/src/ox/std/range.hpp | 25 ++ deps/ox/src/ox/std/serialize.hpp | 81 +++++ deps/ox/src/ox/std/std.hpp | 2 + deps/ox/src/ox/std/string.cpp | 5 + deps/ox/src/ox/std/string.hpp | 256 +++++++++------- deps/ox/src/ox/std/stringview.hpp | 123 ++++++++ deps/ox/src/ox/std/strongint.hpp | 11 +- deps/ox/src/ox/std/test/CMakeLists.txt | 2 + deps/ox/src/ox/std/test/tests.cpp | 35 ++- deps/ox/src/ox/std/typetraits.hpp | 17 ++ deps/ox/src/ox/std/vector.hpp | 89 ++---- deps/ox/src/ox/std/writer.hpp | 78 +++++ 64 files changed, 2343 insertions(+), 417 deletions(-) create mode 100644 deps/ox/src/ox/model/test/CMakeLists.txt create mode 100644 deps/ox/src/ox/model/test/tests.cpp create mode 100644 deps/ox/src/ox/preloader/CMakeLists.txt create mode 100644 deps/ox/src/ox/preloader/alignmentcatcher.hpp create mode 100644 deps/ox/src/ox/preloader/platspecs.hpp create mode 100644 deps/ox/src/ox/preloader/preload.cpp create mode 100644 deps/ox/src/ox/preloader/preload.hpp create mode 100644 deps/ox/src/ox/preloader/preloader.cpp create mode 100644 deps/ox/src/ox/preloader/preloader.hpp create mode 100644 deps/ox/src/ox/preloader/sizecatcher.hpp create mode 100644 deps/ox/src/ox/preloader/unionsizecatcher.hpp create mode 100644 deps/ox/src/ox/std/range.hpp create mode 100644 deps/ox/src/ox/std/serialize.hpp create mode 100644 deps/ox/src/ox/std/stringview.hpp create mode 100644 deps/ox/src/ox/std/writer.hpp diff --git a/deps/ox/src/ox/CMakeLists.txt b/deps/ox/src/ox/CMakeLists.txt index 104479bd..743d0426 100644 --- a/deps/ox/src/ox/CMakeLists.txt +++ b/deps/ox/src/ox/CMakeLists.txt @@ -7,4 +7,5 @@ add_subdirectory(event) add_subdirectory(fs) add_subdirectory(mc) add_subdirectory(model) +add_subdirectory(preloader) add_subdirectory(std) diff --git a/deps/ox/src/ox/claw/read.cpp b/deps/ox/src/ox/claw/read.cpp index cee5f8af..8a89f1dc 100644 --- a/deps/ox/src/ox/claw/read.cpp +++ b/deps/ox/src/ox/claw/read.cpp @@ -15,10 +15,11 @@ namespace ox { Result readClawHeader(const char *buff, std::size_t buffLen) noexcept { const auto s1End = ox_strchr(buff, ';', buffLen); if (!s1End) { + oxAssert(false, "fail"); return OxError(1, "Could not read Claw header"); } const auto s1Size = s1End - buff; - String fmt(buff, s1Size); + const String fmt(buff, s1Size); buff += s1Size + 1; buffLen -= s1Size + 1; @@ -27,7 +28,7 @@ Result readClawHeader(const char *buff, std::size_t buffLen) noexcep return OxError(2, "Could not read Claw header"); } const auto s2Size = s2End - buff; - String typeName(buff, s2Size); + const String typeName(buff, s2Size); buff += s2Size + 1; buffLen -= s2Size + 1; @@ -36,7 +37,7 @@ Result readClawHeader(const char *buff, std::size_t buffLen) noexcep return OxError(3, "Could not read Claw header"); } const auto s3Size = s3End - buff; - String versionStr(buff, s3Size); + const String versionStr(buff, s3Size); buff += s3Size + 1; buffLen -= s3Size + 1; @@ -74,7 +75,7 @@ Result stripClawHeader(const ox::Buffer &buff) noexcept { Result readClaw(TypeStore *ts, const Buffer &buff) noexcept { oxRequire(header, readClawHeader(buff)); - oxRequire(t, ts->template getLoad(header.typeName, header.typeVersion)); + oxRequire(t, ts->template getLoad(header.typeName, header.typeVersion, header.typeParams)); ModelObject obj; oxReturnError(obj.setType(t)); switch (header.fmt) { diff --git a/deps/ox/src/ox/claw/read.hpp b/deps/ox/src/ox/claw/read.hpp index 7864a029..a0d96fa8 100644 --- a/deps/ox/src/ox/claw/read.hpp +++ b/deps/ox/src/ox/claw/read.hpp @@ -25,6 +25,7 @@ constexpr auto Error_ClawTypeVersionMismatch = 201; struct ClawHeader { String typeName; int typeVersion = -1; + TypeParamPack typeParams; ClawFormat fmt = ClawFormat::None; const char *data = nullptr; std::size_t dataSize = 0; diff --git a/deps/ox/src/ox/claw/test/tests.cpp b/deps/ox/src/ox/claw/test/tests.cpp index 8771522b..e8909f2e 100644 --- a/deps/ox/src/ox/claw/test/tests.cpp +++ b/deps/ox/src/ox/claw/test/tests.cpp @@ -96,7 +96,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith auto *obj) { oxReturnError(io->field("Int7", &obj->Int7)); oxReturnError(io->field("Int8", &obj->Int8)); int unionIdx = 0; - if constexpr(ox_strcmp(T::opType(), ox::OpType::Reflect) != 0) { + if constexpr(T::opType() != ox::OpType::Reflect) { unionIdx = obj->unionIdx; } oxReturnError(io->field("Union", ox::UnionView{&obj->Union, unionIdx})); diff --git a/deps/ox/src/ox/claw/write.hpp b/deps/ox/src/ox/claw/write.hpp index 55e36d43..b476ecbd 100644 --- a/deps/ox/src/ox/claw/write.hpp +++ b/deps/ox/src/ox/claw/write.hpp @@ -24,10 +24,12 @@ namespace detail { struct TypeInfoCatcher { const char *name = nullptr; + int version = 0; template - constexpr void setTypeInfo(const char *name = T::TypeName, int = T::TypeVersion) noexcept { + constexpr void setTypeInfo(const char *name = T::TypeName, int v = T::TypeVersion, const Vector& = {}, int = 0) noexcept { this->name = name; + this->version = v; } constexpr Error field(...) noexcept { @@ -57,6 +59,13 @@ constexpr const char *getTypeName(T *t) noexcept { return tnc.name; } +template +constexpr int getTypeVersion(T *t) noexcept { + TypeInfoCatcher tnc; + oxIgnoreError(model(&tnc, t)); + return tnc.version; +} + template Result writeClawHeader(T *t, ClawFormat fmt) noexcept { String out; @@ -72,7 +81,7 @@ Result writeClawHeader(T *t, ClawFormat fmt) noexcept { } out += detail::getTypeName(t); out += ";"; - const auto tn = detail::type_version::value; + const auto tn = detail::getTypeVersion(t); if (tn > -1) { out += tn; } diff --git a/deps/ox/src/ox/fs/filesystem/filelocation.cpp b/deps/ox/src/ox/fs/filesystem/filelocation.cpp index 4ec15139..ccd207e8 100644 --- a/deps/ox/src/ox/fs/filesystem/filelocation.cpp +++ b/deps/ox/src/ox/fs/filesystem/filelocation.cpp @@ -28,10 +28,10 @@ FileAddress::FileAddress(uint64_t inode) noexcept { m_type = FileAddressType::Inode; } -FileAddress::FileAddress(const ox::String &path) noexcept { +FileAddress::FileAddress(ox::CRStringView path) noexcept { auto pathSize = path.bytes(); m_data.path = new char[pathSize]; - memcpy(m_data.path, path.c_str(), pathSize); + memcpy(m_data.path, path.data(), pathSize); m_type = FileAddressType::Path; } @@ -98,7 +98,7 @@ FileAddress &FileAddress::operator=(FileAddress &&other) noexcept { return *this; } -bool FileAddress::operator==(const ox::String &path) const noexcept { +bool FileAddress::operator==(CRStringView path) const noexcept { auto [p, err] = getPath(); if (err) { return false; diff --git a/deps/ox/src/ox/fs/filesystem/filelocation.hpp b/deps/ox/src/ox/fs/filesystem/filelocation.hpp index 05c86c42..947a6236 100644 --- a/deps/ox/src/ox/fs/filesystem/filelocation.hpp +++ b/deps/ox/src/ox/fs/filesystem/filelocation.hpp @@ -57,7 +57,11 @@ class FileAddress { FileAddress(uint64_t inode) noexcept; - FileAddress(const ox::String &path) noexcept; + FileAddress(CRStringView path) noexcept; + + template + FileAddress(const ox::BasicString &path) noexcept: FileAddress(StringView(path)) { + } FileAddress(char *path) noexcept; @@ -69,7 +73,7 @@ class FileAddress { FileAddress &operator=(FileAddress &&other) noexcept; - bool operator==(const ox::String &path) const noexcept; + bool operator==(CRStringView path) const noexcept; [[nodiscard]] constexpr FileAddressType type() const noexcept { @@ -82,6 +86,7 @@ class FileAddress { } } + [[nodiscard]] constexpr Result getInode() const noexcept { switch (m_type) { case FileAddressType::Inode: @@ -141,16 +146,16 @@ constexpr Error model(T *io, CommonPtrWith auto *obj) noexcep template constexpr Error model(T *io, CommonPtrWith auto *fa) noexcept { io->template setTypeInfo(); - if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) { + if constexpr(T::opType() == OpType::Reflect) { int8_t type = 0; oxReturnError(io->field("type", &type)); oxReturnError(io->field("data", UnionView(&fa->m_data, 0))); - } else if constexpr(ox_strcmp(T::opType(), OpType::Read) == 0) { + } else if constexpr(T::opType() == OpType::Read) { auto type = static_cast(fa->m_type); oxReturnError(io->field("type", &type)); fa->m_type = static_cast(type); oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast(fa->m_type)))); - } else if constexpr(ox_strcmp(T::opType(), OpType::Write) == 0) { + } else if constexpr(T::opType() == OpType::Write) { auto type = static_cast(fa->m_type); oxReturnError(io->field("type", &type)); oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast(fa->m_type)))); diff --git a/deps/ox/src/ox/fs/tool.cpp b/deps/ox/src/ox/fs/tool.cpp index 02fdaaf1..da4a5438 100644 --- a/deps/ox/src/ox/fs/tool.cpp +++ b/deps/ox/src/ox/fs/tool.cpp @@ -62,8 +62,8 @@ static ox::Error runRead(ox::FileSystem *fs, int argc, const char **argv) noexce } static ox::Error run(int argc, const char **argv) noexcept { - if (argc < 2) { - oxErr("Subcommand and OxFS file arguments are required\n"); + if (argc < 3) { + oxErr("OxFS file and subcommand arguments are required\n"); return OxError(1); } const auto fsPath = argv[1]; diff --git a/deps/ox/src/ox/mc/read.hpp b/deps/ox/src/ox/mc/read.hpp index 65a5b972..d7965642 100644 --- a/deps/ox/src/ox/mc/read.hpp +++ b/deps/ox/src/ox/mc/read.hpp @@ -100,7 +100,7 @@ class MetalClawReaderTemplate { template constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, - int fields = ModelFieldCount_v) noexcept; + const Vector& = {}, int fields = ModelFieldCount_v) noexcept; /** * Returns a MetalClawReader to parse a child object. @@ -225,7 +225,7 @@ constexpr Error MetalClawReaderTemplate::field(const char *name, a if (valLen >= len) { auto reader = child(""); auto handler = HandlerMaker(&reader); - handler.setTypeInfo("List", 0, static_cast(len)); + handler.setTypeInfo("List", 0, {}, static_cast(len)); for (std::size_t i = 0; i < len; ++i) { oxReturnError(handler.field("", &val[i])); } @@ -254,7 +254,7 @@ constexpr Error MetalClawReaderTemplate::field(const char*, HashMa // read the list auto reader = child(""); auto handler = HandlerMaker(&reader); - handler.setTypeInfo("List", 0, static_cast(len)); + handler.setTypeInfo("List", 0, {}, static_cast(len)); for (std::size_t i = 0; i < len; ++i) { const auto keyLen = handler.stringLength(nullptr); auto wkey = ox_malloca(keyLen + 1, char, 0); @@ -500,7 +500,7 @@ constexpr Error MetalClawReaderTemplate::field(const char*, CB cb) // read the list auto reader = child(""); auto handler = HandlerMaker(&reader); - handler.setTypeInfo("List", 0, static_cast(len)); + handler.setTypeInfo("List", 0, {}, static_cast(len)); for (std::size_t i = 0; i < len; ++i) { T val; oxReturnError(handler.field("", &val)); @@ -527,7 +527,7 @@ constexpr StringLength MetalClawReaderTemplate::stringLength(const template template -constexpr void MetalClawReaderTemplate::setTypeInfo(const char*, int, int fields) noexcept { +constexpr void MetalClawReaderTemplate::setTypeInfo(const char*, int, const Vector&, int fields) noexcept { m_fields = fields; m_buffIt = static_cast((fields / 8 + 1) - (fields % 8 == 0)); m_fieldPresence.setFields(fields); diff --git a/deps/ox/src/ox/mc/test/tests.cpp b/deps/ox/src/ox/mc/test/tests.cpp index 7e109c33..b11d4aa8 100644 --- a/deps/ox/src/ox/mc/test/tests.cpp +++ b/deps/ox/src/ox/mc/test/tests.cpp @@ -89,7 +89,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith auto *obj) noexce oxReturnError(io->field("Int7", &obj->Int7)); oxReturnError(io->field("Int8", &obj->Int8)); oxReturnError(io->field("unionIdx", &obj->unionIdx)); - if (ox_strcmp(io->opType(), ox::OpType::Reflect) == 0) { + if constexpr(T::opType() == ox::OpType::Reflect) { oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 0})); } else { oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx})); @@ -309,10 +309,10 @@ std::map tests = { testIn.Union.Int = 93; oxAssert(ox::writeMC(dataBuff.data(), dataBuff.size(), &testIn), "Data generation failed"); ox::TypeStore typeStore; - auto type = ox::buildTypeDef(&typeStore, &testIn); - oxAssert(type.error, "Descriptor write failed"); + const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn); + oxAssert(typeErr, "Descriptor write failed"); ox::ModelObject testOut; - oxReturnError(testOut.setType(type.value)); + oxReturnError(testOut.setType(type)); oxAssert(ox::readMC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed"); oxAssert(testOut["Int"].get() == testIn.Int, "testOut.Int failed"); oxAssert(testOut["Bool"].get() == testIn.Bool, "testOut.Bool failed"); @@ -361,9 +361,9 @@ std::map tests = { testIn.Struct.BString = "Test String 2"; oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed"); ox::TypeStore typeStore; - auto type = ox::buildTypeDef(&typeStore, &testIn); - oxAssert(type.error, "Descriptor write failed"); - oxReturnError(ox::walkModel(type.value, dataBuff, dataBuffLen, + const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn); + oxAssert(typeErr, "Descriptor write failed"); + oxReturnError(ox::walkModel(type, dataBuff, dataBuffLen, [](const ox::Vector&, const ox::Vector&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error { //std::cout << f.fieldName.c_str() << '\n'; auto fieldName = f.fieldName.c_str(); diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index 68576366..035b122c 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -104,7 +104,7 @@ class MetalClawWriter { template constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, - int fields = ModelFieldCount_v) noexcept; + const Vector& = {}, int fields = ModelFieldCount_v) noexcept; [[nodiscard]] constexpr std::size_t size() const noexcept; @@ -135,10 +135,10 @@ class MetalClawWriter { }; constexpr MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept: - m_fieldPresence(buff, buffLen), - m_unionIdx(unionIdx), - m_buffLen(buffLen), - m_buff(buff) { + m_fieldPresence(buff, buffLen), + m_unionIdx(unionIdx), + m_buffLen(buffLen), + m_buff(buff) { } constexpr MetalClawWriter::~MetalClawWriter() noexcept { @@ -330,7 +330,7 @@ constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noe MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); ModelHandlerInterface handler{&writer}; - handler.setTypeInfo("List", 0, len); + handler.setTypeInfo("List", 0, {}, len); // write the array for (std::size_t i = 0; i < len; i++) { @@ -363,7 +363,7 @@ constexpr Error MetalClawWriter::field(const char*, const HashMap *va MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); ModelHandlerInterface handler{&writer}; // double len for both key and value - handler.setTypeInfo("Map", 0, len * 2); + handler.setTypeInfo("Map", 0, {}, len * 2); // write the array for (std::size_t i = 0; i < len; i++) { const auto &key = keys[i]; @@ -388,7 +388,7 @@ constexpr Error MetalClawWriter::field(const char *name, HashMap *val } template -constexpr void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept { +constexpr void MetalClawWriter::setTypeInfo(const char*, int, const Vector&, int fields) noexcept { m_fields = fields; m_fieldPresence.setFields(fields); m_buffIt = static_cast(m_fieldPresence.getMaxLen()); diff --git a/deps/ox/src/ox/model/CMakeLists.txt b/deps/ox/src/ox/model/CMakeLists.txt index 121e285d..79fbfada 100644 --- a/deps/ox/src/ox/model/CMakeLists.txt +++ b/deps/ox/src/ox/model/CMakeLists.txt @@ -2,6 +2,7 @@ add_library( OxModel desctypes.cpp descwrite.cpp + modelvalue.cpp ) target_link_libraries( @@ -42,3 +43,7 @@ install(TARGETS OxModel LIBRARY DESTINATION lib/ox ARCHIVE DESTINATION lib/ox ) + +if(OX_RUN_TESTS) + add_subdirectory(test) +endif() \ No newline at end of file diff --git a/deps/ox/src/ox/model/desctypes.hpp b/deps/ox/src/ox/model/desctypes.hpp index 45d47a97..fc44ffd6 100644 --- a/deps/ox/src/ox/model/desctypes.hpp +++ b/deps/ox/src/ox/model/desctypes.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,22 @@ namespace ox { using FieldName = String; +using TypeParamPack = Vector; + +static constexpr auto buildTypeId(CRStringView name, int version, + const TypeParamPack &typeParams) noexcept { + String tp; + if (typeParams.size()) { + tp = "<"; + for (const auto &p : typeParams) { + tp += p + ","; + } + tp = tp.substr(0, tp.len() - 1); + tp += ">"; + } + return ox::sfmt("{}{};{}", name, tp, version); +} + enum class PrimitiveType: uint8_t { UnsignedInteger = 0, SignedInteger = 1, @@ -33,45 +50,82 @@ enum class PrimitiveType: uint8_t { Union = 6, }; +struct Subscript { + static constexpr auto TypeName = "net.drinkingtea.ox.Subscript"; + static constexpr auto TypeVersion = 1; + enum class SubscriptType: uint32_t { + None = 0, + Ptr = 1, + PtrArray = 2, + InlineArray = 3, + Vector = 4, + }; + SubscriptType subscriptType = SubscriptType::None; + uint64_t length = 0; + uint64_t smallSzLen = 0; +}; + +template +constexpr Error model(T *io, CommonPtrWith auto *type) noexcept { + io->template setTypeInfo(); + if constexpr(T::opType() == OpType::Reflect) { + uint32_t st = 0; + oxReturnError(io->field("subscriptType", &st)); + } else { + auto pt = type ? static_cast(type->subscriptType) : 0; + oxReturnError(io->field("subscriptType", &pt)); + type->subscriptType = static_cast(pt); + } + oxReturnError(io->field("length", &type->length)); + oxReturnError(io->field("smallSzLen", &type->smallSzLen)); + return OxError(0); +} + +using SubscriptStack = Vector; + struct DescriptorField { // order of fields matters static constexpr auto TypeName = "net.drinkingtea.ox.DescriptorField"; - static constexpr auto TypeVersion = 2; + static constexpr auto TypeVersion = 3; // do not serialize type const struct DescriptorType *type = nullptr; String fieldName; int subscriptLevels = 0; - String typeName; // gives reference to type for lookup if type is null - int typeVersion = 0; - bool list = false; + SubscriptStack subscriptStack; + String typeId; // gives reference to type for lookup if type is null constexpr DescriptorField() noexcept = default; constexpr DescriptorField(const DescriptorType *pType, String pFieldName, - int pSubscriptLevels, String pTypeName, int pTypeVersion) noexcept: + int pSubscriptLevels, + SubscriptStack pSubscriptType, + String pTypeId) noexcept: type(pType), fieldName(std::move(pFieldName)), subscriptLevels(pSubscriptLevels), - typeName(std::move(pTypeName)), - typeVersion(pTypeVersion) { + subscriptStack(std::move(pSubscriptType)), + typeId(std::move(pTypeId)) { } constexpr DescriptorField(const DescriptorField &other) noexcept: type(other.type), fieldName(other.fieldName), subscriptLevels(other.subscriptLevels), - typeName(other.typeName) { + subscriptStack(other.subscriptStack), + typeId(other.typeId) { } constexpr DescriptorField(DescriptorField &&other) noexcept: type(other.type), - fieldName(other.fieldName), + fieldName(std::move(other.fieldName)), subscriptLevels(other.subscriptLevels), - typeName(std::move(other.typeName)) { + subscriptStack(std::move(other.subscriptStack)), + typeId(std::move(other.typeId)) { other.type = {}; other.subscriptLevels = {}; + other.subscriptStack = {}; } constexpr ~DescriptorField() noexcept = default; @@ -86,13 +140,14 @@ using FieldList = Vector; struct DescriptorType { - static constexpr auto TypeName = "net.drinkingtea.ox.DescriptorType"; - static constexpr auto TypeVersion = 2; + static constexpr auto TypeName = "net.drinkingtea.ox.TypeDescriptor"; + static constexpr auto TypeVersion = 1; String typeName; int typeVersion = 0; PrimitiveType primitiveType = PrimitiveType::UnsignedInteger; - // fieldList only applies to structs + TypeParamPack typeParams; + // fieldList only applies to structs and unions FieldList fieldList; // - number of bytes for integer and float types // - number of fields for structs and lists @@ -101,31 +156,26 @@ struct DescriptorType { constexpr DescriptorType() noexcept = default; - constexpr explicit DescriptorType(String tn, int typeVersion) noexcept: - typeName(std::move(tn)), typeVersion(typeVersion) { - } - - constexpr DescriptorType(String tn, PrimitiveType t, int b) noexcept: + constexpr explicit DescriptorType(String tn, int typeVersion, PrimitiveType t, TypeParamPack pTypeParams) noexcept: typeName(std::move(tn)), + typeVersion(typeVersion), primitiveType(t), - length(b) { - } - - constexpr DescriptorType(String tn, PrimitiveType t, FieldList fl) noexcept: - typeName(std::move(tn)), - primitiveType(t), - fieldList(std::move(fl)) { + typeParams(std::move(pTypeParams)) { } }; +[[nodiscard]] +constexpr auto buildTypeId(const DescriptorType &t) noexcept { + return buildTypeId(t.typeName, t.typeVersion, t.typeParams); +} template constexpr Error model(T *io, CommonPtrWith auto *type) noexcept { io->template setTypeInfo(); oxReturnError(io->field("typeName", &type->typeName)); oxReturnError(io->field("typeVersion", &type->typeVersion)); - if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) { + if constexpr(T::opType() == OpType::Reflect) { uint8_t pt = 0; oxReturnError(io->field("primitiveType", &pt)); } else { @@ -133,6 +183,7 @@ constexpr Error model(T *io, CommonPtrWith auto *type) noexcept oxReturnError(io->field("primitiveType", &pt)); type->primitiveType = static_cast(pt); } + oxReturnError(io->field("typeParams", &type->typeParams)); oxReturnError(io->field("fieldList", &type->fieldList)); oxReturnError(io->field("length", &type->length)); oxReturnError(io->field("preloadable", &type->preloadable)); @@ -142,9 +193,10 @@ constexpr Error model(T *io, CommonPtrWith auto *type) noexcept template constexpr Error model(T *io, CommonPtrWith auto *field) noexcept { io->template setTypeInfo(); - oxReturnError(io->field("typeName", &field->typeName)); + oxReturnError(io->field("typeId", &field->typeId)); oxReturnError(io->field("fieldName", &field->fieldName)); oxReturnError(io->field("subscriptLevels", &field->subscriptLevels)); + oxReturnError(io->field("subscriptStack", &field->subscriptStack)); // defaultValue is unused now, but leave placeholder for backwards compatibility int defaultValue = 0; oxReturnError(io->field("defaultValue", &defaultValue)); @@ -154,20 +206,30 @@ constexpr Error model(T *io, CommonPtrWith auto *field) noexcep template class TypeDescReader; +#if 0 // unused right now template constexpr Error model(TypeDescReader *io, CommonPtrWith auto *field) noexcept { - io->template setTypeInfo(DescriptorField::TypeName, DescriptorField::TypeVersion, 4); + io->template setTypeInfo(); oxReturnError(io->field("typeName", &field->typeName)); + oxReturnError(io->field("typeVersion", &field->typeVersion)); auto &typeStore = io->typeStore(); auto &[type, err] = typeStore->at(field->typeName).value; oxReturnError(err); field->type = type.get(); oxReturnError(io->field("fieldName", &field->fieldName)); oxReturnError(io->field("subscriptLevels", &field->subscriptLevels)); + if constexpr(T::opType() != ox::OpType::Reflect) { + auto subscriptStack = static_cast(field->subscriptStack); + oxReturnError(io->field("subscriptStack", &subscriptStack)); + field->subscriptStack = static_cast(subscriptStack); + } else { + oxReturnError(io->field("subscriptStack", &field->subscriptStack)); + } // defaultValue is unused now, but placeholder for backwards compatibility int defaultValue = 0; oxReturnError(io->field("defaultValue", &defaultValue)); return OxError(0); } +#endif } diff --git a/deps/ox/src/ox/model/descwrite.hpp b/deps/ox/src/ox/model/descwrite.hpp index 5b7c96a5..84f3f4f5 100644 --- a/deps/ox/src/ox/model/descwrite.hpp +++ b/deps/ox/src/ox/model/descwrite.hpp @@ -38,6 +38,45 @@ constexpr int indirectionLevels_v = 1 + indirectionLevels_v; template constexpr int indirectionLevels_v = 1 + indirectionLevels_v; +template +constexpr int indirectionLevels_v<::ox::Vector> = 1 + indirectionLevels_v; + +template +constexpr auto buildSubscriptStack(const T*, SubscriptStack*) noexcept { +} + +template +constexpr auto buildSubscriptStack(const T**, SubscriptStack *s) noexcept { + s->push_back({.subscriptType = Subscript::SubscriptType::Ptr}); +} + +template +constexpr auto buildSubscriptStack(const UniquePtr*, SubscriptStack *s) noexcept { + s->push_back({.subscriptType = Subscript::SubscriptType::Ptr}); +} + +template +constexpr auto buildSubscriptStack(const Array*, SubscriptStack *s) noexcept { + s->push_back({.subscriptType = Subscript::SubscriptType::InlineArray, .length = sz}); + buildSubscriptStack(static_cast(nullptr), s); +} + +template +constexpr auto buildSubscriptStack(const Vector*, SubscriptStack *s) noexcept { + s->push_back({ + .subscriptType = Subscript::SubscriptType::Vector, + .smallSzLen = SmallVecSz, + }); + buildSubscriptStack(static_cast(nullptr), s); +} + +template +constexpr auto buildSubscriptStack(const T*) { + SubscriptStack s; + buildSubscriptStack(static_cast(nullptr), &s); + return s; +} + } class TypeDescWriter { @@ -52,21 +91,23 @@ class TypeDescWriter { constexpr ~TypeDescWriter() noexcept = default; template - constexpr void setTypeInfo(const char *name = T::TypeName, + constexpr void setTypeInfo(CRStringView name = T::TypeName, int version = T::TypeVersion, - int fields = ModelFieldCount_v) noexcept; + const TypeParamPack &typeParams = {}, + int fields = ModelFieldCount_v) noexcept; template - constexpr Error field(const char *name, const T *val, std::size_t valLen) noexcept; + constexpr Error field(CRStringView name, const T *val, std::size_t valLen, + const SubscriptStack &subscriptStack = {}) noexcept; + + template + constexpr Error field(CRStringView name, UnionView val) noexcept; template - constexpr Error field(const char *name, T val) noexcept; - - template - constexpr Error field(const char *name, const T *val) noexcept; + constexpr Error field(CRStringView name, const T *val) noexcept; template - constexpr Error fieldCString(const char *name, Args&&...) noexcept; + constexpr Error fieldCString(CRStringView name, Args&&...) noexcept; [[nodiscard]] constexpr DescriptorType *definition() noexcept { @@ -105,8 +146,12 @@ class TypeDescWriter { [[nodiscard]] constexpr const DescriptorType *type(SerStr val) const noexcept; + template [[nodiscard]] - constexpr const DescriptorType *type(const String *val) const noexcept; + constexpr const DescriptorType *type(const BasicString*) const noexcept { + constexpr auto PT = PrimitiveType::String; + return getType(types::BasicString, 1, PT, 0, {sfmt("{}", SmallStrSz)}); + } template [[nodiscard]] @@ -125,71 +170,77 @@ class TypeDescWriter { constexpr const DescriptorType *type(UnionView val) const noexcept; [[nodiscard]] - constexpr const DescriptorType *getType(const String &tn, int typeVersion, PrimitiveType t, int b) const noexcept; + constexpr const DescriptorType *getType(CRStringView tn, int typeVersion, PrimitiveType t, int b, + const TypeParamPack &typeParams = {}) const noexcept; }; -constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) { -} +constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) {} template -constexpr void TypeDescWriter::setTypeInfo(const char *typeName, int typeVersion, int) noexcept { - m_type = m_typeStore->getInit(typeName, typeVersion); +constexpr void TypeDescWriter::setTypeInfo(CRStringView typeName, int typeVersion, + const TypeParamPack &typeParams, int) noexcept { + PrimitiveType pt; if constexpr(is_union_v) { - m_type->primitiveType = PrimitiveType::Union; + pt = PrimitiveType::Union; + } else if constexpr(isBasicString_v || isBString_v) { + pt = PrimitiveType::String; } else { - m_type->primitiveType = PrimitiveType::Struct; + pt = PrimitiveType::Struct; } - m_type->preloadable = detail::preloadable::value; + m_type = m_typeStore->getInit(typeName, typeVersion, pt, typeParams); + m_type->preloadable = preloadable::value; } // array handler template -constexpr Error TypeDescWriter::field(const char *name, const T *val, std::size_t) noexcept { +constexpr Error TypeDescWriter::field(CRStringView name, const T*, std::size_t, const SubscriptStack &subscriptStack) noexcept { if (m_type) { - constexpr typename remove_pointer::type *p = nullptr; + constexpr typename remove_pointer::type *p = nullptr; const auto t = type(p); oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated"); - m_type->fieldList.emplace_back(t, name, detail::indirectionLevels_v + 1, t->typeName, t->typeVersion); + m_type->fieldList.emplace_back(t, name, detail::indirectionLevels_v + 1, subscriptStack, buildTypeId(*t)); + return OxError(0); + } + return OxError(1); +} + +template +constexpr Error TypeDescWriter::field(CRStringView name, UnionView val) noexcept { + if (m_type) { + const auto t = type(val); + oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated"); + m_type->fieldList.emplace_back(t, name, 0, SubscriptStack{}, t->typeName); return OxError(0); } return OxError(1); } template -constexpr Error TypeDescWriter::field(const char *name, T val) noexcept { - if (m_type) { - if constexpr(isVector_v::type> || isArray_v::type>) { - return field(name, val->data(), val->size()); - } else { - const auto t = type(val); - oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated"); - m_type->fieldList.emplace_back(t, name, 0, t->typeName, t->typeVersion); - return OxError(0); - } - } - return OxError(1); -} - -template -constexpr Error TypeDescWriter::field(const char *name, const T *val) noexcept { +constexpr Error TypeDescWriter::field(CRStringView name, const T *val) noexcept { if (m_type) { if constexpr(isVector_v || isArray_v) { - return field(name, val->data(), val->size()); + return field(name, val->data(), 0, detail::buildSubscriptStack(val)); + } else if constexpr(isSmartPtr_v) { + return field(name, val->get(), 0, detail::buildSubscriptStack(val)); + } else if constexpr(is_pointer_v) { + return field(name, val, 0, detail::buildSubscriptStack(val)); } else { const auto t = type(val); oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated"); - m_type->fieldList.emplace_back(t, name, 0, t->typeName, t->typeVersion); - return OxError(0); + m_type->fieldList.emplace_back(t, name, 0, SubscriptStack{}, buildTypeId(*t)); + return {}; } } return OxError(1); } template -constexpr Error TypeDescWriter::fieldCString(const char *name, Args&&...) noexcept { - String s; - return field(name, &s); +constexpr Error TypeDescWriter::fieldCString(CRStringView name, Args&&...) noexcept { + constexpr auto s = ""; + const auto t = type(s); + m_type->fieldList.emplace_back(t, name, 0, SubscriptStack{}, t->typeName); + return {}; } template @@ -286,29 +337,25 @@ constexpr const DescriptorType *TypeDescWriter::type(SerStr) const noexcept { return getType(types::String, 0, PT, 0); } -constexpr const DescriptorType *TypeDescWriter::type(const String*) const noexcept { - constexpr auto PT = PrimitiveType::String; - return getType(types::String, 0, PT, 0); -} - template constexpr const DescriptorType *TypeDescWriter::type(const BString*) const noexcept { constexpr auto PT = PrimitiveType::String; - return getType(types::String, 0, PT, 0); + return getType(types::BString, 0, PT, 0); } -constexpr const DescriptorType *TypeDescWriter::getType(const String &tn, int typeVersion, PrimitiveType pt, int b) const noexcept { - auto t = m_typeStore->get(tn, typeVersion); +constexpr const DescriptorType *TypeDescWriter::getType(CRStringView tn, int typeVersion, PrimitiveType pt, int b, + const TypeParamPack &typeParams) const noexcept { + auto t = m_typeStore->get(tn, typeVersion, typeParams); if (!t.error) { auto type = t.value; oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType"); return type; } else { - auto dt = ox::make_unique(tn, typeVersion); - dt->primitiveType = pt; + auto dt = ox::make_unique(tn, typeVersion, pt, typeParams); dt->length = b; const auto out = dt.get(); - m_typeStore->set(tn, typeVersion, std::move(dt)); + const auto typeId = buildTypeId(tn, typeVersion, typeParams); + m_typeStore->set(typeId, std::move(dt)); return out; } } diff --git a/deps/ox/src/ox/model/fieldcounter.hpp b/deps/ox/src/ox/model/fieldcounter.hpp index d67b7dba..d65af665 100644 --- a/deps/ox/src/ox/model/fieldcounter.hpp +++ b/deps/ox/src/ox/model/fieldcounter.hpp @@ -8,6 +8,7 @@ #pragma once +#include #include #include @@ -23,23 +24,23 @@ class FieldCounter { int fields = 0; template - constexpr void setTypeInfo(const char * = "", int = 0, int = 0) { + constexpr void setTypeInfo(CRStringView = "", int = 0, const Vector& = {}, int = 0) { } template - constexpr ox::Error field(const char *, U) noexcept { + constexpr ox::Error field(CRStringView, U) noexcept { ++fields; return OxError(0); } template - constexpr ox::Error field(const char *, U, std::size_t) noexcept { + constexpr ox::Error field(CRStringView, U, std::size_t) noexcept { ++fields; return OxError(0); } template - constexpr Error field(const char *, Handler) { + constexpr Error field(CRStringView, Handler) { ++fields; return OxError(0); } @@ -49,7 +50,7 @@ class FieldCounter { return OxError(0); } - static constexpr auto opType() { + static constexpr auto opType() noexcept { return OpType::Reflect; } }; diff --git a/deps/ox/src/ox/model/metadata.hpp b/deps/ox/src/ox/model/metadata.hpp index a0cd7f6f..ac8ca63f 100644 --- a/deps/ox/src/ox/model/metadata.hpp +++ b/deps/ox/src/ox/model/metadata.hpp @@ -21,25 +21,29 @@ #include "optype.hpp" #include "types.hpp" -namespace ox::detail { +namespace ox { + +namespace detail { template struct BoolWrapper { }; -template> +template +struct IntWrapper { +}; + +} + +template> struct preloadable: false_type { }; template -struct preloadable> { +struct preloadable> { static constexpr bool value = T::Preloadable; }; -template -struct IntWrapper { -}; - // cannot be done until C++20 //struct PseudoString { // constexpr PseudoString(const char* = "") noexcept {} diff --git a/deps/ox/src/ox/model/modelhandleradaptor.hpp b/deps/ox/src/ox/model/modelhandleradaptor.hpp index 2c5d0fd9..f6995772 100644 --- a/deps/ox/src/ox/model/modelhandleradaptor.hpp +++ b/deps/ox/src/ox/model/modelhandleradaptor.hpp @@ -25,8 +25,8 @@ class ModelHandlerInterface { template constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, - int fields = ModelFieldCount_v) noexcept { - m_handler->setTypeInfo(name, version, fields); + const Vector &typeParams = {}, int fields = ModelFieldCount_v) noexcept { + m_handler->setTypeInfo(name, version, typeParams, fields); } template @@ -63,7 +63,7 @@ class ModelHandlerInterface { return m_handler->fieldCString(name, val, buffLen); } - constexpr Error field(const char *name, CommonPtrWith auto *v) noexcept { + constexpr Error fieldModelValue(const char *name, CommonPtrWith auto *v) noexcept { switch (v->type()) { case ModelValue::Type::Undefined: break; @@ -92,14 +92,17 @@ class ModelHandlerInterface { case ModelValue::Type::Union: { auto &u = v->template get(); - if constexpr(ox_strcmp(Handler::opType(), OpType::Read) == 0) { + if constexpr(Handler::opType() == OpType::Read) { u.setActiveField(m_handler->whichFieldPresent(name, u)); + return m_handler->field(name, UnionView(&u, u.unionIdx())); + } else { + return m_handler->field(name, UnionView(&u, u.unionIdx())); } - return m_handler->field(name, UnionView(&u, u.unionIdx())); } case ModelValue::Type::Vector: return m_handler->field(name, &v->template get()); } + oxErrf("invalid type: {}: {}\n", name, static_cast(v->type())); oxPanic(OxError(1), "invalid type"); return OxError(1, "invalid type"); } @@ -110,12 +113,22 @@ class ModelHandlerInterface { return m_handler->template field(name, cb); } - constexpr Error field(const char *name, const auto *v) noexcept { - return m_handler->field(name, v); + template + constexpr Error field(const char *name, const T *v) noexcept { + if constexpr(ox::is_same_v) { + return fieldModelValue(name, v); + } else { + return m_handler->field(name, v); + } } - constexpr Error field(const char *name, auto *v) noexcept { - return m_handler->field(name, v); + template + constexpr Error field(const char *name, T *v) noexcept { + if constexpr(ox::is_same_v) { + return fieldModelValue(name, v); + } else { + return m_handler->field(name, v); + } } template @@ -156,4 +169,18 @@ class ModelHandlerInterface { }; +template +class ModelHandlerBase { + private: + ModelHandlerInterface m_interface; + public: + constexpr ModelHandlerBase() noexcept: m_interface(static_cast(this)) {} + constexpr ModelHandlerBase(const ModelHandlerBase&) noexcept: m_interface(static_cast(this)) {} + constexpr ModelHandlerBase(ModelHandlerBase&&) noexcept: m_interface(static_cast(this)) {} + [[nodiscard]] + constexpr auto interface() noexcept { + return &m_interface; + } +}; + } diff --git a/deps/ox/src/ox/model/modelops.hpp b/deps/ox/src/ox/model/modelops.hpp index 1b935974..092ae275 100644 --- a/deps/ox/src/ox/model/modelops.hpp +++ b/deps/ox/src/ox/model/modelops.hpp @@ -76,7 +76,8 @@ class MemberList { } template - constexpr void setTypeInfo(const char* = T::TypeName, int = ModelFieldCount_v) noexcept { + constexpr void setTypeInfo(const char* = T::TypeName, int = ModelTypeVersion_v, + const Vector& = {}, int = ModelFieldCount_v) noexcept { } [[nodiscard]] @@ -135,7 +136,7 @@ class Copier { } template - constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, int = ModelFieldCount_v) noexcept { + constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, const Vector& = {}, int = ModelFieldCount_v) noexcept { } [[nodiscard]] @@ -196,7 +197,7 @@ class Mover { } template - constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, int = ModelFieldCount_v) noexcept { + constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, const Vector& = {}, int = ModelFieldCount_v) noexcept { } [[nodiscard]] @@ -272,7 +273,7 @@ class Equals { } template - constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) noexcept { + constexpr void setTypeInfo(const char* = T::TypeName, const Vector& = {}, int = T::Fields) noexcept { } [[nodiscard]] diff --git a/deps/ox/src/ox/model/modelvalue.cpp b/deps/ox/src/ox/model/modelvalue.cpp index 62611763..2d28fe71 100644 --- a/deps/ox/src/ox/model/modelvalue.cpp +++ b/deps/ox/src/ox/model/modelvalue.cpp @@ -7,3 +7,17 @@ */ #include "modelvalue.hpp" + +namespace ox { + +static_assert([]() -> ox::Error { + ox::ModelValue v; + oxReturnError(v.setType()); + if (v.type() != ModelValue::Type::SignedInteger32) { + return OxError(1, "type is wrong"); + } + //oxReturnError(v.set(5)); + return {}; +}() == OxError(0)); + +} diff --git a/deps/ox/src/ox/model/modelvalue.hpp b/deps/ox/src/ox/model/modelvalue.hpp index 22967567..bc40df38 100644 --- a/deps/ox/src/ox/model/modelvalue.hpp +++ b/deps/ox/src/ox/model/modelvalue.hpp @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -60,20 +61,20 @@ class ModelValue { int32_t i32; uint32_t ui32; int64_t i64; - uint64_t ui64; - String *str = nullptr; + uint64_t ui64 = 0; + String *str; ModelObject *obj; ModelUnion *uni; ModelValueVector *vec; } m_data; template - consteval static Type getType() noexcept { + static consteval Type getType() noexcept { using U = typename ox::remove_reference::type; if constexpr(is_bool_v) { return Type::Bool; } else if constexpr(is_integer_v) { - if (!is_signed_v && sizeof(U) == 1) { + if constexpr(!is_signed_v && sizeof(U) == 1) { return Type::UnsignedInteger8; } else if constexpr(!is_signed_v && sizeof(U) == 2) { return Type::UnsignedInteger16; @@ -94,7 +95,7 @@ class ModelValue { return Type::Union; } else if constexpr(is_same_v) { return Type::Object; - } else if constexpr(is_same_v) { + } else if constexpr(isBasicString_v || isBString_v) { return Type::String; } else if constexpr(is_same_v) { return Type::Vector; @@ -198,6 +199,129 @@ class ModelValue { }; +template +[[nodiscard]] +constexpr std::size_t sizeOf(const ModelValueVector*) noexcept { + VectorMemMap v; + return sizeOf(&v); +} + +template +[[nodiscard]] +constexpr std::size_t sizeOf(const ModelUnion*) noexcept { + VectorMemMap v; + return sizeOf(&v); +} + +template +[[nodiscard]] +constexpr std::size_t sizeOf(const ModelValue *t) noexcept { + std::size_t size = 0; + switch (t->type()) { + case ModelValue::Type::Bool: + size = sizeof(t->get()); + break; + case ModelValue::Type::Undefined: + size = 1; + break; + case ModelValue::Type::UnsignedInteger8: + size = sizeof(t->get()); + break; + case ModelValue::Type::UnsignedInteger16: + size = sizeof(t->get()); + break; + case ModelValue::Type::UnsignedInteger32: + size = sizeof(t->get()); + break; + case ModelValue::Type::UnsignedInteger64: + size = sizeof(t->get()); + break; + case ModelValue::Type::SignedInteger8: + size = sizeof(t->get()); + break; + case ModelValue::Type::SignedInteger16: + size = sizeof(t->get()); + break; + case ModelValue::Type::SignedInteger32: + size = sizeof(t->get()); + break; + case ModelValue::Type::SignedInteger64: + size = sizeof(t->get()); + break; + case ModelValue::Type::String: + size = sizeOf(&t->get()); + break; + case ModelValue::Type::Object: + size = sizeOf(&t->get()); + break; + case ModelValue::Type::Union: + size = sizeOf(&t->get()); + break; + case ModelValue::Type::Vector: + size = sizeOf(&t->get()); + break; + } + return size; +} + +template +[[nodiscard]] +constexpr std::size_t alignOf(const ModelValueVector&) noexcept { + VectorMemMap v; + return alignOf(v); +} + +template +[[nodiscard]] +constexpr std::size_t alignOf(const ModelValue &t) noexcept { + std::size_t size = 0; + switch (t.type()) { + case ModelValue::Type::Bool: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::Undefined: + size = 1; + break; + case ModelValue::Type::UnsignedInteger8: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::UnsignedInteger16: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::UnsignedInteger32: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::UnsignedInteger64: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::SignedInteger8: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::SignedInteger16: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::SignedInteger32: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::SignedInteger64: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::String: + size = PlatSpec::alignOf(t.get()); + break; + case ModelValue::Type::Object: + size = alignOf(t.get()); + break; + case ModelValue::Type::Union: + size = alignOf(t.get()); + break; + case ModelValue::Type::Vector: + size = alignOf(t.get()); + break; + } + return size; +} + class ModelValueVector { private: Vector m_vec; @@ -329,6 +453,7 @@ class ModelObject { friend ModelValue; Vector> m_fieldsOrder; HashMap m_fields; + const DescriptorType *m_type = nullptr; String m_typeName; int m_typeVersion = 0; @@ -340,12 +465,14 @@ class ModelObject { auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value}); m_fields[field->name] = &field->value; } + m_type = other.m_type; m_typeName = other.m_typeName; m_typeVersion = other.m_typeVersion; } constexpr ModelObject(ModelObject &&other) noexcept { m_fields = std::move(other.m_fields); + m_type = other.m_type; m_fieldsOrder = std::move(other.m_fieldsOrder); m_typeName = std::move(other.m_typeName); m_typeVersion = other.m_typeVersion; @@ -419,6 +546,7 @@ class ModelObject { auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value}); m_fields[field->name] = &field->value; } + m_type = other.m_type; m_typeName = other.m_typeName; m_typeVersion = other.m_typeVersion; return *this; @@ -428,6 +556,7 @@ class ModelObject { if (&other == this) [[unlikely]] { return *this; } + m_type = other.m_type; m_fields = std::move(other.m_fields); m_fieldsOrder = std::move(other.m_fieldsOrder); m_typeName = std::move(other.m_typeName); @@ -448,7 +577,7 @@ class ModelObject { } [[nodiscard]] - constexpr const String &typeName() const noexcept { + constexpr StringView typeName() const noexcept { return m_typeName; } @@ -457,10 +586,16 @@ class ModelObject { return m_typeVersion; } + [[nodiscard]] + constexpr auto type() const noexcept { + return m_type; + } + constexpr Error setType(const DescriptorType *type) noexcept { if (type->primitiveType != PrimitiveType::Struct && type->primitiveType != PrimitiveType::Union) { return OxError(1, "Cannot load a non-struct type to ModelObject"); } + m_type = type; m_typeName = type->typeName; m_typeVersion = type->typeVersion; for (const auto &f : type->fieldList) { @@ -609,7 +744,7 @@ class ModelUnion { }; constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept { - h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast(obj->m_fieldsOrder.size())); + h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, {}, static_cast(obj->m_fieldsOrder.size())); for (auto &f : obj->m_fieldsOrder) { oxReturnError(h->field(f->name.c_str(), &f->value)); } @@ -617,7 +752,7 @@ constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept { } constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept { - h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast(obj->m_fieldsOrder.size())); + h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, {}, static_cast(obj->m_fieldsOrder.size())); for (auto &f : obj->m_fieldsOrder) { oxReturnError(h->field(f->name.c_str(), &f->value)); } @@ -718,7 +853,9 @@ constexpr Error ModelValue::setType(const DescriptorType *type, int subscriptLev return m_data.vec->setType(type, subscriptLevels - 1); } else if (type->typeName == types::Bool) { m_type = Type::Bool; - } else if (type->typeName == types::String) { + } else if (type->typeName == types::BasicString || + type->typeName == types::BString || + type->typeName == types::String) { m_type = Type::String; m_data.str = new String; } else if (type->typeName == types::Uint8) { @@ -747,13 +884,47 @@ constexpr Error ModelValue::setType(const DescriptorType *type, int subscriptLev m_data.uni = u.release(); oxReturnError(m_data.uni->setType(type)); } + oxAssert(m_type != Type::Undefined, "No type set"); return OxError(0); } template constexpr Error ModelValue::setType() noexcept { constexpr auto type = getType(); - return setType(type); + freeResources(); + m_type = type; + // 2022.09.04: Clang retardedly requires initializing the union values directly, rather than using getValue() + if constexpr(type == Type::Object) { + m_data.obj = new ModelObject; + oxReturnError(m_data.obj->setType(type)); + } else if constexpr(type == Type::Union) { + oxRequireM(u, ModelUnion::make(type)); + m_data.uni = u.release(); + oxReturnError(m_data.uni->setType(type)); + } else if constexpr(type == Type::String) { + m_data.str = new String; + } else if constexpr(type == Type::Vector) { + m_data.vec = new ModelValueVector; + } else if constexpr(type == Type::Bool) { + m_data.b = false; + } else if constexpr(type == Type::SignedInteger8) { + m_data.i8 = 0; + } else if constexpr(type == Type::SignedInteger16) { + m_data.i16 = 0; + } else if constexpr(type == Type::SignedInteger32) { + m_data.i32 = 0; + } else if constexpr(type == Type::SignedInteger64) { + m_data.i64 = 0; + } else if constexpr(type == Type::UnsignedInteger8) { + m_data.ui8 = 0; + } else if constexpr(type == Type::UnsignedInteger16) { + m_data.ui16 = 0; + } else if constexpr(type == Type::UnsignedInteger32) { + m_data.ui32 = 0; + } else if constexpr(type == Type::UnsignedInteger64) { + m_data.ui64 = 0; + } + return {}; } template @@ -763,6 +934,10 @@ constexpr Error ModelValue::set(const T &v) noexcept { return OxError(1, "type mismatch"); } auto &value = getValue(*this); + if constexpr(type == Type::Vector || type == Type::Object || + type == Type::Union || type == Type::String) { + safeDelete(&value); + } value = v; return OxError(0); } diff --git a/deps/ox/src/ox/model/optype.hpp b/deps/ox/src/ox/model/optype.hpp index 3ed29b70..e0e1a856 100644 --- a/deps/ox/src/ox/model/optype.hpp +++ b/deps/ox/src/ox/model/optype.hpp @@ -8,13 +8,14 @@ #pragma once -#include -#include -#include -#include +#include + +namespace ox { + +enum class OpType { + Read = 1, + Write, + Reflect, +}; -namespace ox::OpType { -constexpr auto Read = "Read"; -constexpr auto Write = "Write"; -constexpr auto Reflect = "Reflect"; } diff --git a/deps/ox/src/ox/model/test/CMakeLists.txt b/deps/ox/src/ox/model/test/CMakeLists.txt new file mode 100644 index 00000000..e0edb440 --- /dev/null +++ b/deps/ox/src/ox/model/test/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable( + ModelTest + tests.cpp +) + +target_link_libraries( + ModelTest + OxModel +) + +add_test("[ox/model] ModelTest Writer" ModelTest ModelValue) \ No newline at end of file diff --git a/deps/ox/src/ox/model/test/tests.cpp b/deps/ox/src/ox/model/test/tests.cpp new file mode 100644 index 00000000..5e21982f --- /dev/null +++ b/deps/ox/src/ox/model/test/tests.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2015 - 2022 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#undef NDEBUG + +#include +#include +#include + +std::map tests = { + { + { + "ModelValue", + [] { + ox::ModelValue v; + oxReturnError(v.setType()); + //v.m_type = ox::ModelValue::getType(); + if (v.type() != ox::ModelValue::Type::SignedInteger32) { + return OxError(1, "type is wrong"); + } + oxReturnError(v.set(5)); + return ox::Error{}; + } + }, + } +}; + +int main(int argc, const char **args) { + if (argc > 0) { + auto testName = args[1]; + if (tests.find(testName) != tests.end()) { + oxAssert(tests[testName](), "Test failed..."); + } + } + return 0; +} diff --git a/deps/ox/src/ox/model/typenamecatcher.hpp b/deps/ox/src/ox/model/typenamecatcher.hpp index bf1ec3fc..5c65dc8f 100644 --- a/deps/ox/src/ox/model/typenamecatcher.hpp +++ b/deps/ox/src/ox/model/typenamecatcher.hpp @@ -8,9 +8,9 @@ #pragma once +#include #include #include -#include #include "fieldcounter.hpp" #include "optype.hpp" @@ -25,7 +25,7 @@ struct TypeNameCatcher { constexpr TypeNameCatcher() noexcept = default; template - constexpr void setTypeInfo(const char *n = T::TypeName, int v = 0) noexcept { + constexpr void setTypeInfo(const char *n = T::TypeName, const Vector& = {}, int v = 0) noexcept { this->name = n; this->version = v; } @@ -59,7 +59,7 @@ struct TypeInfoCatcher { constexpr TypeInfoCatcher() noexcept = default; template - constexpr void setTypeInfo(const char *n = T::TypeName, int v = T::TypeVersion, int = 0) noexcept { + constexpr void setTypeInfo(const char *n = T::TypeName, int v = T::TypeVersion, const Vector& = {}, int = 0) noexcept { this->name = n; this->version = v; } @@ -87,7 +87,7 @@ struct TypeInfoCatcher { template constexpr int getModelTypeVersion() noexcept { - auto a = std::allocator(); + std::allocator a; auto t = a.allocate(1); TypeInfoCatcher nc; oxIgnoreError(model(&nc, t)); @@ -111,7 +111,7 @@ consteval int requireModelTypeVersion() noexcept { template constexpr Str getModelTypeName() noexcept { - auto a = std::allocator(); + std::allocator a; auto t = a.allocate(1); TypeNameCatcher nc; oxIgnoreError(model(&nc, t)); diff --git a/deps/ox/src/ox/model/types.hpp b/deps/ox/src/ox/model/types.hpp index 246dbc71..9f51e52c 100644 --- a/deps/ox/src/ox/model/types.hpp +++ b/deps/ox/src/ox/model/types.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -30,25 +31,77 @@ namespace ox { namespace types { -constexpr auto String = "B.string"; -constexpr auto Bool = "B.bool"; -constexpr auto Uint8 = "B.uint8"; -constexpr auto Uint16 = "B.uint16"; -constexpr auto Uint32 = "B.uint32"; -constexpr auto Uint64 = "B.uint64"; -constexpr auto Int8 = "B.int8"; -constexpr auto Int16 = "B.int16"; -constexpr auto Int32 = "B.int32"; -constexpr auto Int64 = "B.int64"; +constexpr StringView BasicString = "net.drinkingtea.ox.BasicString"; +constexpr StringView BString = "net.drinkingtea.ox.BString"; +constexpr StringView String = "B.string"; +constexpr StringView Bool = "B.bool"; +constexpr StringView Uint8 = "B.uint8"; +constexpr StringView Uint16 = "B.uint16"; +constexpr StringView Uint32 = "B.uint32"; +constexpr StringView Uint64 = "B.uint64"; +constexpr StringView Int8 = "B.int8"; +constexpr StringView Int16 = "B.int16"; +constexpr StringView Int32 = "B.int32"; +constexpr StringView Int64 = "B.int64"; } +template +consteval bool isBasicString(const T*) noexcept { + return false; +} + +template +consteval bool isBasicString(const BasicString*) noexcept { + return true; +} + +template +constexpr bool isBasicString_v = isBasicString(static_cast(nullptr)); + +static_assert(isBasicString_v>); +static_assert(isBasicString_v>); +static_assert(isBasicString_v); + +template +consteval bool isBString(const T*) noexcept { + return false; +} + +template +consteval bool isBString(const BasicString*) noexcept { + return true; +} + +template +constexpr bool isBString_v = isBasicString(static_cast(nullptr)); + +static_assert(isBasicString_v>); +static_assert(isBasicString_v>); +static_assert(isBasicString_v); + +template +constexpr bool isOxString_v = isBString_v || isBasicString_v; + +template +consteval bool isOxVector(const T*) noexcept { + return false; +} + +template +consteval bool isOxVector(const Vector*) noexcept { + return true; +} + +template +constexpr bool isOxVector_v = isVector(static_cast(nullptr)); + template consteval bool isVector(const T*) noexcept { return false; } -template -consteval bool isVector(const Vector*) noexcept { +template +consteval bool isVector(const Vector*) noexcept { return true; } @@ -71,21 +124,36 @@ constexpr bool isVector_v = isVector(static_cast(nullptr)); static_assert(isVector_v>); +template +constexpr bool isBareArray_v = false; + +template +constexpr bool isBareArray_v = true; + +template +constexpr bool isBareArray_v = true; + template constexpr bool isArray_v = false; template -constexpr bool isArray_v = false; +constexpr bool isArray_v = true; template -constexpr bool isArray_v = false; +constexpr bool isArray_v = true; template -constexpr bool isArray_v> = false; +constexpr bool isArray_v> = true; + +template +constexpr bool isSmartPtr_v = false; + +template +constexpr bool isSmartPtr_v<::ox::UniquePtr> = true; #if __has_include() -template -constexpr bool isArray_v> = false; +template +constexpr bool isSmartPtr_v<::std::unique_ptr> = true; #endif diff --git a/deps/ox/src/ox/model/typestore.hpp b/deps/ox/src/ox/model/typestore.hpp index bba084bd..899bea5b 100644 --- a/deps/ox/src/ox/model/typestore.hpp +++ b/deps/ox/src/ox/model/typestore.hpp @@ -8,12 +8,12 @@ #pragma once +#include #include #include #include #include -#include "ox/std/fmt.hpp" #include "typenamecatcher.hpp" #include "desctypes.hpp" @@ -23,45 +23,42 @@ class TypeStore { private: HashMap> m_cache; - static constexpr auto buildTypeId(const auto &name, auto version) noexcept { - return ox::sfmt("{};{}", name, version); - } - public: constexpr TypeStore() noexcept = default; constexpr virtual ~TypeStore() noexcept = default; - constexpr Result get(const auto &name, int typeVersion) const noexcept { - const auto typeId = buildTypeId(name, typeVersion); + constexpr Result get(const auto &name, int typeVersion, + const Vector &typeParams) const noexcept { + const auto typeId = buildTypeId(name, typeVersion, typeParams); oxRequire(out, m_cache.at(typeId)); return out->get(); } template constexpr Result get() const noexcept { - constexpr auto typeName = requireModelTypeName(); - constexpr auto typeVersion = requireModelTypeVersion(); - const auto typeId = buildTypeId(typeName, typeVersion); + constexpr auto typeName = ModelTypeName_v; + constexpr auto typeVersion = ModelTypeVersion_v; + const auto typeId = buildTypeId(typeName, typeVersion, {}); oxRequire(out, m_cache.at(typeId)); return out->get(); } - constexpr DescriptorType *getInit(const auto &typeName, int typeVersion) noexcept { - const auto typeId = buildTypeId(typeName, typeVersion); + constexpr DescriptorType *getInit(const auto &typeName, int typeVersion, PrimitiveType pt, + const TypeParamPack &typeParams) noexcept { + const auto typeId = buildTypeId(typeName, typeVersion, typeParams); auto &out = m_cache[typeId]; - out = ox::make_unique(typeName, typeVersion); + out = ox::make_unique(typeName, typeVersion, pt, typeParams); return out.get(); } - constexpr Result getLoad(const auto &typeName, auto typeVersion) noexcept { - const auto typeId = buildTypeId(typeName, typeVersion); + constexpr Result getLoad(const auto &typeId) noexcept { auto [val, err] = m_cache.at(typeId); if (err) { if (!std::is_constant_evaluated()) { - oxRequireM(dt, loadDescriptor(typeName, typeVersion)); + oxRequireM(dt, loadDescriptor(typeId)); for (auto &f : dt->fieldList) { - oxReturnError(this->getLoad(f.typeName, f.typeVersion).moveTo(&f.type)); + oxReturnError(this->getLoad(f.typeId).moveTo(&f.type)); } auto &out = m_cache[typeId]; out = std::move(dt); @@ -73,6 +70,11 @@ class TypeStore { return val->get(); } + constexpr Result getLoad(const auto &typeName, auto typeVersion, + const Vector &typeParams = {}) noexcept { + return getLoad(buildTypeId(typeName, typeVersion, typeParams)); + } + template constexpr Result getLoad() noexcept { constexpr auto typeName = requireModelTypeName(); @@ -80,19 +82,17 @@ class TypeStore { return getLoad(typeName, typeVersion); } - constexpr void set(const auto &typeName, auto typeVersion, UniquePtr dt) noexcept { - const auto typeId = buildTypeId(typeName, typeVersion); + constexpr void set(const auto &typeId, UniquePtr dt) noexcept { m_cache[typeId] = std::move(dt); } - constexpr void set(const auto &typeName, auto typeVersion, DescriptorType *dt) noexcept { - const auto typeId = buildTypeId(typeName, typeVersion); - m_cache[typeId] = UniquePtr(dt); + constexpr void set(const auto &typeId, DescriptorType *dt) noexcept { + m_cache[typeId] = UniquePtr(dt); } [[nodiscard]] constexpr auto typeList() const noexcept { - auto keys = m_cache.keys(); + const auto &keys = m_cache.keys(); ox::Vector descs; for (const auto &k : keys) { descs.emplace_back(m_cache.at(k).value->get()); @@ -101,10 +101,16 @@ class TypeStore { } protected: - virtual Result> loadDescriptor(const ox::String&, int) noexcept { + virtual Result> loadDescriptor(ox::CRStringView) noexcept { return OxError(1); } + Result> loadDescriptor(ox::CRStringView name, int version, + const Vector &typeParams) noexcept { + const auto typeId = buildTypeId(name, version, typeParams); + return loadDescriptor(typeId); + } + }; } diff --git a/deps/ox/src/ox/model/walk.hpp b/deps/ox/src/ox/model/walk.hpp index 21dcaaaa..745d04fb 100644 --- a/deps/ox/src/ox/model/walk.hpp +++ b/deps/ox/src/ox/model/walk.hpp @@ -89,7 +89,7 @@ static constexpr Error parseField(const DescriptorField &field, Reader *rdr, Dat // add array handling oxRequire(arrayLen, rdr->arrayLength(field.fieldName.c_str(), true)); auto child = rdr->child(field.fieldName.c_str()); - child.setTypeInfo(field.type->typeName.c_str(), field.type->typeVersion, arrayLen); + child.setTypeInfo(field.type->typeName.c_str(), field.type->typeVersion, field.type->typeParams, arrayLen); DescriptorField f(field); // create mutable copy --f.subscriptLevels; String subscript; @@ -135,8 +135,9 @@ constexpr Error model(Reader *rdr, DataWalker *walker) noexcept { oxRequire(type, walker->type()); auto typeName = type->typeName.c_str(); auto typeVersion = type->typeVersion; + auto typeParams = type->typeParams; auto &fields = type->fieldList; - rdr->setTypeInfo(typeName, typeVersion, fields.size()); + rdr->setTypeInfo(typeName, typeVersion, typeParams, fields.size()); for (const auto &field : fields) { oxReturnError(parseField(field, rdr, walker)); } diff --git a/deps/ox/src/ox/oc/read.hpp b/deps/ox/src/ox/oc/read.hpp index 3b170418..8938e059 100644 --- a/deps/ox/src/ox/oc/read.hpp +++ b/deps/ox/src/ox/oc/read.hpp @@ -100,11 +100,11 @@ class OrganicClawReader { } template - constexpr void setTypeInfo(const char*, int) noexcept { + constexpr void setTypeInfo(const char*, int, const Vector& = {}) noexcept { } template - constexpr void setTypeInfo(const char*, int, int) noexcept { + constexpr void setTypeInfo(const char*, int, const Vector& = {}, int = {}) noexcept { } /** diff --git a/deps/ox/src/ox/oc/test/tests.cpp b/deps/ox/src/ox/oc/test/tests.cpp index ff6f94eb..4bd28b52 100644 --- a/deps/ox/src/ox/oc/test/tests.cpp +++ b/deps/ox/src/ox/oc/test/tests.cpp @@ -94,7 +94,7 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *obj) noe oxReturnError(io->field("Int7", &obj->Int7)); oxReturnError(io->field("Int8", &obj->Int8)); oxReturnError(io->field("unionIdx", &obj->unionIdx)); - if (ox_strcmp(io->opType(), ox::OpType::Reflect) == 0) { + if (io->opType() == ox::OpType::Reflect) { oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 0})); } else { oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx})); diff --git a/deps/ox/src/ox/oc/write.hpp b/deps/ox/src/ox/oc/write.hpp index efe816b9..1801a6eb 100644 --- a/deps/ox/src/ox/oc/write.hpp +++ b/deps/ox/src/ox/oc/write.hpp @@ -176,7 +176,8 @@ class OrganicClawWriter { Error field(const char*, T *val) noexcept; template - constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, int = ModelFieldCount_v) noexcept { + constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, + const Vector& = {}, int = ModelFieldCount_v) noexcept { } static constexpr auto opType() noexcept { diff --git a/deps/ox/src/ox/preloader/CMakeLists.txt b/deps/ox/src/ox/preloader/CMakeLists.txt new file mode 100644 index 00000000..df43cfcf --- /dev/null +++ b/deps/ox/src/ox/preloader/CMakeLists.txt @@ -0,0 +1,24 @@ + +add_library( + OxPreloader + preload.cpp + preloader.cpp +) + +target_link_libraries( + OxPreloader PUBLIC + OxClaw + OxModel + OxStd +) + +install( + FILES + alignmentcatcher.hpp + platspecs.hpp + preload.hpp + preloader.hpp + unionsizecatcher.hpp + DESTINATION + include/nostalgia/preloader +) diff --git a/deps/ox/src/ox/preloader/alignmentcatcher.hpp b/deps/ox/src/ox/preloader/alignmentcatcher.hpp new file mode 100644 index 00000000..5789ff74 --- /dev/null +++ b/deps/ox/src/ox/preloader/alignmentcatcher.hpp @@ -0,0 +1,62 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ox { + +template +[[nodiscard]] +constexpr std::size_t alignOf(const T &t) noexcept; + +template +[[nodiscard]] +constexpr std::size_t sizeOf(const T *t) noexcept; + +template +struct AlignmentCatcher: public ModelHandlerBase> { + std::size_t biggestAlignment = 1; + + template + constexpr void setTypeInfo(T&&...) const noexcept { + } + + template + constexpr ox::Error field(CRStringView name, const UnionView val) noexcept { + return field(name, val.get()); + } + + template + constexpr ox::Error field(CRStringView, const T *val) noexcept { + if constexpr(ox::is_integer_v) { + biggestAlignment = ox::max(biggestAlignment, PlatSpec::alignOf(*val)); + } else { + biggestAlignment = ox::max(biggestAlignment, alignOf(*val)); + } + return {}; + } + + template + constexpr ox::Error field(CRStringView, const T *val, std::size_t cnt) noexcept { + for (std::size_t i = 0; i < cnt; ++i) { + oxReturnError(field(nullptr, &val[i])); + } + return {}; + } + + [[nodiscard]] + static constexpr auto opType() noexcept { + return ox::OpType::Reflect; + } + +}; + +} diff --git a/deps/ox/src/ox/preloader/platspecs.hpp b/deps/ox/src/ox/preloader/platspecs.hpp new file mode 100644 index 00000000..b8c5507f --- /dev/null +++ b/deps/ox/src/ox/preloader/platspecs.hpp @@ -0,0 +1,126 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include + +#include "alignmentcatcher.hpp" +#include "sizecatcher.hpp" + +namespace ox { + +struct NativePlatSpec { + using PtrType = uintptr_t; + using size_t = std::size_t; + + static constexpr auto PtrAlign = alignof(void*); + static constexpr PtrType RomStart = 0x08000000; + + template + [[nodiscard]] + static constexpr auto alignOf(const T &v) noexcept { + if constexpr(ox::is_integral_v) { + return alignof(T); + } else if constexpr(ox::is_pointer_v) { + return PtrAlign; + } else { + AlignmentCatcher c; + oxAssert(model(c.interface(), &v), "Could not get alignment for type"); + return c.biggestAlignment; + } + } + + [[nodiscard]] + static constexpr auto correctEndianness(auto v) noexcept { + return v; + } +}; + +struct GbaPlatSpec { + using PtrType = uint32_t; + using size_t = uint32_t; + + static constexpr auto PtrAlign = 4; + static constexpr PtrType RomStart = 0x08000000; + + [[nodiscard]] + static constexpr std::size_t alignOf(const bool) noexcept { + return 1; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const uint8_t) noexcept { + return 1; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const uint16_t) noexcept { + return 2; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const uint32_t) noexcept { + return 4; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const uint64_t) noexcept { + return 8; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const int8_t) noexcept { + return 1; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const int16_t) noexcept { + return 2; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const int32_t) noexcept { + return 4; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const int64_t) noexcept { + return 8; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(auto*) noexcept { + return 4; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const auto*) noexcept { + return 4; + } + + [[nodiscard]] + static constexpr std::size_t alignOf(const auto &v) noexcept { + AlignmentCatcher c; + oxAssert(model(c.interface(), &v), "Could not get alignment for type"); + return c.biggestAlignment; + } + + [[nodiscard]] + static constexpr auto correctEndianness(auto v) noexcept { + return ox::toLittleEndian(v); + } +}; + +template +[[nodiscard]] +constexpr std::size_t alignOf(const T &t) noexcept { + return PlatSpec::alignOf(t); +} + +template +constexpr auto alignOf_v = alignOf(static_cast(nullptr)); + +} diff --git a/deps/ox/src/ox/preloader/preload.cpp b/deps/ox/src/ox/preloader/preload.cpp new file mode 100644 index 00000000..17f20174 --- /dev/null +++ b/deps/ox/src/ox/preloader/preload.cpp @@ -0,0 +1,33 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include "preload.hpp" + +namespace ox { + +static ox::Error buildPreloadBuffer(ox::Buffer *buff, std::size_t buffStart, ox::FileSystem *fs, + ox::TypeStore *ts, const char *path) noexcept { + oxRequire(files, fs->ls(path)); + for (const auto &f : files) { + oxRequire(stat, fs->stat(f)); + if (stat.fileType == ox::FileType::NormalFile) { + oxRequire(fileBuff, fs->read(path)); + oxRequire(obj, ox::readClaw(ts, fileBuff)); + } else if (stat.fileType == ox::FileType::Directory) { + const auto childPath = ox::sfmt("{}/{}", path, f); + oxReturnError(buildPreloadBuffer(buff, buffStart, fs, ts, childPath.c_str())); + } + } + return {}; +} + +ox::Result buildPreloadBuffer(std::size_t buffStart, ox::FileSystem *fs, ox::TypeStore *ts) noexcept { + ox::Buffer buff; + oxReturnError(buildPreloadBuffer(&buff, buffStart, fs, ts, "/")); + return buff; +} + +} \ No newline at end of file diff --git a/deps/ox/src/ox/preloader/preload.hpp b/deps/ox/src/ox/preloader/preload.hpp new file mode 100644 index 00000000..9142899f --- /dev/null +++ b/deps/ox/src/ox/preloader/preload.hpp @@ -0,0 +1,21 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include + +namespace ox { + +/** + * + * @param buffStart where the preload buffer will start in ROM + * @param fs an ox::FileSystem containing the contents to be preloaded + * @return preload buffer or error + */ +[[maybe_unused]] +ox::Result buildPreloadBuffer(std::size_t buffStart, ox::FileSystem *fs) noexcept; + +} \ No newline at end of file diff --git a/deps/ox/src/ox/preloader/preloader.cpp b/deps/ox/src/ox/preloader/preloader.cpp new file mode 100644 index 00000000..a5bb1334 --- /dev/null +++ b/deps/ox/src/ox/preloader/preloader.cpp @@ -0,0 +1,33 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include "platspecs.hpp" +#include "preloader.hpp" + +namespace ox { + +struct TestType { + static constexpr auto TypeName = "net.drinkingtea.nostalgia.preloader.TestType"; + static constexpr auto TypeVersion = 1; + uint32_t field1 = 0; + uint32_t *field2 = nullptr; + ox::Vector field3; +}; + +oxModelBegin(TestType) + oxModelField(field1) + oxModelField(field2) + oxModelField(field3) +oxModelEnd() + +constexpr ox::Error asdf() noexcept { + const TestType t; + return preload(&t).error; +} + +//static_assert(asdf().errCode == 0); + +} diff --git a/deps/ox/src/ox/preloader/preloader.hpp b/deps/ox/src/ox/preloader/preloader.hpp new file mode 100644 index 00000000..4ebb8537 --- /dev/null +++ b/deps/ox/src/ox/preloader/preloader.hpp @@ -0,0 +1,287 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "preloader.hpp" +#include "platspecs.hpp" + +namespace ox { + +template +class Preloader: public ModelHandlerBase> { + 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 m_ptrs; + ox::Vector 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> make(ox::ios_base::seekdir anchor = ox::ios_base::cur, + std::size_t sz = 0) noexcept; + + constexpr void setTypeInfo(CRStringView, int, const ox::Vector& = {}, int = 0) noexcept {} + + template + constexpr ox::Error field(CRStringView, const ox::UnionView val) noexcept; + + template + constexpr ox::Error field(CRStringView, const T *val) noexcept; + + template + constexpr ox::Error field(CRStringView, const ox::BasicString *val) noexcept; + + template + constexpr ox::Error field(CRStringView, const ox::Array *valArray) noexcept; + + template + 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 + constexpr ox::Error fieldVector(CRStringView, const ox::Vector *val) noexcept; + + constexpr ox::Error fieldVector(CRStringView, const auto *val, ox::VectorMemMap vecVal) noexcept; + + constexpr ox::Error pad(const auto *val) noexcept; + + constexpr bool unionCheckAndIt() noexcept; +}; + +template +constexpr ox::Result>> +Preloader::make(ox::ios_base::seekdir anchor, std::size_t sz) noexcept { + auto p = ox::UniquePtr(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 +template +constexpr ox::Error Preloader::field(CRStringView, const ox::UnionView 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 +template +constexpr ox::Error Preloader::field(CRStringView name, const T *val) noexcept { + if (!unionCheckAndIt()) { + return {}; + } + oxReturnError(pad(val)); + if constexpr(ox::is_integral_v) { + return ox::serialize(&m_writer, PlatSpec::correctEndianness(*val)); + } else if constexpr(ox::is_pointer_v) { + return {}; + } else if constexpr(ox::isVector_v || ox::is_same_v) { + return fieldVector(name, val); + } else { + m_unionIdx.emplace_back(-1); + const auto out = model(this->interface(), val); + m_unionIdx.pop_back(); + return out; + } +} + +template +template +constexpr ox::Error Preloader::field(CRStringView, const ox::BasicString *val) noexcept { + if (!unionCheckAndIt()) { + return {}; + } + using VecMap = ox::VectorMemMap; + const auto sz = val->bytes(); + oxRequire(a, ox::allocate(&m_writer, sz)); + const VecMap vecVal{ + .smallVecSize = SmallStringSize, + .size = PlatSpec::correctEndianness(static_cast(sz)), + .cap = PlatSpec::correctEndianness(static_cast(sz)), + .items = sz ? PlatSpec::correctEndianness(static_cast(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 +template +constexpr ox::Error Preloader::field(CRStringView name, const ox::Array *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 +template +constexpr ox::Error Preloader::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 +constexpr ox::Error Preloader::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 +constexpr ox::Error Preloader::fieldVector(CRStringView name, const ox::ModelValueVector *val) noexcept { + // serialize the Vector + ox::VectorMemMap vecVal{ + .size = PlatSpec::correctEndianness(static_cast(val->size())), + .cap = PlatSpec::correctEndianness(static_cast(val->size())), + }; + return fieldVector(name, val, vecVal); +} + +template +template +constexpr ox::Error Preloader::fieldVector(CRStringView name, const ox::Vector *val) noexcept { + // serialize the Vector + ox::VectorMemMap vecVal{ + .smallVecSize = SmallVectorSize * sizeOf(static_cast(nullptr)), + .size = PlatSpec::correctEndianness(static_cast(val->size())), + .cap = PlatSpec::correctEndianness(static_cast(val->size())), + }; + return fieldVector(name, val, vecVal); +} + +template +constexpr ox::Error Preloader::fieldVector(CRStringView, const auto *val, ox::VectorMemMap vecVal) noexcept { + oxReturnError(pad(&vecVal)); + const auto vecValPt = m_writer.tellp(); + // serialize the Vector elements + if (val->size()) { + const auto sz = sizeOf(&(*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, items), vecVal.items); + return {}; +} + +template +constexpr ox::Error Preloader::pad(const auto *val) noexcept { + constexpr auto a = alignOf_v; + const auto padding = a - m_writer.tellp() % a; + return m_writer.write(nullptr, padding); +} + +template +constexpr bool Preloader::unionCheckAndIt() noexcept { + auto &u = m_unionIdx.back().unwrap(); + return u.checkAndIterate(); +} + +template +constexpr ox::Result preload(const auto *obj) noexcept { + using Pl = Preloader; + oxRequireM(preloader, Pl::make(ox::ios_base::end)); + oxReturnError(model(preloader->interface(), obj)); + return preloader->buff(); +} + +} diff --git a/deps/ox/src/ox/preloader/sizecatcher.hpp b/deps/ox/src/ox/preloader/sizecatcher.hpp new file mode 100644 index 00000000..77a16665 --- /dev/null +++ b/deps/ox/src/ox/preloader/sizecatcher.hpp @@ -0,0 +1,109 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "unionsizecatcher.hpp" + +namespace ox { + +template +[[nodiscard]] +constexpr std::size_t alignOf(const T &t) noexcept; + +template +[[nodiscard]] +constexpr std::size_t sizeOf(const T *t) noexcept; + +template +class SizeCatcher: public ModelHandlerBase> { + private: + std::size_t m_size = 0; + + public: + constexpr explicit SizeCatcher() noexcept = default; + + template + constexpr void setTypeInfo(T&&...) const noexcept { + } + + template + constexpr ox::Error field(const char*, UnionView) noexcept; + + template + constexpr ox::Error field(const char*, const T *val) noexcept; + + template + constexpr ox::Error field(const char*, const T **val, std::size_t cnt) noexcept; + + [[nodiscard]] + constexpr auto size() const noexcept { + return m_size; + } + + [[nodiscard]] + static constexpr auto opType() noexcept { + return ox::OpType::Reflect; + } + + private: + constexpr void pad(const auto *val) noexcept; +}; + +template +template +constexpr ox::Error SizeCatcher::field(const char*, const UnionView val) noexcept { + pad(val.get()); + UnionSizeCatcher sc; + oxReturnError(model(sc.interface(), val.get())); + m_size += sc.size(); + return {}; +} + +template +template +constexpr ox::Error SizeCatcher::field(const char*, const T *val) noexcept { + pad(val); + m_size += sizeOf(val); + return {}; +} + +template +template +constexpr ox::Error SizeCatcher::field(const char*, const T **val, std::size_t cnt) noexcept { + for (std::size_t i = 0; i < cnt; ++i) { + oxReturnError(field("", &val[i])); + } + return {}; +} + +template +constexpr void SizeCatcher::pad(const auto *val) noexcept { + const auto padding = m_size - m_size % alignOf(*val); + m_size += padding; +} + +template +[[nodiscard]] +constexpr std::size_t sizeOf(const T *t) noexcept { + if constexpr(ox::is_integral_v) { + return sizeof(T); + } else if constexpr(ox::is_pointer_v) { + return sizeof(PlatSpec::PtrType); + } else { + SizeCatcher sc; + const auto err = model(sc.interface(), t); + oxAssert(err, "Could not get size of type"); + return sc.size(); + } +} + +} diff --git a/deps/ox/src/ox/preloader/unionsizecatcher.hpp b/deps/ox/src/ox/preloader/unionsizecatcher.hpp new file mode 100644 index 00000000..53b876c9 --- /dev/null +++ b/deps/ox/src/ox/preloader/unionsizecatcher.hpp @@ -0,0 +1,97 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ox { + +template +class UnionSizeCatcher: public ModelHandlerBase> { + private: + std::size_t m_size = 0; + + public: + template + constexpr void setTypeInfo(T&&...) const noexcept { + } + + template + constexpr ox::Error field(CRStringView, const UnionView val) noexcept { + UnionSizeCatcher sc; + oxReturnError(model(sc.interface(), val.get())); + m_size += sc.size(); + return {}; + } + + template + constexpr ox::Error field(CRStringView, const T *val) noexcept; + + template + constexpr ox::Error field(CRStringView, const T **val, std::size_t cnt) noexcept; + + [[nodiscard]] + constexpr auto size() const noexcept { + return m_size; + } + + [[nodiscard]] + static constexpr auto opType() noexcept { + return ox::OpType::Reflect; + } + + private: + template + constexpr ox::Error fieldStr(CRStringView, const ox::BasicString *val) noexcept; + + template + constexpr ox::Error fieldVector(CRStringView, const ox::Vector *val) noexcept; + + constexpr void setSize(std::size_t sz) noexcept; +}; + +template +template +constexpr ox::Error UnionSizeCatcher::field(CRStringView, const T *val) noexcept { + setSize(sizeOf(val)); + return {}; +} + +template +template +constexpr ox::Error UnionSizeCatcher::field(CRStringView, const T **val, std::size_t cnt) noexcept { + for (std::size_t i = 0; i < cnt; ++i) { + oxReturnError(field("", &val[i])); + } + return {}; +} + +template +template +constexpr ox::Error UnionSizeCatcher::fieldStr(CRStringView, const ox::BasicString*) noexcept { + ox::VectorMemMap v; + setSize(sizeOf(v)); + return {}; +} + +template +template +constexpr ox::Error UnionSizeCatcher::fieldVector(CRStringView, const ox::Vector*) noexcept { + ox::VectorMemMap v; + setSize(sizeOf(v)); + return {}; +} + +template +constexpr void UnionSizeCatcher::setSize(std::size_t sz) noexcept { + m_size = ox::max(m_size, sz); +} + +} diff --git a/deps/ox/src/ox/std/CMakeLists.txt b/deps/ox/src/ox/std/CMakeLists.txt index 2d1c5115..bda8b575 100644 --- a/deps/ox/src/ox/std/CMakeLists.txt +++ b/deps/ox/src/ox/std/CMakeLists.txt @@ -90,10 +90,12 @@ install( new.hpp optional.hpp random.hpp + serialize.hpp std.hpp stddef.hpp stacktrace.hpp string.hpp + stringview.hpp strongint.hpp strops.hpp trace.hpp @@ -102,6 +104,7 @@ install( typetraits.hpp units.hpp vector.hpp + writer.hpp DESTINATION include/ox/std ) diff --git a/deps/ox/src/ox/std/algorithm.hpp b/deps/ox/src/ox/std/algorithm.hpp index d61e76ff..f4ae777f 100644 --- a/deps/ox/src/ox/std/algorithm.hpp +++ b/deps/ox/src/ox/std/algorithm.hpp @@ -30,4 +30,14 @@ constexpr It find_if(It begin, It end, auto predicate) { return end; } +template +constexpr OutIt copy_n(It in, Size cnt, OutIt out) { + for (Size i = 0; i < cnt; ++i) { + *out = *in; + ++out; + ++in; + } + return out; +} + } \ No newline at end of file diff --git a/deps/ox/src/ox/std/assert.hpp b/deps/ox/src/ox/std/assert.hpp index abb39a21..b5abb015 100644 --- a/deps/ox/src/ox/std/assert.hpp +++ b/deps/ox/src/ox/std/assert.hpp @@ -51,7 +51,7 @@ constexpr void assertFunc(const char *file, int line, bool pass, [[maybe_unused] constexpr void assertFunc(const char *file, int line, const Error &err, const char*, const char *assertMsg) noexcept { if (err) { - if (!std::is_constant_evaluated()) { + if (!std::is_constant_evaluated()) { #if defined(OX_USE_STDLIB) oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg); if (err.msg) { @@ -73,4 +73,22 @@ constexpr void assertFunc(const char *file, int line, const Error &err, const ch } } +constexpr void expect(const char *file, int line, const auto &actual, const auto &expected) noexcept { + if (actual != expected) { + if (!std::is_constant_evaluated()) { +#if defined(OX_USE_STDLIB) + oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, "Value incorrect"); + oxErrf("expected: {}, actual: {}\n", detail::toStringView(expected), detail::toStringView(actual)); + printStackTrace(2); + oxTracef("assert::expect", "Failed assert: {} == {} [{}:{}]", detail::toStringView(actual), detail::toStringView(expected), file, line); + std::abort(); +#else + constexprPanic(file, line, "Comparison failed"); +#endif + } else { + while (true); + } + } +} + } diff --git a/deps/ox/src/ox/std/bit.hpp b/deps/ox/src/ox/std/bit.hpp index 23cb75a8..7f9e5d4b 100644 --- a/deps/ox/src/ox/std/bit.hpp +++ b/deps/ox/src/ox/std/bit.hpp @@ -21,7 +21,8 @@ namespace std { template -constexpr typename ox::enable_if::type bit_cast(const From &src) noexcept { +[[nodiscard]] +constexpr To bit_cast(const From &src) noexcept requires(sizeof(To) == sizeof(From)) { return __builtin_bit_cast(To, src); } diff --git a/deps/ox/src/ox/std/bstring.hpp b/deps/ox/src/ox/std/bstring.hpp index aaaa5f2b..dbfeedf8 100644 --- a/deps/ox/src/ox/std/bstring.hpp +++ b/deps/ox/src/ox/std/bstring.hpp @@ -9,6 +9,7 @@ #pragma once #include "memops.hpp" +#include "stringview.hpp" #include "strops.hpp" #include "typetraits.hpp" @@ -23,6 +24,8 @@ class BString { public: constexpr BString() noexcept; + constexpr BString(StringView str) noexcept; + constexpr BString(const char *str) noexcept; constexpr BString &operator=(const char *str) noexcept; @@ -37,6 +40,8 @@ class BString { constexpr BString &operator+=(Integer_c auto i) noexcept; + constexpr BString &operator+=(StringView s) noexcept; + constexpr BString operator+(const char *str) const noexcept; constexpr BString operator+(char *str) const noexcept; @@ -81,6 +86,11 @@ template constexpr BString::BString() noexcept: m_buff{{0}} { } +template +constexpr BString::BString(StringView str) noexcept: m_buff{{0}} { + *this = str; +} + template constexpr BString::BString(const char *str) noexcept: m_buff{{0}} { *this = str; @@ -129,6 +139,12 @@ constexpr BString &BString::operator+=(Integer_c auto i) noexcept { return this->operator+=(str); } +template +constexpr BString &BString::operator+=(StringView s) noexcept { + std::size_t strLen = s.bytes(); + oxIgnoreError(append(s.data(), strLen)); +} + template constexpr BString BString::operator+(const char *str) const noexcept { auto out = *this; diff --git a/deps/ox/src/ox/std/buffer.cpp b/deps/ox/src/ox/std/buffer.cpp index 029eb6bb..85c33666 100644 --- a/deps/ox/src/ox/std/buffer.cpp +++ b/deps/ox/src/ox/std/buffer.cpp @@ -13,4 +13,7 @@ namespace ox { template class Vector; +template class WriterT; +template class WriterT; + } diff --git a/deps/ox/src/ox/std/buffer.hpp b/deps/ox/src/ox/std/buffer.hpp index 2d5c86c0..eb331420 100644 --- a/deps/ox/src/ox/std/buffer.hpp +++ b/deps/ox/src/ox/std/buffer.hpp @@ -10,6 +10,7 @@ #include "error.hpp" #include "vector.hpp" +#include "writer.hpp" namespace ox { @@ -17,4 +18,155 @@ extern template class Vector; using Buffer = Vector; +class BufferWriter { + private: + std::size_t m_it = 0; + ox::Buffer &m_buff; + + public: + explicit constexpr BufferWriter(Buffer *buff) noexcept: m_it(buff->size()), m_buff(*buff) { + } + + explicit constexpr BufferWriter(Buffer *buff, std::size_t it) noexcept: m_it(it), m_buff(*buff) { + } + + constexpr ox::Error seekp(std::size_t p) noexcept { + m_it = p; + return {}; + } + + constexpr ox::Error seekp(ox::Signed off, ox::ios_base::seekdir dir) noexcept { + ox::Signed base = 0; + switch (dir) { + case ox::ios_base::beg: + base = 0; + break; + case ox::ios_base::end: + base = static_cast>(m_buff.size()); + break; + case ox::ios_base::cur: + base = static_cast>(m_it); + break; + default: + return OxError(1, "Invalid seekdir"); + } + m_it = static_cast(base + off); + return {}; + } + + [[nodiscard]] + constexpr auto tellp() const noexcept { + return m_it; + } + + constexpr ox::Error put(char val) noexcept { + if (m_it >= m_buff.size()) [[unlikely]] { + m_buff.resize(m_buff.size() + 1); + } + m_buff[m_it] = val; + ++m_it; + return {}; + } + + constexpr ox::Error write(const char *inBuff, std::size_t cnt) noexcept { + const auto end = m_it + cnt; + if (end >= m_buff.size()) { + m_buff.resize(end); + } + if (inBuff) { + const auto buff = m_buff.data() + m_it; + for (auto i = 0u; i < cnt; ++i) { + buff[i] = inBuff[i]; + } + } + m_it += cnt; + return {}; + } + + [[nodiscard]] + constexpr auto data() const noexcept { + return &m_buff; + } +}; + +class CharBuffWriter { + private: + std::size_t m_it = 0; + std::size_t m_cap = 0; + std::size_t m_size = 0; + char *m_buff = nullptr; + + public: + template + explicit constexpr CharBuffWriter(ox::Array *buff) noexcept: + m_cap(buff->size()), + m_buff(buff->data()) { + } + + explicit constexpr CharBuffWriter(char *buff, std::size_t size) noexcept: m_cap(size), m_buff(buff) { + } + + constexpr ox::Error seekp(std::size_t p) noexcept { + m_it = p; + return {}; + } + + constexpr ox::Error seekp(ox::Signed off, ox::ios_base::seekdir dir) noexcept { + ox::Signed base = 0; + switch (dir) { + case ox::ios_base::beg: + base = 0; + break; + case ox::ios_base::end: + base = static_cast>(m_size); + break; + case ox::ios_base::cur: + base = static_cast>(m_it); + break; + default: + return OxError(1, "Invalid seekdir"); + } + m_it = static_cast(base + off); + return {}; + } + + [[nodiscard]] + constexpr auto tellp() const noexcept { + return m_it; + } + + constexpr ox::Error put(char val) noexcept { + if (m_it >= m_cap) [[unlikely]] { + return OxError(1, "Buffer overrun"); + } + m_buff[m_it] = val; + ++m_it; + m_size = ox::max(m_it, m_size); + return {}; + } + + constexpr ox::Error write(const char *buff, std::size_t cnt) noexcept { + const auto end = m_it + cnt; + if (end > m_cap) [[unlikely]] { + return OxError(1, "Buffer overrun"); + } + if (buff) { + for (auto i = 0u; i < cnt; ++i) { + m_buff[m_it + i] = buff[i]; + } + } + m_it += cnt; + m_size = ox::max(m_it, m_size); + return {}; + } + + [[nodiscard]] + constexpr auto data() const noexcept { + return m_buff; + } +}; + +extern template class WriterT; +extern template class WriterT; + } diff --git a/deps/ox/src/ox/std/concepts.hpp b/deps/ox/src/ox/std/concepts.hpp index 8c8c14a3..fb5c358f 100644 --- a/deps/ox/src/ox/std/concepts.hpp +++ b/deps/ox/src/ox/std/concepts.hpp @@ -11,7 +11,43 @@ #include "typetraits.hpp" namespace ox { + template concept CommonPtrWith = ox::is_same_v::type, typename ox::remove_pointer::type>; + +template +concept same_as = ox::is_same_v; + +template +class BasicString; +template +class BString; +class StringView; + +namespace detail { + +constexpr auto isOxString(const auto*) noexcept { + return false; +} + +template +constexpr auto isOxString(const BasicString*) noexcept { + return true; +} + +template +constexpr auto isOxString(const BString*) noexcept { + return true; +} + +constexpr auto isOxString(const StringView*) noexcept { + return true; +} + +} + +template +concept OxString_c = detail::isOxString(static_cast(nullptr)); + } \ No newline at end of file diff --git a/deps/ox/src/ox/std/def.hpp b/deps/ox/src/ox/std/def.hpp index b7f81338..2ecd87c9 100644 --- a/deps/ox/src/ox/std/def.hpp +++ b/deps/ox/src/ox/std/def.hpp @@ -75,6 +75,7 @@ constexpr void oxAssert(bool, const char*) noexcept {} constexpr void oxAssert(const ox::Error&, const char*) noexcept {} #endif +#define oxExpect(actual, expected) ox::expect(__FILE__, __LINE__, actual, expected) // Alloca diff --git a/deps/ox/src/ox/std/error.hpp b/deps/ox/src/ox/std/error.hpp index b78f298f..f039426d 100644 --- a/deps/ox/src/ox/std/error.hpp +++ b/deps/ox/src/ox/std/error.hpp @@ -122,6 +122,8 @@ struct Exception: public std::exception { } }; +void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept; + template struct [[nodiscard]] Result { @@ -182,6 +184,19 @@ struct [[nodiscard]] Result { return error; } + constexpr auto &unwrap() noexcept { + if (error) { + oxPanic(error, "Failed unwrap"); + } + return value; + } + + constexpr const auto &unwrap() const noexcept { + if (error) [[unlikely]] { + oxPanic(error, "Failed unwrap"); + } + return value; + } }; namespace detail { diff --git a/deps/ox/src/ox/std/fmt.hpp b/deps/ox/src/ox/std/fmt.hpp index b3dfbbe6..6019adb3 100644 --- a/deps/ox/src/ox/std/fmt.hpp +++ b/deps/ox/src/ox/std/fmt.hpp @@ -27,60 +27,77 @@ namespace ox { namespace detail { -constexpr const char *toCString(const char *s) noexcept { +template +constexpr StringView toStringView(const StringView &s) noexcept { return s; } -template -constexpr const char *toCString(const BString &s) noexcept { +template +constexpr StringView toStringView(const char *s) noexcept { + return s; +} + +template +constexpr StringView toStringView(const BString &s) noexcept { return s.c_str(); } -template -constexpr const char *toCString(const BasicString &s) noexcept { +template +constexpr StringView toStringView(const BasicString &s) noexcept { return s.c_str(); } #if __has_include() +template #ifdef OX_OS_Darwin constexpr #else inline #endif -const char *toCString(const std::string &s) noexcept { +StringView toStringView(const std::string &s) noexcept { return s.c_str(); } #endif #if __has_include() -inline const char *toCString(const QString &s) noexcept { +template +inline StringView toStringView(const QString &s) noexcept { return s.toUtf8(); } #endif +template +constexpr StringView toStringView(const auto&) noexcept requires(force) { + return ""; +} + class FmtArg { private: char dataStr[10] = {}; + template + static StringView sv(const T &v, char *dataStr) noexcept { + if constexpr(is_bool_v) { + return v ? "true" : "false"; + } else if constexpr(is_integer_v) { + return ox_itoa(v, dataStr); + } else { + return toStringView(v); + } + } + public: - const char *out = nullptr; + const StringView out = nullptr; template - constexpr FmtArg(const T &v) noexcept { - if constexpr(is_bool_v) { - out = v ? "true" : "false"; - } else if constexpr(is_integer_v) { - out = ox_itoa(v, dataStr); - } else { - out = toCString(v); - } + constexpr FmtArg(const T &v) noexcept: out(sv(v, dataStr)) { } }; [[nodiscard]] -constexpr uint64_t argCount(const char *str) noexcept { +constexpr uint64_t argCount(StringView str) noexcept { uint64_t cnt = 0; const auto prev = [str](std::size_t i) -> char { if (i > 0) { @@ -90,13 +107,13 @@ constexpr uint64_t argCount(const char *str) noexcept { } }; const auto next = [str](std::size_t i) -> char { - if (i < ox_strlen(str) - 1) { + if (i < str.bytes() - 1) { return str[i + 1]; } else { return '\0'; } }; - for (std::size_t i = 0; i < ox_strlen(str); ++i) { + for (std::size_t i = 0; i < str.bytes(); ++i) { if (str[i] == '{' && prev(i) != '\\' && next(i) == '}') { ++cnt; } @@ -120,7 +137,7 @@ struct FmtSegment { template struct Fmt { static constexpr std::size_t size = sz; - FmtSegment segments[sz]; + ox::Array segments; constexpr bool operator==(const Fmt &o) const noexcept { for (std::size_t i = 0; i < sz; ++i) { @@ -134,7 +151,7 @@ struct Fmt { template [[nodiscard]] -constexpr Fmt fmtSegments(const char *fmt) noexcept { +constexpr Fmt fmtSegments(StringView fmt) noexcept { Fmt out; const auto prev = [fmt](std::size_t i) -> char { if (i > 0) { @@ -144,18 +161,18 @@ constexpr Fmt fmtSegments(const char *fmt) noexcept { } }; const auto next = [fmt](std::size_t i) -> char { - if (i < ox_strlen(fmt) - 1) { + if (i < fmt.bytes() - 1) { return fmt[i + 1]; } else { return '\0'; } }; auto current = &out.segments[0]; - current->str = fmt; - for (std::size_t i = 0; i < ox_strlen(fmt); ++i) { + current->str = fmt.data(); + for (std::size_t i = 0; i < fmt.bytes(); ++i) { if (fmt[i] == '{' && prev(i) != '\\' && next(i) == '}') { ++current; - current->str = fmt + i + 2; + current->str = fmt.data() + i + 2; current->length = 0; i += 1; } else { @@ -169,7 +186,7 @@ constexpr Fmt fmtSegments(const char *fmt) noexcept { template [[nodiscard]] -constexpr StringType sfmt(const char *fmt, Args... args) noexcept { +constexpr StringType sfmt(StringView fmt, Args... args) noexcept { assert(ox::detail::argCount(fmt) == sizeof...(args)); StringType out; const auto fmtSegments = ox::detail::fmtSegments(fmt); diff --git a/deps/ox/src/ox/std/memops.hpp b/deps/ox/src/ox/std/memops.hpp index be999020..820f3288 100644 --- a/deps/ox/src/ox/std/memops.hpp +++ b/deps/ox/src/ox/std/memops.hpp @@ -30,8 +30,8 @@ int ox_memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept; constexpr void *ox_memcpy(void *dest, const void *src, std::size_t size) noexcept { if (std::is_constant_evaluated() || !ox::defines::UseStdLib) { - auto srcBuf = static_cast(src); - auto dstBuf = static_cast(dest); + auto srcBuf = static_cast(src); + auto dstBuf = static_cast(dest); for (std::size_t i = 0; i < size; ++i) { dstBuf[i] = static_cast(srcBuf[i]); } @@ -56,7 +56,7 @@ constexpr void *ox_memmove(void *dest, const void *src, std::size_t size) noexce constexpr void *ox_memset(void *ptr, int val, std::size_t size) noexcept { if (std::is_constant_evaluated() || !ox::defines::UseStdLib) { - auto buf = static_cast(ptr); + auto buf = static_cast(ptr); for (std::size_t i = 0; i < size; ++i) { buf[i] = static_cast(val); } diff --git a/deps/ox/src/ox/std/memory.hpp b/deps/ox/src/ox/std/memory.hpp index a30fe874..78440edc 100644 --- a/deps/ox/src/ox/std/memory.hpp +++ b/deps/ox/src/ox/std/memory.hpp @@ -282,7 +282,7 @@ constexpr bool operator!=(std::nullptr_t, const UniquePtr &p2) noexcept { template [[nodiscard]] constexpr auto make_unique(Args&&... args) { - return UniquePtr(new T(forward(args)...)); + return UniquePtr(new T(ox::forward(args)...)); } } diff --git a/deps/ox/src/ox/std/range.hpp b/deps/ox/src/ox/std/range.hpp new file mode 100644 index 00000000..279321d2 --- /dev/null +++ b/deps/ox/src/ox/std/range.hpp @@ -0,0 +1,25 @@ +/* + * Copyright 2015 - 2022 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +namespace ox { + +template +class range { + + private: + T m_begin = 0; + T m_end = 0; + + public: + constexpr range(T begin, T end) noexcept: m_begin(begin), m_end(end) { + } +}; + +} diff --git a/deps/ox/src/ox/std/serialize.hpp b/deps/ox/src/ox/std/serialize.hpp new file mode 100644 index 00000000..94cd77cd --- /dev/null +++ b/deps/ox/src/ox/std/serialize.hpp @@ -0,0 +1,81 @@ +/* + * Copyright 2015 - 2022 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "array.hpp" +#include "buffer.hpp" +#include "types.hpp" +#include "typetraits.hpp" +#include "writer.hpp" + +namespace ox { + +template +struct VectorMemMap { + const std::size_t smallVecSize = 0; // not a map value + uint8_t allocator = 0; + typename PlatSpec::size_t size = 0; + typename PlatSpec::size_t cap = 0; + typename PlatSpec::PtrType items = 0; +}; + +template +[[nodiscard]] +constexpr auto sizeOf(const VectorMemMap *t) noexcept { + constexpr auto padding = [](std::size_t size, std::size_t al) { + return size % al; + }; + std::size_t size = 0; + if (t->smallVecSize) { + size += t->smallVecSize; + size += padding(size, PlatSpec::alignOf(t->size)); + } + size += sizeof(t->size); + size += padding(size, PlatSpec::alignOf(t->cap)); + size += sizeof(t->cap); + size += padding(size, PlatSpec::alignOf(t->items)); + size += sizeof(t->items); + return size; +} + +template +[[nodiscard]] +constexpr auto alignOf(const VectorMemMap&) noexcept { + const typename PlatSpec::size_t i = 0; + return PlatSpec::alignOf(i); +} + +template +constexpr ox::Error serialize(Writer_c auto *buff, const VectorMemMap &vm) noexcept { + oxReturnError(buff->write(nullptr, vm.smallVecSize)); + oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.allocator))); + oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.size))); + oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.cap))); + oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.items))); + return {}; +} + +template +constexpr ox::Error serialize(Writer_c auto *buff, T val) noexcept requires(is_integer_v) { + ox::Array tmp; + for (auto i = 0u; i < sizeof(T); ++i) { + tmp[i] = static_cast((val >> i * 8) & 255); + } + return buff->write(tmp.data(), tmp.size()); +}; + +template +constexpr ox::Result> serialize(const T &in) noexcept { + ox::Array out = {}; + CharBuffWriter w(&out); + oxReturnError(serialize(&w, in)); + return out; +}; + +} \ No newline at end of file diff --git a/deps/ox/src/ox/std/std.hpp b/deps/ox/src/ox/std/std.hpp index f6d6f8f0..5ba52f6a 100644 --- a/deps/ox/src/ox/std/std.hpp +++ b/deps/ox/src/ox/std/std.hpp @@ -30,9 +30,11 @@ #include "optional.hpp" #include "random.hpp" #include "realstd.hpp" +#include "serialize.hpp" #include "stacktrace.hpp" #include "stddef.hpp" #include "string.hpp" +#include "stringview.hpp" #include "strongint.hpp" #include "strops.hpp" #include "trace.hpp" diff --git a/deps/ox/src/ox/std/string.cpp b/deps/ox/src/ox/std/string.cpp index f78d63a7..d80b1a53 100644 --- a/deps/ox/src/ox/std/string.cpp +++ b/deps/ox/src/ox/std/string.cpp @@ -12,4 +12,9 @@ namespace ox { template class BasicString<8>; +static_assert(StringView("Write") != String("")); +static_assert(String("Write") != StringView("")); +static_assert(String("Write") == StringView("Write")); +static_assert(String(StringView("Write")) == StringView("Write")); + } diff --git a/deps/ox/src/ox/std/string.hpp b/deps/ox/src/ox/std/string.hpp index ffa82436..ee48b7cc 100644 --- a/deps/ox/src/ox/std/string.hpp +++ b/deps/ox/src/ox/std/string.hpp @@ -12,20 +12,24 @@ #include #endif +#include "algorithm.hpp" #include "buffer.hpp" #include "memops.hpp" +#include "serialize.hpp" +#include "stringview.hpp" #include "strops.hpp" #include "typetraits.hpp" #include "vector.hpp" namespace ox { -template +template class BasicString { private: - Vector m_buff; + Vector m_buff; public: + static constexpr auto SmallStringSize = SmallStringSize_v; constexpr BasicString() noexcept; constexpr explicit BasicString(std::size_t cap) noexcept; @@ -36,6 +40,8 @@ class BasicString { constexpr BasicString(const char *str, std::size_t size) noexcept; + constexpr BasicString(CRStringView str) noexcept; + constexpr BasicString(const BasicString&) noexcept; constexpr BasicString(BasicString&&) noexcept; @@ -122,6 +128,8 @@ class BasicString { constexpr BasicString &operator+=(Integer_c auto i) noexcept; + constexpr BasicString &operator+=(StringView src) noexcept; + constexpr BasicString &operator+=(const BasicString &src) noexcept; constexpr BasicString operator+(const char *str) const noexcept; @@ -136,11 +144,11 @@ class BasicString { constexpr bool operator==(const char *other) const noexcept; - constexpr bool operator==(const BasicString &other) const noexcept; + constexpr bool operator==(const OxString_c auto &other) const noexcept; constexpr bool operator!=(const char *other) const noexcept; - constexpr bool operator!=(const BasicString &other) const noexcept; + constexpr bool operator!=(const OxString_c auto &other) const noexcept; constexpr bool operator<(const BasicString &other) const noexcept; @@ -230,13 +238,15 @@ class BasicString { template constexpr void set(const BasicString &src) noexcept; + constexpr void set(StringView str) noexcept; + constexpr void set(const char *str) noexcept; constexpr void set(const char8_t *str) noexcept; }; -template -constexpr BasicString::BasicString() noexcept { +template +constexpr BasicString::BasicString() noexcept { if (m_buff.size()) { m_buff[0] = 0; } else { @@ -244,16 +254,16 @@ constexpr BasicString::BasicString() noexcept { } } -template -constexpr BasicString::BasicString(std::size_t cap) noexcept: m_buff(cap + 1) { +template +constexpr BasicString::BasicString(std::size_t cap) noexcept: m_buff(cap + 1) { // GCC complains if you don't do this pretty unnecessary size check if (m_buff.size()) { m_buff[0] = 0; } } -template -constexpr BasicString::BasicString(const char *str) noexcept { +template +constexpr BasicString::BasicString(const char *str) noexcept { if (m_buff.size()) { m_buff[0] = 0; } else { @@ -262,8 +272,8 @@ constexpr BasicString::BasicString(const char *str) noexcept { set(str); } -template -constexpr BasicString::BasicString(const char8_t *str) noexcept { +template +constexpr BasicString::BasicString(const char8_t *str) noexcept { if (m_buff.size()) { m_buff[0] = 0; } else { @@ -272,105 +282,122 @@ constexpr BasicString::BasicString(const char8_t *str) noexcept set(str); } -template -constexpr BasicString::BasicString(const char *str, std::size_t size) noexcept { +template +constexpr BasicString::BasicString(const char *str, std::size_t size) noexcept { m_buff.resize(size + 1); memcpy(m_buff.data(), str, size); m_buff[size] = 0; } -template -constexpr BasicString::BasicString(const BasicString &other) noexcept { +template +constexpr BasicString::BasicString(CRStringView str) noexcept { + if (m_buff.size()) { + m_buff[0] = 0; + } else { + m_buff.push_back(0); + } + set(str); +} + +template +constexpr BasicString::BasicString(const BasicString &other) noexcept { m_buff = other.m_buff; } -template -constexpr BasicString::BasicString(BasicString &&other) noexcept: m_buff(std::move(other.m_buff)) { +template +constexpr BasicString::BasicString(BasicString &&other) noexcept: m_buff(std::move(other.m_buff)) { } -template -constexpr BasicString &BasicString::operator=(const char *str) noexcept { +template +constexpr BasicString &BasicString::operator=(const char *str) noexcept { set(str); return *this; } -template -constexpr BasicString &BasicString::operator=(char c) noexcept { +template +constexpr BasicString &BasicString::operator=(char c) noexcept { char str[] = {c, 0}; set(str); return *this; } -template -constexpr BasicString &BasicString::operator=(int i) noexcept { +template +constexpr BasicString &BasicString::operator=(int i) noexcept { this->operator=(static_cast(i)); return *this; } -template -constexpr BasicString &BasicString::operator=(int64_t i) noexcept { +template +constexpr BasicString &BasicString::operator=(int64_t i) noexcept { char str[65] = {}; ox_itoa(i, str); set(str); return *this; } -template -constexpr BasicString &BasicString::operator=(uint64_t i) noexcept { +template +constexpr BasicString &BasicString::operator=(uint64_t i) noexcept { char str[65] = {}; ox_itoa(i, str); set(str); return *this; } -template -constexpr BasicString &BasicString::operator=(const BasicString &src) noexcept { +template +constexpr BasicString &BasicString::operator=(const BasicString &src) noexcept { set(src); return *this; } -template -constexpr BasicString &BasicString::operator=(BasicString &&src) noexcept { +template +constexpr BasicString &BasicString::operator=(BasicString &&src) noexcept { m_buff = std::move(src.m_buff); return *this; } -template -constexpr BasicString &BasicString::operator+=(const char *str) noexcept { +template +constexpr BasicString &BasicString::operator+=(const char *str) noexcept { std::size_t strLen = ox_strlen(str); oxIgnoreError(append(str, strLen)); return *this; } -template -constexpr BasicString &BasicString::operator+=(char *str) noexcept { +template +constexpr BasicString &BasicString::operator+=(char *str) noexcept { return *this += static_cast(str); } -template -constexpr BasicString &BasicString::operator+=(char c) noexcept { +template +constexpr BasicString &BasicString::operator+=(char c) noexcept { const char str[] = {c, 0}; return this->operator+=(str); } -template -constexpr BasicString &BasicString::operator+=(Integer_c auto i) noexcept { +template +constexpr BasicString &BasicString::operator+=(Integer_c auto i) noexcept { char str[65] = {}; ox_itoa(i, str); return this->operator+=(str); } -template -constexpr BasicString &BasicString::operator+=(const BasicString &src) noexcept { +template +constexpr BasicString &BasicString::operator+=(StringView s) noexcept { + std::size_t strLen = s.bytes(); + oxIgnoreError(append(s.data(), strLen)); + return *this; +} + +template +constexpr BasicString &BasicString::operator+=(const BasicString &src) noexcept { oxIgnoreError(append(src.c_str(), src.len())); return *this; } -template -constexpr BasicString BasicString::operator+(const char *str) const noexcept { +template +constexpr BasicString BasicString::operator+(const char *str) const noexcept { const std::size_t strLen = ox_strlen(str); const auto currentLen = len(); - BasicString cpy(currentLen + strLen); + BasicString cpy(currentLen + strLen); cpy.m_buff.resize(m_buff.size() + strLen); memcpy(&cpy.m_buff[0], m_buff.data(), currentLen); memcpy(&cpy.m_buff[currentLen], str, strLen); @@ -379,37 +406,37 @@ constexpr BasicString BasicString::operator+(c return cpy; } -template -constexpr BasicString BasicString::operator+(char *str) const noexcept { +template +constexpr BasicString BasicString::operator+(char *str) const noexcept { return *this + static_cast(str); } -template -constexpr BasicString BasicString::operator+(char c) const noexcept { +template +constexpr BasicString BasicString::operator+(char c) const noexcept { const char str[] = {c, 0}; return *this + str; } -template -constexpr BasicString BasicString::operator+(Integer_c auto i) const noexcept { +template +constexpr BasicString BasicString::operator+(Integer_c auto i) const noexcept { char str[65] = {}; ox_itoa(i, str); return *this + str; } -template -constexpr BasicString BasicString::operator+(const BasicString &src) const noexcept { +template +constexpr BasicString BasicString::operator+(const BasicString &src) const noexcept { const std::size_t strLen = src.len(); const auto currentLen = len(); - BasicString cpy(currentLen + strLen); + BasicString cpy(currentLen + strLen); cpy.m_buff.resize(m_buff.size() + strLen); memcpy(&cpy.m_buff[0], m_buff.data(), currentLen); memcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1); return cpy; } -template -constexpr bool BasicString::operator==(const char *other) const noexcept { +template +constexpr bool BasicString::operator==(const char *other) const noexcept { bool retval = true; for (auto i = 0u; i < m_buff.size() && (m_buff[i] || other[i]); ++i) { if (m_buff[i] != other[i]) { @@ -420,15 +447,15 @@ constexpr bool BasicString::operator==(const char *other) const return retval; } -template -constexpr bool BasicString::operator==(const BasicString &other) const noexcept { +template +constexpr bool BasicString::operator==(const OxString_c auto &other) const noexcept { if (len() != other.len()) { return false; } bool retval = true; std::size_t i = 0; - while (i < m_buff.size() && (m_buff[i] || other.m_buff[i])) { - if (m_buff[i] != other.m_buff[i]) { + while (i < m_buff.size() && (m_buff[i] || other[i])) { + if (m_buff[i] != other[i]) { retval = false; break; } @@ -437,95 +464,95 @@ constexpr bool BasicString::operator==(const BasicString &other return retval; } -template -constexpr bool BasicString::operator!=(const char *other) const noexcept { +template +constexpr bool BasicString::operator!=(const char *other) const noexcept { return !operator==(other); } -template -constexpr bool BasicString::operator!=(const BasicString &other) const noexcept { +template +constexpr bool BasicString::operator!=(const OxString_c auto &other) const noexcept { return !operator==(other); } -template -constexpr bool BasicString::operator<(const BasicString &other) const noexcept { +template +constexpr bool BasicString::operator<(const BasicString &other) const noexcept { return ox_strcmp(c_str(), other.c_str()) < 0; } -template -constexpr bool BasicString::operator>(const BasicString &other) const noexcept { +template +constexpr bool BasicString::operator>(const BasicString &other) const noexcept { return ox_strcmp(c_str(), other.c_str()) > 0; } -template -constexpr bool BasicString::operator<=(const BasicString &other) const noexcept { +template +constexpr bool BasicString::operator<=(const BasicString &other) const noexcept { return ox_strcmp(c_str(), other.c_str()) < 1; } -template -constexpr bool BasicString::operator>=(const BasicString &other) const noexcept { +template +constexpr bool BasicString::operator>=(const BasicString &other) const noexcept { return ox_strcmp(c_str(), other.c_str()) > -1; } -template -constexpr char BasicString::operator[](std::size_t i) const noexcept { +template +constexpr char BasicString::operator[](std::size_t i) const noexcept { return m_buff[i]; } -template -constexpr char &BasicString::operator[](std::size_t i) noexcept { +template +constexpr char &BasicString::operator[](std::size_t i) noexcept { return m_buff[i]; } -template -constexpr BasicString BasicString::substr(std::size_t pos) const noexcept { - return m_buff.data() + pos; +template +constexpr BasicString BasicString::substr(std::size_t pos) const noexcept { + return BasicString(m_buff.data() + pos, m_buff.size() - pos); } -template -constexpr BasicString BasicString::substr(std::size_t begin, std::size_t end) const noexcept { +template +constexpr BasicString BasicString::substr(std::size_t begin, std::size_t end) const noexcept { const auto src = m_buff.data() + begin; const auto size = end - begin; - BasicString out(size); + BasicString out(size); const auto buff = out.data(); memcpy(buff, src, size); buff[size] = 0; return out; } -template -constexpr bool BasicString::beginsWith(const char *beginning) const noexcept { +template +constexpr bool BasicString::beginsWith(const char *beginning) const noexcept { const auto beginningLen = ox::min(ox_strlen(beginning), len()); return ox_strncmp(data(), beginning, beginningLen) == 0; } -template -constexpr bool BasicString::beginsWith(const BasicString &beginning) const noexcept { +template +constexpr bool BasicString::beginsWith(const BasicString &beginning) const noexcept { const auto sz = ox::min(beginning.len(), len());; return ox_strncmp(data(), beginning.c_str(), sz) == 0; } -template -constexpr bool BasicString::endsWith(const char *ending) const noexcept { +template +constexpr bool BasicString::endsWith(const char *ending) const noexcept { const auto endingLen = ox_strlen(ending); return len() >= endingLen && ox_strcmp(data() + (len() - endingLen), ending) == 0; } -template -constexpr bool BasicString::endsWith(const BasicString &ending) const noexcept { +template +constexpr bool BasicString::endsWith(const BasicString &ending) const noexcept { const auto endingLen = ending.len(); return len() >= endingLen && ox_strcmp(data() + (len() - endingLen), ending.c_str()) == 0; } -template -constexpr std::size_t BasicString::bytes() const noexcept { +template +constexpr std::size_t BasicString::bytes() const noexcept { std::size_t i; for (i = 0; i < m_buff.size() && m_buff[i]; i++); return i + 1; // add one for null terminator } -template -constexpr std::size_t BasicString::len() const noexcept { +template +constexpr std::size_t BasicString::len() const noexcept { std::size_t length = 0; for (const auto c : m_buff) { auto b = static_cast(c); @@ -542,29 +569,39 @@ constexpr std::size_t BasicString::len() const noexcept { return length; } -template +template template -constexpr void BasicString::set(const BasicString &src) noexcept { +constexpr void BasicString::set(const BasicString &src) noexcept { std::size_t strBytes = src.bytes(); if (strBytes > 1) { m_buff.resize(strBytes); - memcpy(m_buff.data(), src.data(), strBytes); + copy_n(src.begin(), strBytes, m_buff.data()); m_buff.back().value = 0; } } -template -constexpr void BasicString::set(const char *str) noexcept { +template +constexpr void BasicString::set(StringView str) noexcept { + std::size_t strBytes = str.bytes(); + if (strBytes > 1) { + m_buff.resize(strBytes + 1); + copy_n(str.data(), strBytes, m_buff.data()); + m_buff.back().value = 0; + } +} + +template +constexpr void BasicString::set(const char *str) noexcept { std::size_t strBytes = ox_strlen(str) + 1; if (strBytes > 1) { m_buff.resize(strBytes); - memcpy(m_buff.data(), str, strBytes); + copy_n(str, strBytes, m_buff.data()); m_buff.back().value = 0; } } -template -constexpr void BasicString::set(const char8_t *str) noexcept { +template +constexpr void BasicString::set(const char8_t *str) noexcept { std::size_t strBytes = ox_strlen(str) + 1; if (strBytes > 1) { m_buff.resize(strBytes); @@ -576,5 +613,20 @@ constexpr void BasicString::set(const char8_t *str) noexcept { extern template class BasicString<8>; using String = BasicString<8>; +using CRString = String const&; + +template +[[nodiscard]] +constexpr auto sizeOf(const ox::BasicString*) noexcept { + VectorMemMap v{.smallVecSize = SmallStringSize_v}; + return sizeOf(&v); +} + +template +[[nodiscard]] +constexpr auto alignOf(const ox::BasicString&) noexcept { + VectorMemMap v{.smallVecSize = SmallStringSize_v}; + return alignOf(&v); +} } diff --git a/deps/ox/src/ox/std/stringview.hpp b/deps/ox/src/ox/std/stringview.hpp new file mode 100644 index 00000000..5b1e824f --- /dev/null +++ b/deps/ox/src/ox/std/stringview.hpp @@ -0,0 +1,123 @@ +/* + * Copyright 2015 - 2022 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "strops.hpp" +#include "types.hpp" + +namespace ox { + +template +class BString; + +template +class BasicString; + +class StringView { + private: + const char *m_str = nullptr; + std::size_t m_len = 0; + public: + constexpr StringView() noexcept = default; + + constexpr StringView(const StringView &sv) noexcept: m_str(sv.m_str), m_len(sv.m_len) { + } + + template + constexpr StringView(const BasicString &str) noexcept: m_str(str.c_str()), m_len(str.len()) {} + + template + constexpr StringView(const BString &str) noexcept: m_str(str.c_str()), m_len(str.len()) {} + + constexpr StringView(std::nullptr_t) noexcept {} + + constexpr StringView(const char *str) noexcept: m_str(str), m_len(str ? ox_strlen(str) : 0) {} + + constexpr StringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {} + + [[nodiscard]] + constexpr auto bytes() const noexcept { + return m_len; + } + + [[nodiscard]] + constexpr auto len() const noexcept { + return m_len; + } + + [[nodiscard]] + constexpr auto *data() const noexcept { + return &m_str[0]; + } + + [[nodiscard]] + constexpr auto &front() const noexcept { + return m_str[0]; + } + + [[nodiscard]] + constexpr auto &back() const noexcept { + return m_str[m_len - 1]; + } + + constexpr auto operator[](std::size_t i) const noexcept { + return m_str[i]; + } + + constexpr auto operator=(const StringView &other) noexcept { + m_str = other.m_str; + m_len = other.m_len; + return *this; + } + + constexpr auto operator==(const StringView &other) const noexcept { + if (other.len() != len()) { + return false; + } + return ox_strncmp(m_str, other.m_str, len()) == 0; + } + + constexpr auto operator<=>(const StringView &str2) const noexcept { + const StringView &str1 = *this; + const auto maxLen = ox::min(str1.len(), str2.len()); + const auto a = &str1.front(); + const auto b = &str2.front(); + for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) { + if (a[i] < b[i]) { + return -1; + } else if (a[i] > b[i]) { + return 1; + } + } + if (str1.len() > str2.len()) { + return 1; + } else if (str1.len() < str2.len()) { + return -1; + } else { + return 0; + } + } + +}; + +using CRStringView = const StringView&; + +static_assert(StringView("Read").bytes() == 4); +static_assert(StringView("Read") == StringView("Read")); +static_assert(StringView("Read") != StringView("Write")); +static_assert(StringView("Write") != StringView("Read")); +static_assert(StringView("Write") != StringView("")); +static_assert(StringView("") != StringView("Read")); +static_assert(StringView("") == StringView("")); +static_assert(StringView("") == ""); +static_assert("Read" == StringView("Read")); +static_assert(StringView("Read") == StringView("Read")); + +} + diff --git a/deps/ox/src/ox/std/strongint.hpp b/deps/ox/src/ox/std/strongint.hpp index 7dd47206..83359b7e 100644 --- a/deps/ox/src/ox/std/strongint.hpp +++ b/deps/ox/src/ox/std/strongint.hpp @@ -13,16 +13,9 @@ namespace ox { struct BaseInteger { - constexpr BaseInteger() noexcept = default; - - constexpr BaseInteger(const BaseInteger&) noexcept { - } - - constexpr BaseInteger operator=(const BaseInteger&) noexcept { - return *this; - } - + constexpr BaseInteger(const BaseInteger&) noexcept = default; + constexpr BaseInteger &operator=(const BaseInteger&) noexcept = default; }; /** diff --git a/deps/ox/src/ox/std/test/CMakeLists.txt b/deps/ox/src/ox/std/test/CMakeLists.txt index 832f6d1a..d77197eb 100644 --- a/deps/ox/src/ox/std/test/CMakeLists.txt +++ b/deps/ox/src/ox/std/test/CMakeLists.txt @@ -16,3 +16,5 @@ add_test("[ox/std] String" StdTest "String") add_test("[ox/std] Vector" StdTest "Vector") add_test("[ox/std] HashMap" StdTest "HashMap") add_test("[ox/std] HeapMgr" StdTest malloc) +add_test("[ox/std] Serialize-Int" StdTest "Serialize-Int") +add_test("[ox/std] BufferWriter" StdTest "BufferWriter") diff --git a/deps/ox/src/ox/std/test/tests.cpp b/deps/ox/src/ox/std/test/tests.cpp index 952e38b1..afbdc492 100644 --- a/deps/ox/src/ox/std/test/tests.cpp +++ b/deps/ox/src/ox/std/test/tests.cpp @@ -11,7 +11,7 @@ #include #include -std::map tests = { +static std::map tests = { { "malloc", [] { @@ -122,6 +122,39 @@ std::map tests = { return OxError(0); } }, + { + "Serialize-Int", + [] { + using BA = ox::Array; + const auto actual = ox::serialize(256).unwrap(); + oxOutf("[{}, {}, {}, {}]", static_cast(actual[0]), static_cast(actual[1]), static_cast(actual[2]), static_cast(actual[3])); + oxExpect(ox::serialize(4).unwrap(), BA({4, 0, 0, 0})); + oxExpect(ox::serialize(256).unwrap(), BA({0, 1, 0, 0})); + oxExpect(ox::serialize(257).unwrap(), BA({1, 1, 0, 0})); + oxExpect(ox::serialize(4).unwrap(), BA({4, 0, 0, 0})); + oxExpect(ox::serialize(256).unwrap(), BA({0, 1, 0, 0})); + oxExpect(ox::serialize(257).unwrap(), BA({1, 1, 0, 0})); + oxExpect(ox::serialize(0xffff'ffff).unwrap(), BA({-1, -1, -1, -1})); + return OxError(0); + } + }, + { + "BufferWriter", + [] { + ox::Buffer b; + ox::BufferWriter w(&b); + oxAssert(w.write("asdf", 4), "write failed"); + oxExpect(b.size(), 4u); + oxAssert(w.write("aoeu", 4), "write failed"); + oxExpect(b.size(), 8u); + oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeu"); + ox::StringView qwerty = "qwerty"; + oxAssert(w.write(qwerty.data(), qwerty.bytes()), "write failed"); + oxExpect(b.size(), 14u); + oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeuqwerty"); + return OxError(0); + } + }, }; int main(int argc, const char **args) { diff --git a/deps/ox/src/ox/std/typetraits.hpp b/deps/ox/src/ox/std/typetraits.hpp index fba353a2..068ca274 100644 --- a/deps/ox/src/ox/std/typetraits.hpp +++ b/deps/ox/src/ox/std/typetraits.hpp @@ -73,6 +73,14 @@ template<> struct is_integral : true_type {}; template<> struct is_integral: true_type {}; template<> struct is_integral : true_type {}; template<> struct is_integral: true_type {}; +template<> struct is_integral : true_type {}; +template<> struct is_integral : true_type {}; +template<> struct is_integral : true_type {}; +template<> struct is_integral : true_type {}; +template<> struct is_integral : true_type {}; +template<> struct is_integral: true_type {}; +template<> struct is_integral : true_type {}; +template<> struct is_integral: true_type {}; // some of these need to be done with the actual language syntax because no one // can agree on what an (u)int64_t is... @@ -80,6 +88,10 @@ template<> struct is_integral: true_type {}; template<> struct is_integral: true_type {}; template<> struct is_integral: true_type {}; template<> struct is_integral: true_type {}; +template<> struct is_integral: true_type {}; +template<> struct is_integral: true_type {}; +template<> struct is_integral: true_type {}; +template<> struct is_integral: true_type {}; template constexpr bool is_integral_v = is_integral::value; @@ -184,6 +196,11 @@ struct is_pointer { static constexpr bool value = true; }; +template +struct is_pointer { + static constexpr bool value = true; +}; + template constexpr bool is_pointer_v = is_pointer::value; diff --git a/deps/ox/src/ox/std/vector.hpp b/deps/ox/src/ox/std/vector.hpp index a13892b1..3712f29d 100644 --- a/deps/ox/src/ox/std/vector.hpp +++ b/deps/ox/src/ox/std/vector.hpp @@ -22,38 +22,6 @@ namespace ox { -template -struct VectorMemMap { - typename PlatSpec::size_t size = 0; - typename PlatSpec::size_t cap = 0; - typename PlatSpec::PtrType items = 0; - uint8_t allocator = 0; -}; - -template -[[nodiscard]] -constexpr auto sizeOf(const VectorMemMap &t) noexcept { - constexpr auto padding = [](std::size_t size, std::size_t al) { - return size - size % al; - }; - std::size_t size = 0; - size += sizeof(t.size); - size += padding(size, PlatSpec::alignOf(t.cap)); - size += sizeof(t.cap); - size += padding(size, PlatSpec::alignOf(t.items)); - size += sizeof(t.items); - size += padding(size, PlatSpec::alignOf(t.allocator)); - size += sizeof(t.allocator); - return size; -} - -template -[[nodiscard]] -constexpr auto alignOf(const VectorMemMap&) noexcept { - const typename PlatSpec::size_t i = 0; - return PlatSpec::alignOf(i); -} - namespace detail { template @@ -75,12 +43,12 @@ struct VectorAllocator { } } - constexpr void moveConstructItemsFrom(T **items, VectorAllocator &src, const std::size_t count, const std::size_t cap) noexcept { + constexpr void moveConstructItemsFrom(T **items, VectorAllocator *src, const std::size_t count, const std::size_t cap) noexcept { // this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, // try removing it later if (cap <= Size && count <= Size) { const auto dstItems = reinterpret_cast(m_data.data()); - const auto srcItems = reinterpret_cast(src.m_data.data()); + const auto srcItems = reinterpret_cast(src->m_data.data()); for (auto i = 0u; i < count; ++i) { std::construct_at(&dstItems[i], std::move(srcItems[i])); } @@ -88,12 +56,12 @@ struct VectorAllocator { } } - constexpr void moveItemsFrom(T **items, VectorAllocator &src, const std::size_t count, const std::size_t cap) noexcept { + constexpr void moveItemsFrom(T **items, VectorAllocator *src, const std::size_t count, const std::size_t cap) noexcept { // this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, // try removing it later if (cap <= Size && count <= Size) { const auto dstItems = reinterpret_cast(m_data.data()); - const auto srcItems = reinterpret_cast(src.m_data.data()); + const auto srcItems = reinterpret_cast(src->m_data.data()); for (std::size_t i = 0; i < count; ++i) { dstItems[i] = std::move(srcItems[i]); } @@ -124,11 +92,11 @@ struct VectorAllocator { } [[maybe_unused]] - constexpr void moveConstructItemsFrom(T**, VectorAllocator&, const std::size_t, const std::size_t) noexcept { + constexpr void moveConstructItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept { } [[maybe_unused]] - constexpr void moveItemsFrom(T**, VectorAllocator&, const std::size_t, const std::size_t) noexcept { + constexpr void moveItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept { } constexpr void deallocate(T *items, std::size_t cap) noexcept { @@ -142,7 +110,7 @@ struct VectorAllocator { } template> -class Vector { +class Vector: detail::VectorAllocator { public: using value_type = T; @@ -257,7 +225,6 @@ class Vector { std::size_t m_size = 0; std::size_t m_cap = 0; T *m_items = nullptr; - detail::VectorAllocator m_allocator; public: constexpr Vector() noexcept = default; @@ -408,8 +375,7 @@ class Vector { */ constexpr Error unordered_erase(std::size_t pos); - private: - constexpr void expandCap(std::size_t cap); + constexpr void reserve(std::size_t cap); }; @@ -425,7 +391,7 @@ template constexpr Vector::Vector(std::size_t size) noexcept { m_size = size; m_cap = m_size; - m_allocator.allocate(&m_items, m_cap); + this->allocate(&m_items, m_cap); for (std::size_t i = 0; i < size; ++i) { std::construct_at(&m_items[i]); } @@ -442,7 +408,7 @@ template constexpr Vector::Vector(const Vector &other) { m_size = other.m_size; m_cap = other.m_cap; - m_allocator.allocate(&m_items, other.m_cap); + this->allocate(&m_items, other.m_cap); for (std::size_t i = 0; i < m_size; ++i) { std::construct_at(&m_items[i], other.m_items[i]); } @@ -453,7 +419,7 @@ constexpr Vector::Vector(Vector &&other) noexcept m_size = other.m_size; m_cap = other.m_cap; m_items = other.m_items; - m_allocator.moveConstructItemsFrom(&m_items, other.m_allocator, m_size, m_cap); + this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap); other.m_size = 0; other.m_cap = 0; other.m_items = nullptr; @@ -462,7 +428,7 @@ constexpr Vector::Vector(Vector &&other) noexcept template constexpr Vector::~Vector() { clear(); - m_allocator.deallocate(m_items, m_cap); + this->deallocate(m_items, m_cap); m_items = nullptr; } @@ -483,11 +449,11 @@ template constexpr Vector &Vector::operator=(const Vector &other) { if (this != &other) { clear(); - m_allocator.deallocate(m_items, m_cap); + this->deallocate(m_items, m_cap); m_items = nullptr; m_size = other.m_size; m_cap = other.m_cap; - m_allocator.allocate(&m_items, other.m_cap); + this->allocate(&m_items, other.m_cap); for (std::size_t i = 0; i < m_size; i++) { std::construct_at(&m_items[i], other.m_items[i]); } @@ -499,11 +465,11 @@ template constexpr Vector &Vector::operator=(Vector &&other) noexcept { if (this != &other) { clear(); - m_allocator.deallocate(m_items, m_cap); + this->deallocate(m_items, m_cap); m_size = other.m_size; m_cap = other.m_cap; m_items = other.m_items; - m_allocator.moveItemsFrom(&m_items, other.m_allocator, m_size, m_cap); + this->moveItemsFrom(&m_items, &other, m_size, m_cap); other.m_size = 0; other.m_cap = 0; other.m_items = nullptr; @@ -580,7 +546,7 @@ constexpr void Vector::clear() { template constexpr void Vector::resize(std::size_t size) { if (m_cap < size) { - expandCap(size); + reserve(size * 2); } if (m_size < size) { for (std::size_t i = m_size; i < size; i++) { @@ -606,9 +572,9 @@ constexpr bool Vector::contains(const T &v) const template constexpr void Vector::insert(std::size_t pos, std::size_t cnt, const T &val) { - // TODO: insert should ideally have its own expandCap + // TODO: insert should ideally have its own reserve if (m_size + cnt > m_cap) { - expandCap(m_cap ? m_size + cnt : initialSize); + reserve(m_cap ? m_size + cnt : initialSize); } if (pos < m_size) { for (auto i = m_size + cnt - 1; i > pos; --i) { @@ -625,9 +591,9 @@ constexpr void Vector::insert(std::size_t pos, st template constexpr void Vector::insert(std::size_t pos, const T &val) { - // TODO: insert should ideally have its own expandCap + // TODO: insert should ideally have its own reserve if (m_size == m_cap) { - expandCap(m_cap ? m_cap * 2 : initialSize); + reserve(m_cap ? m_cap * 2 : initialSize); } if (pos < m_size) { for (auto i = m_size; i > pos; --i) { @@ -644,7 +610,7 @@ template template constexpr T &Vector::emplace_back(Args&&... args) { if (m_size == m_cap) { - expandCap(m_cap ? m_cap * 2 : initialSize); + reserve(m_cap ? m_cap * 2 : initialSize); } auto out = std::construct_at(&m_items[m_size], ox::forward(args)...); ++m_size; @@ -654,7 +620,7 @@ constexpr T &Vector::emplace_back(Args&&... args) template constexpr void Vector::push_back(const T &item) { if (m_size == m_cap) { - expandCap(m_cap ? m_cap * 2 : initialSize); + reserve(m_cap ? m_cap * 2 : initialSize); } std::construct_at(&m_items[m_size], item); ++m_size; @@ -696,18 +662,21 @@ constexpr Error Vector::unordered_erase(std::size } template -constexpr void Vector::expandCap(std::size_t cap) { +constexpr void Vector::reserve(std::size_t cap) { + if (cap <= m_cap) { + return; + } const auto oldItems = m_items; const auto oldCap = m_cap; m_cap = cap; - m_allocator.allocate(&m_items, cap); + this->allocate(&m_items, cap); if (oldItems) { // move over old items const auto itRange = ox::min(cap, m_size); for (std::size_t i = 0; i < itRange; ++i) { std::construct_at(&m_items[i], std::move(oldItems[i])); oldItems[i].~T(); } - m_allocator.deallocate(oldItems, oldCap); + this->deallocate(oldItems, oldCap); } } diff --git a/deps/ox/src/ox/std/writer.hpp b/deps/ox/src/ox/std/writer.hpp new file mode 100644 index 00000000..e163c6ed --- /dev/null +++ b/deps/ox/src/ox/std/writer.hpp @@ -0,0 +1,78 @@ +/* + * Copyright 2015 - 2022 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "concepts.hpp" +#include "error.hpp" +#include "types.hpp" + +namespace ox { + +namespace ios_base { +enum seekdir { + beg, + end, + cur, +}; +} + +template +concept Writer_c = requires(T v) { + {v.put(static_cast(0))} -> ox::same_as; + {v.write(static_cast(""), static_cast(0))} -> ox::same_as; + {v.seekp(static_cast(0))} -> ox::same_as; + {v.seekp(static_cast(0), ios_base::beg)} -> ox::same_as; + {v.tellp()} -> ox::same_as; +}; + +class Writer_v { + public: + virtual constexpr ~Writer_v() noexcept = default; + virtual constexpr auto put(char) noexcept -> ox::Error = 0; + virtual constexpr auto write(const char*, std::size_t) noexcept -> ox::Error = 0; + virtual constexpr auto seekp(std::size_t) noexcept -> ox::Error = 0; + virtual constexpr auto seekp(int, ios_base::seekdir) -> ox::Error = 0; + virtual constexpr auto tellp() noexcept -> std::size_t = 0; +}; + +template +class WriterT: public Writer_v { + private: + T m_writer{}; + public: + template + constexpr explicit WriterT(Args&&... args) noexcept: m_writer(args...) { + } + constexpr auto put(char v) noexcept -> ox::Error override { + return m_writer.put(v); + } + constexpr auto write(const char *v, std::size_t cnt) noexcept -> ox::Error override { + return m_writer.write(v, cnt); + } + constexpr auto seekp(std::size_t p) noexcept -> ox::Error override { + return m_writer.seekp(p); + } + constexpr auto seekp(int p, ios_base::seekdir sd) noexcept -> ox::Error override { + return m_writer.seekp(p, sd); + } + constexpr auto tellp() noexcept -> std::size_t override { + return m_writer.tellp(); + } +}; + +constexpr ox::Result allocate(Writer_c auto *writer, std::size_t sz) noexcept { + const auto p = writer->tellp(); + oxReturnError(writer->seekp(0, ios_base::end)); + const auto out = writer->tellp(); + oxReturnError(writer->write(nullptr, sz)); + oxReturnError(writer->seekp(p)); + return out; +} + +}