From 2c8e073172774d7c97ee97ec01588edf751db196 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Thu, 8 Jun 2023 21:14:27 -0500 Subject: [PATCH] [ox] Cleanup serialization writers, make MC and Claw use Writer_c --- deps/ox/src/ox/claw/test/tests.cpp | 2 +- deps/ox/src/ox/claw/write.hpp | 50 ++++++++++++++++---------- deps/ox/src/ox/mc/write.hpp | 2 +- deps/ox/src/ox/oc/test/tests.cpp | 8 ++--- deps/ox/src/ox/oc/write.hpp | 6 ++-- deps/ox/src/ox/std/buffer.hpp | 8 ++--- deps/ox/src/ox/std/serialize.hpp | 2 +- deps/ox/src/ox/std/stringview.hpp | 2 +- deps/ox/src/ox/std/strops.hpp | 37 +++++++++++++++++++ deps/ox/src/ox/std/test/CMakeLists.txt | 1 + deps/ox/src/ox/std/test/tests.cpp | 16 +++++++++ 11 files changed, 100 insertions(+), 34 deletions(-) diff --git a/deps/ox/src/ox/claw/test/tests.cpp b/deps/ox/src/ox/claw/test/tests.cpp index d1483076..beefb8a6 100644 --- a/deps/ox/src/ox/claw/test/tests.cpp +++ b/deps/ox/src/ox/claw/test/tests.cpp @@ -139,7 +139,7 @@ static std::map tests = { // This test doesn't confirm much, but it does show that the writer // doesn't segfault TestStruct ts; - oxReturnError(ox::writeClaw(&ts, ox::ClawFormat::Metal)); + oxReturnError(ox::writeClaw(ts, ox::ClawFormat::Metal)); return OxError(0); } }, diff --git a/deps/ox/src/ox/claw/write.hpp b/deps/ox/src/ox/claw/write.hpp index a1dca232..231ac689 100644 --- a/deps/ox/src/ox/claw/write.hpp +++ b/deps/ox/src/ox/claw/write.hpp @@ -14,6 +14,7 @@ #endif #include #include +#include #include "format.hpp" @@ -27,7 +28,11 @@ struct TypeInfoCatcher { int version = 0; template - constexpr void setTypeInfo(const char *name = T::TypeName, int v = T::TypeVersion, const Vector& = {}, std::size_t = 0) noexcept { + constexpr void setTypeInfo( + const char *name = T::TypeName, + int v = T::TypeVersion, + const Vector& = {}, + std::size_t = 0) noexcept { this->name = name; this->version = v; } @@ -53,57 +58,64 @@ struct type_version { }; template -constexpr const char *getTypeName(T *t) noexcept { +constexpr const char *getTypeName(const T *t) noexcept { TypeInfoCatcher tnc; oxIgnoreError(model(&tnc, t)); return tnc.name; } template -constexpr int getTypeVersion(T *t) noexcept { +constexpr int getTypeVersion(const T *t) noexcept { TypeInfoCatcher tnc; oxIgnoreError(model(&tnc, t)); return tnc.version; } template -Result writeClawHeader(T *t, ClawFormat fmt) noexcept { - String out; +ox::Error writeClawHeader(Writer_c auto &writer, T *t, ClawFormat fmt) noexcept { switch (fmt) { case ClawFormat::Metal: - out += "M2;"; + oxReturnError(write(&writer, "M2;")); break; case ClawFormat::Organic: - out += "O1;"; + oxReturnError(write(&writer, "O1;")); break; default: return OxError(1); } - out += detail::getTypeName(t); - out += ";"; + oxReturnError(write(&writer, detail::getTypeName(t))); + oxReturnError(writer.put(';')); const auto tn = detail::getTypeVersion(t); if (tn > -1) { - out += tn; + oxReturnError(ox::itoa(tn, writer)); } - out += ";"; - return out; + oxReturnError(writer.put(';')); + return {}; } } -Result writeClaw(auto *t, ClawFormat fmt = ClawFormat::Metal) { - oxRequire(header, detail::writeClawHeader(t, fmt)); +Result writeClaw( + auto &t, + ClawFormat fmt = ClawFormat::Metal, + std::size_t buffReserveSz = 2 * units::KB) noexcept { + Buffer out(buffReserveSz); + BufferWriter bw(&out, 0); + oxReturnError(detail::writeClawHeader(bw, &t, fmt)); #ifdef OX_USE_STDLIB - oxRequire(data, fmt == ClawFormat::Metal ? writeMC(t) : writeOC(t)); + if (fmt == ClawFormat::Metal) { + oxReturnError(writeMC(bw, t)); + } else if (fmt == ClawFormat::Organic) { + oxRequire(data, writeOC(t)); + oxReturnError(bw.write(data.data(), data.size())); + } #else if (fmt != ClawFormat::Metal) { return OxError(1, "OC is not supported in this build"); } - oxRequire(data, writeMC(t)); + oxReturnError(writeMC(bw, t)); #endif - Buffer out(header.len() + data.size()); - memcpy(out.data(), header.data(), header.len()); - memcpy(out.data() + header.len(), data.data(), data.size()); + out.resize(bw.tellp()); return out; } diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index 0f8002a8..78031420 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -31,7 +31,7 @@ template class MetalClawWriter { private: - ox::Vector m_presenceMapBuff; + ox::Vector m_presenceMapBuff{}; FieldBitmap m_fieldPresence; int m_field = 0; int m_unionIdx = -1; diff --git a/deps/ox/src/ox/oc/test/tests.cpp b/deps/ox/src/ox/oc/test/tests.cpp index 5bf209f4..593d41d0 100644 --- a/deps/ox/src/ox/oc/test/tests.cpp +++ b/deps/ox/src/ox/oc/test/tests.cpp @@ -132,7 +132,7 @@ const std::map tests = { // This test doesn't confirm much, but it does show that the writer // doesn't segfault TestStruct ts; - return ox::writeOC(&ts).error; + return ox::writeOC(ts).error; } }, { @@ -153,7 +153,7 @@ const std::map tests = { testIn.Struct.Int = 300; testIn.Struct.String = "Test String 2"; - auto [oc, writeErr] = ox::writeOC(&testIn); + auto [oc, writeErr] = ox::writeOC(testIn); oxAssert(writeErr, "writeOC failed"); oxOutf("{}\n", oc.data()); auto [testOut, readErr] = ox::readOC(oc.data()); @@ -205,7 +205,7 @@ const std::map tests = { testIn.Struct.String = "Test String 2"; testIn.unionIdx = 1; testIn.Union.Int = 93; - oxAssert(ox::writeOC(&testIn).moveTo(&dataBuff), "Data generation failed"); + oxAssert(ox::writeOC(testIn).moveTo(&dataBuff), "Data generation failed"); ox::TypeStore typeStore; auto type = ox::buildTypeDef(&typeStore, &testIn); oxAssert(type.error, "Descriptor write failed"); @@ -254,7 +254,7 @@ const std::map tests = { testIn.Struct.Int = 300; testIn.Struct.String = "Test String 2"; - auto [oc, ocErr] = ox::writeOC(&testIn); + auto [oc, ocErr] = ox::writeOC(testIn); oxAssert(ocErr, "Data generation failed"); ox::TypeStore typeStore; auto type = ox::buildTypeDef(&typeStore, &testIn); diff --git a/deps/ox/src/ox/oc/write.hpp b/deps/ox/src/ox/oc/write.hpp index 3e461bdb..59dfaf80 100644 --- a/deps/ox/src/ox/oc/write.hpp +++ b/deps/ox/src/ox/oc/write.hpp @@ -24,7 +24,7 @@ namespace ox { class OrganicClawWriter { - friend Result writeOC(auto *val) noexcept; + friend Result writeOC(auto &val) noexcept; protected: Json::Value m_json; @@ -242,10 +242,10 @@ Error OrganicClawWriter::field(const char *key, UnionView val) noexcep return OxError(0); } -Result writeOC(auto *val) noexcept { +Result writeOC(auto &val) noexcept { OrganicClawWriter writer; ModelHandlerInterface handler(&writer); - oxReturnError(model(&handler, val)); + oxReturnError(model(&handler, &val)); Json::StreamWriterBuilder jsonBuilder; const auto str = Json::writeString(jsonBuilder, writer.m_json); Buffer buff(str.size() + 1); diff --git a/deps/ox/src/ox/std/buffer.hpp b/deps/ox/src/ox/std/buffer.hpp index bc8ffbb1..14f7f6b2 100644 --- a/deps/ox/src/ox/std/buffer.hpp +++ b/deps/ox/src/ox/std/buffer.hpp @@ -60,7 +60,7 @@ class BufferWriter { } constexpr ox::Error put(char val) noexcept { - if (m_it >= m_buff.size()) [[unlikely]] { + if (m_it >= m_buff.size()) { m_buff.resize(m_buff.size() + 1); } m_buff[m_it] = val; @@ -98,9 +98,9 @@ class CharBuffWriter { public: template - explicit constexpr CharBuffWriter(ox::Array *buff) noexcept: - m_cap(buff->size()), - m_buff(buff->data()) { + 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) { diff --git a/deps/ox/src/ox/std/serialize.hpp b/deps/ox/src/ox/std/serialize.hpp index 4a5dd912..d4ee43f1 100644 --- a/deps/ox/src/ox/std/serialize.hpp +++ b/deps/ox/src/ox/std/serialize.hpp @@ -87,7 +87,7 @@ constexpr ox::Error serialize(Writer_c auto *buff, T val) noexcept requires(is_i template constexpr ox::Result> serialize(const T &in) noexcept { ox::Array out = {}; - CharBuffWriter w(&out); + CharBuffWriter w(out); oxReturnError(serialize(&w, in)); return out; }; diff --git a/deps/ox/src/ox/std/stringview.hpp b/deps/ox/src/ox/std/stringview.hpp index c61d6f27..02fda82b 100644 --- a/deps/ox/src/ox/std/stringview.hpp +++ b/deps/ox/src/ox/std/stringview.hpp @@ -280,7 +280,7 @@ using CRStringView = const StringView&; [[nodiscard]] constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept { const auto beginningLen = ox::min(beginning.len(), base.len()); - return ox_strncmp(base.data(), beginning, beginningLen) == 0; + return base.len() >= beginning.len() && ox_strncmp(base.data(), beginning, beginningLen) == 0; } [[nodiscard]] diff --git a/deps/ox/src/ox/std/strops.hpp b/deps/ox/src/ox/std/strops.hpp index bb3f969f..dd97178b 100644 --- a/deps/ox/src/ox/std/strops.hpp +++ b/deps/ox/src/ox/std/strops.hpp @@ -12,6 +12,7 @@ #include "math.hpp" #include "types.hpp" #include "typetraits.hpp" +#include "writer.hpp" template constexpr char *ox_strcpy(T1 dest, T2 src) noexcept { @@ -125,6 +126,42 @@ constexpr int ox_lastIndexOf(const auto &str, int character, std::size_t maxLen return retval; } +namespace ox { + +template +constexpr ox::Error itoa(Integer v, ox::Writer_c auto &writer) noexcept { + if (v) { + ox::ResizedInt_t mod = 1000000000000000000; + ox::ResizedInt_t val = v; + constexpr auto base = 10; + auto it = 0; + if (val < 0) { + oxReturnError(writer.put('-')); + ++it; + } + while (mod) { + auto digit = val / mod; + val %= mod; + mod /= base; + if (it || digit) { + ox::ResizedInt_t start = '0'; + if (digit >= 10) { + start = 'a'; + digit -= 10; + } + oxReturnError(writer.put(static_cast(start + digit))); + ++it; + } + } + } else { + // 0 is a special case + oxReturnError(writer.put('0')); + } + return {}; +} + +} + template constexpr T ox_itoa(Integer v, T str) noexcept { if (v) { diff --git a/deps/ox/src/ox/std/test/CMakeLists.txt b/deps/ox/src/ox/std/test/CMakeLists.txt index 8914db50..cf4e58bc 100644 --- a/deps/ox/src/ox/std/test/CMakeLists.txt +++ b/deps/ox/src/ox/std/test/CMakeLists.txt @@ -11,6 +11,7 @@ add_test("[ox/std] ox_memcmp ABCDEFG != HIJKLMN" StdTest "ABCDEFG != HIJKLMN") add_test("[ox/std] ox_memcmp HIJKLMN != ABCDEFG" StdTest "HIJKLMN != ABCDEFG") add_test("[ox/std] ox_memcmp ABCDEFG == ABCDEFG" StdTest "ABCDEFG == ABCDEFG") add_test("[ox/std] ox_memcmp ABCDEFGHI == ABCDEFG" StdTest "ABCDEFGHI == ABCDEFG") +add_test("[ox/std] itoa" StdTest "itoa") add_test("[ox/std] BString" StdTest "BString") add_test("[ox/std] String" StdTest "String") add_test("[ox/std] Vector" StdTest "Vector") diff --git a/deps/ox/src/ox/std/test/tests.cpp b/deps/ox/src/ox/std/test/tests.cpp index c2e895e5..8ad2e3f3 100644 --- a/deps/ox/src/ox/std/test/tests.cpp +++ b/deps/ox/src/ox/std/test/tests.cpp @@ -25,6 +25,22 @@ static std::map tests = { return OxError(0); } }, + { + "itoa", + []() { + ox::Array buff; + ox::CharBuffWriter bw(buff); + oxAssert(ox::itoa(5, bw), "ox::itoa returned Error"); + oxExpect(ox::StringView(buff.data()), ox::StringView("5")); + oxReturnError(bw.seekp(0)); + oxAssert(ox::itoa(50, bw), "ox::itoa returned Error"); + oxExpect(ox::StringView(buff.data()), ox::StringView("50")); + oxReturnError(bw.seekp(0)); + oxAssert(ox::itoa(500, bw), "ox::itoa returned Error"); + oxExpect(ox::StringView(buff.data()), ox::StringView("500")); + return ox::Error{}; + } + }, { "ABCDEFG != HIJKLMN", []() {