diff --git a/deps/ox/src/ox/mc/CMakeLists.txt b/deps/ox/src/ox/mc/CMakeLists.txt index 7aff415d..2824b974 100644 --- a/deps/ox/src/ox/mc/CMakeLists.txt +++ b/deps/ox/src/ox/mc/CMakeLists.txt @@ -3,6 +3,7 @@ add_library( defwriter.cpp presencemask.cpp read.cpp + walker.cpp write.cpp ) @@ -27,6 +28,7 @@ install( presencemask.hpp read.hpp types.hpp + walker.cpp write.hpp DESTINATION include/ox/mc diff --git a/deps/ox/src/ox/mc/deftypes.hpp b/deps/ox/src/ox/mc/deftypes.hpp index 40e50431..be7ecb17 100644 --- a/deps/ox/src/ox/mc/deftypes.hpp +++ b/deps/ox/src/ox/mc/deftypes.hpp @@ -22,26 +22,29 @@ enum class PrimitiveType: uint8_t { Bool = 2, Float = 3, String = 4, - List = 5, - Struct = 6, + Struct = 5, }; +using FieldName = String; + struct Field { // order of fields matters // only serialize type name if type has already been serialized const struct Type *type = nullptr; - String fieldName; + FieldName fieldName; int subscriptLevels = 0; // do not serialize the following + String typeName; // gives reference to type for lookup if type is null bool serializeType = false; }; using FieldList = Vector; +using TypeName = String; struct Type { - String typeName; + TypeName typeName; PrimitiveType primitiveType; // fieldList only applies to structs Vector fieldList; @@ -59,23 +62,6 @@ struct Type { }; -template -int ioOp(T *io, Field *field) { - int32_t err = 0; - io->setTypeInfo("ox::mc::Field", 5); - if (field->serializeType) { - err |= io->op("typeName", ""); - err |= io->op("type", &field->type); - } else { - err |= io->op("typeName", &field->type->typeName); - 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); - return err; -} - template int ioOp(T *io, Type *type) { int32_t err = 0; @@ -87,6 +73,45 @@ int ioOp(T *io, Type *type) { return err; } +template +int ioOpWrite(T *io, Field *field) { + int32_t err = 0; + io->setTypeInfo("ox::mc::Field", 4); + if (field->serializeType) { + err |= io->op("typeName", ""); + err |= io->op("type", field->type); + } else { + err |= io->op("typeName", &field->type->typeName); + 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); + return err; +} + +template +int ioOpRead(T *io, Field *field) { + int32_t err = 0; + io->setTypeInfo("ox::mc::Field", 4); + err |= io->op("typeName", &field->typeName); + if (field->typeName == "") { + field->serializeType = true; + if (field->type == nullptr) { + field->type = new Type; + } + err |= io->op("type", field->type); + } else { + // should be empty, so discard + Type t; + err |= io->op("type", &t); + } + err |= io->op("fieldName", &field->fieldName); + // defaultValue is unused now, but placeholder for backwards compatibility + err |= io->op("defaultValue", nullptr); + return err; +} + using TypeStore = ox::HashMap; } diff --git a/deps/ox/src/ox/mc/defwriter.cpp b/deps/ox/src/ox/mc/defwriter.cpp index ae3ba90b..a9698292 100644 --- a/deps/ox/src/ox/mc/defwriter.cpp +++ b/deps/ox/src/ox/mc/defwriter.cpp @@ -21,9 +21,7 @@ MetalClawDefWriter::MetalClawDefWriter(mc::TypeStore *typeStore) { } MetalClawDefWriter::~MetalClawDefWriter() { - if (m_typeStoreOwnerRef) { - delete m_typeStoreOwnerRef; - } + delete m_typeStoreOwnerRef; } constexpr mc::Type *MetalClawDefWriter::type(int8_t*, bool *alreadyExisted) { @@ -96,6 +94,7 @@ constexpr mc::Type *MetalClawDefWriter::type(bool*, bool *alreadyExisted) { } constexpr void MetalClawDefWriter::setTypeInfo(const char *name, int) { + m_typeAlreayExisted = m_typeStore->contains(name); m_type = &m_typeStore->at(name); m_type->typeName = name; m_type->primitiveType = mc::PrimitiveType::Struct; diff --git a/deps/ox/src/ox/mc/defwriter.hpp b/deps/ox/src/ox/mc/defwriter.hpp index e0835462..45682a1b 100644 --- a/deps/ox/src/ox/mc/defwriter.hpp +++ b/deps/ox/src/ox/mc/defwriter.hpp @@ -80,7 +80,7 @@ class MetalClawDefWriter { constexpr void setTypeInfo(const char *name, int fields); - constexpr OpType opType() { + static constexpr OpType opType() { return OpType::WriteDefinition; } diff --git a/deps/ox/src/ox/mc/mc.hpp b/deps/ox/src/ox/mc/mc.hpp index 7d1c88ab..7b24c350 100644 --- a/deps/ox/src/ox/mc/mc.hpp +++ b/deps/ox/src/ox/mc/mc.hpp @@ -12,4 +12,5 @@ #include "defwriter.hpp" #include "read.hpp" #include "types.hpp" +#include "walker.hpp" #include "write.hpp" diff --git a/deps/ox/src/ox/mc/optype.hpp b/deps/ox/src/ox/mc/optype.hpp index f6cac4c5..19ec49df 100644 --- a/deps/ox/src/ox/mc/optype.hpp +++ b/deps/ox/src/ox/mc/optype.hpp @@ -8,7 +8,7 @@ #pragma once -#include "ox/std/error.hpp" +#include namespace ox { @@ -18,13 +18,33 @@ enum class OpType { WriteDefinition = 3, }; +// empty default implementations of ioOp functions + +template +ox::Error ioOpRead(T*, O*) { + return OxError(1); +} + +template +ox::Error ioOpWrite(T*, O*) { + return OxError(1); +} + +template +ox::Error ioOpWriteDefinition(T*, O*) { + return OxError(1); +} + template ox::Error ioOp(T *io, O *obj) { - if (io->opType() == ox::OpType::Read) { + if constexpr (T::opType() == ox::OpType::Read) { return ioOpRead(io, obj); - } else { + } else if constexpr (T::opType() == ox::OpType::Write) { return ioOpWrite(io, obj); + } else if constexpr (T::opType() == ox::OpType::WriteDefinition) { + return ioOpWriteDefinition(io, obj); } + return OxError(1); } } diff --git a/deps/ox/src/ox/mc/presencemask.cpp b/deps/ox/src/ox/mc/presencemask.cpp index 006a21b2..106b7db5 100644 --- a/deps/ox/src/ox/mc/presencemask.cpp +++ b/deps/ox/src/ox/mc/presencemask.cpp @@ -14,11 +14,11 @@ namespace ox { FieldPresenseMask::FieldPresenseMask(uint8_t *mask, std::size_t maxLen) { m_mask = mask; - m_maxLen = maxLen; + m_maskLen = maxLen; } bool FieldPresenseMask::get(int i) { - if (i / 8 < m_maxLen) { + if (i / 8 < m_maskLen) { return (m_mask[i / 8] >> (i % 8)) & 1; } else { return MC_PRESENCEMASKOUTBOUNDS; @@ -26,7 +26,7 @@ bool FieldPresenseMask::get(int i) { } int FieldPresenseMask::set(int i, bool on) { - if (i / 8 < m_maxLen) { + if (i / 8 < m_maskLen) { if (on) { m_mask[i / 8] |= 1 << (i % 8); } else { @@ -38,12 +38,4 @@ int FieldPresenseMask::set(int i, bool on) { } } -void FieldPresenseMask::setMaxLen(int maxLen) { - m_maxLen = maxLen; -} - -int FieldPresenseMask::getMaxLen() { - return m_maxLen; -} - } diff --git a/deps/ox/src/ox/mc/presencemask.hpp b/deps/ox/src/ox/mc/presencemask.hpp index 3da1627e..9d411a2e 100644 --- a/deps/ox/src/ox/mc/presencemask.hpp +++ b/deps/ox/src/ox/mc/presencemask.hpp @@ -14,8 +14,9 @@ namespace ox { class FieldPresenseMask { private: - uint8_t *m_mask; - int m_maxLen = 0; + uint8_t *m_mask = nullptr; + int m_maskLen = 0; + int m_fields = 0; public: FieldPresenseMask(uint8_t *mask, std::size_t maxLen); @@ -24,9 +25,30 @@ class FieldPresenseMask { int set(int i, bool on); - void setMaxLen(int); + constexpr void setFields(int) noexcept; + + constexpr int getFields() noexcept; + + constexpr void setMaxLen(int) noexcept; + + constexpr int getMaxLen() noexcept; - int getMaxLen(); }; +constexpr void FieldPresenseMask::setFields(int fields) noexcept { + m_fields = fields; +} + +constexpr int FieldPresenseMask::getFields() noexcept { + return m_fields; +} + +constexpr void FieldPresenseMask::setMaxLen(int maxLen) noexcept { + m_maskLen = maxLen; +} + +constexpr int FieldPresenseMask::getMaxLen() noexcept { + return m_maskLen; +} + } diff --git a/deps/ox/src/ox/mc/read.cpp b/deps/ox/src/ox/mc/read.cpp index 3a3dcc31..b401cc49 100644 --- a/deps/ox/src/ox/mc/read.cpp +++ b/deps/ox/src/ox/mc/read.cpp @@ -91,7 +91,7 @@ Error MetalClawReader::op(const char*, McStr val) { return err; } -std::size_t MetalClawReader::arrayLength(const char*) { +[[nodiscard]] std::size_t MetalClawReader::arrayLength() { std::size_t len = 0; if (m_fieldPresence.get(m_field)) { // read the length @@ -116,6 +116,7 @@ std::size_t MetalClawReader::stringLength(const char*) { void MetalClawReader::setTypeInfo(const char*, int fields) { m_fields = fields; m_buffIt = (fields / 8 + 1) - (fields % 8 == 0); + m_fieldPresence.setFields(fields); m_fieldPresence.setMaxLen(m_buffIt); } diff --git a/deps/ox/src/ox/mc/read.hpp b/deps/ox/src/ox/mc/read.hpp index 0b12134c..41dc2d73 100644 --- a/deps/ox/src/ox/mc/read.hpp +++ b/deps/ox/src/ox/mc/read.hpp @@ -46,6 +46,11 @@ class MetalClawReader { int op(const char*, bool *val); + /** + * Reads an array length from the current location in the buffer. + */ + [[nodiscard]] std::size_t arrayLength(); + template int op(const char*, T *val, std::size_t len); @@ -87,9 +92,9 @@ class MetalClawReader { */ bool fields(); - static constexpr OpType opType() { - return OpType::Read; - } + static constexpr OpType opType() { + return OpType::Read; + } private: template diff --git a/deps/ox/src/ox/mc/test/CMakeLists.txt b/deps/ox/src/ox/mc/test/CMakeLists.txt index ca5a06fd..a4b1e270 100644 --- a/deps/ox/src/ox/mc/test/CMakeLists.txt +++ b/deps/ox/src/ox/mc/test/CMakeLists.txt @@ -1,5 +1,3 @@ -cmake_minimum_required(VERSION 2.8) - add_executable( McTest tests.cpp diff --git a/deps/ox/src/ox/mc/walker.hpp b/deps/ox/src/ox/mc/walker.hpp new file mode 100644 index 00000000..1ff945f8 --- /dev/null +++ b/deps/ox/src/ox/mc/walker.hpp @@ -0,0 +1,116 @@ +/* + * 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 "deftypes.hpp" +#include "read.hpp" + +namespace ox { + +template +class MetalClawWalker { + template + friend ox::Error ioOp(class MetalClawReader*, MetalClawWalker*); + + private: + mc::Type *m_type = nullptr; + T *m_fieldHandler = nullptr; + Vector m_path; + Vector m_typePath; + + public: + MetalClawWalker(T *fieldHandler); + + [[nodiscard]] const mc::Type *type() const noexcept; + + void read(const mc::Field&, MetalClawReader *rdr); + + protected: + void pushNamePath(mc::FieldName fn); + + void popNamePath(); + +}; + +template +MetalClawWalker::MetalClawWalker(T *fieldHandler) { + m_fieldHandler = fieldHandler; +} + +template +const mc::Type *MetalClawWalker::type() const noexcept { + return m_type; +} + +template +void MetalClawWalker::read(const mc::Field &f, MetalClawReader *rdr) { + const auto &pathCr = m_path; + m_fieldHandler->read(pathCr, f, rdr); +} + +template +static ox::Error parseField(mc::Field field, MetalClawReader *rdr, MetalClawWalker *walker) { + ox::Error err = 0; + walker->pushNamePath(field.fieldName); + if (field.subscriptLevels) { + // add array handling + auto child = rdr->child(); + const auto arrayLen = rdr->arrayLength(); + auto f = field; + --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(); + } + } 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); + 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); + } else { + // skip and discard absent field + int discard; + err |= rdr->op("", &discard); + } + break; + } + } + walker->popNamePath(); + return err; +} + +template +ox::Error ioOp(MetalClawReader *rdr, MetalClawWalker *walker) { + Error err = 0; + auto &fields = walker->type()->fieldList; + for (std::size_t i = 0; i < fields.size(); i++) { + auto &field = fields[i]; + parseField(field, rdr, walker); + } + return OxError(err); +} + +} diff --git a/deps/ox/src/ox/mc/write.cpp b/deps/ox/src/ox/mc/write.cpp index 8ae92f8f..6a3cbcdd 100644 --- a/deps/ox/src/ox/mc/write.cpp +++ b/deps/ox/src/ox/mc/write.cpp @@ -85,6 +85,7 @@ Error MetalClawWriter::op(const char*, McStr val) { void MetalClawWriter::setTypeInfo(const char*, int fields) { m_fields = fields; m_buffIt = (fields / 8 + 1) - (fields % 8 == 0); + m_fieldPresence.setFields(fields); m_fieldPresence.setMaxLen(m_buffIt); } diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index 84a4e47c..f1a059e3 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -65,9 +65,9 @@ class MetalClawWriter { std::size_t size(); - static constexpr OpType opType() { - return OpType::Write; - } + static constexpr OpType opType() { + return OpType::Write; + } private: template