From ce4dcdcd1863610c80ae7b71797b0eb3044939de Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Thu, 8 Jun 2023 00:56:02 -0500 Subject: [PATCH] [ox/mc] Make MC Write use Writer_c --- deps/ox/src/ox/claw/test/tests.cpp | 8 +- deps/ox/src/ox/mc/presenceindicator.hpp | 8 + deps/ox/src/ox/mc/test/tests.cpp | 7 +- deps/ox/src/ox/mc/write.cpp | 3 +- deps/ox/src/ox/mc/write.hpp | 255 ++++++++++++------------ deps/ox/src/ox/std/writer.hpp | 6 + 6 files changed, 150 insertions(+), 137 deletions(-) diff --git a/deps/ox/src/ox/claw/test/tests.cpp b/deps/ox/src/ox/claw/test/tests.cpp index af5b1151..d1483076 100644 --- a/deps/ox/src/ox/claw/test/tests.cpp +++ b/deps/ox/src/ox/claw/test/tests.cpp @@ -158,12 +158,10 @@ static std::map tests = { testIn.Struct.Bool = false; testIn.Struct.Int = 300; testIn.Struct.String = "Test String 2"; - - auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal); - oxAssert(err, "writeMC failed"); - oxAssert(ox::readClaw(buff.data(), buff.size(), &testOut), "readMC failed"); + const auto [buff, err] = ox::writeMC(&testIn); + oxAssert(err, "writeClaw failed"); + oxAssert(ox::readMC(buff.data(), buff.size(), &testOut), "readClaw failed"); //std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n"; - oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); oxAssert(testIn.Int == testOut.Int, "Int value mismatch"); oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch"); diff --git a/deps/ox/src/ox/mc/presenceindicator.hpp b/deps/ox/src/ox/mc/presenceindicator.hpp index e64e8fe0..ca40debe 100644 --- a/deps/ox/src/ox/mc/presenceindicator.hpp +++ b/deps/ox/src/ox/mc/presenceindicator.hpp @@ -24,6 +24,8 @@ class FieldBitmapReader { public: constexpr FieldBitmapReader(T map, std::size_t maxLen) noexcept; + constexpr auto setBuffer(T map, std::size_t maxLen) noexcept; + constexpr Result get(std::size_t i) const noexcept; constexpr void setFields(int) noexcept; @@ -41,6 +43,12 @@ constexpr FieldBitmapReader::FieldBitmapReader(T map, std::size_t maxLen) noe m_mapLen = maxLen; } +template +constexpr auto FieldBitmapReader::setBuffer(T map, std::size_t maxLen) noexcept { + m_map = map; + m_mapLen = maxLen; +} + template constexpr Result FieldBitmapReader::get(std::size_t i) const noexcept { if (i / 8 < m_mapLen) { diff --git a/deps/ox/src/ox/mc/test/tests.cpp b/deps/ox/src/ox/mc/test/tests.cpp index b11d4aa8..a140a4d8 100644 --- a/deps/ox/src/ox/mc/test/tests.cpp +++ b/deps/ox/src/ox/mc/test/tests.cpp @@ -122,8 +122,6 @@ std::map tests = { "MetalClawReader", [] { // setup for tests - static constexpr size_t buffLen = 1024; - char buff[buffLen]; TestStruct testIn, testOut; testIn.Bool = true; testIn.Int = 42; @@ -140,8 +138,9 @@ std::map tests = { testIn.Struct.Int = 300; testIn.Struct.BString = "Test String 2"; // run tests - oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed"); - oxAssert(ox::readMC(buff, buffLen, &testOut), "readMC failed"); + const auto [buff, err] = ox::writeMC(&testIn); + oxAssert(err, "writeMC failed"); + oxAssert(ox::readMC(buff.data(), buff.size(), &testOut), "readMC failed"); //std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n"; oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); oxAssert(testIn.Int == testOut.Int, "Int value mismatch"); diff --git a/deps/ox/src/ox/mc/write.cpp b/deps/ox/src/ox/mc/write.cpp index 08887eb5..973f2ae7 100644 --- a/deps/ox/src/ox/mc/write.cpp +++ b/deps/ox/src/ox/mc/write.cpp @@ -15,6 +15,7 @@ namespace ox { -template class ModelHandlerInterface; +template class ModelHandlerInterface>; +template class ModelHandlerInterface>; } diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index bd90a661..8bf67fc5 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -27,19 +27,19 @@ namespace ox { +template class MetalClawWriter { private: + ox::Vector m_presenceMapBuff; FieldBitmap m_fieldPresence; - int m_fields = 0; int m_field = 0; int m_unionIdx = -1; - std::size_t m_buffIt = 0; - std::size_t m_buffLen = 0; - uint8_t *m_buff = nullptr; + std::size_t m_writerBeginP{}; + Writer &m_writer; public: - constexpr MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept; + constexpr explicit MetalClawWriter(Writer &writer, int unionIdx = -1) noexcept; constexpr ~MetalClawWriter() noexcept = default; @@ -122,77 +122,81 @@ class MetalClawWriter { return 0; } - [[nodiscard]] - constexpr std::size_t size() const noexcept; - [[nodiscard]] static constexpr auto opType() noexcept { return OpType::Write; } + ox::Error finalize() noexcept; + private: constexpr Error appendInteger(Integer_c auto val) noexcept { bool fieldSet = false; if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) { auto mi = mc::encodeInteger(val); - if (mi.length < m_buffLen) { - fieldSet = true; - ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length); - m_buffIt += mi.length; - } else { - return OxError(MC_BUFFENDED); - } + oxReturnError(m_writer.write(reinterpret_cast(mi.data), mi.length)); + fieldSet = true; } oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); - m_field++; + ++m_field; return OxError(0); } }; -extern template class ModelHandlerInterface; +extern template class ModelHandlerInterface>; +extern template class ModelHandlerInterface>; -constexpr MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept: - m_fieldPresence(buff, buffLen), +template +constexpr MetalClawWriter::MetalClawWriter(Writer &writer, int unionIdx) noexcept: + m_fieldPresence(m_presenceMapBuff.data(), m_presenceMapBuff.size()), m_unionIdx(unionIdx), - m_buffLen(buffLen), - m_buff(buff) { + m_writerBeginP(writer.tellp()), + m_writer(writer) { } -constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { return appendInteger(*val); } -constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { return appendInteger(*val); } -constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { return appendInteger(*val); } -constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { return appendInteger(*val); } - -constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { return appendInteger(*val); } -constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { return appendInteger(*val); } -constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { return appendInteger(*val); } -constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { return appendInteger(*val); } -constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { if (m_unionIdx == -1 || m_unionIdx == m_field) { oxReturnError(m_fieldPresence.set(static_cast(m_field), *val)); } @@ -200,108 +204,97 @@ constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *va return OxError(0); } +template template -constexpr Error MetalClawWriter::field(const char*, const BasicString *val) noexcept { +constexpr Error MetalClawWriter::field(const char*, const BasicString *val) noexcept { bool fieldSet = false; if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) { // write the length const auto strLen = mc::encodeInteger(val->len()); - if (m_buffIt + strLen.length + static_cast(val->len()) < m_buffLen) { - memcpy(&m_buff[m_buffIt], strLen.data, strLen.length); - m_buffIt += strLen.length; - // write the string - memcpy(&m_buff[m_buffIt], val->c_str(), static_cast(val->len())); - m_buffIt += static_cast(val->len()); - fieldSet = true; - } else { - return OxError(MC_BUFFENDED); - } + oxReturnError(m_writer.write(reinterpret_cast(strLen.data), strLen.length)); + // write the string + oxReturnError(m_writer.write(val->c_str(), static_cast(val->len()))); + fieldSet = true; } oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); ++m_field; return OxError(0); } +template template -constexpr Error MetalClawWriter::field(const char *name, const BString *val) noexcept { +constexpr Error MetalClawWriter::field(const char *name, const BString *val) noexcept { return fieldCString(name, val->data(), val->cap()); } +template template -constexpr Error MetalClawWriter::field(const char *name, BasicString *val) noexcept { +constexpr Error MetalClawWriter::field(const char *name, BasicString *val) noexcept { return field(name, const_cast*>(val)); } +template template -constexpr Error MetalClawWriter::field(const char *name, BString *val) noexcept { +constexpr Error MetalClawWriter::field(const char *name, BString *val) noexcept { return fieldCString(name, val->data(), val->cap()); } -constexpr Error MetalClawWriter::fieldCString(const char*, const char *const*val, std::size_t) noexcept { +template +constexpr Error MetalClawWriter::fieldCString(const char*, const char *const*val, std::size_t) noexcept { bool fieldSet = false; if (m_unionIdx == -1 || m_unionIdx == m_field) { const auto strLen = *val ? ox_strlen(*val) : 0; // write the length const auto strLenBuff = mc::encodeInteger(strLen); - if (m_buffIt + strLenBuff.length + static_cast(strLen) < m_buffLen) { - ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length); - m_buffIt += strLenBuff.length; - // write the string - ox_memcpy(&m_buff[m_buffIt], *val, static_cast(strLen)); - m_buffIt += static_cast(strLen); - fieldSet = true; - } else { - return OxError(MC_BUFFENDED); - } + oxReturnError(m_writer.write(reinterpret_cast(strLenBuff.data), strLenBuff.length)); + // write the string + oxReturnError(m_writer.write(*val, static_cast(strLen))); + fieldSet = true; } oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); ++m_field; return OxError(0); } -constexpr Error MetalClawWriter::fieldCString(const char *name, const char **val) noexcept { +template +constexpr Error MetalClawWriter::fieldCString(const char *name, const char **val) noexcept { return fieldCString(name, val, {}); } -constexpr Error MetalClawWriter::fieldCString(const char *name, const char *const*val) noexcept { +template +constexpr Error MetalClawWriter::fieldCString(const char *name, const char *const*val) noexcept { return fieldCString(name, val, {}); } -constexpr Error MetalClawWriter::fieldCString(const char*, const char *val, std::size_t strLen) noexcept { +template +constexpr Error MetalClawWriter::fieldCString(const char*, const char *val, std::size_t strLen) noexcept { bool fieldSet = false; if (strLen && (m_unionIdx == -1 || m_unionIdx == m_field)) { // write the length const auto strLenBuff = mc::encodeInteger(strLen); - if (m_buffIt + strLenBuff.length + static_cast(strLen) < m_buffLen) { - ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length); - m_buffIt += strLenBuff.length; - // write the string - ox_memcpy(&m_buff[m_buffIt], val, static_cast(strLen)); - m_buffIt += static_cast(strLen); - fieldSet = true; - } else { - return OxError(MC_BUFFENDED); - } + oxReturnError(m_writer.write(reinterpret_cast(strLenBuff.data), strLenBuff.length)); + // write the string + oxReturnError(m_writer.write(val, static_cast(strLen))); + fieldSet = true; } oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); ++m_field; return OxError(0); } +template template -constexpr Error MetalClawWriter::field(const char*, T *val) noexcept { +constexpr Error MetalClawWriter::field(const char*, T *val) noexcept { if constexpr(isVector_v || isArray_v) { return field(nullptr, val->data(), val->size()); } else { bool fieldSet = false; if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) { - MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); - ModelHandlerInterface handler{&writer}; + MetalClawWriter writer(m_writer); + ModelHandlerInterface> handler{&writer}; oxReturnError(model(&handler, val)); - if (static_cast(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) { - m_buffIt += writer.m_buffIt; - fieldSet = true; - } + oxReturnError(writer.finalize()); + fieldSet = true; } oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); ++m_field; @@ -309,70 +302,57 @@ constexpr Error MetalClawWriter::field(const char*, T *val) noexcept { } } +template template -constexpr Error MetalClawWriter::field(const char*, UnionView val) noexcept { +constexpr Error MetalClawWriter::field(const char*, UnionView val) noexcept { bool fieldSet = false; if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) { - MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt, val.idx()); + MetalClawWriter writer(m_writer, val.idx()); ModelHandlerInterface handler{&writer}; oxReturnError(model(&handler, val.get())); - if (static_cast(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) { - m_buffIt += writer.m_buffIt; - fieldSet = true; - } + oxReturnError(writer.finalize()); + fieldSet = true; } oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); - m_field++; + ++m_field; return OxError(0); } +template template -constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept { +constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept { bool fieldSet = false; - if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) { // write the length const auto arrLen = mc::encodeInteger(len); - if (m_buffIt + arrLen.length < m_buffLen) { - ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length); - m_buffIt += arrLen.length; - } else { - return OxError(MC_BUFFENDED); - } - - MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); + oxReturnError(m_writer.write(reinterpret_cast(arrLen.data), arrLen.length)); + MetalClawWriter writer(m_writer); ModelHandlerInterface handler{&writer}; - handler.setTypeInfo("List", 0, {}, static_cast(len)); - + handler.template setTypeInfo("List", 0, {}, static_cast(len)); // write the array for (std::size_t i = 0; i < len; i++) { oxReturnError(handler.field("", &val[i])); } - - m_buffIt += writer.m_buffIt; + oxReturnError(writer.finalize()); fieldSet = true; } - oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); - m_field++; + ++m_field; return OxError(0); } +template template -constexpr Error MetalClawWriter::field(const char*, const HashMap *val) noexcept { +constexpr Error MetalClawWriter::field(const char*, const HashMap *val) noexcept { const auto &keys = val->keys(); const auto len = keys.size(); bool fieldSet = false; if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) { // write the length const auto arrLen = mc::encodeInteger(len); - if (m_buffIt + arrLen.length < m_buffLen) { - ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length); - m_buffIt += arrLen.length; - } else { - return OxError(MC_BUFFENDED); - } - MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); + oxReturnError(m_writer.write(reinterpret_cast(arrLen.data), arrLen.length)); + // write map + MetalClawWriter writer(m_writer); ModelHandlerInterface handler{&writer}; // double len for both key and value handler.setTypeInfo("Map", 0, {}, len * 2); @@ -386,48 +366,69 @@ constexpr Error MetalClawWriter::field(const char*, const HashMap *va oxRequireM(value, val->at(key)); oxReturnError(handler.field("", value)); } - m_buffIt += writer.m_buffIt; + oxReturnError(writer.finalize()); fieldSet = true; } oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); - m_field++; + ++m_field; return OxError(0); } +template template -constexpr Error MetalClawWriter::field(const char *name, HashMap *val) noexcept { +constexpr Error MetalClawWriter::field(const char *name, HashMap *val) noexcept { return field(name, const_cast*>(val)); } +template template -constexpr void MetalClawWriter::setTypeInfo(const char*, int, const Vector&, std::size_t fields) noexcept { - m_fields = static_cast(fields); +constexpr void MetalClawWriter::setTypeInfo( + const char*, + int, + const Vector&, + std::size_t fields) noexcept { + // TODO: change all setTypeInfo signatures to return Errors + const auto fieldPresenceLen = (fields - 1) / 8 + 1; + oxIgnoreError(m_writer.write(nullptr, fieldPresenceLen)); + m_presenceMapBuff.resize(fieldPresenceLen); + m_fieldPresence.setBuffer(m_presenceMapBuff.data(), m_presenceMapBuff.size()); m_fieldPresence.setFields(static_cast(fields)); - m_buffIt = static_cast(m_fieldPresence.getMaxLen()); - ox_memset(m_buff, 0, m_buffIt); } -constexpr std::size_t MetalClawWriter::size() const noexcept { - return m_buffIt; +template +ox::Error MetalClawWriter::finalize() noexcept { + const auto end = m_writer.tellp(); + oxReturnError(m_writer.seekp(m_writerBeginP)); + oxReturnError(m_writer.write( + reinterpret_cast(m_presenceMapBuff.data()), + m_presenceMapBuff.size())); + oxReturnError(m_writer.seekp(end)); + return {}; } -Result writeMC(auto *val) noexcept { - Buffer buff(10 * units::MB); - MetalClawWriter writer(reinterpret_cast(buff.data()), buff.size()); - ModelHandlerInterface handler{&writer}; - oxReturnError(model(&handler, val)); - buff.resize(writer.size()); +Result writeMC(Writer_c auto &writer, auto &val) noexcept { + MetalClawWriter mcWriter(writer); + ModelHandlerInterface handler{&mcWriter}; + oxReturnError(model(&handler, &val)); + oxReturnError(mcWriter.finalize()); + return {}; +} + +Result writeMC(auto *val, std::size_t buffReserveSz = 2 * units::KB) noexcept { + Buffer buff(buffReserveSz); + BufferWriter bw(&buff, 0); + oxReturnError(writeMC(bw, *val)); + buff.resize(bw.tellp()); return buff; } Error writeMC(char *buff, std::size_t buffLen, auto *val, std::size_t *sizeOut = nullptr) noexcept { - MetalClawWriter writer(reinterpret_cast(buff), buffLen); - ModelHandlerInterface handler(&writer); - auto err = model(&handler, val); + CharBuffWriter bw(buff, buffLen); + oxReturnError(writeMC(bw, *val)); if (sizeOut) { - *sizeOut = writer.size(); + *sizeOut = bw.tellp(); } - return err; + return {}; } } diff --git a/deps/ox/src/ox/std/writer.hpp b/deps/ox/src/ox/std/writer.hpp index e163c6ed..df73b2ca 100644 --- a/deps/ox/src/ox/std/writer.hpp +++ b/deps/ox/src/ox/std/writer.hpp @@ -66,6 +66,12 @@ class WriterT: public Writer_v { } }; +/** + * Allocates the specified amount of data at the end of the current write stream. + * @param writer + * @param sz + * @return + */ 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));