[ox/mc] Add Walker

This commit is contained in:
Gary Talent 2019-02-24 23:57:31 -06:00
parent 3facd25794
commit def449607c
14 changed files with 234 additions and 52 deletions

View File

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

View File

@ -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<Field>;
using TypeName = String;
struct Type {
String typeName;
TypeName typeName;
PrimitiveType primitiveType;
// fieldList only applies to structs
Vector<Field> fieldList;
@ -59,23 +62,6 @@ struct Type {
};
template<typename T>
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_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);
return err;
}
template<typename T>
int ioOp(T *io, Type *type) {
int32_t err = 0;
@ -87,6 +73,45 @@ int ioOp(T *io, Type *type) {
return err;
}
template<typename T>
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_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);
return err;
}
template<typename T>
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<mc::String, mc::Type>;
}

View File

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

View File

@ -80,7 +80,7 @@ class MetalClawDefWriter {
constexpr void setTypeInfo(const char *name, int fields);
constexpr OpType opType() {
static constexpr OpType opType() {
return OpType::WriteDefinition;
}

View File

@ -12,4 +12,5 @@
#include "defwriter.hpp"
#include "read.hpp"
#include "types.hpp"
#include "walker.hpp"
#include "write.hpp"

View File

@ -8,7 +8,7 @@
#pragma once
#include "ox/std/error.hpp"
#include <ox/std/error.hpp>
namespace ox {
@ -18,13 +18,33 @@ enum class OpType {
WriteDefinition = 3,
};
// empty default implementations of ioOp functions
template<typename T, typename O>
ox::Error ioOpRead(T*, O*) {
return OxError(1);
}
template<typename T, typename O>
ox::Error ioOpWrite(T*, O*) {
return OxError(1);
}
template<typename T, typename O>
ox::Error ioOpWriteDefinition(T*, O*) {
return OxError(1);
}
template<typename T, typename O>
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);
}
}

View File

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

View File

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

View File

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

View File

@ -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<typename T>
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<typename I>

View File

@ -1,5 +1,3 @@
cmake_minimum_required(VERSION 2.8)
add_executable(
McTest
tests.cpp

116
deps/ox/src/ox/mc/walker.hpp vendored Normal file
View File

@ -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 <ox/std/error.hpp>
#include "deftypes.hpp"
#include "read.hpp"
namespace ox {
template<typename T>
class MetalClawWalker {
template<typename FH>
friend ox::Error ioOp(class MetalClawReader*, MetalClawWalker<FH>*);
private:
mc::Type *m_type = nullptr;
T *m_fieldHandler = nullptr;
Vector<mc::FieldName> m_path;
Vector<mc::TypeName> 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<typename T>
MetalClawWalker<T>::MetalClawWalker(T *fieldHandler) {
m_fieldHandler = fieldHandler;
}
template<typename T>
const mc::Type *MetalClawWalker<T>::type() const noexcept {
return m_type;
}
template<typename T>
void MetalClawWalker<T>::read(const mc::Field &f, MetalClawReader *rdr) {
const auto &pathCr = m_path;
m_fieldHandler->read(pathCr, f, rdr);
}
template<typename FH>
static ox::Error parseField(mc::Field field, MetalClawReader *rdr, MetalClawWalker<FH> *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<typename FH>
ox::Error ioOp(MetalClawReader *rdr, MetalClawWalker<FH> *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);
}
}

View File

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

View File

@ -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<typename I>