[ox/mc] Add basic walking of data by data descriptor

This commit is contained in:
Gary Talent 2019-03-07 06:05:08 -06:00
parent 8b7db3d544
commit cd91f6b60a
15 changed files with 571 additions and 168 deletions

20
deps/ox/src/ox/mc/defread.cpp vendored Normal file
View File

@ -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;
}
}

34
deps/ox/src/ox/mc/defread.hpp vendored Normal file
View File

@ -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<typename T>
int readMCDef(uint8_t *buff, std::size_t buffLen, T *val) {
MetalClawDefReader reader(buff, buffLen);
return ioOp(&reader, val);
}
}

19
deps/ox/src/ox/mc/deftypes.cpp vendored Normal file
View File

@ -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;
}
}
}

View File

@ -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<Field>;
@ -86,8 +138,9 @@ int ioOpWrite(T *io, Field *field) {
err |= io->op("type", static_cast<decltype(field->type)>(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<mc::String, mc::Type>;
using TypeStore = ox::HashMap<mc::String, mc::Type*>;
}

View File

@ -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;

View File

@ -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<typename T>
constexpr ox::Error op(const char*, T*, std::size_t) noexcept {
return OxError(0);
}
template<typename T>
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<std::size_t sz>
mc::Type *type(BString<sz> *val, bool *alreadyExisted);
template<typename T>
mc::Type *type(T *val, bool *alreadyExisted);
@ -90,10 +114,14 @@ class MetalClawDefWriter {
template<typename T>
ox::Error MetalClawDefWriter::op(const char *name, T *val, std::size_t) {
if (m_type) {
constexpr typename RemoveIndirection<decltype(val)>::type *p = nullptr;
constexpr typename ox::remove_pointer<decltype(val)>::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<typename T>
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<std::size_t sz>
mc::Type *MetalClawDefWriter::type(BString<sz> *val, bool *alreadyExisted) {
return type(McStr(val), alreadyExisted);
}
template<typename T>
[[nodiscard]] ValErr<mc::Type*> 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<typename T>
[[nodiscard]] ValErr<mc::Type*> buildMCDef(T *val) {
MetalClawDefWriter writer;
ox::Error err = ioOp(&writer, val);
Error err = ioOp(&writer, val);
return {writer.definition(), err};
}
template<typename T>
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;
}
}

View File

@ -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<LittleEndian<StringLength>*>(&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<StringLength>(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<LittleEndian<ArrayLength>*>(&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;
}
}

View File

@ -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<typename T>
Error op(const char*, T *val, std::size_t len);
template<typename T>
int op(const char*, T *val, std::size_t len);
Error op(const char*, ox::Vector<T> *val);
template<typename T>
int op(const char*, ox::Vector<T> *val);
template<typename T>
int op(const char*, T *val);
Error op(const char*, T *val);
template<std::size_t L>
int op(const char*, ox::BString<L> *val);
Error op(const char*, ox::BString<L> *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<typename I>
int readInteger(I *val);
Error readInteger(I *val);
};
template<typename T>
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<std::size_t L>
int MetalClawReader::op(const char *name, ox::BString<L> *val) {
Error MetalClawReader::op(const char *name, ox::BString<L> *val) {
return op(name, McStr(val->data(), val->cap()));
}
template<typename I>
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<LittleEndian<I>*>(&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<typename T>
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<LittleEndian<ArrayLength>*>(&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<typename T>
int MetalClawReader::op(const char*, ox::Vector<T> *val) {
Error MetalClawReader::op(const char*, ox::Vector<T> *val) {
return op(nullptr, val->data(), val->size());
}

View File

@ -7,7 +7,9 @@
*/
#include <assert.h>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <ox/mc/mc.hpp>
#include <ox/std/std.hpp>
@ -36,8 +38,8 @@ struct TestStruct {
};
template<typename T>
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<typename T>
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<std::string, ox::Error(*)()> tests = {
{
"MetalClawReader",
[] {
ox::Error err = 0;
constexpr size_t buffLen = 1024;
uint8_t buff[buffLen];
TestStruct testIn, testOut;
@ -102,41 +103,144 @@ std::map<std::string, ox::Error(*)()> 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<ox::mc::FieldName>&, const ox::Vector<ox::mc::TypeName>&, 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<char> 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;
}
},

View File

@ -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<char*>(str);
m_cap = -1;
}
template<std::size_t sz>
constexpr McStr(BString<sz> *str) noexcept {
m_str = const_cast<char*>(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 {

View File

@ -20,97 +20,141 @@ class MetalClawWalker {
template<typename FH>
friend ox::Error ioOp(class MetalClawReader*, MetalClawWalker<FH>*);
template<typename FH>
friend ox::Error parseField(const mc::Field &field, MetalClawReader *rdr, MetalClawWalker<FH> *walker);
private:
mc::Type *m_type = nullptr;
T *m_fieldHandler = nullptr;
Vector<const mc::Type*> m_typeStack;
T m_fieldHandler;
Vector<mc::FieldName> m_path;
Vector<mc::TypeName> 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<typename T>
MetalClawWalker<T>::MetalClawWalker(T *fieldHandler) {
m_fieldHandler = fieldHandler;
MetalClawWalker<T>::MetalClawWalker(mc::Type *type, T fieldHandler): m_fieldHandler(fieldHandler) {
m_typeStack.push_back(type);
}
template<typename T>
const mc::Type *MetalClawWalker<T>::type() const noexcept {
return m_type;
return m_typeStack.back();
}
template<typename T>
void MetalClawWalker<T>::read(const mc::Field &f, MetalClawReader *rdr) {
ox::Error MetalClawWalker<T>::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<typename T>
void MetalClawWalker<T>::pushNamePath(mc::FieldName fn) {
m_path.push_back(fn);
}
template<typename T>
void MetalClawWalker<T>::popNamePath() {
m_path.pop_back();
}
template<typename T>
void MetalClawWalker<T>::pushType(const mc::Type *type) {
m_typeStack.push_back(type);
}
template<typename T>
void MetalClawWalker<T>::popType() {
m_typeStack.pop_back();
}
template<typename FH>
static ox::Error parseField(mc::Field field, MetalClawReader *rdr, MetalClawWalker<FH> *walker) {
ox::Error err = 0;
static ox::Error parseField(const mc::Field &field, MetalClawReader *rdr, MetalClawWalker<FH> *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<typename FH>
ox::Error ioOp(MetalClawReader *rdr, MetalClawWalker<FH> *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<typename Handler>
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);
}
}

View File

@ -18,8 +18,8 @@ class HashMap {
private:
struct Pair {
K key;
T value;
K key = {};
T value = {};
};
Vector<K> m_keys;
Vector<Pair*> m_pairs;

View File

@ -10,7 +10,7 @@
#include "memops.hpp"
#include "strops.hpp"
#include "types.hpp"
#include "typetraits.hpp"
namespace ox {

20
deps/ox/src/ox/std/utility.hpp vendored Normal file
View File

@ -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<typename T>
constexpr typename ox::remove_reference<T>::type &&move(T &&t) noexcept {
return static_cast<typename ox::remove_reference<T>::type&&>(t);
}
}

View File

@ -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<typename... Args>
void emplace_back(Args&&... args) noexcept;
void push_back(const T &item) noexcept;
void pop_back() noexcept;
@ -85,7 +97,7 @@ Vector<T>::Vector(Vector<T> &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<T>::operator[](std::size_t i) const noexcept {
return m_items[i];
}
template<typename T>
T &Vector<T>::front() noexcept {
return m_items[0];
}
template<typename T>
const T &Vector<T>::front() const noexcept {
return m_items[0];
}
template<typename T>
T &Vector<T>::back() noexcept {
return m_items[m_size - 1];
}
template<typename T>
const T &Vector<T>::back() const noexcept {
return m_items[m_size - 1];
}
template<typename T>
std::size_t Vector<T>::size() const noexcept {
return m_size;
@ -170,6 +202,16 @@ bool Vector<T>::contains(T v) const noexcept {
return false;
}
template<typename T>
template<typename... Args>
void Vector<T>::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<typename T>
void Vector<T>::push_back(const T &item) noexcept {
if (m_size == m_cap) {
@ -206,10 +248,10 @@ void Vector<T>::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;
}