From cd91f6b60a5cbb62ba3d4f86ce8866e44657f03d Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Thu, 7 Mar 2019 06:05:08 -0600 Subject: [PATCH] [ox/mc] Add basic walking of data by data descriptor --- deps/ox/src/ox/mc/defread.cpp | 20 ++++ deps/ox/src/ox/mc/defread.hpp | 34 +++++++ deps/ox/src/ox/mc/deftypes.cpp | 19 ++++ deps/ox/src/ox/mc/deftypes.hpp | 61 ++++++++++- deps/ox/src/ox/mc/defwriter.cpp | 22 +++- deps/ox/src/ox/mc/defwriter.hpp | 82 ++++++++++++--- deps/ox/src/ox/mc/read.cpp | 54 ++++++---- deps/ox/src/ox/mc/read.hpp | 92 ++++++++--------- deps/ox/src/ox/mc/test/tests.cpp | 168 +++++++++++++++++++++++++------ deps/ox/src/ox/mc/types.hpp | 17 +--- deps/ox/src/ox/mc/walker.hpp | 96 +++++++++++++----- deps/ox/src/ox/std/hashmap.hpp | 4 +- deps/ox/src/ox/std/string.hpp | 2 +- deps/ox/src/ox/std/utility.hpp | 20 ++++ deps/ox/src/ox/std/vector.hpp | 48 ++++++++- 15 files changed, 571 insertions(+), 168 deletions(-) create mode 100644 deps/ox/src/ox/mc/defread.cpp create mode 100644 deps/ox/src/ox/mc/defread.hpp create mode 100644 deps/ox/src/ox/mc/deftypes.cpp create mode 100644 deps/ox/src/ox/std/utility.hpp diff --git a/deps/ox/src/ox/mc/defread.cpp b/deps/ox/src/ox/mc/defread.cpp new file mode 100644 index 00000000..ecc75cc8 --- /dev/null +++ b/deps/ox/src/ox/mc/defread.cpp @@ -0,0 +1,20 @@ +/* + * Copyright 2015 - 2019 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/. + */ + +#include "defread.hpp" + +namespace ox::mc { + +MetalClawDefReader::MetalClawDefReader(uint8_t *buff, std::size_t buffLen): MetalClawReader(buff, buffLen) { +} + +const mc::TypeStore &MetalClawDefReader::typeStore() const { + return m_typeStore; +} + +} diff --git a/deps/ox/src/ox/mc/defread.hpp b/deps/ox/src/ox/mc/defread.hpp new file mode 100644 index 00000000..e4708a66 --- /dev/null +++ b/deps/ox/src/ox/mc/defread.hpp @@ -0,0 +1,34 @@ +/* + * 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 "deftypes.hpp" +#include "read.hpp" + +namespace ox::mc { + + +class MetalClawDefReader: public MetalClawReader { + private: + TypeStore m_typeStore; + + public: + MetalClawDefReader(uint8_t *buff, std::size_t buffLen); + + const mc::TypeStore &typeStore() const; + +}; + +template +int readMCDef(uint8_t *buff, std::size_t buffLen, T *val) { + MetalClawDefReader reader(buff, buffLen); + return ioOp(&reader, val); +} + +} diff --git a/deps/ox/src/ox/mc/deftypes.cpp b/deps/ox/src/ox/mc/deftypes.cpp new file mode 100644 index 00000000..734cf502 --- /dev/null +++ b/deps/ox/src/ox/mc/deftypes.cpp @@ -0,0 +1,19 @@ +/* + * 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/. + */ + +#include "deftypes.hpp" + +namespace ox::mc { + +Field::~Field() { + if (ownsType) { + delete type; + } +} + +} diff --git a/deps/ox/src/ox/mc/deftypes.hpp b/deps/ox/src/ox/mc/deftypes.hpp index cfe5084c..51226325 100644 --- a/deps/ox/src/ox/mc/deftypes.hpp +++ b/deps/ox/src/ox/mc/deftypes.hpp @@ -22,7 +22,7 @@ enum class PrimitiveType: uint8_t { UnsignedInteger = 0, SignedInteger = 1, Bool = 2, - Float = 3, + // Float = 3, reserved, but not implemented String = 4, Struct = 5, }; @@ -39,7 +39,59 @@ struct Field { TypeName typeName; // gives reference to type for lookup if type is null bool ownsType = false; + constexpr Field() noexcept = default; + + /** + * Allow for explicit copying. + */ + constexpr explicit Field(const Field &other) noexcept { + type = other.type; + fieldName = other.fieldName; + subscriptLevels = other.subscriptLevels; + typeName = other.typeName; + ownsType = false; // is copy, only owns type if move + } + + constexpr Field(const Type *type, const FieldName &fieldName, int subscriptLevels, const TypeName &typeName, bool ownsType) noexcept { + this->type = type; + this->fieldName = fieldName; + this->subscriptLevels = subscriptLevels; + this->typeName = typeName; + this->ownsType = ownsType; + } + + constexpr Field(Field &&other) noexcept { + type = other.type; + fieldName = other.fieldName; + subscriptLevels = other.subscriptLevels; + typeName = other.typeName; + ownsType = other.ownsType; + + other.type = {}; + other.fieldName = ""; + other.subscriptLevels = {}; + other.typeName = ""; + other.ownsType = {}; + } + ~Field(); + + constexpr const Field &operator=(Field &&other) noexcept { + type = other.type; + fieldName = other.fieldName; + subscriptLevels = other.subscriptLevels; + typeName = other.typeName; + ownsType = other.ownsType; + + other.type = {}; + other.fieldName = ""; + other.subscriptLevels = {}; + other.typeName = ""; + other.ownsType = {}; + + return *this; + } + }; using FieldList = Vector; @@ -86,8 +138,9 @@ int ioOpWrite(T *io, Field *field) { err |= io->op("type", static_casttype)>(nullptr)); } err |= io->op("fieldName", &field->fieldName); - // defaultValue is unused now, but placeholder for backwards compatibility - err |= io->op("defaultValue", nullptr); + // defaultValue is unused now, but leave placeholder for backwards compatibility + const int DefaultValue = 0; + err |= io->op("defaultValue", &DefaultValue); return err; } @@ -116,6 +169,6 @@ int ioOpRead(T *io, Field *field) { 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 593b3824..4a5e5c59 100644 --- a/deps/ox/src/ox/mc/defwriter.cpp +++ b/deps/ox/src/ox/mc/defwriter.cpp @@ -102,6 +102,12 @@ mc::Type *MetalClawDefWriter::type(uint64_t*, bool *alreadyExisted) { return getType(TypeName, PT, Bytes, alreadyExisted); } +mc::Type *MetalClawDefWriter::type(const char*, bool *alreadyExisted) { + constexpr auto TypeName = "B:string"; + constexpr auto PT = mc::PrimitiveType::String; + return getType(TypeName, PT, 0, alreadyExisted); +} + mc::Type *MetalClawDefWriter::type(McStr, bool *alreadyExisted) { constexpr auto TypeName = "B:string"; constexpr auto PT = mc::PrimitiveType::String; @@ -116,8 +122,11 @@ mc::Type *MetalClawDefWriter::type(bool*, bool *alreadyExisted) { } void MetalClawDefWriter::setTypeInfo(const char *name, int) { - m_typeAlreayExisted = m_typeStore->contains(name); - m_type = &m_typeStore->at(name); + auto &t = m_typeStore->at(name); + if (!t) { + t = new mc::Type; + } + m_type = t; m_type->typeName = name; m_type->primitiveType = mc::PrimitiveType::Struct; } @@ -125,10 +134,15 @@ void MetalClawDefWriter::setTypeInfo(const char *name, int) { mc::Type *MetalClawDefWriter::getType(mc::TypeName tn, mc::PrimitiveType pt, int b, bool *alreadyExisted) { if (m_typeStore->contains(tn)) { *alreadyExisted = true; - return &m_typeStore->at(tn); + auto type = m_typeStore->at(tn); + oxAssert(type != nullptr, "MetalClawDefWriter::getType returning null Type"); + return type; } else { *alreadyExisted = false; - auto t = &m_typeStore->at(tn); + auto &t = m_typeStore->at(tn); + if (!t) { + t = new mc::Type; + } t->typeName = tn; t->primitiveType = pt; t->length = b; diff --git a/deps/ox/src/ox/mc/defwriter.hpp b/deps/ox/src/ox/mc/defwriter.hpp index 16f131a8..d493816d 100644 --- a/deps/ox/src/ox/mc/defwriter.hpp +++ b/deps/ox/src/ox/mc/defwriter.hpp @@ -19,6 +19,7 @@ #include "err.hpp" #include "optype.hpp" #include "types.hpp" +#include "write.hpp" namespace ox { @@ -35,11 +36,29 @@ static constexpr int indirectionLevels(T *t) { class MetalClawDefWriter { private: + struct NameCatcher { + + mc::TypeName name; + + constexpr void setTypeInfo(const char *name, int) noexcept { + this->name = name; + } + + template + constexpr ox::Error op(const char*, T*, std::size_t) noexcept { + return OxError(0); + } + + template + constexpr ox::Error op(const char*, T*) noexcept { + return OxError(0); + } + + }; + mc::TypeStore *m_typeStoreOwnerRef = nullptr; mc::TypeStore *m_typeStore = nullptr; mc::Type *m_type = nullptr; - // indicates whether or not m_type already existed in the TypeStore - bool m_typeAlreayExisted = false; public: explicit MetalClawDefWriter(mc::TypeStore *typeStore = nullptr); @@ -61,9 +80,9 @@ class MetalClawDefWriter { return m_type; } - static constexpr OpType opType() { + static constexpr OpType opType() { return OpType::WriteDefinition; - } + } private: mc::Type *type(int8_t *val, bool *alreadyExisted); @@ -78,8 +97,13 @@ class MetalClawDefWriter { mc::Type *type(bool *val, bool *alreadyExisted); + mc::Type *type(const char *val, bool *alreadyExisted); + mc::Type *type(McStr val, bool *alreadyExisted); + template + mc::Type *type(BString *val, bool *alreadyExisted); + template mc::Type *type(T *val, bool *alreadyExisted); @@ -90,10 +114,14 @@ class MetalClawDefWriter { template ox::Error MetalClawDefWriter::op(const char *name, T *val, std::size_t) { if (m_type) { - constexpr typename RemoveIndirection::type *p = nullptr; + constexpr typename ox::remove_pointer::type *p = nullptr; bool alreadyExisted = false; const auto t = type(p, &alreadyExisted); - m_type->fieldList.push_back(mc::Field{t, name, indirectionLevels(val), alreadyExisted ? t->typeName : "", !alreadyExisted}); + oxAssert(t != nullptr, "op(const char *name, T *val, std::size_t): Type not found or generated"); + if (t == nullptr) { + type(p, &alreadyExisted); + } + m_type->fieldList.emplace_back(t, name, indirectionLevels(val), alreadyExisted ? t->typeName : "", !alreadyExisted); return OxError(0); } return OxError(1); @@ -109,25 +137,49 @@ ox::Error MetalClawDefWriter::op(const char *name, T *val) { if (m_type) { bool alreadyExisted = false; const auto t = type(val, &alreadyExisted); - m_type->fieldList.push_back(mc::Field{t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted}); + oxAssert(t != nullptr, "op(const char *name, T *val): Type not found or generated"); + m_type->fieldList.emplace_back(t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted); return OxError(0); } return OxError(1); } -template -mc::Type *MetalClawDefWriter::type(T *val, bool *alreadyExisted) { - MetalClawDefWriter dw(m_typeStore); - oxLogError(ioOp(&dw, val)); - *alreadyExisted = dw.m_typeAlreayExisted; - return dw.m_type; +template +mc::Type *MetalClawDefWriter::type(BString *val, bool *alreadyExisted) { + return type(McStr(val), alreadyExisted); } template -[[nodiscard]] ValErr writeMCDef(T *val) { +mc::Type *MetalClawDefWriter::type(T *val, bool *alreadyExisted) { + NameCatcher nc; + ioOp(&nc, val); + if (m_typeStore->contains(nc.name)) { + *alreadyExisted = true; + return m_typeStore->at(nc.name); + } else { + MetalClawDefWriter dw(m_typeStore); + oxLogError(ioOp(&dw, val)); + *alreadyExisted = false; + return dw.m_type; + } +} + +template +[[nodiscard]] ValErr buildMCDef(T *val) { MetalClawDefWriter writer; - ox::Error err = ioOp(&writer, val); + Error err = ioOp(&writer, val); return {writer.definition(), err}; } +template +Error writeMCDef(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) { + auto def = buildMCDef(val); + auto err = def.error; + if (!err) { + err |= writeMC(buff, buffLen, def.value, sizeOut); + } + delete def.value; + return err; +} + } diff --git a/deps/ox/src/ox/mc/read.cpp b/deps/ox/src/ox/mc/read.cpp index b401cc49..0773932e 100644 --- a/deps/ox/src/ox/mc/read.cpp +++ b/deps/ox/src/ox/mc/read.cpp @@ -14,95 +14,101 @@ namespace ox { -MetalClawReader::MetalClawReader(uint8_t *buff, std::size_t buffLen): m_fieldPresence(buff, buffLen) { +MetalClawReader::MetalClawReader(uint8_t *buff, std::size_t buffLen, MetalClawReader *parent): m_fieldPresence(buff, buffLen) { m_buff = buff; m_buffLen = buffLen; + m_parent = parent; } MetalClawReader::~MetalClawReader() { + if (m_parent) { + m_parent->m_buffIt += m_buffIt; + } oxAssert(m_field == m_fields, "MetalClawReader: incorrect fields number given"); } -int MetalClawReader::op(const char*, int8_t *val) { +Error MetalClawReader::op(const char*, int8_t *val) { return readInteger(val); } -int MetalClawReader::op(const char*, int16_t *val) { +Error MetalClawReader::op(const char*, int16_t *val) { return readInteger(val); } -int MetalClawReader::op(const char*, int32_t *val) { +Error MetalClawReader::op(const char*, int32_t *val) { return readInteger(val); } -int MetalClawReader::op(const char*, int64_t *val) { +Error MetalClawReader::op(const char*, int64_t *val) { return readInteger(val); } -int MetalClawReader::op(const char*, uint8_t *val) { +Error MetalClawReader::op(const char*, uint8_t *val) { return readInteger(val); } -int MetalClawReader::op(const char*, uint16_t *val) { +Error MetalClawReader::op(const char*, uint16_t *val) { return readInteger(val); } -int MetalClawReader::op(const char*, uint32_t *val) { +Error MetalClawReader::op(const char*, uint32_t *val) { return readInteger(val); } -int MetalClawReader::op(const char*, uint64_t *val) { +Error MetalClawReader::op(const char*, uint64_t *val) { return readInteger(val); } -int MetalClawReader::op(const char*, bool *val) { +Error MetalClawReader::op(const char*, bool *val) { *val = m_fieldPresence.get(m_field++); return 0; } Error MetalClawReader::op(const char*, McStr val) { - int err = 0; if (m_fieldPresence.get(m_field)) { // read the length - int size = 0; + StringLength size = 0; if (m_buffIt + sizeof(StringLength) < m_buffLen) { size = *reinterpret_cast*>(&m_buff[m_buffIt]); m_buffIt += sizeof(StringLength); } else { - err |= MC_BUFFENDED; + return OxError(MC_BUFFENDED); } // read the string - if (val.cap() >= size) { + if (val.cap() > -1 && static_cast(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; + return OxError(MC_BUFFENDED); } } else { - err |= MC_OUTBUFFENDED; + return OxError(MC_OUTBUFFENDED); } } else { val.data()[0] = 0; } m_field++; - return err; + return OxError(0); } -[[nodiscard]] std::size_t MetalClawReader::arrayLength() { +[[nodiscard]] ArrayLength MetalClawReader::arrayLength(bool pass) { std::size_t len = 0; if (m_fieldPresence.get(m_field)) { // read the length if (m_buffIt + sizeof(ArrayLength) < m_buffLen) { len = *reinterpret_cast*>(&m_buff[m_buffIt]); + if (pass) { + m_buffIt += sizeof(ArrayLength); + } } } return len; } -std::size_t MetalClawReader::stringLength(const char*) { +[[nodiscard]] StringLength MetalClawReader::stringLength() { std::size_t len = 0; if (m_fieldPresence.get(m_field)) { // read the length @@ -121,15 +127,19 @@ void MetalClawReader::setTypeInfo(const char*, int fields) { } MetalClawReader MetalClawReader::child() { - return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt); + return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, this); } -bool MetalClawReader::fieldPresent() { +bool MetalClawReader::fieldPresent() const { return m_fieldPresence.get(m_field); } -bool MetalClawReader::fieldPresent(int fieldNo) { +bool MetalClawReader::fieldPresent(int fieldNo) const { return m_fieldPresence.get(fieldNo); } +void MetalClawReader::nextField() noexcept { + ++m_field; +} + } diff --git a/deps/ox/src/ox/mc/read.hpp b/deps/ox/src/ox/mc/read.hpp index 41dc2d73..76e82890 100644 --- a/deps/ox/src/ox/mc/read.hpp +++ b/deps/ox/src/ox/mc/read.hpp @@ -28,69 +28,69 @@ class MetalClawReader { std::size_t m_buffIt = 0; std::size_t m_buffLen = 0; uint8_t *m_buff = nullptr; + MetalClawReader *m_parent = nullptr; public: - MetalClawReader(uint8_t *buff, std::size_t buffLen); + MetalClawReader(uint8_t *buff, std::size_t buffLen, MetalClawReader *parent = nullptr); ~MetalClawReader(); - 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); - /** - * Reads an array length from the current location in the buffer. - */ - [[nodiscard]] std::size_t arrayLength(); + // array handler + template + Error op(const char*, T *val, std::size_t len); template - int op(const char*, T *val, std::size_t len); + Error op(const char*, ox::Vector *val); template - int op(const char*, ox::Vector *val); - - template - int op(const char*, T *val); + Error op(const char*, T *val); template - int op(const char*, ox::BString *val); + Error op(const char*, ox::BString *val); Error op(const char*, McStr val); - std::size_t arrayLength(const char*); + /** + * Reads an array length from the current location in the buffer. + * @param pass indicates that the parsing should iterate past the array length + */ + [[nodiscard]] ArrayLength arrayLength(bool pass = true); - // stringLength returns the length of the string, including the null terminator. - std::size_t stringLength(const char*); + /** + * Reads an string length from the current location in the buffer. + */ + [[nodiscard]] StringLength stringLength(); void setTypeInfo(const char *name, int fields); /** * Returns a MetalClawReader to parse a child object. */ - MetalClawReader child(); + [[nodiscard]] MetalClawReader child(); /** * Indicates whether or not the next field to be read is present. */ - bool fieldPresent(); + bool fieldPresent() const; /** * Indicates whether or not the given field is present. */ - bool fieldPresent(int fieldNo); + bool fieldPresent(int fieldNo) const; - /** - * @return the number of fields in this struct or list - */ - bool fields(); + void nextField() noexcept; static constexpr OpType opType() { return OpType::Read; @@ -98,35 +98,35 @@ class MetalClawReader { private: template - int readInteger(I *val); + Error readInteger(I *val); + }; template -int MetalClawReader::op(const char*, T *val) { - int err = 0; +Error MetalClawReader::op(const char*, T *val) { + Error err = 0; if (val && m_fieldPresence.get(m_field)) { - MetalClawReader reader(m_buff + m_buffIt, m_buffLen - m_buffIt); + auto reader = child(); err |= ioOp(&reader, val); - m_buffIt += reader.m_buffIt; } m_field++; return err; }; template -int MetalClawReader::op(const char *name, ox::BString *val) { +Error MetalClawReader::op(const char *name, ox::BString *val) { return op(name, McStr(val->data(), val->cap())); } template -int MetalClawReader::readInteger(I *val) { - int err = 0; +Error MetalClawReader::readInteger(I *val) { + Error err = 0; if (m_fieldPresence.get(m_field)) { if (m_buffIt + sizeof(I) < m_buffLen) { *val = *reinterpret_cast*>(&m_buff[m_buffIt]); m_buffIt += sizeof(I); } else { - err = MC_BUFFENDED; + err = OxError(MC_BUFFENDED); } } else { *val = 0; @@ -135,17 +135,18 @@ int MetalClawReader::readInteger(I *val) { return err; }; +// array handler template -int MetalClawReader::op(const char*, T *val, std::size_t valLen) { - int err = 0; +Error MetalClawReader::op(const char*, T *val, std::size_t valLen) { + Error err = 0; if (m_fieldPresence.get(m_field)) { // read the length - std::size_t len = 0; + ArrayLength len = 0; if (m_buffIt + sizeof(ArrayLength) < m_buffLen) { len = *reinterpret_cast*>(&m_buff[m_buffIt]); m_buffIt += sizeof(ArrayLength); } else { - err = MC_BUFFENDED; + err = OxError(MC_BUFFENDED); } // read the list @@ -155,9 +156,8 @@ int MetalClawReader::op(const char*, T *val, std::size_t valLen) { for (std::size_t i = 0; i < len; i++) { err |= reader.op("", &val[i]); } - m_buffIt += reader.m_buffIt; } else { - err = MC_OUTBUFFENDED; + err = OxError(MC_OUTBUFFENDED); } } m_field++; @@ -165,7 +165,7 @@ int MetalClawReader::op(const char*, T *val, std::size_t valLen) { }; template -int MetalClawReader::op(const char*, ox::Vector *val) { +Error MetalClawReader::op(const char*, ox::Vector *val) { return op(nullptr, val->data(), val->size()); } diff --git a/deps/ox/src/ox/mc/test/tests.cpp b/deps/ox/src/ox/mc/test/tests.cpp index e8c079ab..f729e06b 100644 --- a/deps/ox/src/ox/mc/test/tests.cpp +++ b/deps/ox/src/ox/mc/test/tests.cpp @@ -7,7 +7,9 @@ */ #include +#include #include +#include #include #include #include @@ -36,8 +38,8 @@ struct TestStruct { }; template -int ioOp(T *io, TestStructNest *obj) { - int32_t err = 0; +ox::Error ioOp(T *io, TestStructNest *obj) { + ox::Error err = 0; io->setTypeInfo("TestStructNest", 3); err |= io->op("Bool", &obj->Bool); err |= io->op("Int", &obj->Int); @@ -46,8 +48,8 @@ int ioOp(T *io, TestStructNest *obj) { } template -int ioOp(T *io, TestStruct *obj) { - int err = 0; +ox::Error ioOp(T *io, TestStruct *obj) { + ox::Error err = 0; io->setTypeInfo("TestStruct", 14); err |= io->op("Bool", &obj->Bool); err |= io->op("Int", &obj->Int); @@ -86,7 +88,6 @@ std::map tests = { { "MetalClawReader", [] { - ox::Error err = 0; constexpr size_t buffLen = 1024; uint8_t buff[buffLen]; TestStruct testIn, testOut; @@ -102,41 +103,144 @@ std::map tests = { testIn.Struct.Int = 300; testIn.Struct.String = "Test String 2"; - err |= ox::writeMC(buff, buffLen, &testIn); - err |= ox::readMC(buff, buffLen, &testOut); + oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed"); + oxAssert(ox::readMC(buff, buffLen, &testOut), "writeMC failed"); - err |= !(testIn.Bool == testOut.Bool); - err |= !(testIn.Int == testOut.Int); - err |= !(testIn.Int1 == testOut.Int1); - err |= !(testIn.Int2 == testOut.Int2); - err |= !(testIn.Int3 == testOut.Int3); - err |= !(testIn.Int4 == testOut.Int4); - err |= !(testIn.Int5 == testOut.Int5); - err |= !(testIn.Int6 == testOut.Int6); - err |= !(testIn.Int7 == testOut.Int7); - err |= !(testIn.Int8 == testOut.Int8); - err |= !(testIn.String == testOut.String); - err |= !(testIn.List[0] == testOut.List[0]); - err |= !(testIn.List[1] == testOut.List[1]); - err |= !(testIn.List[2] == testOut.List[2]); - err |= !(testIn.List[3] == testOut.List[3]); - err |= !(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool); - err |= !(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int); - err |= !(testIn.EmptyStruct.String == testOut.EmptyStruct.String); - err |= !(testIn.Struct.Int == testOut.Struct.Int); - err |= !(testIn.Struct.String == testOut.Struct.String); - err |= !(testIn.Struct.Bool == testOut.Struct.Bool); + oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); + oxAssert(testIn.Int == testOut.Int, "Int value mismatch"); + oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch"); + oxAssert(testIn.Int2 == testOut.Int2, "Int2 value mismatch"); + oxAssert(testIn.Int3 == testOut.Int3, "Int3 value mismatch"); + oxAssert(testIn.Int4 == testOut.Int4, "Int4 value mismatch"); + oxAssert(testIn.Int5 == testOut.Int5, "Int5 value mismatch"); + oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch"); + oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch"); + oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch"); + oxAssert(testIn.String == testOut.String, "String value mismatch"); + oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch"); + oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch"); + oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch"); + oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch"); + oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch"); + oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch"); + oxAssert(testIn.EmptyStruct.String == testOut.EmptyStruct.String, "EmptyStruct.String value mismatch"); + oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch"); + oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch"); + oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch"); - auto def = ox::writeMCDef(&testIn); - err |= def.error; - - return err; + return OxError(0); } }, { "MetalClawDef", [] { ox::Error err = 0; + //constexpr size_t descBuffLen = 1024; + //uint8_t descBuff[descBuffLen]; + constexpr size_t dataBuffLen = 1024; + uint8_t dataBuff[dataBuffLen]; + TestStruct testIn, testOut; + + testIn.Bool = true; + testIn.Int = 42; + testIn.String = "Test String 1"; + testIn.List[0] = 1; + testIn.List[1] = 2; + testIn.List[2] = 3; + testIn.List[3] = 4; + testIn.Struct.Bool = false; + testIn.Struct.Int = 300; + testIn.Struct.String = "Test String 2"; + + oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed"); + auto type = ox::buildMCDef(&testIn); + oxAssert(type.error, "Descriptor write failed"); + ox::walkMC(type.value, dataBuff, dataBuffLen, + [](const ox::Vector&, const ox::Vector&, const ox::mc::Field &f, ox::MetalClawReader *rdr) -> ox::Error { + //std::cout << f.fieldName.c_str() << '\n'; + auto fieldName = f.fieldName.c_str(); + switch (f.type->primitiveType) { + case ox::mc::PrimitiveType::UnsignedInteger: + std::cout << fieldName << ":\tuint" << f.type->length << "_t:\t"; + switch (f.type->length) { + case 8: { + uint8_t i = {}; + oxAssert(rdr->op(fieldName, &i), "Walking ioOp failed."); + std::cout << i; + break; + } + case 16: { + uint16_t i = {}; + oxAssert(rdr->op(fieldName, &i), "Walking ioOp failed."); + std::cout << i; + break; + } + case 32: { + uint32_t i = {}; + oxAssert(rdr->op(fieldName, &i), "Walking ioOp failed."); + std::cout << i; + break; + } + case 64: { + uint64_t i = {}; + oxAssert(rdr->op(fieldName, &i), "Walking ioOp failed."); + std::cout << i; + break; + } + } + std::cout << '\n'; + break; + case ox::mc::PrimitiveType::SignedInteger: + std::cout << fieldName << ":\tint" << f.type->length << "_t:\t"; + switch (f.type->length) { + case 8: { + int8_t i = {}; + oxAssert(rdr->op(fieldName, &i), "Walking ioOp failed."); + std::cout << i; + break; + } + case 16: { + int16_t i = {}; + oxAssert(rdr->op(fieldName, &i), "Walking ioOp failed."); + std::cout << i; + break; + } + case 32: { + int32_t i = {}; + oxAssert(rdr->op(fieldName, &i), "Walking ioOp failed."); + std::cout << i; + break; + } + case 64: { + int64_t i = {}; + oxAssert(rdr->op(fieldName, &i), "Walking ioOp failed."); + std::cout << i; + break; + } + } + std::cout << '\n'; + break; + case ox::mc::PrimitiveType::Bool: { + bool i = {}; + oxAssert(rdr->op(fieldName, &i), "Walking ioOp failed."); + std::cout << fieldName << ":\t" << "bool:\t" << (i ? "true" : "false") << '\n'; + break; + } + case ox::mc::PrimitiveType::String: { + ox::Vector v(rdr->stringLength()); + //std::cout << rdr->stringLength() << '\n'; + oxAssert(rdr->op(fieldName, ox::McStr(v.data(), v.size())), "Walking ioOp failed."); + std::cout << fieldName << ":\t" << "string: " << v.data() << '\n'; + break; + } + case ox::mc::PrimitiveType::Struct: + break; + } + return OxError(0); + } + ); + delete type.value; + return err; } }, diff --git a/deps/ox/src/ox/mc/types.hpp b/deps/ox/src/ox/mc/types.hpp index c5e9d5f0..31b66cd6 100644 --- a/deps/ox/src/ox/mc/types.hpp +++ b/deps/ox/src/ox/mc/types.hpp @@ -20,19 +20,14 @@ using ArrayLength = uint32_t; class McStr { protected: - int m_cap = -1; + int m_cap = 0; char *m_str = nullptr; public: - explicit constexpr McStr(const char *str) noexcept { - m_str = const_cast(str); - m_cap = -1; - } - template constexpr McStr(BString *str) noexcept { - m_str = const_cast(str->data()); - m_cap = -1; + m_str = str->data(); + m_cap = str->cap(); } constexpr McStr(char *str, int cap) noexcept { @@ -46,11 +41,7 @@ class McStr { 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; - } + return m_str; } constexpr int len() noexcept { diff --git a/deps/ox/src/ox/mc/walker.hpp b/deps/ox/src/ox/mc/walker.hpp index 1ff945f8..dc5954aa 100644 --- a/deps/ox/src/ox/mc/walker.hpp +++ b/deps/ox/src/ox/mc/walker.hpp @@ -20,97 +20,141 @@ class MetalClawWalker { template friend ox::Error ioOp(class MetalClawReader*, MetalClawWalker*); + template + friend ox::Error parseField(const mc::Field &field, MetalClawReader *rdr, MetalClawWalker *walker); + private: - mc::Type *m_type = nullptr; - T *m_fieldHandler = nullptr; + Vector m_typeStack; + T m_fieldHandler; Vector m_path; Vector m_typePath; public: - MetalClawWalker(T *fieldHandler); + MetalClawWalker(mc::Type *type, T fieldHandler); [[nodiscard]] const mc::Type *type() const noexcept; - void read(const mc::Field&, MetalClawReader *rdr); + ox::Error read(const mc::Field&, MetalClawReader *rdr); protected: void pushNamePath(mc::FieldName fn); void popNamePath(); + void pushType(const mc::Type *type); + + void popType(); + }; template -MetalClawWalker::MetalClawWalker(T *fieldHandler) { - m_fieldHandler = fieldHandler; +MetalClawWalker::MetalClawWalker(mc::Type *type, T fieldHandler): m_fieldHandler(fieldHandler) { + m_typeStack.push_back(type); } template const mc::Type *MetalClawWalker::type() const noexcept { - return m_type; + return m_typeStack.back(); } template -void MetalClawWalker::read(const mc::Field &f, MetalClawReader *rdr) { +ox::Error MetalClawWalker::read(const mc::Field &f, MetalClawReader *rdr) { + // get const ref of paths const auto &pathCr = m_path; - m_fieldHandler->read(pathCr, f, rdr); + const auto &typePathCr = m_typePath; + return m_fieldHandler(pathCr, typePathCr, f, rdr); +} + +template +void MetalClawWalker::pushNamePath(mc::FieldName fn) { + m_path.push_back(fn); +} + +template +void MetalClawWalker::popNamePath() { + m_path.pop_back(); +} + +template +void MetalClawWalker::pushType(const mc::Type *type) { + m_typeStack.push_back(type); +} + +template +void MetalClawWalker::popType() { + m_typeStack.pop_back(); } template -static ox::Error parseField(mc::Field field, MetalClawReader *rdr, MetalClawWalker *walker) { - ox::Error err = 0; +static ox::Error parseField(const mc::Field &field, MetalClawReader *rdr, MetalClawWalker *walker) { walker->pushNamePath(field.fieldName); if (field.subscriptLevels) { // add array handling + const auto arrayLen = rdr->arrayLength(true); auto child = rdr->child(); - const auto arrayLen = rdr->arrayLength(); - auto f = field; + child.setTypeInfo(field.fieldName.c_str(), arrayLen); + mc::Field f(field); // create mutable copy --f.subscriptLevels; - rdr->setTypeInfo(field.type->typeName.c_str(), arrayLen); BString<100> subscript; for (ArrayLength i = 0; i < arrayLen; i++) { subscript = "["; subscript += i; subscript += "]"; walker->pushNamePath(subscript); - err |= parseField(f, &child, walker); - walker->pophNamePath(); + oxReturnError(parseField(f, &child, walker)); + walker->popNamePath(); } + rdr->nextField(); } else { switch (field.type->primitiveType) { case mc::PrimitiveType::UnsignedInteger: case mc::PrimitiveType::SignedInteger: case mc::PrimitiveType::Bool: - case mc::PrimitiveType::Float: case mc::PrimitiveType::String: - err |= walker->read(field, rdr); + oxReturnError(walker->read(field, rdr)); break; case mc::PrimitiveType::Struct: if (rdr->fieldPresent()) { auto child = rdr->child(); - rdr->setTypeInfo(field.type->typeName.c_str(), field.type->fieldList.size()); - err |= ioOp(&child, walker); + walker->pushType(field.type); + oxReturnError(ioOp(&child, walker)); + walker->popType(); + rdr->nextField(); } else { // skip and discard absent field int discard; - err |= rdr->op("", &discard); + oxReturnError(rdr->op("", &discard)); } break; } } walker->popNamePath(); - return err; + return OxError(0); } template ox::Error ioOp(MetalClawReader *rdr, MetalClawWalker *walker) { - Error err = 0; - auto &fields = walker->type()->fieldList; + auto type = walker->type(); + if (!type) { + return OxError(1); + } + auto typeName = type->typeName.c_str(); + auto &fields = type->fieldList; + rdr->setTypeInfo(typeName, fields.size()); for (std::size_t i = 0; i < fields.size(); i++) { auto &field = fields[i]; - parseField(field, rdr, walker); + if (field.type->primitiveType == mc::PrimitiveType::Struct) { + } + oxReturnError(parseField(field, rdr, walker)); } - return OxError(err); + return OxError(0); +} + +template +ox::Error walkMC(mc::Type *type, uint8_t *data, std::size_t dataLen, Handler handler) { + MetalClawWalker walker(type, handler); + MetalClawReader rdr(data, dataLen); + return ioOp(&rdr, &walker); } } diff --git a/deps/ox/src/ox/std/hashmap.hpp b/deps/ox/src/ox/std/hashmap.hpp index 514a4338..12d0de5a 100644 --- a/deps/ox/src/ox/std/hashmap.hpp +++ b/deps/ox/src/ox/std/hashmap.hpp @@ -18,8 +18,8 @@ class HashMap { private: struct Pair { - K key; - T value; + K key = {}; + T value = {}; }; Vector m_keys; Vector m_pairs; diff --git a/deps/ox/src/ox/std/string.hpp b/deps/ox/src/ox/std/string.hpp index c4cf90dc..4f6c4397 100644 --- a/deps/ox/src/ox/std/string.hpp +++ b/deps/ox/src/ox/std/string.hpp @@ -10,7 +10,7 @@ #include "memops.hpp" #include "strops.hpp" -#include "types.hpp" +#include "typetraits.hpp" namespace ox { diff --git a/deps/ox/src/ox/std/utility.hpp b/deps/ox/src/ox/std/utility.hpp new file mode 100644 index 00000000..d6b01a72 --- /dev/null +++ b/deps/ox/src/ox/std/utility.hpp @@ -0,0 +1,20 @@ +/* + * Copyright 2015 - 2019 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 "typetraits.hpp" + +namespace ox { + +template +constexpr typename ox::remove_reference::type &&move(T &&t) noexcept { + return static_cast::type&&>(t); +} + +} diff --git a/deps/ox/src/ox/std/vector.hpp b/deps/ox/src/ox/std/vector.hpp index e604fd79..8389ca51 100644 --- a/deps/ox/src/ox/std/vector.hpp +++ b/deps/ox/src/ox/std/vector.hpp @@ -9,6 +9,7 @@ #pragma once #include "types.hpp" +#include "utility.hpp" namespace ox { @@ -39,6 +40,14 @@ class Vector { const T &operator[](std::size_t i) const noexcept; + T &front() noexcept; + + const T &front() const noexcept; + + T &back() noexcept; + + const T &back() const noexcept; + std::size_t size() const noexcept; void resize(std::size_t size) noexcept; @@ -47,6 +56,9 @@ class Vector { bool contains(T) const noexcept; + template + void emplace_back(Args&&... args) noexcept; + void push_back(const T &item) noexcept; void pop_back() noexcept; @@ -85,7 +97,7 @@ Vector::Vector(Vector &other) noexcept { m_cap = other.m_cap; m_items = new T[m_cap]; for (std::size_t i = 0; i < m_size; i++) { - m_items[i] = other.m_items[i]; + m_items[i] = ox::move(other.m_items[i]); } } @@ -139,6 +151,26 @@ const T &Vector::operator[](std::size_t i) const noexcept { return m_items[i]; } +template +T &Vector::front() noexcept { + return m_items[0]; +} + +template +const T &Vector::front() const noexcept { + return m_items[0]; +} + +template +T &Vector::back() noexcept { + return m_items[m_size - 1]; +} + +template +const T &Vector::back() const noexcept { + return m_items[m_size - 1]; +} + template std::size_t Vector::size() const noexcept { return m_size; @@ -170,6 +202,16 @@ bool Vector::contains(T v) const noexcept { return false; } +template +template +void Vector::emplace_back(Args&&... args) noexcept { + if (m_size == m_cap) { + expandCap(m_cap ? m_cap * 2 : 100); + } + new (&m_items[m_size]) T{args...}; + ++m_size; +} + template void Vector::push_back(const T &item) noexcept { if (m_size == m_cap) { @@ -206,10 +248,10 @@ void Vector::expandCap(std::size_t cap) noexcept { if (oldItems) { // move over old items const auto itRange = cap > m_size ? m_size : cap; for (std::size_t i = 0; i < itRange; i++) { - m_items[i] = oldItems[i]; + m_items[i] = ox::move(oldItems[i]); } for (std::size_t i = itRange; i < m_cap; i++) { - m_items[i] = T(); + new (&m_items[i]) T; } delete[] oldItems; }