[ox/mc] Add Walker
This commit is contained in:
parent
3facd25794
commit
def449607c
2
deps/ox/src/ox/mc/CMakeLists.txt
vendored
2
deps/ox/src/ox/mc/CMakeLists.txt
vendored
@ -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
|
||||
|
67
deps/ox/src/ox/mc/deftypes.hpp
vendored
67
deps/ox/src/ox/mc/deftypes.hpp
vendored
@ -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>;
|
||||
|
||||
}
|
||||
|
5
deps/ox/src/ox/mc/defwriter.cpp
vendored
5
deps/ox/src/ox/mc/defwriter.cpp
vendored
@ -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;
|
||||
|
2
deps/ox/src/ox/mc/defwriter.hpp
vendored
2
deps/ox/src/ox/mc/defwriter.hpp
vendored
@ -80,7 +80,7 @@ class MetalClawDefWriter {
|
||||
|
||||
constexpr void setTypeInfo(const char *name, int fields);
|
||||
|
||||
constexpr OpType opType() {
|
||||
static constexpr OpType opType() {
|
||||
return OpType::WriteDefinition;
|
||||
}
|
||||
|
||||
|
1
deps/ox/src/ox/mc/mc.hpp
vendored
1
deps/ox/src/ox/mc/mc.hpp
vendored
@ -12,4 +12,5 @@
|
||||
#include "defwriter.hpp"
|
||||
#include "read.hpp"
|
||||
#include "types.hpp"
|
||||
#include "walker.hpp"
|
||||
#include "write.hpp"
|
||||
|
26
deps/ox/src/ox/mc/optype.hpp
vendored
26
deps/ox/src/ox/mc/optype.hpp
vendored
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
14
deps/ox/src/ox/mc/presencemask.cpp
vendored
14
deps/ox/src/ox/mc/presencemask.cpp
vendored
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
30
deps/ox/src/ox/mc/presencemask.hpp
vendored
30
deps/ox/src/ox/mc/presencemask.hpp
vendored
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
3
deps/ox/src/ox/mc/read.cpp
vendored
3
deps/ox/src/ox/mc/read.cpp
vendored
@ -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);
|
||||
}
|
||||
|
||||
|
11
deps/ox/src/ox/mc/read.hpp
vendored
11
deps/ox/src/ox/mc/read.hpp
vendored
@ -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>
|
||||
|
2
deps/ox/src/ox/mc/test/CMakeLists.txt
vendored
2
deps/ox/src/ox/mc/test/CMakeLists.txt
vendored
@ -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
116
deps/ox/src/ox/mc/walker.hpp
vendored
Normal 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);
|
||||
}
|
||||
|
||||
}
|
1
deps/ox/src/ox/mc/write.cpp
vendored
1
deps/ox/src/ox/mc/write.cpp
vendored
@ -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);
|
||||
}
|
||||
|
||||
|
6
deps/ox/src/ox/mc/write.hpp
vendored
6
deps/ox/src/ox/mc/write.hpp
vendored
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user