From 1c64096c38dde4819aadc30189cd7c9623c8a597 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Wed, 13 Feb 2019 02:42:33 +0000 Subject: [PATCH] [ox/mc] Add McStr to wrap C style strings to distinguish them from arrays --- deps/ox/src/ox/mc/deftypes.hpp | 17 ++++----- deps/ox/src/ox/mc/defwriter.cpp | 14 ++++---- deps/ox/src/ox/mc/defwriter.hpp | 16 +++++++-- deps/ox/src/ox/mc/mc.hpp | 1 + deps/ox/src/ox/mc/read.cpp | 30 ++++++++++++++++ deps/ox/src/ox/mc/read.hpp | 37 ++++--------------- deps/ox/src/ox/mc/types.hpp | 60 +++++++++++++++++++++++++++++++ deps/ox/src/ox/mc/write.cpp | 41 ++++++++++++++++----- deps/ox/src/ox/mc/write.hpp | 64 ++++++++++++--------------------- 9 files changed, 179 insertions(+), 101 deletions(-) create mode 100644 deps/ox/src/ox/mc/types.hpp diff --git a/deps/ox/src/ox/mc/deftypes.hpp b/deps/ox/src/ox/mc/deftypes.hpp index 2298314f..40e50431 100644 --- a/deps/ox/src/ox/mc/deftypes.hpp +++ b/deps/ox/src/ox/mc/deftypes.hpp @@ -14,7 +14,7 @@ namespace ox::mc { -using String = const char*; +using String = BString<100>; enum class PrimitiveType: uint8_t { UnsignedInteger = 0, @@ -26,38 +26,35 @@ enum class PrimitiveType: uint8_t { Struct = 6, }; -using FieldName = String; - struct Field { // order of fields matters // only serialize type name if type has already been serialized const struct Type *type = nullptr; - FieldName fieldName; + String fieldName; int subscriptLevels = 0; // do not serialize the following bool serializeType = false; }; -using TypeName = String; using FieldList = Vector; struct Type { - TypeName typeName; + String typeName; PrimitiveType primitiveType; // fieldList only applies to structs - FieldList fieldList; + Vector fieldList; // - number of bytes for integer and float types // - number of fields for structs and lists int64_t length = 0; Type() = default; - Type(TypeName tn, PrimitiveType t, int b): typeName(tn), primitiveType(t), length(b) { + Type(String tn, PrimitiveType t, int b): typeName(tn), primitiveType(t), length(b) { } - Type(TypeName tn, PrimitiveType t, FieldList fl): typeName(tn), primitiveType(t), fieldList(fl) { + Type(String tn, PrimitiveType t, FieldList fl): typeName(tn), primitiveType(t), fieldList(fl) { } }; @@ -90,6 +87,6 @@ int ioOp(T *io, Type *type) { return err; } -using TypeStore = ox::HashMap; +using TypeStore = ox::HashMap; } diff --git a/deps/ox/src/ox/mc/defwriter.cpp b/deps/ox/src/ox/mc/defwriter.cpp index c7ddb0c5..ae3ba90b 100644 --- a/deps/ox/src/ox/mc/defwriter.cpp +++ b/deps/ox/src/ox/mc/defwriter.cpp @@ -82,6 +82,12 @@ constexpr mc::Type *MetalClawDefWriter::type(uint64_t*, bool *alreadyExisted) { return getPrimitive(TypeName, PT, Bytes, alreadyExisted); } +mc::Type *MetalClawDefWriter::type(McStr, bool *alreadyExisted) { + constexpr auto TypeName = "B:string"; + constexpr auto PT = mc::PrimitiveType::String; + return getPrimitive(TypeName, PT, 0, alreadyExisted); +} + constexpr mc::Type *MetalClawDefWriter::type(bool*, bool *alreadyExisted) { constexpr auto TypeName = "B:bool"; constexpr auto PT = mc::PrimitiveType::Bool; @@ -95,13 +101,7 @@ constexpr void MetalClawDefWriter::setTypeInfo(const char *name, int) { m_type->primitiveType = mc::PrimitiveType::Struct; } -constexpr mc::Type *MetalClawDefWriter::type(const char*, bool *alreadyExisted) { - constexpr auto TypeName = "B:string"; - constexpr auto PT = mc::PrimitiveType::String; - return getPrimitive(TypeName, PT, 0, alreadyExisted); -} - -constexpr mc::Type *MetalClawDefWriter::getPrimitive(mc::TypeName tn, mc::PrimitiveType pt, int b, bool *alreadyExisted) { +constexpr mc::Type *MetalClawDefWriter::getPrimitive(mc::String tn, mc::PrimitiveType pt, int b, bool *alreadyExisted) { if (m_typeStore->contains(tn)) { *alreadyExisted = true; return &m_typeStore->at(tn); diff --git a/deps/ox/src/ox/mc/defwriter.hpp b/deps/ox/src/ox/mc/defwriter.hpp index 58330328..39e1619b 100644 --- a/deps/ox/src/ox/mc/defwriter.hpp +++ b/deps/ox/src/ox/mc/defwriter.hpp @@ -18,6 +18,7 @@ #include "deftypes.hpp" #include "err.hpp" #include "optype.hpp" +#include "types.hpp" namespace ox { @@ -31,6 +32,11 @@ static constexpr int indirectionLevels(T *t) { return 1 + indirectionLevels(*t); } +static_assert([] { + int i = 0; + return indirectionLevels(i) == 0; +}(), "indirectionLevels broken: indirectionLevels(int)"); + static_assert([] { int i = 0; return indirectionLevels(&i) == 1; @@ -93,13 +99,15 @@ class MetalClawDefWriter { constexpr mc::Type *type(const char *val, bool *alreadyExisted); + mc::Type *type(McStr val, bool *alreadyExisted); + template constexpr mc::Type *type(ox::BString *val, bool *alreadyExisted); template mc::Type *type(T *val, bool *alreadyExisted); - constexpr mc::Type *getPrimitive(mc::TypeName tn, mc::PrimitiveType t, int b, bool *alreadyExisted); + constexpr mc::Type *getPrimitive(mc::String tn, mc::PrimitiveType t, int b, bool *alreadyExisted); }; // array handler @@ -145,8 +153,10 @@ mc::Type *MetalClawDefWriter::type(T *val, bool *alreadyExisted) { } template -constexpr mc::Type *MetalClawDefWriter::type(ox::BString *val, bool *alreadyExisted) { - return type(val->c_str(), alreadyExisted); +constexpr mc::Type *MetalClawDefWriter::type(ox::BString*, bool *alreadyExisted) { + constexpr auto TypeName = "B:string"; + constexpr auto PT = mc::PrimitiveType::String; + return getPrimitive(TypeName, PT, 0, alreadyExisted); } } diff --git a/deps/ox/src/ox/mc/mc.hpp b/deps/ox/src/ox/mc/mc.hpp index d3453cab..7d1c88ab 100644 --- a/deps/ox/src/ox/mc/mc.hpp +++ b/deps/ox/src/ox/mc/mc.hpp @@ -11,4 +11,5 @@ #include "deftypes.hpp" #include "defwriter.hpp" #include "read.hpp" +#include "types.hpp" #include "write.hpp" diff --git a/deps/ox/src/ox/mc/read.cpp b/deps/ox/src/ox/mc/read.cpp index 537c68fa..1a117145 100644 --- a/deps/ox/src/ox/mc/read.cpp +++ b/deps/ox/src/ox/mc/read.cpp @@ -61,6 +61,36 @@ int MetalClawReader::op(const char*, bool *val) { return 0; } +Error MetalClawReader::op(const char*, McStr val) { + int err = 0; + if (m_fieldPresence.get(m_field)) { + // read the length + int size = 0; + if (m_buffIt + sizeof(StringLength) < m_buffLen) { + size = *reinterpret_cast*>(&m_buff[m_buffIt]); + m_buffIt += sizeof(StringLength); + } else { + err |= MC_BUFFENDED; + } + + // read the string + if (val.cap() >= size) { + if (m_buffIt + size < m_buffLen) { + ox_memcpy(val.data(), &m_buff[m_buffIt], size); + m_buffIt += size; + } else { + err |= MC_BUFFENDED; + } + } else { + err |= MC_OUTBUFFENDED; + } + } else { + val.data()[0] = 0; + } + m_field++; + return err; +} + std::size_t MetalClawReader::arrayLength(const char*) { std::size_t len = 0; if (m_fieldPresence.get(m_field)) { diff --git a/deps/ox/src/ox/mc/read.hpp b/deps/ox/src/ox/mc/read.hpp index da760bf5..09d5035a 100644 --- a/deps/ox/src/ox/mc/read.hpp +++ b/deps/ox/src/ox/mc/read.hpp @@ -14,6 +14,7 @@ #include "err.hpp" #include "optype.hpp" #include "presencemask.hpp" +#include "types.hpp" namespace ox { @@ -59,6 +60,8 @@ class MetalClawReader { template int op(const char*, ox::BString *val); + Error op(const char*, McStr val); + std::size_t arrayLength(const char*); // stringLength returns the length of the string, including the null terminator. @@ -66,7 +69,7 @@ class MetalClawReader { void setTypeInfo(const char *name, int fields); - OpType opType() { + constexpr OpType opType() { return OpType::Read; } @@ -88,35 +91,9 @@ int MetalClawReader::op(const char*, T *val) { }; template -int MetalClawReader::op(const char*, ox::BString *val) { - int err = 0; - if (m_fieldPresence.get(m_field)) { - // read the length - std::size_t size = 0; - if (m_buffIt + sizeof(StringLength) < m_buffLen) { - size = *reinterpret_cast*>(&m_buff[m_buffIt]); - m_buffIt += sizeof(StringLength); - } else { - err |= MC_BUFFENDED; - } - - // read the string - if (val->cap() >= size) { - if (m_buffIt + size < m_buffLen) { - ox_memcpy(val, &m_buff[m_buffIt], size); - m_buffIt += size; - } else { - err |= MC_BUFFENDED; - } - } else { - err |= MC_OUTBUFFENDED; - } - } else { - *val = ""; - } - m_field++; - return err; -}; +int MetalClawReader::op(const char *name, ox::BString *val) { + return op(name, McStr(val->data(), val->cap())); +} template int MetalClawReader::readInteger(I *val) { diff --git a/deps/ox/src/ox/mc/types.hpp b/deps/ox/src/ox/mc/types.hpp new file mode 100644 index 00000000..cccc2cd0 --- /dev/null +++ b/deps/ox/src/ox/mc/types.hpp @@ -0,0 +1,60 @@ +/* + * Copyright 2015 - 2018 gtalent2@gmail.com + * + * 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 +#include + +namespace ox { + +class McStr { + + protected: + int m_cap = -1; + char *m_str = nullptr; + + public: + explicit constexpr McStr(const char *str) noexcept { + m_str = const_cast(str); + m_cap = -1; + } + + constexpr McStr(char *str, int cap) noexcept { + m_str = str; + m_cap = cap; + } + + constexpr const char *c_str() noexcept { + return m_str; + } + + constexpr char *data() noexcept { + // do not return a non-const pointer to the const_casted m_str + if (m_cap > -1) { + return m_str; + } else { + return nullptr; + } + } + + constexpr int len() noexcept { + return ox_strlen(m_str); + } + + constexpr int bytes() noexcept { + return ox_strlen(m_str) + 1; // adds 1 for \0 + } + + constexpr int cap() noexcept { + return m_cap; + } + +}; + +} diff --git a/deps/ox/src/ox/mc/write.cpp b/deps/ox/src/ox/mc/write.cpp index 2050b12f..cbafb184 100644 --- a/deps/ox/src/ox/mc/write.cpp +++ b/deps/ox/src/ox/mc/write.cpp @@ -23,43 +23,66 @@ MetalClawWriter::~MetalClawWriter() noexcept { oxAssert(m_field == m_fields, "MetalClawWriter: incorrect fields number given"); } -int MetalClawWriter::op(const char*, int8_t *val) { +Error MetalClawWriter::op(const char*, int8_t *val) { return appendInteger(*val); } -int MetalClawWriter::op(const char*, int16_t *val) { +Error MetalClawWriter::op(const char*, int16_t *val) { return appendInteger(*val); } -int MetalClawWriter::op(const char*, int32_t *val) { +Error MetalClawWriter::op(const char*, int32_t *val) { return appendInteger(*val); } -int MetalClawWriter::op(const char*, int64_t *val) { +Error MetalClawWriter::op(const char*, int64_t *val) { return appendInteger(*val); } -int MetalClawWriter::op(const char*, uint8_t *val) { +Error MetalClawWriter::op(const char*, uint8_t *val) { return appendInteger(*val); } -int MetalClawWriter::op(const char*, uint16_t *val) { +Error MetalClawWriter::op(const char*, uint16_t *val) { return appendInteger(*val); } -int MetalClawWriter::op(const char*, uint32_t *val) { +Error MetalClawWriter::op(const char*, uint32_t *val) { return appendInteger(*val); } -int MetalClawWriter::op(const char*, uint64_t *val) { +Error MetalClawWriter::op(const char*, uint64_t *val) { return appendInteger(*val); } -int MetalClawWriter::op(const char*, bool *val) { +Error MetalClawWriter::op(const char*, bool *val) { return m_fieldPresence.set(m_field++, *val); } +Error MetalClawWriter::op(const char*, McStr val) { + int err = 0; + bool fieldSet = false; + if (val.cap()) { + // write the length + typedef uint32_t StringLength; + if (m_buffIt + sizeof(StringLength) + val.bytes() < m_buffLen) { + *reinterpret_cast*>(&m_buff[m_buffIt]) = static_cast(val.bytes()); + m_buffIt += sizeof(StringLength); + + // write the string + ox_memcpy(&m_buff[m_buffIt], val.c_str(), val.bytes()); + m_buffIt += val.bytes(); + fieldSet = true; + } else { + err = MC_BUFFENDED; + } + } + err |= m_fieldPresence.set(m_field, fieldSet); + m_field++; + return err; +} + void MetalClawWriter::setTypeInfo(const char*, int fields) { m_fields = fields; m_buffIt = (fields / 8 + 1) - (fields % 8 == 0); diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index 9d28e389..25003c2a 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -15,6 +15,7 @@ #include "err.hpp" #include "optype.hpp" #include "presencemask.hpp" +#include "types.hpp" namespace ox { @@ -22,7 +23,6 @@ class MetalClawWriter { private: FieldPresenseMask m_fieldPresence; - const char *m_typeName = nullptr; int m_fields = 0; int m_field = 0; std::size_t m_buffIt = 0; @@ -34,29 +34,28 @@ class MetalClawWriter { ~MetalClawWriter() noexcept; - int op(const char*, int8_t *val); - int op(const char*, int16_t *val); - int op(const char*, int32_t *val); - int op(const char*, int64_t *val); + Error op(const char*, int8_t *val); + Error op(const char*, int16_t *val); + Error op(const char*, int32_t *val); + Error op(const char*, int64_t *val); - int op(const char*, uint8_t *val); - int op(const char*, uint16_t *val); - int op(const char*, uint32_t *val); - int op(const char*, uint64_t *val); + Error op(const char*, uint8_t *val); + Error op(const char*, uint16_t *val); + Error op(const char*, uint32_t *val); + Error op(const char*, uint64_t *val); - int op(const char*, bool *val); + Error op(const char*, bool *val); template - int op(const char*, T *val, std::size_t len); + Error op(const char*, T *val, std::size_t len); template - int op(const char*, ox::Vector *val); + Error op(const char*, ox::Vector *val); template - int op(const char*, const char *val); + Error op(const char*, ox::BString *val); - template - int op(const char*, ox::BString *val); + Error op(const char*, McStr val); template int op(const char*, T *val); @@ -65,37 +64,18 @@ class MetalClawWriter { std::size_t size(); - OpType opType() { + constexpr OpType opType() { return OpType::Write; } private: template - int appendInteger(I val); + Error appendInteger(I val); }; template -int MetalClawWriter::op(const char*, ox::BString *val) { - int err = 0; - bool fieldSet = false; - if (val->len()) { - // write the length - typedef uint32_t StringLength; - if (m_buffIt + sizeof(StringLength) + val->bytes() < m_buffLen) { - *reinterpret_cast*>(&m_buff[m_buffIt]) = static_cast(val->bytes()); - m_buffIt += sizeof(StringLength); - - // write the string - ox_memcpy(&m_buff[m_buffIt], val, val->bytes()); - m_buffIt += val->bytes(); - fieldSet = true; - } else { - err = MC_BUFFENDED; - } - } - err |= m_fieldPresence.set(m_field, fieldSet); - m_field++; - return err; +Error MetalClawWriter::op(const char *name, ox::BString *val) { + return op(name, McStr(val->data(), val->cap())); } template @@ -116,12 +96,12 @@ int MetalClawWriter::op(const char*, T *val) { } template -int MetalClawWriter::op(const char*, ox::Vector *val) { +Error MetalClawWriter::op(const char*, ox::Vector *val) { return op(nullptr, val->data(), val->size()); } template -int MetalClawWriter::appendInteger(I val) { +Error MetalClawWriter::appendInteger(I val) { int err = 0; bool fieldSet = false; if (val) { @@ -139,7 +119,7 @@ int MetalClawWriter::appendInteger(I val) { } template -int MetalClawWriter::op(const char*, T *val, std::size_t len) { +Error MetalClawWriter::op(const char*, T *val, std::size_t len) { int err = 0; bool fieldSet = false; @@ -171,7 +151,7 @@ int MetalClawWriter::op(const char*, T *val, std::size_t len) { } template -int writeMC(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) { +Error writeMC(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) { MetalClawWriter writer(buff, buffLen); auto err = ioOp(&writer, val); if (sizeOut) {