[ox] Overhaul serialization/model system and add ModelValue/ModelObject/ModelUnion variant system

This commit is contained in:
Gary Talent 2022-06-21 21:43:49 -05:00
parent bc391b45fc
commit ca64f95be3
47 changed files with 2696 additions and 973 deletions

2
deps/ox/.liccor.yml vendored
View File

@ -6,4 +6,4 @@ copyright_notice: |-
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/.
file, You can obtain one at https://mozilla.org/MPL/2.0/.

View File

@ -191,6 +191,10 @@ if(JSONCPP_WITH_TESTS)
include(CTest)
endif()
# DrinkingTea - begin
set(CMAKE_CXX_FLAGS "-Wno-everything")
# DrinkingTea - end
# Build the different applications
add_subdirectory(src)

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <ox/std/buffer.hpp>
@ -72,4 +72,34 @@ Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept {
return stripClawHeader(buff.data(), buff.size());
}
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept {
oxRequire(header, readClawHeader(buff));
oxRequire(t, ts->template getLoad(header.typeName, header.typeVersion));
ModelObject obj;
oxReturnError(obj.setType(t));
switch (header.fmt) {
case ClawFormat::Metal:
{
MetalClawReader reader(reinterpret_cast<const uint8_t*>(header.data), header.dataSize);
ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj));
return obj;
}
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, header.dataSize);
ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj));
return obj;
#else
break;
#endif
}
case ClawFormat::None:
return OxError(1);
}
return OxError(1);
}
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -50,13 +50,14 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) {
switch (header.fmt) {
case ClawFormat::Metal:
{
MetalClawReader reader(reinterpret_cast<const uint8_t*>(header.data), buffLen);
return model(&reader, val);
MetalClawReader reader(reinterpret_cast<const uint8_t*>(header.data), header.dataSize);
ModelHandlerInterface handler(&reader);
return model(&handler, val);
}
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, buffLen);
OrganicClawReader reader(header.data, header.dataSize);
return model(&reader, val);
#else
break;
@ -85,4 +86,6 @@ Result<T> readClaw(const Buffer &buff) {
return readClaw<T>(buff.data(), buff.size());
}
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept;
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#undef NDEBUG
@ -25,7 +25,7 @@ union TestUnion {
static constexpr auto TypeVersion = 1;
bool Bool;
uint32_t Int = 5;
char String[32];
char *String;
};
struct TestStructNest {
@ -49,6 +49,7 @@ struct TestStruct {
int32_t Int6 = 0;
int32_t Int7 = 0;
int32_t Int8 = 0;
int unionIdx = 1;
TestUnion Union;
ox::BString<32> String = "";
uint32_t List[4] = {0, 0, 0, 0};
@ -56,21 +57,24 @@ struct TestStruct {
TestStructNest Struct;
~TestStruct() {
if (unionIdx == 2) {
ox::safeDelete(Union.String);
}
}
};
template<typename T>
constexpr ox::Error model(T *io, TestUnion *obj) {
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) {
io->template setTypeInfo<TestUnion>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("String", ox::SerStr(obj->String)));
oxReturnError(io->fieldCString("String", &obj->String));
return OxError(0);
}
template<typename T>
constexpr ox::Error model(T *io, TestStructNest *obj) {
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStructNest> auto *obj) {
io->template setTypeInfo<TestStructNest>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
@ -79,7 +83,7 @@ constexpr ox::Error model(T *io, TestStructNest *obj) {
}
template<typename T>
constexpr ox::Error model(T *io, TestStruct *obj) {
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) {
io->template setTypeInfo<TestStruct>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
@ -91,7 +95,11 @@ constexpr ox::Error model(T *io, TestStruct *obj) {
oxReturnError(io->field("Int6", &obj->Int6));
oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
int unionIdx = 0;
if constexpr(ox_strcmp(T::opType(), ox::OpType::Reflect) != 0) {
unionIdx = obj->unionIdx;
}
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, unionIdx}));
oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
@ -99,7 +107,7 @@ constexpr ox::Error model(T *io, TestStruct *obj) {
return OxError(0);
}
std::map<std::string_view, ox::Error(*)()> tests = {
static std::map<std::string_view, ox::Error(*)()> tests = {
{
{
"ClawHeaderReader",
@ -153,7 +161,7 @@ std::map<std::string_view, ox::Error(*)()> tests = {
auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal);
oxAssert(err, "writeMC failed");
oxAssert(ox::readClaw(buff.data(), buff.size(), &testOut), "writeMC failed");
oxAssert(ox::readClaw(buff.data(), buff.size(), &testOut), "readMC failed");
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");

View File

@ -82,8 +82,7 @@ Result<String> writeClawHeader(T *t, ClawFormat fmt) noexcept {
}
template<typename T>
Result<Buffer> writeClaw(T *t, ClawFormat fmt = ClawFormat::Metal) {
Result<Buffer> writeClaw(auto *t, ClawFormat fmt = ClawFormat::Metal) {
oxRequire(header, detail::writeClawHeader(t, fmt));
oxRequire(data, fmt == ClawFormat::Metal ? writeMC(t) : writeOC(t));
Buffer out(header.len() + data.size());

View File

@ -3,12 +3,13 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/std.hpp>
#include <ox/model/def.hpp>
#include <ox/model/typenamecatcher.hpp>
#include <ox/model/types.hpp>
@ -24,7 +25,7 @@ enum class FileAddressType: int8_t {
class FileAddress {
template<typename T>
friend constexpr Error model(T*, FileAddress*) noexcept;
friend constexpr Error model(T*, CommonPtrWith<FileAddress> auto*) noexcept;
public:
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
@ -129,22 +130,16 @@ constexpr const char *getModelTypeName<FileAddress>() noexcept {
}
template<typename T>
constexpr Error model(T *io, FileAddress::Data *obj) noexcept {
constexpr Error model(T *io, CommonPtrWith<FileAddress::Data> auto *obj) noexcept {
io->template setTypeInfo<FileAddress::Data>();
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
String dummy;
oxReturnError(io->field("path", &dummy));
oxReturnError(io->field("constPath", &dummy));
} else {
oxReturnError(io->field("path", SerStr(&obj->path)));
oxReturnError(io->field("constPath", SerStr(&obj->path)));
}
oxReturnError(io->fieldCString("path", &obj->path));
oxReturnError(io->fieldCString("constPath", &obj->path));
oxReturnError(io->field("inode", &obj->inode));
return OxError(0);
}
template<typename T>
constexpr Error model(T *io, FileAddress *fa) noexcept {
constexpr Error model(T *io, CommonPtrWith<FileAddress> auto *fa) noexcept {
io->template setTypeInfo<FileAddress>();
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
int8_t type = 0;

View File

@ -64,7 +64,7 @@ template<typename I>
[[nodiscard]]
constexpr McInt encodeInteger(I input) noexcept {
McInt out;
auto inputNegative = is_signed_v<I> && input < 0;
const auto inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation, and to avoid
// overflow concerns
uint64_t val = 0;
@ -72,7 +72,7 @@ constexpr McInt encodeInteger(I input) noexcept {
if (val) {
// bits needed to represent number factoring in space possibly
// needed for signed bit
const auto highBit = inputNegative ? (highestBit(~val)) : highestBit(val);
const auto highBit = inputNegative ? highestBit(~val) : highestBit(val);
const auto bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
// bytes needed to store value
std::size_t bytes = bits / 8 + (bits % 8 != 0);
@ -84,7 +84,6 @@ constexpr McInt encodeInteger(I input) noexcept {
++bytes;
}
const auto bytesIndicator = onMask<uint8_t>(bytes - 1);
// ensure we are copying from little endian representation
LittleEndian<uint64_t> leVal = val;
if (inputNegative) {
@ -116,7 +115,7 @@ constexpr McInt encodeInteger(I input) noexcept {
[[nodiscard]]
static constexpr std::size_t countBytes(uint8_t b) noexcept {
std::size_t i = 0;
for (; (b >> i) & 1; i++);
while ((b >> i) & 1) ++i;
return i + 1;
}

View File

@ -3,157 +3,9 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <ox/std/assert.hpp>
#include <ox/std/byteswap.hpp>
#include <ox/std/memops.hpp>
#include "read.hpp"
namespace ox {
MetalClawReader::MetalClawReader(const uint8_t *buff, std::size_t buffLen, int unionIdx, MetalClawReader *parent) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff),
m_parent(parent) {
}
MetalClawReader::~MetalClawReader() noexcept {
if (m_parent) {
m_parent->m_buffIt += m_buffIt;
}
if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawReader::error") << "MetalClawReader: incorrect fields number given";
}
}
Error MetalClawReader::field(const char*, int8_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, int16_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, int32_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, int64_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, uint8_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, uint16_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, uint32_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, uint64_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
auto valErr = m_fieldPresence.get(static_cast<std::size_t>(m_field));
*val = valErr.value;
oxReturnError(valErr.error);
}
++m_field;
return OxError(0);
}
Error MetalClawReader::field(const char*, SerStr val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
auto data = val.data(size + 1);
// read the string
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
} else {
return OxError(MC_OUTBUFFENDED);
}
} else {
auto data = val.data();
if (data) {
data[0] = 0;
}
}
}
++m_field;
return OxError(0);
}
Error MetalClawReader::fieldCString(const char *name, char **val, int len) noexcept {
return field(name, SerStr(val, len));
}
Result<ArrayLength> MetalClawReader::arrayLength(const char*, bool pass) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto out = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead).value;
if (pass) {
m_buffIt += bytesRead;
}
return out;
}
return OxError(1);
}
[[nodiscard]]
StringLength MetalClawReader::stringLength(const char*) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
return len.value;
}
return 0;
}
MetalClawReader MetalClawReader::child(const char*, int unionIdx) noexcept {
return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this);
}
bool MetalClawReader::fieldPresent(const char*) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value;
}
bool MetalClawReader::fieldPresent(int fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
}
void MetalClawReader::nextField() noexcept {
++m_field;
}
}

View File

@ -3,12 +3,13 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/typenamecatcher.hpp>
#include <ox/model/types.hpp>
@ -25,7 +26,8 @@
namespace ox {
class MetalClawReader {
template<auto HandlerMaker>
class MetalClawReaderTemplate {
private:
FieldBitmapReader<const uint8_t*> m_fieldPresence;
@ -35,87 +37,93 @@ class MetalClawReader {
std::size_t m_buffIt = 0;
std::size_t m_buffLen = 0;
const uint8_t *m_buff = nullptr;
MetalClawReader *m_parent = nullptr;
MetalClawReaderTemplate<HandlerMaker> *m_parent = nullptr;
public:
MetalClawReader(const uint8_t *buff, std::size_t buffLen, int unionIdx = -1, MetalClawReader *parent = nullptr) noexcept;
constexpr MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen, int unionIdx = -1,
MetalClawReaderTemplate<HandlerMaker> *parent = nullptr) noexcept;
~MetalClawReader() noexcept;
constexpr ~MetalClawReaderTemplate() noexcept;
Error field(const char*, int8_t *val) noexcept;
Error field(const char*, int16_t *val) noexcept;
Error field(const char*, int32_t *val) noexcept;
Error field(const char*, int64_t *val) noexcept;
constexpr Error field(const char*, int8_t *val) noexcept;
constexpr Error field(const char*, int16_t *val) noexcept;
constexpr Error field(const char*, int32_t *val) noexcept;
constexpr Error field(const char*, int64_t *val) noexcept;
Error field(const char*, uint8_t *val) noexcept;
Error field(const char*, uint16_t *val) noexcept;
Error field(const char*, uint32_t *val) noexcept;
Error field(const char*, uint64_t *val) noexcept;
constexpr Error field(const char*, uint8_t *val) noexcept;
constexpr Error field(const char*, uint16_t *val) noexcept;
constexpr Error field(const char*, uint32_t *val) noexcept;
constexpr Error field(const char*, uint64_t *val) noexcept;
Error field(const char*, bool *val) noexcept;
constexpr Error field(const char*, bool *val) noexcept;
// array handler
template<typename T>
Error field(const char*, T *val, std::size_t len) noexcept;
constexpr Error field(const char*, auto *val, std::size_t len) noexcept;
// map handler
template<typename T>
Error field(const char*, HashMap<String, T> *val) noexcept;
constexpr Error field(const char*, HashMap<String, T> *val) noexcept;
// array handler, with callback to allow handling individual elements
template<typename T, typename Handler>
Error field(const char*, Handler handler) noexcept;
template<typename T, typename CB>
constexpr Error field(const char*, CB cb) noexcept;
template<typename T>
Error field(const char*, T *val) noexcept;
constexpr Error field(const char*, T *val) noexcept;
template<typename U>
Error field(const char*, UnionView<U> val) noexcept;
template<typename U, bool force>
constexpr Error field(const char*, UnionView<U, force> val) noexcept;
template<std::size_t SmallStringSize>
Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept;
constexpr Error field(const char*, BString<L> *val) noexcept;
Error field(const char*, SerStr val) noexcept;
constexpr Error fieldCString(const char*, char *val, std::size_t buffLen) noexcept;
Error fieldCString(const char *name, char **val, int len) noexcept;
constexpr Error fieldCString(const char*, char **val) noexcept;
constexpr Error fieldCString(const char*, char **val, std::size_t buffLen) noexcept;
/**
* Reads an array length from the current location in the buffer.
* @param pass indicates that the parsing should iterate past the array length
*/
Result<ArrayLength> arrayLength(const char *name, bool pass = true) noexcept;
constexpr Result<ArrayLength> arrayLength(const char *name, bool pass = true) noexcept;
/**
* Reads an string length from the current location in the buffer.
*/
[[nodiscard]]
StringLength stringLength(const char *name) noexcept;
constexpr StringLength stringLength(const char *name) noexcept;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, int fields = ModelFieldCount_v<T>) noexcept;
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
/**
* Returns a MetalClawReader to parse a child object.
*/
[[nodiscard]]
MetalClawReader child(const char *name, int unionIdx = -1) noexcept;
constexpr MetalClawReaderTemplate<HandlerMaker> child(const char *name, int unionIdx = -1) noexcept;
/**
* Indicates whether or not the next field to be read is present.
*/
[[nodiscard]]
bool fieldPresent(const char *name) const noexcept;
constexpr bool fieldPresent(const char *name) const noexcept;
/**
* Indicates whether or not the given field is present.
*/
[[nodiscard]]
bool fieldPresent(int fieldNo) const noexcept;
constexpr bool fieldPresent(int fieldNo) const noexcept;
void nextField() noexcept;
[[nodiscard]]
constexpr int whichFieldPresent(const char *name, const ModelUnion&) const noexcept;
constexpr void nextField() noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
@ -124,12 +132,145 @@ class MetalClawReader {
private:
template<typename I>
Error readInteger(I *val) noexcept;
constexpr Error readInteger(I *val) noexcept;
};
template<auto HandlerMaker>
constexpr MetalClawReaderTemplate<HandlerMaker>::MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen,
int unionIdx,
MetalClawReaderTemplate *parent) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff),
m_parent(parent) {
}
template<auto HandlerMaker>
constexpr MetalClawReaderTemplate<HandlerMaker>::~MetalClawReaderTemplate() noexcept {
if (m_parent) {
m_parent->m_buffIt += m_buffIt;
}
if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawReader::error") << "MetalClawReader: incorrect fields number given";
}
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int8_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int16_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int32_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int64_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint8_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint16_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint32_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint64_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
auto valErr = m_fieldPresence.get(static_cast<std::size_t>(m_field));
*val = valErr.value;
oxReturnError(valErr.error);
}
++m_field;
return OxError(0);
}
// array handler
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, auto *val, std::size_t valLen) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
// read the list
if (valLen >= len) {
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(handler.field("", &val[i]));
}
} else {
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
return OxError(MC_OUTBUFFENDED);
}
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
template<typename T>
Error MetalClawReader::field(const char *name, T *val) noexcept {
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, HashMap<String, T> *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
// read the list
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
const auto keyLen = handler.stringLength(nullptr);
auto wkey = ox_malloca(keyLen + 1, char, 0);
auto wkeyPtr = wkey.get();
oxReturnError(handler.fieldCString("", &wkeyPtr, static_cast<int>(keyLen + 1)));
oxReturnError(handler.field("", &val->operator[](wkey.get())));
}
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
template<typename T>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, T *val) noexcept {
if constexpr(isVector_v<T>) {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
// set size of val if the field is present, don't worry about it if not
@ -142,27 +283,35 @@ Error MetalClawReader::field(const char *name, T *val) noexcept {
++m_field;
return OxError(0);
} else {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val && m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
auto reader = child("");
oxReturnError(model(&reader, val));
auto handler = HandlerMaker(&reader);
oxReturnError(model(&handler, val));
}
}
++m_field;
return OxError(0);
}
}
template<typename U>
Error MetalClawReader::field(const char*, UnionView<U> val) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get() && m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
template<auto HandlerMaker>
template<typename U, bool force>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, UnionView<U, force> val) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
auto reader = child("", val.idx());
oxReturnError(model(&reader, val.get()));
auto handler = HandlerMaker(&reader);
oxReturnError(model(&handler, val.get()));
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
template<std::size_t SmallStringSize>
Error MetalClawReader::field(const char*, BasicString<SmallStringSize> *val) noexcept {
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
@ -193,13 +342,129 @@ Error MetalClawReader::field(const char*, BasicString<SmallStringSize> *val) noe
return OxError(0);
}
template<auto HandlerMaker>
template<std::size_t L>
Error MetalClawReader::field(const char *name, BString<L> *val) noexcept {
return field(name, SerStr(val->data(), val->cap()));
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char *val, std::size_t buffLen) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
if (size > buffLen) {
return OxError(MC_OUTBUFFENDED);
}
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate in case too small
auto data = val;
// read the string
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char **val) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate in case too small
safeDelete(*val);
*val = new char[size + 1];
auto data = *val;
// read the string
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate if too small
if (buffLen < size + 1) {
safeDelete(*val);
*val = new char[size + 1];
buffLen = size + 1;
}
auto data = *val;
// read the string
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
} else {
auto data = *val;
if (data) {
data[0] = 0;
}
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
constexpr Result<ArrayLength> MetalClawReaderTemplate<HandlerMaker>::arrayLength(const char*, bool pass) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field)) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto out = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead).value;
if (pass) {
m_buffIt += bytesRead;
}
return out;
}
}
return OxError(1);
}
template<auto HandlerMaker>
template<typename I>
Error MetalClawReader::readInteger(I *val) noexcept {
constexpr Error MetalClawReaderTemplate<HandlerMaker>::readInteger(I *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
std::size_t bytesRead = 0;
@ -219,65 +484,9 @@ Error MetalClawReader::readInteger(I *val) noexcept {
return OxError(0);
}
// array handler
template<typename T>
Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
// read the list
if (valLen >= len) {
auto reader = child("");
reader.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(reader.field("", &val[i]));
}
} else {
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
return OxError(MC_OUTBUFFENDED);
}
}
}
++m_field;
return OxError(0);
}
template<typename T>
Error MetalClawReader::field(const char*, HashMap<String, T> *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
// read the list
auto reader = child("");
reader.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
const auto keyLen = reader.stringLength(nullptr);
auto wkey = ox_malloca(keyLen + 1, char, 0);
auto wkeyPtr = wkey.get();
oxReturnError(reader.fieldCString("", &wkeyPtr, static_cast<int>(keyLen + 1)));
oxReturnError(reader.field("", &val->operator[](wkey.get())));
}
}
}
++m_field;
return OxError(0);
}
template<typename T, typename Handler>
Error MetalClawReader::field(const char*, Handler handler) noexcept {
template<auto HandlerMaker>
template<typename T, typename CB>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, CB cb) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
@ -290,11 +499,12 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept {
// read the list
auto reader = child("");
reader.setTypeInfo("List", 0, static_cast<int>(len));
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
T val;
oxReturnError(reader.field("", &val));
oxReturnError(handler(i, &val));
oxReturnError(handler.field("", &val));
oxReturnError(cb(i, &val));
}
}
}
@ -302,18 +512,70 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept {
return OxError(0);
}
template<auto HandlerMaker>
constexpr StringLength MetalClawReaderTemplate<HandlerMaker>::stringLength(const char*) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field)) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
return len.value;
}
}
return 0;
}
template<auto HandlerMaker>
template<typename T>
constexpr void MetalClawReader::setTypeInfo(const char*, int, int fields) noexcept {
constexpr void MetalClawReaderTemplate<HandlerMaker>::setTypeInfo(const char*, int, int fields) noexcept {
m_fields = fields;
m_buffIt = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
m_fieldPresence.setFields(fields);
m_fieldPresence.setMaxLen(static_cast<int>(m_buffIt));
}
template<auto HandlerMaker>
constexpr MetalClawReaderTemplate<HandlerMaker> MetalClawReaderTemplate<HandlerMaker>::child(const char*, int unionIdx) noexcept {
return MetalClawReaderTemplate<HandlerMaker>(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this);
}
template<auto HandlerMaker>
constexpr bool MetalClawReaderTemplate<HandlerMaker>::fieldPresent(const char*) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value;
}
template<auto HandlerMaker>
constexpr bool MetalClawReaderTemplate<HandlerMaker>::fieldPresent(int fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
}
template<auto HandlerMaker>
[[nodiscard]]
constexpr int MetalClawReaderTemplate<HandlerMaker>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept {
FieldBitmapReader<const uint8_t*> p(m_buff + m_buffIt, m_buffLen - m_buffIt);
p.setFields(u.fieldCount());
for (auto i = 0u; i < u.fieldCount(); ++i) {
if (p.get(i)) {
return static_cast<int>(i);
}
}
return -1;
}
template<auto HandlerMaker>
constexpr void MetalClawReaderTemplate<HandlerMaker>::nextField() noexcept {
++m_field;
}
using MetalClawReader = MetalClawReaderTemplate<[](auto r) {
return ModelHandlerInterface{r};
}>;
template<typename T>
Error readMC(const char *buff, std::size_t buffLen, T *val) noexcept {
MetalClawReader reader(reinterpret_cast<const uint8_t*>(buff), buffLen);
return model(&reader, val);
ModelHandlerInterface handler(&reader);
return model(&handler, val);
}
template<typename T>

View File

@ -10,6 +10,7 @@ target_link_libraries(
add_test("[ox/mc] McTest Writer" McTest MetalClawWriter)
add_test("[ox/mc] McTest Reader" McTest MetalClawReader)
add_test("[ox/mc] McTest MetalClawDef" McTest MetalClawDef)
#add_test("[ox/mc] McTest MetalClawDef" McTest MetalClawDef)
add_test("[ox/mc] McTest MetalClawModelValue" McTest MetalClawModelValue)
add_test("[ox/mc] McTest encodeInteger" McTest encodeInteger)
add_test("[ox/mc] McTest decodeInteger" McTest decodeInteger)

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#undef NDEBUG
@ -19,7 +19,7 @@ union TestUnion {
static constexpr auto TypeVersion = 1;
bool Bool;
uint32_t Int = 5;
char CString[32];
char *CString;
};
struct TestStructNest {
@ -43,6 +43,7 @@ struct TestStruct {
int32_t Int6 = 0;
int32_t Int7 = 0;
int32_t Int8 = 0;
int unionIdx = 1;
TestUnion Union;
ox::String String = "";
ox::BString<32> BString = "";
@ -50,14 +51,19 @@ struct TestStruct {
ox::HashMap<ox::String, int> Map;
TestStructNest EmptyStruct;
TestStructNest Struct;
constexpr ~TestStruct() noexcept {
if (unionIdx == 2) {
ox::safeDelete(Union.CString);
}
}
};
template<typename T>
constexpr ox::Error model(T *io, TestUnion *obj) noexcept {
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcept {
io->template setTypeInfo<TestUnion>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("CString", ox::SerStr(obj->CString)));
oxReturnError(io->fieldCString("CString", &obj->CString));
return OxError(0);
}
@ -68,7 +74,7 @@ oxModelBegin(TestStructNest)
oxModelEnd()
template<typename T>
constexpr ox::Error model(T *io, TestStruct *obj) noexcept {
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept {
io->template setTypeInfo<TestStruct>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
@ -80,7 +86,12 @@ constexpr ox::Error model(T *io, TestStruct *obj) noexcept {
oxReturnError(io->field("Int6", &obj->Int6));
oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
oxReturnError(io->field("unionIdx", &obj->unionIdx));
if (ox_strcmp(io->opType(), ox::OpType::Reflect) == 0) {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 0}));
} else {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
}
oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("BString", &obj->BString));
oxReturnError(io->field("List", obj->List, 4));
@ -165,14 +176,15 @@ std::map<ox::String, ox::Error(*)()> tests = {
using ox::MaxValue;
using ox::mc::McInt;
using ox::mc::encodeInteger;
static constexpr auto check = [](McInt val, ox::Vector<uint8_t, 9> &&expected) {
static constexpr auto check = [](McInt val, const ox::Vector<uint8_t, 9> &expected) {
if (val.length != expected.size()) {
std::cout << "val.length: " << val.length << ", expected: " << expected.size() << '\n';
return OxError(1);
}
for (std::size_t i = 0; i < expected.size(); i++) {
if (expected[i] != val.data[i]) {
std::cout << i << ": " << static_cast<uint32_t>(val.data[i]) << '\n';
std::cout << "decoded: " << static_cast<uint32_t>(val.data[i]) << ", expected: " << static_cast<uint32_t>(expected[i]) << '\n';
std::cout << "decoded: " << i << ": " << static_cast<uint32_t>(val.data[i]) << '\n';
return OxError(1);
}
}
@ -195,6 +207,7 @@ std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(check(encodeInteger(int64_t(2)), {0b000'0010'0}), "Encode 2 fail");
oxAssert(check(encodeInteger(int64_t(3)), {0b000'0011'0}), "Encode 3 fail");
oxAssert(check(encodeInteger(int64_t(4)), {0b000'0100'0}), "Encode 4 fail");
oxAssert(check(encodeInteger(int64_t(64)), {0b00'0000'01, 0b1}), "Encode 64 fail");
oxAssert(check(encodeInteger(int64_t(128)), {0b00'0000'01, 0b10}), "Encode 128 fail");
oxAssert(check(encodeInteger(int64_t(129)), {0b00'0001'01, 0b10}), "Encode 129 fail");
oxAssert(check(encodeInteger(int64_t(130)), {0b00'0010'01, 0b10}), "Encode 130 fail");
@ -204,6 +217,7 @@ std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(check(encodeInteger( int64_t(-2)), {0b111'1110'0}), "Encode -2 fail");
oxAssert(check(encodeInteger( int64_t(-3)), {0b111'1101'0}), "Encode -3 fail");
oxAssert(check(encodeInteger( int64_t(-4)), {0b111'1100'0}), "Encode -4 fail");
oxAssert(check(encodeInteger( int64_t(-64)), {0b100'0000'0}), "Encode -64 fail");
oxAssert(check(encodeInteger(int64_t(-128)), {0b00'0000'01, 0b11'1111'10}), "Encode -128 fail");
oxAssert(check(encodeInteger(int64_t(-129)), {0b11'1111'01, 0b11'1111'01}), "Encode -129 fail");
oxAssert(check(encodeInteger(int64_t(-130)), {0b11'1110'01, 0b11'1111'01}), "Encode -130 fail");
@ -214,6 +228,7 @@ std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(check(encodeInteger(uint64_t(2)), {0b0100}), "Encode 2 fail");
oxAssert(check(encodeInteger(uint64_t(3)), {0b0110}), "Encode 3 fail");
oxAssert(check(encodeInteger(uint64_t(4)), {0b1000}), "Encode 4 fail");
oxAssert(check(encodeInteger(uint64_t(64)), {0b1000'000'0}), "Encode 4 fail");
oxAssert(check(encodeInteger(uint64_t(128)), {0b0001, 0b10}), "Encode 128 fail");
oxAssert(check(encodeInteger(uint64_t(129)), {0b0101, 0b10}), "Encode 129 fail");
oxAssert(check(encodeInteger(uint64_t(130)), {0b1001, 0b10}), "Encode 130 fail");
@ -267,6 +282,58 @@ std::map<ox::String, ox::Error(*)()> tests = {
}
},
{
"MetalClawModelValue",
[] {
static constexpr size_t dataBuffLen = ox::units::MB;
ox::Buffer dataBuff(dataBuffLen);
TestStruct testIn;
testIn.Bool = true;
testIn.Int = 42;
testIn.BString = "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.BString = "Test String 2";
testIn.unionIdx = 1;
testIn.Union.Int = 93;
oxAssert(ox::writeMC(dataBuff.data(), dataBuff.size(), &testIn), "Data generation failed");
ox::TypeStore typeStore;
auto type = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(type.error, "Descriptor write failed");
ox::ModelObject testOut;
oxReturnError(testOut.setType(type.value));
oxAssert(ox::readMC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed");
oxAssert(testOut["Int"].get<int>() == testIn.Int, "testOut.Int failed");
oxAssert(testOut["Bool"].get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut["String"].get<ox::String>() == testIn.String, "testOut.String failed");
auto &testOutStruct = testOut["Struct"].get<ox::ModelObject>();
auto &testOutUnion = testOut["Union"].get<ox::ModelUnion>();
auto &testOutList = testOut["List"].get<ox::ModelValueVector>();
auto testOutStructCopy = testOut["Struct"].get<ox::ModelObject>();
auto testOutUnionCopy = testOut["Union"].get<ox::ModelUnion>();
auto testOutListCopy = testOut["List"].get<ox::ModelValueVector>();
oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed");
oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed");
oxAssert(testOutStruct["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed");
oxAssert(testOutStruct["BString"].get<ox::String>() == testIn.Struct.BString.c_str(), "testOut.Struct.BString failed");
oxAssert(testOut["unionIdx"].get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong");
oxAssert(testOutUnion["Int"].get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed");
oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed");
oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed");
oxAssert(testOutStructCopy["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed");
oxAssert(testOutStructCopy["BString"].get<ox::String>() == testIn.Struct.BString.c_str(), "testOut.Struct.BString (copy) failed");
oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed");
oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed");
return OxError(0);
}
},
{
"MetalClawDef",
[] {
@ -382,12 +449,11 @@ std::map<ox::String, ox::Error(*)()> tests = {
};
int main(int argc, const char **args) {
int retval = -1;
if (argc > 0) {
auto testName = args[1];
if (tests.find(testName) != tests.end()) {
retval = tests[testName]();
oxAssert(tests[testName](), "Test failed...");
}
}
return retval;
return 0;
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <ox/std/assert.hpp>
@ -15,87 +15,4 @@
namespace ox {
MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff) {
}
MetalClawWriter::~MetalClawWriter() noexcept {
if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawWriter::error") << "MetalClawReader: incorrect fields number given";
}
}
Error MetalClawWriter::field(const char*, int8_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, int16_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, int32_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, int64_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint8_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint16_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint32_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint64_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
}
++m_field;
return OxError(0);
}
Error MetalClawWriter::field(const char*, SerStr val) noexcept {
bool fieldSet = false;
if (val.len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto strLen = mc::encodeInteger(val.len());
if (m_buffIt + strLen.length + static_cast<std::size_t>(val.len()) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
m_buffIt += strLen.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], val.c_str(), static_cast<std::size_t>(val.len()));
m_buffIt += static_cast<std::size_t>(val.len());
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
Error MetalClawWriter::fieldCString(const char *name, char **val, int len) noexcept {
return field(name, SerStr(val, len));
}
std::size_t MetalClawWriter::size() const noexcept {
return m_buffIt;
}
}

View File

@ -3,12 +3,13 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/types.hpp>
#include <ox/std/bit.hpp>
@ -38,49 +39,73 @@ class MetalClawWriter {
uint8_t *m_buff = nullptr;
public:
MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept;
constexpr MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept;
~MetalClawWriter() noexcept;
constexpr ~MetalClawWriter() noexcept;
Error field(const char*, int8_t *val) noexcept;
Error field(const char*, int16_t *val) noexcept;
Error field(const char*, int32_t *val) noexcept;
Error field(const char*, int64_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int8_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int16_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int32_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int64_t> auto *val) noexcept;
Error field(const char*, uint8_t *val) noexcept;
Error field(const char*, uint16_t *val) noexcept;
Error field(const char*, uint32_t *val) noexcept;
Error field(const char*, uint64_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept;
Error field(const char*, bool *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<bool> auto *val) noexcept;
template<typename T>
Error field(const char*, T *val, std::size_t len) noexcept;
constexpr Error field(const char*, T *val, std::size_t len) noexcept;
template<typename T>
Error field(const char*, HashMap<String, T> *val) noexcept;
constexpr Error field(const char *name, const HashMap<String, T> *val) noexcept;
template<typename T>
constexpr Error field(const char*, HashMap<String, T> *val) noexcept;
template<std::size_t SmallStringSize>
Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept;
constexpr Error field(const char*, const BString<L> *val) noexcept;
Error field(const char*, SerStr val) noexcept;
template<std::size_t SmallStringSize>
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
Error fieldCString(const char *name, char **val, int len) noexcept;
template<std::size_t L>
constexpr Error field(const char*, BString<L> *val) noexcept;
constexpr Error fieldCString(const char *name, const char **val, std::size_t buffLen) noexcept;
constexpr Error fieldCString(const char *name, const char **val) noexcept;
constexpr Error fieldCString(const char *name, const char *val, std::size_t len) noexcept;
constexpr Error fieldCString(const char *name, char **val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char**>(val), buffLen);
}
constexpr Error fieldCString(const char *name, char **val) noexcept {
return fieldCString(name, const_cast<const char**>(val));
}
constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char*>(val), buffLen);
}
template<typename T>
Error field(const char*, T *val) noexcept;
constexpr Error field(const char*, T *val) noexcept;
template<typename U>
Error field(const char*, UnionView<U> val) noexcept;
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> val) noexcept;
template<typename T = std::nullptr_t>
void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, int fields = ModelFieldCount_v<T>) noexcept;
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
[[nodiscard]]
std::size_t size() const noexcept;
constexpr std::size_t size() const noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
@ -88,13 +113,81 @@ class MetalClawWriter {
}
private:
template<typename I>
Error appendInteger(I val) noexcept;
constexpr Error appendInteger(Integer_c auto val) noexcept {
bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
if (mi.length < m_buffLen) {
fieldSet = true;
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
m_buffIt += mi.length;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
};
constexpr MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff) {
}
constexpr MetalClawWriter::~MetalClawWriter() noexcept {
if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawWriter::error") << "MetalClawReader: incorrect fields number given";
}
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int8_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int16_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int32_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int64_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<bool> auto *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
}
++m_field;
return OxError(0);
}
template<std::size_t SmallStringSize>
Error MetalClawWriter::field(const char*, BasicString<SmallStringSize> *val) noexcept {
constexpr Error MetalClawWriter::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false;
if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
@ -116,19 +209,77 @@ Error MetalClawWriter::field(const char*, BasicString<SmallStringSize> *val) noe
}
template<std::size_t L>
Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept {
return field(name, SerStr(val->data(), val->cap()));
constexpr Error MetalClawWriter::field(const char *name, const BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter::field(const char *name, BasicString<SmallStringSize> *val) noexcept {
return field(name, const_cast<const BasicString<SmallStringSize>*>(val));
}
template<std::size_t L>
constexpr Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
constexpr Error MetalClawWriter::fieldCString(const char*, const char **val, std::size_t) noexcept {
bool fieldSet = false;
if (m_unionIdx == -1 || m_unionIdx == m_field) {
const auto strLen = *val ? ox_strlen(*val) : 0;
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], *val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
constexpr Error MetalClawWriter::fieldCString(const char *name, const char **val) noexcept {
return fieldCString(name, val, {});
}
constexpr Error MetalClawWriter::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
bool fieldSet = false;
if (strLen && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
template<typename T>
Error MetalClawWriter::field(const char*, T *val) noexcept {
constexpr Error MetalClawWriter::field(const char*, T *val) noexcept {
if constexpr(isVector_v<T>) {
return field(nullptr, val->data(), val->size());
} else {
bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
oxReturnError(model(&writer, val));
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
@ -140,12 +291,13 @@ Error MetalClawWriter::field(const char*, T *val) noexcept {
}
}
template<typename U>
Error MetalClawWriter::field(const char*, UnionView<U> val) noexcept {
template<typename U, bool force>
constexpr Error MetalClawWriter::field(const char*, UnionView<U, force> val) noexcept {
bool fieldSet = false;
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt, val.idx());
oxReturnError(model(&writer, val.get()));
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val.get()));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
@ -157,7 +309,7 @@ Error MetalClawWriter::field(const char*, UnionView<U> val) noexcept {
}
template<typename T>
Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
@ -171,11 +323,12 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
writer.setTypeInfo<T>("List", 0, len);
ModelHandlerInterface handler{&writer};
handler.setTypeInfo<T>("List", 0, len);
// write the array
for (std::size_t i = 0; i < len; i++) {
oxReturnError(writer.field("", &val[i]));
oxReturnError(handler.field("", &val[i]));
}
m_buffIt += writer.m_buffIt;
@ -188,11 +341,10 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
}
template<typename T>
Error MetalClawWriter::field(const char*, HashMap<String, T> *val) noexcept {
constexpr Error MetalClawWriter::field(const char*, const HashMap<String, T> *val) noexcept {
const auto &keys = val->keys();
const auto len = keys.size();
bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto arrLen = mc::encodeInteger(len);
@ -202,69 +354,57 @@ Error MetalClawWriter::field(const char*, HashMap<String, T> *val) noexcept {
} else {
return OxError(MC_BUFFENDED);
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
ModelHandlerInterface handler{&writer};
// double len for both key and value
writer.setTypeInfo("Map", 0, len * 2);
handler.setTypeInfo("Map", 0, len * 2);
// write the array
for (std::size_t i = 0; i < len; i++) {
const auto &key = keys[i];
const auto keyLen = ox_strlen(key);
auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey, key.c_str(), keyLen + 1);
oxReturnError(writer.field("", SerStr(wkey.get(), keyLen)));
oxReturnError(writer.field("", &(*val)[key]));
oxReturnError(handler.fieldCString("", wkey.get(), keyLen));
oxReturnError(handler.field("", val->at(key).value));
}
m_buffIt += writer.m_buffIt;
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
template<typename I>
Error MetalClawWriter::appendInteger(I val) noexcept {
bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
if (mi.length < m_buffLen) {
fieldSet = true;
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
m_buffIt += mi.length;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
template<typename T>
void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept {
constexpr Error MetalClawWriter::field(const char *name, HashMap<String, T> *val) noexcept {
return field(name, const_cast<const HashMap<String, T>*>(val));
}
template<typename T>
constexpr void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept {
m_fields = fields;
m_fieldPresence.setFields(fields);
m_buffIt = static_cast<std::size_t>(m_fieldPresence.getMaxLen());
ox_memset(m_buff, 0, m_buffIt);
}
template<typename T>
Result<Buffer> writeMC(T *val) noexcept {
constexpr std::size_t MetalClawWriter::size() const noexcept {
return m_buffIt;
}
Result<Buffer> writeMC(auto *val) noexcept {
Buffer buff(10 * units::MB);
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff.data()), buff.size());
oxReturnError(model(&writer, val));
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val));
buff.resize(writer.size());
return buff;
}
template<typename T>
Error writeMC(char *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) noexcept {
Error writeMC(char *buff, std::size_t buffLen, auto *val, std::size_t *sizeOut = nullptr) noexcept {
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff), buffLen);
auto err = model(&writer, val);
ModelHandlerInterface handler(&writer);
auto err = model(&handler, val);
if (sizeOut) {
*sizeOut = writer.size();
}

View File

@ -27,7 +27,9 @@ install(
optype.hpp
metadata.hpp
model.hpp
modelhandleradaptor.hpp
modelops.hpp
modelvalue.hpp
typenamecatcher.hpp
types.hpp
typestore.hpp

View File

@ -3,13 +3,15 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, modelName *o) noexcept { io->template setTypeInfo<modelName>();
#include <ox/std/concepts.hpp>
#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept { io->template setTypeInfo<modelName>();
#define oxModelEnd() return OxError(0); }
#define oxModelField(fieldName) oxReturnError(io->field(#fieldName, &o->fieldName));
#define oxModelFieldRename(serFieldName, objFieldName) oxReturnError(io->field(#serFieldName, &o->objFieldName));
#define oxModelFriend(modelName) friend constexpr ox::Error model(auto*, modelName*) noexcept
#define oxModelFriend(modelName) friend constexpr ox::Error model(auto*, ox::CommonPtrWith<modelName> auto*) noexcept

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -13,8 +13,11 @@
#include <ox/std/hashmap.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
#include <ox/std/typetraits.hpp>
#include <ox/std/vector.hpp>
#include <utility>
#include "optype.hpp"
#include "types.hpp"
namespace ox {
@ -42,15 +45,16 @@ struct DescriptorField {
String fieldName;
int subscriptLevels = 0;
String typeName; // gives reference to type for lookup if type is null
bool list = false;
constexpr DescriptorField() noexcept = default;
constexpr DescriptorField(const DescriptorType *pType, String pFieldName,
int pSubscriptLevels, String pTypeName) noexcept:
type(pType),
fieldName(pFieldName),
fieldName(std::move(pFieldName)),
subscriptLevels(pSubscriptLevels),
typeName(pTypeName) {
typeName(std::move(pTypeName)) {
}
constexpr DescriptorField(const DescriptorField &other) noexcept:
@ -96,7 +100,8 @@ struct DescriptorType {
constexpr DescriptorType() noexcept = default;
constexpr explicit DescriptorType(String tn) noexcept: typeName(std::move(tn)) {
constexpr explicit DescriptorType(String tn, int typeVersion) noexcept:
typeName(std::move(tn)), typeVersion(typeVersion) {
}
constexpr DescriptorType(String tn, PrimitiveType t, int b) noexcept:
@ -115,11 +120,11 @@ struct DescriptorType {
template<typename T>
constexpr Error model(T *io, DescriptorType *type) noexcept {
constexpr Error model(T *io, CommonPtrWith<DescriptorType> auto *type) noexcept {
io->template setTypeInfo<DescriptorType>();
oxReturnError(io->field("typeName", &type->typeName));
oxReturnError(io->field("typeVersion", &type->typeVersion));
if constexpr(ox_strcmp(T::opType(), "Reflect") == 0) {
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
uint8_t pt = 0;
oxReturnError(io->field("primitiveType", &pt));
} else {
@ -134,7 +139,7 @@ constexpr Error model(T *io, DescriptorType *type) noexcept {
}
template<typename T>
constexpr Error model(T *io, DescriptorField *field) noexcept {
constexpr Error model(T *io, CommonPtrWith<DescriptorField> auto *field) noexcept {
io->template setTypeInfo<DescriptorField>();
oxReturnError(io->field("typeName", &field->typeName));
oxReturnError(io->field("fieldName", &field->fieldName));
@ -149,7 +154,7 @@ template<typename ReaderBase>
class TypeDescReader;
template<typename T>
constexpr Error model(TypeDescReader<T> *io, DescriptorField *field) noexcept {
constexpr Error model(TypeDescReader<T> *io, CommonPtrWith<DescriptorField> auto *field) noexcept {
io->template setTypeInfo<DescriptorField>(DescriptorField::TypeName, DescriptorField::TypeVersion, 4);
oxReturnError(io->field("typeName", &field->typeName));
auto &typeStore = io->typeStore();

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <ox/std/typeinfo.hpp>
@ -33,115 +33,19 @@ static_assert(!preloadable<non_preloadable_type2>::value);
static_assert([] {
int i = 0;
return detail::indirectionLevels(i) == 0;
return detail::indirectionLevels_v<int> == 0;
}(), "indirectionLevels broken: indirectionLevels(int)");
static_assert([] {
int i = 0;
return detail::indirectionLevels(&i) == 1;
return detail::indirectionLevels_v<int*> == 1;
}(), "indirectionLevels broken: indirectionLevels(int*)");
static_assert([] {
int i[2] = {};
return detail::indirectionLevels(i) == 1;
return detail::indirectionLevels_v<int[2]> == 1;
}(), "indirectionLevels broken: indirectionLevels(int[])");
const DescriptorType *TypeDescWriter::type(int8_t*) noexcept {
constexpr auto String = "B:int8_t";
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 1;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(int16_t*) noexcept {
constexpr auto String = "B:int16_t";
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 2;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(int32_t*) noexcept {
constexpr auto String = "B:int32_t";
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 4;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(int64_t*) noexcept {
constexpr auto String = "B:int64_t";
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 8;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(uint8_t*) noexcept {
constexpr auto String = "B:uint8_t";
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 1;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(uint16_t*) noexcept {
constexpr auto String = "B:uint16_t";
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 2;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(uint32_t*) noexcept {
constexpr auto String = "B:uint32_t";
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 4;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(uint64_t*) noexcept {
constexpr auto String = "B:uint64_t";
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 8;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(char*) noexcept {
constexpr auto String = "B:string";
constexpr auto PT = PrimitiveType::String;
return getType(String, PT, 0);
}
const DescriptorType *TypeDescWriter::type(SerStr) noexcept {
constexpr auto String = "B:string";
constexpr auto PT = PrimitiveType::String;
return getType(String, PT, 0);
}
const DescriptorType *TypeDescWriter::type(String*) noexcept {
constexpr auto String = "B:string";
constexpr auto PT = PrimitiveType::String;
return getType(String, PT, 0);
}
const DescriptorType *TypeDescWriter::type(bool*) noexcept {
constexpr auto String = "B:bool";
constexpr auto PT = PrimitiveType::Bool;
constexpr auto Bytes = 0;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::getType(const String &tn, PrimitiveType pt, int b) noexcept {
auto t = m_typeStore->get(tn);
if (!t.error) {
auto type = t.value;
oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType");
return type;
} else {
auto dt = ox::make_unique<DescriptorType>(tn);
dt->primitiveType = pt;
dt->length = b;
const auto out = dt.get();
m_typeStore->set(tn, std::move(dt));
return out;
}
}
static_assert([] {
return detail::indirectionLevels_v<int**> == 2;
}(), "indirectionLevels broken: indirectionLevels(int[])");
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -19,6 +19,7 @@
#include "desctypes.hpp"
#include "fieldcounter.hpp"
#include "metadata.hpp"
#include "modelhandleradaptor.hpp"
#include "optype.hpp"
#include "typenamecatcher.hpp"
#include "types.hpp"
@ -29,14 +30,13 @@ namespace ox {
namespace detail {
template<typename T>
static constexpr int indirectionLevels(T) noexcept {
return 0;
}
constexpr int indirectionLevels_v = 0;
template<typename T>
static constexpr int indirectionLevels(T *t) noexcept {
return 1 + indirectionLevels(*t);
}
constexpr int indirectionLevels_v<T*> = 1 + indirectionLevels_v<T>;
template<typename T, std::size_t sz>
constexpr int indirectionLevels_v<T[sz]> = 1 + indirectionLevels_v<T>;
}
@ -49,17 +49,24 @@ class TypeDescWriter {
public:
explicit constexpr TypeDescWriter(TypeStore *typeStore = nullptr) noexcept;
constexpr ~TypeDescWriter() noexcept = default;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName,
int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
template<typename T>
constexpr Error field(const char *name, T *val, std::size_t valLen) noexcept;
constexpr Error field(const char *name, const T *val, std::size_t valLen) noexcept;
template<typename T>
constexpr Error field(const char *name, T val) noexcept;
template<typename T>
constexpr Error field(const char *name, T *val) noexcept;
constexpr Error field(const char *name, const T *val) noexcept;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int fields = ModelFieldCount_v<T>) noexcept;
template<typename ...Args>
constexpr Error fieldCString(const char *name, Args&&...) noexcept;
[[nodiscard]]
constexpr DescriptorType *definition() noexcept {
@ -71,56 +78,79 @@ class TypeDescWriter {
}
private:
const DescriptorType *type(int8_t *val) noexcept;
const DescriptorType *type(int16_t *val) noexcept;
const DescriptorType *type(int32_t *val) noexcept;
const DescriptorType *type(int64_t *val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const int8_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const int16_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const int32_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const int64_t *val) const noexcept;
const DescriptorType *type(uint8_t *val) noexcept;
const DescriptorType *type(uint16_t *val) noexcept;
const DescriptorType *type(uint32_t *val) noexcept;
const DescriptorType *type(uint64_t *val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint8_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint16_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint32_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint64_t *val) const noexcept;
const DescriptorType *type(bool *val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const bool *val) const noexcept;
const DescriptorType *type(char *val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const char *val) const noexcept;
const DescriptorType *type(SerStr val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(SerStr val) const noexcept;
const DescriptorType *type(String *val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const String *val) const noexcept;
template<std::size_t sz>
constexpr const DescriptorType *type(BString<sz> *val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const BString<sz> *val) const noexcept;
template<typename T>
constexpr const DescriptorType *type(T *val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const T *val) const noexcept;
template<typename T>
constexpr const DescriptorType *type(Vector<T> *val) noexcept;
template<typename T>
constexpr const DescriptorType *type(HashMap<String, T> *val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const HashMap<String, T> *val) const noexcept;
template<typename U>
constexpr const DescriptorType *type(UnionView<U> val) noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(UnionView<U> val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *getType(const String &tn, int typeVersion, PrimitiveType t, int b) const noexcept;
const DescriptorType *getType(const String &tn, PrimitiveType t, int b) noexcept;
};
constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) {
}
template<typename T>
constexpr void TypeDescWriter::setTypeInfo(const char *typeName, int typeVersion, int) noexcept {
m_type = m_typeStore->getInit(typeName, typeVersion);
if constexpr(is_union_v<T>) {
m_type->primitiveType = PrimitiveType::Union;
} else {
m_type->primitiveType = PrimitiveType::Struct;
}
m_type->preloadable = detail::preloadable<T>::value;
}
// array handler
template<typename T>
constexpr Error TypeDescWriter::field(const char *name, T *val, std::size_t) noexcept {
constexpr Error TypeDescWriter::field(const char *name, const T *val, std::size_t) noexcept {
if (m_type) {
constexpr typename remove_pointer<decltype(val)>::type *p = nullptr;
const auto t = type(p);
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
if (t == nullptr) {
type(p);
}
m_type->fieldList.emplace_back(t, name, detail::indirectionLevels(val), t->typeName);
m_type->fieldList.emplace_back(t, name, detail::indirectionLevels_v<T> + 1, t->typeName);
return OxError(0);
}
return OxError(1);
@ -138,70 +168,153 @@ constexpr Error TypeDescWriter::field(const char *name, T val) noexcept {
}
template<typename T>
constexpr Error TypeDescWriter::field(const char *name, T *val) noexcept {
constexpr Error TypeDescWriter::field(const char *name, const T *val) noexcept {
if (m_type) {
if constexpr(isVector_v<T> || isArray_v<T>) {
return field(name, val->data(), val->size());
} else {
const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated");
m_type->fieldList.emplace_back(t, name, 0, t->typeName);
return OxError(0);
}
}
return OxError(1);
}
template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(BString<sz> *val) noexcept {
return type(SerStr(val));
template<typename ...Args>
constexpr Error TypeDescWriter::fieldCString(const char *name, Args&&...) noexcept {
String s;
return field(name, &s);
}
template<typename T>
constexpr const DescriptorType *TypeDescWriter::type(T *val) noexcept {
constexpr const DescriptorType *TypeDescWriter::type(const T *val) const noexcept {
if constexpr(isVector_v<T>) {
return type(val->data());
} else {
auto [t, err] = m_typeStore->template get<T>();
if (!err) {
return t;
} else {
TypeDescWriter dw(m_typeStore);
oxLogError(model(&dw, val));
const auto reflectErr = model(&dw, val);
oxLogError(reflectErr);
oxAssert(reflectErr, "field(const char *name, T val): Type info could not be generated");
return dw.m_type;
}
}
template<typename T>
constexpr const DescriptorType *TypeDescWriter::type(Vector<T> *val) noexcept {
return type(val->data());
}
template<typename T>
constexpr const DescriptorType *TypeDescWriter::type(HashMap<String, T>*) noexcept {
constexpr const DescriptorType *TypeDescWriter::type(const HashMap<String, T>*) const noexcept {
return type(static_cast<T*>(nullptr));
}
template<typename U>
constexpr const DescriptorType *TypeDescWriter::type(UnionView<U> val) noexcept {
return type(val.get());
constexpr const DescriptorType *TypeDescWriter::type(UnionView<U> val) const noexcept {
const auto t = type(val.get());
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
return t;
}
template<typename T>
constexpr void TypeDescWriter::setTypeInfo(const char *name, int) noexcept {
m_type = m_typeStore->getInit(name);
if constexpr(is_union_v<T>) {
m_type->primitiveType = PrimitiveType::Union;
constexpr const DescriptorType *TypeDescWriter::type(const int8_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 1;
return getType(types::Int8, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const int16_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 2;
return getType(types::Int16, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const int32_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 4;
return getType(types::Int32, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const int64_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 8;
return getType(types::Int64, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint8_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 1;
return getType(types::Uint8, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint16_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 2;
return getType(types::Uint16, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint32_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 4;
return getType(types::Uint32, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint64_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 8;
return getType(types::Uint64, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const bool*) const noexcept {
constexpr auto PT = PrimitiveType::Bool;
constexpr auto Bytes = 0;
return getType(types::Bool, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
}
constexpr const DescriptorType *TypeDescWriter::type(SerStr) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
}
constexpr const DescriptorType *TypeDescWriter::type(const String*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
}
template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(const BString<sz>*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
}
constexpr const DescriptorType *TypeDescWriter::getType(const String &tn, int typeVersion, PrimitiveType pt, int b) const noexcept {
auto t = m_typeStore->get(tn, typeVersion);
if (!t.error) {
auto type = t.value;
oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType");
return type;
} else {
m_type->primitiveType = PrimitiveType::Struct;
auto dt = ox::make_unique<DescriptorType>(tn, typeVersion);
dt->primitiveType = pt;
dt->length = b;
const auto out = dt.get();
m_typeStore->set(tn, typeVersion, std::move(dt));
return out;
}
m_type->preloadable = detail::preloadable<T>::value;
}
template<typename T>
Result<DescriptorType*> buildTypeDef(TypeStore *typeStore, T *val) noexcept {
constexpr Result<DescriptorType*> buildTypeDef(TypeStore *typeStore, T *val) noexcept {
TypeDescWriter writer(typeStore);
oxReturnError(model(&writer, val));
ModelHandlerInterface handler(&writer);
oxReturnError(model(&handler, val));
return writer.definition();
}
auto writeTypeDefOC(auto *val) noexcept {
TypeStore typeStore;
oxRequire(def, buildTypeDef(&typeStore, val));
return writeOC(def.get());
}
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -44,6 +44,11 @@ class FieldCounter {
return OxError(0);
}
template<typename ...Args>
constexpr Error fieldCString(Args&&...) noexcept {
return OxError(0);
}
static constexpr auto opType() {
return OpType::Reflect;
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -13,7 +13,9 @@
#include "desctypes.hpp"
#include "descwrite.hpp"
#include "fieldcounter.hpp"
#include "modelhandleradaptor.hpp"
#include "modelops.hpp"
#include "modelvalue.hpp"
#include "typenamecatcher.hpp"
#include "types.hpp"
#include "typestore.hpp"

View File

@ -0,0 +1,155 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* 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 https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/utility.hpp>
#include "modelvalue.hpp"
namespace ox {
template<typename Handler>
class ModelHandlerInterface {
private:
Handler *m_handler = nullptr;
public:
constexpr explicit ModelHandlerInterface(Handler *handler) noexcept: m_handler(handler) {
}
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept {
m_handler->setTypeInfo(name, version, fields);
}
template<std::size_t len>
constexpr Error fieldCString(const char *name, char val[len]) noexcept {
return m_handler->fieldCString(name, &val[0], len);
}
template<std::size_t len>
constexpr Error fieldCString(const char *name, const char val[len]) noexcept {
return m_handler->fieldCString(name, &val[0], len);
}
constexpr Error fieldCString(const char *name, char **val) noexcept {
return m_handler->fieldCString(name, val);
}
constexpr Error fieldCString(const char *name, const char **val) noexcept {
return m_handler->fieldCString(name, val);
}
constexpr Error fieldCString(const char *name, char **val, std::size_t buffLen) noexcept {
return m_handler->fieldCString(name, val, buffLen);
}
constexpr Error fieldCString(const char *name, const char **val, std::size_t buffLen) noexcept {
return m_handler->fieldCString(name, val, buffLen);
}
constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept {
return m_handler->fieldCString(name, val, buffLen);
}
constexpr Error field(const char *name, CommonPtrWith<ModelValue> auto *v) noexcept {
switch (v->type()) {
case ModelValue::Type::Undefined:
break;
case ModelValue::Type::Bool:
return m_handler->field(name, &v->template get<bool>());
case ModelValue::Type::UnsignedInteger8:
return m_handler->field(name, &v->template get<uint8_t>());
case ModelValue::Type::UnsignedInteger16:
return m_handler->field(name, &v->template get<uint16_t>());
case ModelValue::Type::UnsignedInteger32:
return m_handler->field(name, &v->template get<uint32_t>());
case ModelValue::Type::UnsignedInteger64:
return m_handler->field(name, &v->template get<uint64_t>());
case ModelValue::Type::SignedInteger8:
return m_handler->field(name, &v->template get<int8_t>());
case ModelValue::Type::SignedInteger16:
return m_handler->field(name, &v->template get<int16_t>());
case ModelValue::Type::SignedInteger32:
return m_handler->field(name, &v->template get<int32_t>());
case ModelValue::Type::SignedInteger64:
return m_handler->field(name, &v->template get<int64_t>());
case ModelValue::Type::String:
return m_handler->field(name, &v->template get<String>());
case ModelValue::Type::Object:
return m_handler->field(name, &v->template get<ModelObject>());
case ModelValue::Type::Union:
{
auto &u = v->template get<ModelUnion>();
if constexpr(ox_strcmp(Handler::opType(), OpType::Read) == 0) {
u.setActiveField(m_handler->whichFieldPresent(name, u));
}
return m_handler->field(name, UnionView<ModelUnion, true>(&u, u.unionIdx()));
}
case ModelValue::Type::Vector:
return m_handler->field(name, &v->template get<ModelValueVector>());
}
oxPanic(OxError(1), "invalid type");
return OxError(1, "invalid type");
}
// array handler, with callback to allow handling individual elements
template<typename T, typename Callback>
constexpr Error field(const char *name, Callback cb) noexcept {
return m_handler->template field<T, Callback>(name, cb);
}
constexpr Error field(const char *name, const auto *v) noexcept {
return m_handler->field(name, v);
}
constexpr Error field(const char *name, auto *v) noexcept {
return m_handler->field(name, v);
}
template<typename U, bool force = false>
constexpr Error field(const char *name, UnionView<U, force> val) noexcept {
return m_handler->field(name, val);
}
constexpr Error field(const char *name, auto *val, std::size_t len) noexcept {
return m_handler->field(name, val, len);
}
/**
* Reads an array length from the current location in the buffer.
* @param pass indicates that the parsing should iterate past the array length
*/
[[nodiscard]]
constexpr auto arrayLength(const char *name, bool pass = true) noexcept {
return m_handler->arrayLength(name, pass);
}
/**
* Reads an string length from the current location in the buffer.
*/
[[nodiscard]]
constexpr auto stringLength(const char *name) noexcept {
return m_handler->stringLength(name);
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return Handler::opType();
}
[[nodiscard]]
constexpr auto handler() noexcept {
return m_handler;
}
};
}

View File

@ -14,12 +14,36 @@
#include <ox/std/utility.hpp>
#include "fieldcounter.hpp"
#include "modelvalue.hpp"
#include "optype.hpp"
#include "types.hpp"
namespace ox {
namespace detail {
class Wrap {
public:
virtual ~Wrap() = default;
};
template<typename T>
class WrapT: public Wrap {
private:
T *m_obj = nullptr;
public:
constexpr WrapT(T *obj) noexcept: m_obj(obj) {
}
constexpr WrapT() = default;
[[nodiscard]]
constexpr auto obj() noexcept {
return m_obj;
}
};
template<std::size_t size>
class MemberList {
@ -27,7 +51,7 @@ class MemberList {
std::size_t m_i = 0;
public:
void *vars[size];
Array<void*, size> vars;
template<typename T>
constexpr Error field(const char*, T *v) noexcept {
@ -41,8 +65,8 @@ class MemberList {
return OxError(0);
}
template<typename U>
constexpr Error field(const char*, UnionView<U> u) noexcept {
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) noexcept {
vars[m_i++] = static_cast<void*>(u.get());
return OxError(0);
}
@ -57,7 +81,7 @@ class MemberList {
[[nodiscard]]
static constexpr auto opType() noexcept {
return "GetMembers";
return OpType::Reflect;
}
};
@ -97,8 +121,8 @@ class Copier {
return OxError(0);
}
template<typename U>
constexpr Error field(const char*, UnionView<U> u) {
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) {
auto &dst = *cbit_cast<U*>(m_dst->vars[m_i]);
auto &src = *u.get();
dst = src;
@ -116,7 +140,7 @@ class Copier {
[[nodiscard]]
static constexpr auto opType() noexcept {
return "Copy";
return OpType::Read;
}
};
@ -158,8 +182,8 @@ class Mover {
return OxError(0);
}
template<typename U>
constexpr Error field(const char*, UnionView<U> u) noexcept {
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) noexcept {
auto &dst = *cbit_cast<U*>(m_dst->vars[m_i]);
auto &src = *u.get();
dst = std::move(src);
@ -177,7 +201,7 @@ class Mover {
[[nodiscard]]
static constexpr auto opType() noexcept {
return "Copy";
return OpType::Read;
}
};
@ -222,8 +246,8 @@ class Equals {
return OxError(0);
}
template<typename U>
constexpr Error field(const char*, UnionView<U> u) noexcept {
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) noexcept {
const auto &dst = *cbit_cast<U*>(m_other->vars[m_i]);
const auto &src = *u.get();
++m_i;
@ -253,13 +277,31 @@ class Equals {
[[nodiscard]]
static constexpr auto opType() noexcept {
return "Copy";
return OpType::Read;
}
};
}
template<typename T>
constexpr void moveModel(ModelObject *dst, T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Mover<size> mover(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&mover, src));
}
template<typename T>
constexpr void moveModel(T *dst, ModelObject *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Mover<size> mover(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&mover, src));
}
template<typename T>
constexpr void moveModel(T *dst, T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
@ -269,6 +311,24 @@ constexpr void moveModel(T *dst, T *src) noexcept {
oxIgnoreError(model(&mover, src));
}
template<typename T>
constexpr void copyModel(ModelObject *dst, const T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Copier<size> copier(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&copier, src));
}
template<typename T>
constexpr void copyModel(T *dst, const ModelObject *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Copier<size> copier(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&copier, src));
}
template<typename T>
constexpr void copyModel(T *dst, const T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;

9
deps/ox/src/ox/model/modelvalue.cpp vendored Normal file
View File

@ -0,0 +1,9 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* 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 https://mozilla.org/MPL/2.0/.
*/
#include "modelvalue.hpp"

886
deps/ox/src/ox/model/modelvalue.hpp vendored Normal file
View File

@ -0,0 +1,886 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* 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 https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
#include <ox/std/trace.hpp>
#include <ox/std/types.hpp>
#include <ox/std/vector.hpp>
#include "def.hpp"
#include "desctypes.hpp"
#include "fieldcounter.hpp"
#include "metadata.hpp"
#include "optype.hpp"
#include "typenamecatcher.hpp"
#include "types.hpp"
#include "typestore.hpp"
namespace ox {
class ModelObject;
class ModelUnion;
class ModelValue;
class ModelValueVector;
class ModelValue {
public:
enum class Type {
Undefined,
Bool,
UnsignedInteger8,
UnsignedInteger16,
UnsignedInteger32,
UnsignedInteger64,
SignedInteger8,
SignedInteger16,
SignedInteger32,
SignedInteger64,
String,
Object,
Union,
Vector,
};
private:
Type m_type = Type::Undefined;
union {
bool b{};
int8_t i8;
uint8_t ui8;
int16_t i16;
uint16_t ui16;
int32_t i32;
uint32_t ui32;
int64_t i64;
uint64_t ui64;
String *str;
ModelObject *obj;
ModelUnion *uni;
ModelValueVector *vec;
} m_data;
template<typename T>
consteval static Type getType() noexcept {
if constexpr(is_bool_v<T>) {
return Type::Bool;
} else if constexpr(is_integer_v<T>) {
if (!is_signed_v<T> && sizeof(T) == 1) {
return Type::UnsignedInteger8;
} else if constexpr(!is_signed_v<T> && sizeof(T) == 2) {
return Type::UnsignedInteger16;
} else if constexpr(!is_signed_v<T> && sizeof(T) == 4) {
return Type::UnsignedInteger32;
} else if constexpr(!is_signed_v<T> && sizeof(T) == 8) {
return Type::UnsignedInteger64;
} else if constexpr(is_signed_v<T> && sizeof(T) == 1) {
return Type::SignedInteger8;
} else if constexpr(is_signed_v<T> && sizeof(T) == 2) {
return Type::SignedInteger16;
} else if constexpr(is_signed_v<T> && sizeof(T) == 4) {
return Type::SignedInteger32;
} else if constexpr(is_signed_v<T> && sizeof(T) == 8) {
return Type::SignedInteger64;
}
} else if constexpr(is_same_v<T, ModelUnion>) {
return Type::Union;
} else if constexpr(is_same_v<T, ModelObject>) {
return Type::Object;
} else if constexpr(is_same_v<T, String>) {
return Type::String;
} else if constexpr(is_same_v<T, ModelValueVector>) {
return Type::Vector;
} else {
return Type::Undefined;
}
}
template<Type type>
static constexpr auto &getValue(auto &t) noexcept {
if constexpr(type == Type::Bool) {
return t.m_data.b;
} else if constexpr(type == Type::UnsignedInteger8) {
return t.m_data.ui8;
} else if constexpr(type == Type::UnsignedInteger16) {
return t.m_data.ui16;
} else if constexpr(type == Type::UnsignedInteger32) {
return t.m_data.ui32;
} else if constexpr(type == Type::UnsignedInteger64) {
return t.m_data.ui64;
} else if constexpr(type == Type::SignedInteger8) {
return t.m_data.i8;
} else if constexpr(type == Type::SignedInteger16) {
return t.m_data.i16;
} else if constexpr(type == Type::SignedInteger32) {
return t.m_data.i32;
} else if constexpr(type == Type::SignedInteger64) {
return t.m_data.i64;
} else if constexpr(type == Type::String) {
return *t.m_data.str;
} else if constexpr(type == Type::Union) {
return *t.m_data.uni;
} else if constexpr(type == Type::Object) {
return *t.m_data.obj;
} else if constexpr(type == Type::Vector) {
return *t.m_data.vec;
} else {
return t.m_data.i32;
}
}
public:
constexpr ModelValue() noexcept = default;
constexpr ModelValue(const ModelValue &other) noexcept;
constexpr ModelValue(ModelValue &other) noexcept;
constexpr ModelValue(ModelValue &&other) noexcept;
template<typename T>
explicit constexpr ModelValue(const T &val) noexcept;
template<typename T>
explicit constexpr ModelValue(T &&val) noexcept;
constexpr ~ModelValue() noexcept;
template<typename T>
[[nodiscard]]
constexpr const auto &get() const noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
oxPanic(OxError(1), "invalid cast");
}
return getValue<type>(*this);
}
template<typename T>
[[nodiscard]]
constexpr auto &get() noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
oxPanic(OxError(1), "invalid cast");
}
return getValue<type>(*this);
}
[[nodiscard]]
constexpr Type type() const noexcept;
constexpr Error setType(const DescriptorType *type, int subscriptLevels = 0) noexcept;
template<typename T>
constexpr Error setType() noexcept;
template<typename T>
constexpr Error set(const T &v) noexcept;
template<typename T>
constexpr Error set(T &&v) noexcept;
constexpr ModelValue &operator=(ModelValue &val) noexcept;
constexpr ModelValue &operator=(const ModelValue &val) noexcept;
constexpr ModelValue &operator=(ModelValue &&val) noexcept;
constexpr ModelValue &operator=(const auto &val) noexcept;
constexpr ModelValue &operator=(auto &&val) noexcept;
private:
constexpr void freeResources() noexcept;
};
class ModelValueVector {
private:
Vector<ModelValue> m_vec;
ModelValue m_templateValue;
String m_typeName;
int m_typeVersion = 0;
public:
constexpr ModelValueVector() noexcept = default;
constexpr ModelValueVector(const ModelValueVector &other) noexcept;
constexpr ModelValueVector(ModelValueVector &&other) noexcept;
constexpr ModelValueVector &operator=(const ModelValueVector &other) noexcept;
constexpr ModelValueVector &operator=(ModelValueVector &&other) noexcept;
[[nodiscard]]
constexpr auto data() const noexcept {
return m_vec.data();
}
[[nodiscard]]
constexpr auto data() noexcept {
return m_vec.data();
}
constexpr void resize(std::size_t sz) noexcept {
const auto oldSz = m_vec.size();
m_vec.resize(sz);
if (sz > oldSz) {
for (auto i = oldSz; i < sz; ++i) {
m_vec[i] = m_templateValue;
}
}
}
[[nodiscard]]
constexpr auto &get() noexcept {
return m_vec;
}
[[nodiscard]]
constexpr const auto &get() const noexcept {
return m_vec;
}
constexpr Error setType(const DescriptorType *type, int subscriptLevels) noexcept {
return m_templateValue.setType(type, subscriptLevels);
}
[[nodiscard]]
constexpr const String &typeName() const noexcept {
return m_typeName;
}
[[nodiscard]]
constexpr int typeVersion() const noexcept {
return m_typeVersion;
}
[[nodiscard]]
constexpr std::size_t size() const noexcept {
return m_vec.size();
}
constexpr auto &operator[](std::size_t i) noexcept {
return m_vec[i];
}
constexpr auto &operator[](std::size_t i) const noexcept {
return m_vec[i];
}
[[nodiscard]]
auto begin() noexcept {
return m_vec.begin();
}
[[nodiscard]]
auto cbegin() const noexcept {
return m_vec.cbegin();
}
[[nodiscard]]
auto rbegin() noexcept {
return m_vec.rbegin();
}
[[nodiscard]]
auto crbegin() const noexcept {
return m_vec.crbegin();
}
[[nodiscard]]
auto end() noexcept {
return m_vec.end();
}
[[nodiscard]]
auto cend() const noexcept {
return m_vec.cend();
}
[[nodiscard]]
auto rend() noexcept {
return m_vec.rend();
}
[[nodiscard]]
auto crend() const noexcept {
return m_vec.crend();
}
};
consteval bool isVector(const ModelValueVector*) noexcept {
return true;
}
class ModelObject {
protected:
struct Field {
String name;
ModelValue value;
};
oxModelFriend(ModelObject);
friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, ModelValue*> m_fields;
String m_typeName;
int m_typeVersion = 0;
public:
constexpr ModelObject() noexcept = default;
constexpr ModelObject(const ModelObject &other) noexcept {
for (const auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value});
m_fields[field->name] = &field->value;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
}
constexpr ModelObject(ModelObject &&other) noexcept {
for (auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(std::move(f));
m_fields[field->name] = &field->value;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
}
constexpr auto &operator=(const ModelObject &other) noexcept {
if (&other == this) [[unlikely]] {
return *this;
}
for (const auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value});
m_fields[field->name] = &field->value;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
return *this;
}
constexpr auto &operator=(ModelObject &&other) noexcept {
if (&other == this) [[unlikely]] {
return *this;
}
for (auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(std::move(f));
m_fields[field->name] = &field->value;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
return *this;
}
constexpr auto &operator[](const std::size_t &i) noexcept {
return *m_fieldsOrder[i];
}
constexpr auto &operator[](const String &k) noexcept {
return *m_fields[k];
}
constexpr auto &operator[](const std::size_t i) noexcept {
return *m_fieldsOrder[i];
}
[[nodiscard]]
constexpr const String &typeName() const noexcept {
return m_typeName;
}
[[nodiscard]]
constexpr int typeVersion() const noexcept {
return m_typeVersion;
}
constexpr Error setType(const DescriptorType *type) noexcept {
if (type->primitiveType != PrimitiveType::Struct && type->primitiveType != PrimitiveType::Union) {
return OxError(1, "Cannot load a non-struct type to ModelObject");
}
m_typeName = type->typeName;
m_typeVersion = type->typeVersion;
for (const auto &f : type->fieldList) {
auto field = make_unique<Field>();
field->name = f.fieldName;
oxReturnError(field->value.setType(f.type, f.subscriptLevels));
m_fields[field->name] = &field->value;
m_fieldsOrder.emplace_back(std::move(field));
}
return OxError(0);
}
};
class ModelUnion {
protected:
struct Field {
int idx = -1;
String name;
ModelValue value;
};
oxModelFriend(ModelUnion);
friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, Field*> m_fields;
String m_typeName;
int m_typeVersion = 0;
int m_unionIdx = -1;
private:
constexpr ModelUnion() noexcept = default;
public:
constexpr ModelUnion(const ModelUnion &other) noexcept {
for (auto i = 0; const auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(new Field{i, f->name, f->value});
m_fields[field->name] = field.get();
++i;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
m_unionIdx = other.m_unionIdx;
}
static constexpr Result<UniquePtr<ModelUnion>> make(const DescriptorType *type) noexcept {
UniquePtr<ModelUnion> out(new ModelUnion);
oxReturnError(out->setType(type));
return out;
}
static constexpr Result<UniquePtr<ModelUnion>> make(const ModelUnion &other) noexcept {
return UniquePtr<ModelUnion>(new ModelUnion(other));
}
constexpr auto &operator[](const String &k) noexcept {
return m_fields[k]->value;
}
constexpr auto &operator[](const std::size_t i) noexcept {
return m_fieldsOrder[i]->value;
}
constexpr void setActiveField(int i) noexcept {
m_unionIdx = i;
}
constexpr void set(int i, auto val) noexcept {
m_unionIdx = i;
*m_fieldsOrder[i] = val;
}
constexpr void set(std::size_t i, auto val) noexcept {
m_unionIdx = static_cast<int>(i);
*m_fieldsOrder[i] = val;
}
[[nodiscard]]
constexpr ModelValue &get(std::size_t i) noexcept {
return m_fieldsOrder[i]->value;
}
[[nodiscard]]
constexpr ModelValue &get(const String &k) noexcept {
return (*m_fields.at(k).value)->value;
}
[[nodiscard]]
constexpr int getKeyIdx(const auto &k) const noexcept {
for (auto i = 0; const auto &f : m_fieldsOrder) {
if (f->name == k) {
return i;
}
++i;
}
return -1;
}
[[nodiscard]]
constexpr const String &typeName() const noexcept {
return m_typeName;
}
[[nodiscard]]
constexpr int typeVersion() const noexcept {
return m_typeVersion;
}
constexpr Error setType(const DescriptorType *type) noexcept {
if (type->primitiveType != PrimitiveType::Struct && type->primitiveType != PrimitiveType::Union) {
return OxError(1, "Cannot load a non-struct type to ModelUnion");
}
m_fields.clear();
m_fieldsOrder.clear();
m_typeName = type->typeName;
m_typeVersion = type->typeVersion;
for (auto i = 0; const auto &f : type->fieldList) {
auto field = make_unique<Field>();
field->name = f.fieldName;
field->idx = i;
oxReturnError(field->value.setType(f.type, f.subscriptLevels));
m_fields[field->name] = field.get();
m_fieldsOrder.emplace_back(std::move(field));
++i;
}
return OxError(0);
}
[[nodiscard]]
constexpr auto fieldCount() const noexcept {
return m_fields.size();
}
[[nodiscard]]
constexpr auto unionIdx() const noexcept {
return m_unionIdx;
}
};
constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast<int>(obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value));
}
return OxError(0);
}
constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast<int>(obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value));
}
return OxError(0);
}
constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
break;
case Type::String:
m_data.str = new String(other.get<String>());
break;
case Type::Union:
m_data.uni = new ModelUnion(other.get<ModelUnion>());
break;
case Type::Object:
m_data.obj = new ModelObject(other.get<ModelObject>());
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
}
}
constexpr ModelValue::ModelValue(ModelValue &other) noexcept: ModelValue(const_cast<const ModelValue&>(other)) {
}
constexpr ModelValue::ModelValue(ModelValue &&other) noexcept {
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
ox_memset(&other.m_data, 0, sizeof(m_data));
break;
case Type::String:
m_data.str = other.m_data.str;
other.m_data.str = new String;
break;
case Type::Union:
m_data.uni = new ModelUnion(*other.m_data.uni);
break;
case Type::Object:
m_data.obj = new ModelObject(*other.m_data.obj);
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
}
}
template<typename T>
constexpr ModelValue::ModelValue(const T &val) noexcept {
set(val);
}
template<typename T>
constexpr ModelValue::ModelValue(T &&val) noexcept {
set(ox::forward(val));
}
constexpr ModelValue::~ModelValue() noexcept {
freeResources();
}
constexpr ModelValue::Type ModelValue::type() const noexcept {
return m_type;
}
constexpr Error ModelValue::setType(const DescriptorType *type, int subscriptLevels) noexcept {
freeResources();
if (subscriptLevels) {
m_type = Type::Vector;
m_data.vec = new ModelValueVector;
return m_data.vec->setType(type, subscriptLevels - 1);
} else if (type->typeName == types::Bool) {
m_type = Type::Bool;
} else if (type->typeName == types::String) {
m_type = Type::String;
m_data.str = new String;
} else if (type->typeName == types::Uint8) {
m_type = Type::UnsignedInteger8;
} else if (type->typeName == types::Uint16) {
m_type = Type::UnsignedInteger16;
} else if (type->typeName == types::Uint32) {
m_type = Type::UnsignedInteger32;
} else if (type->typeName == types::Uint64) {
m_type = Type::UnsignedInteger64;
} else if (type->typeName == types::Int8) {
m_type = Type::SignedInteger8;
} else if (type->typeName == types::Int16) {
m_type = Type::SignedInteger16;
} else if (type->typeName == types::Int32) {
m_type = Type::SignedInteger32;
} else if (type->typeName == types::Int64) {
m_type = Type::SignedInteger64;
} else if (type->primitiveType == PrimitiveType::Struct) {
m_type = Type::Object;
m_data.obj = new ModelObject;
oxReturnError(m_data.obj->setType(type));
} else if (type->primitiveType == PrimitiveType::Union) {
m_type = Type::Union;
oxRequireM(u, ModelUnion::make(type));
m_data.uni = u.release();
oxReturnError(m_data.uni->setType(type));
}
return OxError(0);
}
template<typename T>
constexpr Error ModelValue::setType() noexcept {
constexpr auto type = getType<T>();
return setType(type);
}
template<typename T>
constexpr Error ModelValue::set(const T &v) noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
return OxError(1, "type mismatch");
}
auto &value = getValue<type>(*this);
value = v;
return OxError(0);
}
template<typename T>
constexpr Error ModelValue::set(T &&v) noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
return OxError(1, "type mismatch");
}
auto &value = getValue<type>(*this);
if constexpr(type == Type::Vector || type == Type::Object ||
type == Type::Union || type == Type::String) {
safeDelete(value);
}
value = ox::forward<T>(v);
return OxError(0);
}
constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept {
return this->operator=(const_cast<const ModelValue&>(other));
}
constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept {
if (this == &other) [[unlikely]] {
return *this;
}
freeResources();
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
break;
case Type::String:
m_data.str = new String(other.get<String>());
break;
case Type::Union:
m_data.uni = new ModelUnion(other.get<ModelUnion>());
break;
case Type::Object:
m_data.obj = new ModelObject(other.get<ModelObject>());
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
}
return *this;
}
constexpr ModelValue &ModelValue::operator=(ModelValue &&other) noexcept {
if (this == &other) [[unlikely]] {
return *this;
}
freeResources();
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
ox_memset(&other.m_data, 0, sizeof(m_data));
break;
case Type::String:
m_data.str = other.m_data.str;
other.m_data.str = new String;
break;
case Type::Object:
m_data.obj = new ModelObject(*other.m_data.obj);
break;
case Type::Union:
m_data.uni = new ModelUnion(*other.m_data.uni);
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
}
return *this;
}
constexpr ModelValue &ModelValue::operator=(const auto &val) noexcept {
if (this == &val) {
return *this;
}
set(val);
return *this;
}
constexpr ModelValue &ModelValue::operator=(auto &&val) noexcept {
if (this == &val) {
return *this;
}
set(ox::forward(val));
return *this;
}
constexpr void ModelValue::freeResources() noexcept {
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
break;
case Type::String:
safeDelete(m_data.str);
break;
case Type::Object:
safeDelete(m_data.obj);
break;
case Type::Union:
safeDelete(m_data.uni);
break;
case Type::Vector:
safeDelete(m_data.vec);
break;
}
m_type = Type::Undefined;
}
constexpr ModelValueVector::ModelValueVector(const ModelValueVector &other) noexcept {
for (auto &v : other.m_vec) {
m_vec.emplace_back(v);
}
m_templateValue = other.m_templateValue;
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
}
constexpr ModelValueVector::ModelValueVector(ModelValueVector &&other) noexcept {
for (auto &v : other.m_vec) {
m_vec.emplace_back(std::move(v));
}
m_templateValue = std::move(other.m_templateValue);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
}
constexpr ModelValueVector &ModelValueVector::operator=(const ModelValueVector &other) noexcept {
if (this == &other) {
return *this;
}
for (auto &v : other.m_vec) {
m_vec.emplace_back(v);
}
m_templateValue = other.m_templateValue;
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
return *this;
}
constexpr ModelValueVector &ModelValueVector::operator=(ModelValueVector &&other) noexcept {
if (this == &other) {
return *this;
}
for (auto &v : other.m_vec) {
m_vec.emplace_back(std::move(v));
}
m_templateValue = std::move(other.m_templateValue);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
return *this;
}
}

View File

@ -3,54 +3,18 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/assert.hpp>
#include <ox/std/concepts.hpp>
#include <ox/std/error.hpp>
#include <ox/std/strops.hpp>
namespace ox {
namespace OpType {
namespace ox::OpType {
constexpr auto Read = "Read";
constexpr auto Write = "Write";
constexpr auto Reflect = "Reflect";
}
// empty default implementations of model functions
template<typename T, typename O>
constexpr Error modelRead(T*, O*) noexcept {
oxAssert(OxError(1), "Missing modelRead function");
return OxError(1, "Model: modelRead not implemented");
}
template<typename T, typename O>
constexpr Error modelWrite(T*, O*) noexcept {
oxAssert(OxError(1), "Missing modelWrite function");
return OxError(1, "Model: modelWrite not implemented");
}
template<typename T, typename O>
constexpr Error modelReflect(T*, O*) noexcept {
return OxError(1, "Model: modelReflect not implemented");
}
template<typename T, typename O>
constexpr Error model(T *io, O *obj) noexcept {
if constexpr(ox_strcmp(T::opType(), OpType::Read) == 0) {
return modelRead(io, obj);
} else if constexpr(ox_strcmp(T::opType(), OpType::Write) == 0) {
return modelWrite(io, obj);
} else if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
return modelReflect(io, obj);
} else {
oxAssert(OxError(1), "Missing model function");
return OxError(1);
}
}
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -40,8 +40,8 @@ struct TypeNameCatcher {
return OxError(0);
}
template<typename T>
constexpr Error fieldCString(const char*, T) noexcept {
template<typename ...Args>
constexpr Error fieldCString(Args&&...) noexcept {
return OxError(0);
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -12,10 +12,15 @@
#include <vector>
#endif
#if __has_include(<array>)
#include <array>
#endif
#if __has_include(<QVector>)
#include <QVector>
#endif
#include <ox/std/array.hpp>
#include <ox/std/bstring.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/types.hpp>
@ -24,19 +29,32 @@
namespace ox {
namespace types {
constexpr auto String = "B:string";
constexpr auto Bool = "B:bool";
constexpr auto Uint8 = "B:uint8_t";
constexpr auto Uint16 = "B:uint16_t";
constexpr auto Uint32 = "B:uint32_t";
constexpr auto Uint64 = "B:uint64_t";
constexpr auto Int8 = "B:int8_t";
constexpr auto Int16 = "B:int16_t";
constexpr auto Int32 = "B:int32_t";
constexpr auto Int64 = "B:int64_t";
}
template<typename T>
constexpr bool isVector(const T*) noexcept {
consteval bool isVector(const T*) noexcept {
return false;
}
template<typename T>
constexpr bool isVector(const Vector<T>*) noexcept {
consteval bool isVector(const Vector<T>*) noexcept {
return true;
}
#if __has_include(<vector>)
template<typename T>
constexpr bool isVector(const std::vector<T>*) noexcept {
consteval bool isVector(const std::vector<T>*) noexcept {
return true;
}
#endif
@ -51,6 +69,24 @@ constexpr bool isVector(const QVector<T>*) noexcept {
template<typename T>
constexpr bool isVector_v = isVector(static_cast<const T*>(nullptr));
template<typename T>
constexpr bool isArray_v = false;
template<typename T>
constexpr bool isArray_v<T[]> = false;
template<typename T, std::size_t sz>
constexpr bool isArray_v<T[sz]> = false;
template<typename T, std::size_t sz>
constexpr bool isArray_v<Array<T, sz>> = false;
#if __has_include(<array>)
template<typename T, std::size_t sz>
constexpr bool isArray_v<std::array<T, sz>> = false;
#endif
class SerStr {
protected:
@ -121,12 +157,12 @@ class SerStr {
};
template<typename Union>
template<typename Union, bool force = false>
class UnionView {
protected:
int m_idx = -1;
typename enable_if<is_union_v<Union>, Union>::type *m_union = nullptr;
typename enable_if<is_union_v<Union> || force, Union>::type *m_union = nullptr;
public:
constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -13,6 +13,7 @@
#include <ox/std/string.hpp>
#include <ox/std/typetraits.hpp>
#include "ox/std/fmt.hpp"
#include "typenamecatcher.hpp"
#include "desctypes.hpp"
@ -22,29 +23,37 @@ class TypeStore {
private:
HashMap<String, UniquePtr<DescriptorType>> m_cache;
static constexpr auto buildTypeId(const auto &name, auto version) noexcept {
return ox::sfmt("{};{}", name, version);
}
public:
constexpr TypeStore() noexcept = default;
constexpr virtual ~TypeStore() noexcept = default;
constexpr Result<DescriptorType*> get(const auto &name) const noexcept {
oxRequire(out, m_cache.at(name));
constexpr Result<DescriptorType*> get(const auto &name, int typeVersion) const noexcept {
const auto typeId = buildTypeId(name, typeVersion);
oxRequire(out, m_cache.at(typeId));
return out->get();
}
template<typename T>
constexpr Result<DescriptorType*> get() const noexcept {
constexpr auto name = requireModelTypeName<T>();
oxRequire(out, m_cache.at(name));
constexpr auto typeName = requireModelTypeName<T>();
constexpr auto typeVersion = requireModelTypeVersion<T>();
const auto typeId = buildTypeId(typeName, typeVersion);
oxRequire(out, m_cache.at(typeId));
return out->get();
}
constexpr DescriptorType *getInit(const auto &name) noexcept {
auto [out, err] = m_cache.at(name);
constexpr DescriptorType *getInit(const auto &typeName, int typeVersion) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion);
auto [out, err] = m_cache.at(typeId);
if (err) {
auto &out = m_cache[name];
out = ox::make_unique<DescriptorType>(name);
return out.get();
out = &m_cache[typeId];
*out = ox::make_unique<DescriptorType>(typeName, typeVersion);
return out->get();
}
return out->get();
}
@ -55,15 +64,13 @@ class TypeStore {
return getInit(name);
}
template<typename T>
constexpr Result<DescriptorType*> getLoad() noexcept {
constexpr auto nameCstr = requireModelTypeName<T>();
const String name = nameCstr;
auto [val, err] = m_cache.at(name);
constexpr Result<DescriptorType*> getLoad(const auto &typeName, auto typeVersion) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion);
auto [val, err] = m_cache.at(typeId);
if (err) {
if (!std::is_constant_evaluated()) {
oxRequireM(dt, loadDescriptor(name));
auto &out = m_cache[name];
oxRequireM(dt, loadDescriptor(typeName, typeVersion));
auto &out = m_cache[typeId];
out = std::move(dt);
return out.get();
} else {
@ -73,12 +80,21 @@ class TypeStore {
return val->get();
}
constexpr void set(const String &name, UniquePtr<DescriptorType> dt) noexcept {
m_cache[name] = std::move(dt);
template<typename T>
constexpr Result<DescriptorType*> getLoad() noexcept {
constexpr auto typeName = requireModelTypeName<T>();
constexpr auto typeVersion = requireModelTypeVersion<T>();
return getLoad(typeName, typeVersion);
}
constexpr void set(const String &name, DescriptorType *dt) noexcept {
m_cache[name] = UniquePtr<DescriptorType>(dt);
constexpr void set(const auto &typeName, auto typeVersion, UniquePtr<DescriptorType> dt) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion);
m_cache[typeId] = std::move(dt);
}
constexpr void set(const auto &typeName, auto typeVersion, DescriptorType *dt) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion);
m_cache[typeId] = UniquePtr<DescriptorType>(dt);
}
[[nodiscard]]
@ -92,7 +108,7 @@ class TypeStore {
}
protected:
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(const ox::String&) noexcept {
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(const ox::String&, int) noexcept {
return OxError(1);
}

View File

@ -3,10 +3,11 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <ox/std/bit.hpp>
#include <utility>
#include "read.hpp"
@ -18,7 +19,7 @@ OrganicClawReader::OrganicClawReader(const uint8_t *buff, std::size_t buffSize)
Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
throw OxError(1, "Could not parse JSON");
throw OxException(1, "Could not parse JSON");
}
}
@ -26,12 +27,12 @@ OrganicClawReader::OrganicClawReader(const char *json, std::size_t jsonLen) {
Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
throw OxError(1, "Could not parse JSON");
throw OxException(1, "Could not parse JSON");
}
}
OrganicClawReader::OrganicClawReader(const Json::Value &json, int unionIdx) noexcept:
m_json(json),
OrganicClawReader::OrganicClawReader(Json::Value json, int unionIdx) noexcept:
m_json(std::move(json)),
m_unionIdx(unionIdx) {
}
@ -208,6 +209,87 @@ Error OrganicClawReader::field(const char *key, SerStr val) noexcept {
return err;
}
Error OrganicClawReader::fieldCString(const char *key, char *val, std::size_t buffLen) noexcept {
auto err = OxError(0);
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
if (targetValid()) {
if (jv.empty()) {
auto data = val;
if (data) {
data[0] = 0;
}
} else if (jv.isString()) {
jv.getString(&begin, &end);
const auto strSize = static_cast<std::size_t>(end - begin);
auto data = val;
if (strSize >= buffLen) {
err = OxError(2, "String size exceeds capacity of destination");
} else {
ox_memcpy(data, begin, static_cast<std::size_t>(strSize));
data[strSize] = 0;
}
} else {
err = OxError(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Error OrganicClawReader::fieldCString(const char *key, char **val) noexcept {
auto err = OxError(0);
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
auto &data = *val;
if (targetValid()) {
if (jv.empty()) {
if (data) {
data[0] = 0;
}
} else if (jv.isString()) {
jv.getString(&begin, &end);
const auto strSize = static_cast<std::size_t>(end - begin);
safeDelete(*val);
*val = new char[strSize + 1];
ox_memcpy(data, begin, static_cast<std::size_t>(strSize));
data[strSize] = 0;
} else {
err = OxError(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Error OrganicClawReader::fieldCString(const char *key, char **val, std::size_t buffLen) noexcept {
auto err = OxError(0);
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
if (targetValid()) {
if (jv.empty()) {
auto data = val;
if (data) {
data[0] = 0;
}
} else if (jv.isString()) {
jv.getString(&begin, &end);
const auto strSize = static_cast<std::size_t>(end - begin);
auto data = val;
if (strSize >= buffLen) {
safeDelete(*val);
*val = new char[strSize + 1];
}
ox_memcpy(data, begin, static_cast<std::size_t>(strSize));
data[strSize] = 0;
} else {
err = OxError(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Result<std::size_t> OrganicClawReader::arrayLength(const char *key, bool) noexcept {
const auto &jv = value(key);
if (jv.empty()) {
@ -234,13 +316,25 @@ std::size_t OrganicClawReader::stringLength(const char *key) noexcept {
}
OrganicClawReader OrganicClawReader::child(const char *key, int unionIdx) noexcept {
return OrganicClawReader(m_json[key], unionIdx);
return OrganicClawReader(value(key), unionIdx);
}
bool OrganicClawReader::fieldPresent(const char *key) noexcept {
return !m_json[key].empty();
}
int OrganicClawReader::whichFieldPresent(const char *name, const ModelUnion &u) const noexcept {
const auto &obj = m_json[name];
if (!obj.isObject()) {
return -1;
}
const auto &keys = obj.getMemberNames();
if (keys.size() != 1) {
return -1;
}
return u.getKeyIdx(keys.front().c_str());
}
Json::Value &OrganicClawReader::value(const char *key) noexcept {
if (m_json.isArray()) {
return m_json[m_fieldIt];
@ -249,7 +343,7 @@ Json::Value &OrganicClawReader::value(const char *key) noexcept {
}
}
bool OrganicClawReader::targetValid() noexcept {
bool OrganicClawReader::targetValid() const noexcept {
return static_cast<int>(m_fieldIt) == m_unionIdx || m_unionIdx == -1;
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -11,6 +11,7 @@
#include <json/json.h>
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/typenamecatcher.hpp>
#include <ox/model/types.hpp>
@ -37,7 +38,7 @@ class OrganicClawReader {
OrganicClawReader(const char *json, std::size_t buffSize);
explicit OrganicClawReader(const Json::Value &json, int unionIdx = -1) noexcept;
explicit OrganicClawReader(Json::Value json, int unionIdx = -1) noexcept;
Error field(const char *key, int8_t *val) noexcept;
Error field(const char *key, int16_t *val) noexcept;
@ -61,8 +62,8 @@ class OrganicClawReader {
template<typename T>
Error field(const char *key, T *val) noexcept;
template<typename U>
Error field(const char *key, UnionView<U> val) noexcept;
template<typename U, bool force = false>
Error field(const char *key, UnionView<U, force> val) noexcept;
template<std::size_t L>
Error field(const char *key, BasicString<L> *val) noexcept;
@ -72,6 +73,12 @@ class OrganicClawReader {
Error field(const char *key, SerStr val) noexcept;
Error fieldCString(const char *key, char *val, std::size_t buffLen) noexcept;
Error fieldCString(const char *key, char **val) noexcept;
Error fieldCString(const char *key, char **val, std::size_t buffLen) noexcept;
/**
* Reads an array length from the current location in the buffer.
* @param pass indicates that the parsing should iterate past the array length
@ -109,16 +116,23 @@ class OrganicClawReader {
// compatibility stub
constexpr void nextField() noexcept {}
[[nodiscard]]
bool fieldPresent(const char *key) noexcept;
[[nodiscard]]
int whichFieldPresent(const char *name, const ModelUnion &u) const noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Read;
}
private:
[[nodiscard]]
Json::Value &value(const char *key) noexcept;
bool targetValid() noexcept;
[[nodiscard]]
bool targetValid() const noexcept;
};
@ -134,7 +148,8 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
const auto &jv = value(key);
if (jv.empty() || jv.isObject()) {
auto reader = child(key);
return model(&reader, val);
ModelHandlerInterface handler(&reader);
return model(&handler, val);
} else {
err = OxError(1, "Type mismatch");
}
@ -143,14 +158,15 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
return err;
}
template<typename U>
Error OrganicClawReader::field(const char *key, UnionView<U> val) noexcept {
template<typename U, bool force>
Error OrganicClawReader::field(const char *key, UnionView<U, force> val) noexcept {
auto err = OxError(0);
if (targetValid()) {
const auto &jv = value(key);
if (jv.empty() || jv.isObject()) {
auto reader = child(key, val.idx());
err = model(&reader, val.get());
ModelHandlerInterface handler(&reader);
err = model(&handler, val.get());
} else {
err = OxError(1, "Type mismatch");
}
@ -185,13 +201,17 @@ Error OrganicClawReader::field(const char *key, BString<L> *val) noexcept {
template<typename T>
Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) noexcept {
const auto &srcVal = value(key);
if (!srcVal.isNull() && !srcVal.isArray()) {
return OxError(1, "Type mismatch");
}
auto srcSize = srcVal.size();
if (srcSize > valLen) {
return OxError(1);
}
OrganicClawReader r(srcVal);
ModelHandlerInterface handler{&r};
for (decltype(srcSize) i = 0; i < srcSize; ++i) {
oxReturnError(r.field("", &val[i]));
oxReturnError(handler.field("", &val[i]));
}
return OxError(0);
}
@ -199,28 +219,32 @@ Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) noex
template<typename T>
Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) noexcept {
const auto &srcVal = value(key);
if (!srcVal.isObject()) {
return OxError(1, "Type mismatch");
}
auto keys = srcVal.getMemberNames();
auto srcSize = srcVal.size();
OrganicClawReader r(srcVal);
ModelHandlerInterface handler{&r};
for (decltype(srcSize) i = 0; i < srcSize; ++i) {
const auto k = keys[i].c_str();
oxReturnError(r.field(k, &val->operator[](k)));
oxReturnError(handler.field(k, &val->operator[](k)));
}
return OxError(0);
}
template<typename T>
Error readOC(const char *json, std::size_t jsonSize, T *val) noexcept {
Error readOC(const char *buff, std::size_t buffSize, auto *val) noexcept {
// OrganicClawReader constructor can throw, but readOC should return its errors.
try {
Json::Value doc;
Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonSize, &doc, nullptr)) {
auto parser = UniquePtr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(buff, buff + buffSize, &doc, nullptr)) {
return OxError(1, "Could not parse JSON");
}
OrganicClawReader reader(json, jsonSize);
return model(&reader, val);
OrganicClawReader reader(buff, buffSize);
ModelHandlerInterface handler(&reader);
return model(&handler, val);
} catch (const Error &err) {
return err;
} catch (...) {

View File

@ -10,4 +10,5 @@ target_link_libraries(
add_test("[ox/oc] OcTest Writer" OcTest OrganicClawWriter)
add_test("[ox/oc] OcTest Reader" OcTest OrganicClawReader)
add_test("[ox/oc] OcTest OrganicClawModelValue" OcTest OrganicClawModelValue)
add_test("[ox/oc] OcTest OrganicClawDef" OcTest OrganicClawDef)

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#undef NDEBUG
@ -19,7 +19,7 @@ union TestUnion {
static constexpr auto TypeVersion = 1;
bool Bool;
uint32_t Int = 5;
char String[32];
char *String;
};
struct TestStructNest {
@ -43,8 +43,9 @@ struct TestStruct {
int32_t Int6 = 0;
int32_t Int7 = 0;
int32_t Int8 = 0;
int unionIdx = 1;
TestUnion Union;
ox::BString<32> String = "";
ox::String String = "";
uint32_t List[4] = {0, 0, 0, 0};
ox::HashMap<ox::String, int> Map;
TestStructNest EmptyStruct;
@ -55,23 +56,24 @@ struct TestStruct {
TestStruct(TestStruct &&other) noexcept;
constexpr ~TestStruct() noexcept {
if (unionIdx == 2) {
ox::safeDelete(Union.String);
}
}
constexpr TestStruct &operator=(TestStruct&&) noexcept;
};
template<typename T>
constexpr ox::Error model(T *io, TestUnion *obj) noexcept {
constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcept {
io->template setTypeInfo<TestUnion>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("String", ox::SerStr(obj->String)));
oxReturnError(io->fieldCString("String", &obj->String));
return OxError(0);
}
template<typename T>
constexpr ox::Error model(T *io, TestStructNest *obj) noexcept {
constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestStructNest> auto *obj) noexcept {
io->template setTypeInfo<TestStructNest>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
@ -79,8 +81,7 @@ constexpr ox::Error model(T *io, TestStructNest *obj) noexcept {
return OxError(0);
}
template<typename T>
constexpr ox::Error model(T *io, TestStruct *obj) noexcept {
constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept {
io->template setTypeInfo<TestStruct>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
@ -92,7 +93,12 @@ constexpr ox::Error model(T *io, TestStruct *obj) noexcept {
oxReturnError(io->field("Int6", &obj->Int6));
oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
oxReturnError(io->field("unionIdx", &obj->unionIdx));
if (ox_strcmp(io->opType(), ox::OpType::Reflect) == 0) {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 0}));
} else {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
}
oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("Map", &obj->Map));
@ -173,6 +179,57 @@ const std::map<std::string_view, ox::Error(*)()> tests = {
return OxError(0);
}
},
{
"OrganicClawModelValue",
[] {
ox::Buffer dataBuff;
TestStruct testIn;
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";
testIn.unionIdx = 1;
testIn.Union.Int = 93;
oxAssert(ox::writeOC(&testIn).moveTo(&dataBuff), "Data generation failed");
ox::TypeStore typeStore;
auto type = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(type.error, "Descriptor write failed");
ox::ModelObject testOut;
oxReturnError(testOut.setType(type.value));
oxAssert(ox::readOC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed");
oxAssert(testOut["Int"].get<int>() == testIn.Int, "testOut.Int failed");
oxAssert(testOut["Bool"].get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut["String"].get<ox::String>() == testIn.String, "testOut.String failed");
auto &testOutStruct = testOut["Struct"].get<ox::ModelObject>();
auto &testOutUnion = testOut["Union"].get<ox::ModelUnion>();
auto &testOutList = testOut["List"].get<ox::ModelValueVector>();
auto testOutStructCopy = testOut["Struct"].get<ox::ModelObject>();
auto testOutUnionCopy = testOut["Union"].get<ox::ModelUnion>();
auto testOutListCopy = testOut["List"].get<ox::ModelValueVector>();
oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed");
oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed");
oxAssert(testOutStruct["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed");
oxAssert(testOutStruct["String"].get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String failed");
oxAssert(testOut["unionIdx"].get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong");
oxAssert(testOutUnion["Int"].get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed");
oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed");
oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed");
oxAssert(testOutStructCopy["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed");
oxAssert(testOutStructCopy["String"].get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String (copy) failed");
oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed");
oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed");
return OxError(0);
}
},
{
"OrganicClawDef",
[] {

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "write.hpp"
@ -18,87 +18,6 @@ OrganicClawWriter::OrganicClawWriter(Json::Value json, int unionIdx) noexcept:
m_unionIdx(unionIdx) {
}
Error OrganicClawWriter::field(const char *key, int8_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, int16_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, int32_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, int64_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, uint8_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, uint16_t *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, uint32_t *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, uint64_t *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, bool *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, String *val) noexcept {
if (targetValid() && val->len()) {
value(key) = val->c_str();
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, SerStr val) noexcept {
if (targetValid() && val.len()) {
value(key) = val.c_str();
@ -107,6 +26,26 @@ Error OrganicClawWriter::field(const char *key, SerStr val) noexcept {
return OxError(0);
}
Error OrganicClawWriter::fieldCString(const char *key, const char **val, int len) noexcept {
if (targetValid() && len) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::fieldCString(const char *key, char **val, int len) noexcept {
return fieldCString(key, const_cast<const char**>(val), len);
}
Error OrganicClawWriter::fieldCString(const char *key, const char **val) noexcept {
return fieldCString(key, const_cast<const char**>(val), {});
}
Error OrganicClawWriter::fieldCString(const char *key, char **val) noexcept {
return fieldCString(key, const_cast<const char**>(val), {});
}
Json::Value &OrganicClawWriter::value(const char *key) noexcept {
if (m_json.isArray()) {
return m_json[m_fieldIt];

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -11,6 +11,7 @@
#include <json/json.h>
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/types.hpp>
#include <ox/model/typenamecatcher.hpp>
@ -22,8 +23,7 @@ namespace ox {
class OrganicClawWriter {
template<typename T>
friend Result<Buffer> writeOC(T *val) noexcept;
friend Result<Buffer> writeOC(auto *val) noexcept;
protected:
Json::Value m_json;
@ -35,36 +35,140 @@ class OrganicClawWriter {
explicit OrganicClawWriter(Json::Value json, int unionIdx = -1) noexcept;
Error field(const char*, int8_t *val) noexcept;
Error field(const char*, int16_t *val) noexcept;
Error field(const char*, int32_t *val) noexcept;
Error field(const char*, int64_t *val) noexcept;
Error field(const char *key, CommonPtrWith<int8_t> auto *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char*, uint8_t *val) noexcept;
Error field(const char*, uint16_t *val) noexcept;
Error field(const char*, uint32_t *val) noexcept;
Error field(const char*, uint64_t *val) noexcept;
Error field(const char *key, CommonPtrWith<int16_t> auto *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char*, bool *val) noexcept;
Error field(const char *key, CommonPtrWith<int32_t> auto *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<int64_t> auto *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<uint8_t> auto *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<uint16_t> auto *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<uint32_t> auto *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<uint64_t> auto *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<bool> auto *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
template<typename T>
Error field(const char*, T *val, std::size_t len) noexcept;
template<typename U>
Error field(const char*, UnionView<U> val) noexcept;
template<typename U, bool force = true>
Error field(const char*, UnionView<U, force> val) noexcept;
template<typename T>
Error field(const char*, HashMap<String, T> *val) noexcept;
Error field(const char *key, const HashMap<String, T> *val) noexcept {
if (targetValid()) {
const auto &keys = val->keys();
OrganicClawWriter w;
ModelHandlerInterface handler{&w};
for (std::size_t i = 0; i < keys.size(); ++i) {
const auto k = keys[i].c_str();
oxReturnError(handler.field(k, val->at(k).value));
}
value(key) = w.m_json;
}
++m_fieldIt;
return OxError(0);
}
template<typename T>
Error field(const char *key, HashMap<String, T> *val) noexcept {
return field(key, const_cast<const HashMap<String, T>*>(val));
}
template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept;
Error field(const char *key, const BString<L> *val) noexcept {
return field(key, SerStr(val->data(), val->cap()));
}
Error field(const char*, String *val) noexcept;
template<std::size_t L>
Error field(const char *key, BString<L> *val) noexcept {
return field(key, SerStr(val->data(), val->cap()));
}
template<std::size_t L>
Error field(const char *key, const BasicString<L> *val) noexcept {
if (targetValid() && val->len()) {
value(key) = val->c_str();
}
++m_fieldIt;
return OxError(0);
}
template<std::size_t L>
Error field(const char *key, BasicString<L> *val) noexcept {
return field(key, const_cast<const BasicString<L>*>(val));
}
Error field(const char*, SerStr val) noexcept;
Error fieldCString(const char*, const char **val, int len) noexcept;
Error fieldCString(const char *name, char **val, int len) noexcept;
Error fieldCString(const char *name, const char **val) noexcept;
Error fieldCString(const char *name, char **val) noexcept;
template<typename T>
Error field(const char*, T *val) noexcept;
@ -91,8 +195,9 @@ template<typename T>
Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) noexcept {
if (targetValid() && len) {
OrganicClawWriter w((Json::Value(Json::arrayValue)));
ModelHandlerInterface handler{&w};
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(w.field("", &val[i]));
oxReturnError(handler.field("", &val[i]));
}
value(key) = w.m_json;
}
@ -100,18 +205,14 @@ Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) noexcep
return OxError(0);
}
template<std::size_t L>
Error OrganicClawWriter::field(const char *key, BString<L> *val) noexcept {
return field(key, SerStr(val->data(), val->cap()));
}
template<typename T>
Error OrganicClawWriter::field(const char *key, T *val) noexcept {
if constexpr(isVector_v<T>) {
return field(key, val->data(), val->size());
} else if (val && targetValid()) {
OrganicClawWriter w;
oxReturnError(model(&w, val));
ModelHandlerInterface handler{&w};
oxReturnError(model(&handler, val));
if (!w.m_json.isNull()) {
value(key) = w.m_json;
}
@ -120,11 +221,12 @@ Error OrganicClawWriter::field(const char *key, T *val) noexcept {
return OxError(0);
}
template<typename U>
Error OrganicClawWriter::field(const char *key, UnionView<U> val) noexcept {
template<typename U, bool force>
Error OrganicClawWriter::field(const char *key, UnionView<U, force> val) noexcept {
if (targetValid()) {
OrganicClawWriter w(val.idx());
oxReturnError(model(&w, val.get()));
ModelHandlerInterface handler{&w};
oxReturnError(model(&handler, val.get()));
if (!w.m_json.isNull()) {
value(key) = w.m_json;
}
@ -133,25 +235,10 @@ Error OrganicClawWriter::field(const char *key, UnionView<U> val) noexcept {
return OxError(0);
}
template<typename T>
Error OrganicClawWriter::field(const char *key, HashMap<String, T> *val) noexcept {
if (targetValid()) {
const auto &keys = val->keys();
OrganicClawWriter w;
for (std::size_t i = 0; i < keys.size(); ++i) {
const auto k = keys[i].c_str();
oxReturnError(w.field(k, &val->operator[](k)));
}
value(key) = w.m_json;
}
++m_fieldIt;
return OxError(0);
}
template<typename T>
Result<Buffer> writeOC(T *val) noexcept {
Result<Buffer> writeOC(auto *val) noexcept {
OrganicClawWriter writer;
oxReturnError(model(&writer, val));
ModelHandlerInterface handler(&writer);
oxReturnError(model(&handler, val));
Json::StreamWriterBuilder jsonBuilder;
const auto str = Json::writeString(jsonBuilder, writer.m_json);
Buffer buff(str.size() + 1);

View File

@ -24,6 +24,7 @@ add_library(
buffer.cpp
buildinfo.cpp
byteswap.cpp
concepts.cpp
fmt.cpp
heapmgr.cpp
math.cpp
@ -73,6 +74,7 @@ install(
buffer.hpp
buildinfo.hpp
byteswap.hpp
concepts.hpp
def.hpp
defines.hpp
defer.hpp

23
deps/ox/src/ox/std/concepts.cpp vendored Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* 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 https://mozilla.org/MPL/2.0/.
*/
#include "concepts.hpp"
namespace ox::detail::test {
class TestType;
[[nodiscard]] constexpr bool ok(auto*) noexcept { return false; }
[[nodiscard]] constexpr bool ok(CommonPtrWith<TestType> auto*) noexcept { return true; }
static_assert(ok(static_cast<TestType*>(nullptr)));
static_assert(ok(static_cast<const TestType*>(nullptr)));
static_assert(!ok(static_cast<int*>(nullptr)));
static_assert(!ok(static_cast<const int*>(nullptr)));
}

17
deps/ox/src/ox/std/concepts.hpp vendored Normal file
View File

@ -0,0 +1,17 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* 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 https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "typetraits.hpp"
namespace ox {
template<typename T, typename U>
concept CommonPtrWith = ox::is_same_v<typename ox::remove_pointer<const T*>::type,
typename ox::remove_pointer<const U*>::type>;
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -31,7 +31,7 @@ class exception {
#include "utility.hpp"
#define OxError(...) ox::Error(__FILE__, __LINE__, __VA_ARGS__)
#define OxException(...) ox::Error(__FILE__, __LINE__, __VA_ARGS__)
#define OxException(...) ox::Exception(__FILE__, __LINE__, __VA_ARGS__)
namespace ox {
@ -83,7 +83,7 @@ constexpr auto errCode(const Error &err) noexcept {
template<typename T=const char*>
[[nodiscard]]
constexpr auto toStr(const Error &err) noexcept {
return T(err.msg);
return err.msg ? T(err.msg) : "";
}
struct Exception: public std::exception {

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -46,21 +46,21 @@ class HashMap {
/**
* K is assumed to be a null terminated string.
*/
constexpr T &operator[](K key);
constexpr T &operator[](const K &key);
/**
* K is assumed to be a null terminated string.
*/
constexpr Result<T*> at(K key) noexcept;
constexpr Result<T*> at(const K &key) noexcept;
/**
* K is assumed to be a null terminated string.
*/
constexpr Result<const T*> at(K key) const noexcept;
constexpr Result<const T*> at(const K &key) const noexcept;
constexpr void erase(const K &key);
constexpr bool contains(K key) const noexcept;
constexpr bool contains(const K &key) const noexcept;
[[nodiscard]]
constexpr std::size_t size() const noexcept;
@ -68,6 +68,8 @@ class HashMap {
[[nodiscard]]
constexpr const Vector<K> &keys() const noexcept;
constexpr void clear();
private:
constexpr void expand();
@ -79,14 +81,12 @@ class HashMap {
/**
* K is assumed to be a null terminated string.
*/
constexpr Pair *const&access(const Vector<Pair*> &pairs, K key) const;
constexpr Pair *const&access(const Vector<Pair*> &pairs, const K &key) const;
/**
* K is assumed to be a null terminated string.
*/
constexpr Pair *&access(Vector<Pair*> &pairs, K key);
constexpr void clear();
constexpr Pair *&access(Vector<Pair*> &pairs, const K &key);
};
@ -145,7 +145,7 @@ constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &&other) {
}
template<typename K, typename T>
constexpr T &HashMap<K, T>::operator[](K k) {
constexpr T &HashMap<K, T>::operator[](const K &k) {
auto &p = access(m_pairs, k);
if (p == nullptr) {
if (m_pairs.size() * 0.7 < m_keys.size()) {
@ -159,19 +159,19 @@ constexpr T &HashMap<K, T>::operator[](K k) {
}
template<typename K, typename T>
constexpr Result<T*> HashMap<K, T>::at(K k) noexcept {
constexpr Result<T*> HashMap<K, T>::at(const K &k) noexcept {
auto p = access(m_pairs, k);
if (!p) {
return {nullptr, OxError(1)};
return {nullptr, OxError(1, "value not found for given key")};
}
return &p->value;
}
template<typename K, typename T>
constexpr Result<const T*> HashMap<K, T>::at(K k) const noexcept {
constexpr Result<const T*> HashMap<K, T>::at(const K &k) const noexcept {
auto p = access(m_pairs, k);
if (!p) {
return {nullptr, OxError(1)};
return {nullptr, OxError(1, "value not found for given key")};
}
return &p->value;
}
@ -196,8 +196,9 @@ constexpr void HashMap<K, T>::erase(const K &k) {
}
oxIgnoreError(m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k)));
}
template<typename K, typename T>
constexpr bool HashMap<K, T>::contains(K k) const noexcept {
constexpr bool HashMap<K, T>::contains(const K &k) const noexcept {
return access(m_pairs, k) != nullptr;
}
@ -211,12 +212,21 @@ constexpr const Vector<K> &HashMap<K, T>::keys() const noexcept {
return m_keys;
}
template<typename K, typename T>
constexpr void HashMap<K, T>::clear() {
for (std::size_t i = 0; i < m_pairs.size(); i++) {
delete m_pairs[i];
}
m_pairs.clear();
m_pairs.resize(100);
}
template<typename K, typename T>
constexpr void HashMap<K, T>::expand() {
Vector<Pair*> r;
for (std::size_t i = 0; i < m_keys.size(); ++i) {
auto k = m_keys[i];
access(r, k) = access(m_pairs, k);
access(r, k) = std::move(access(m_pairs, k));
}
m_pairs = std::move(r);
}
@ -231,43 +241,29 @@ constexpr uint64_t HashMap<K, T>::hash(K k, int len) noexcept {
}
template<typename K, typename T>
constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(const Vector<Pair*> &pairs, K k) const {
constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(const Vector<Pair*> &pairs, const K &k) const {
auto h = hash(k) % pairs.size();
char hashStr[sizeof(h) + 1];
ox_memcpy(hashStr, &h, sizeof(h));
hashStr[sizeof(h)] = 0;
while (true) {
const auto &p = pairs[h];
if (p == nullptr || ox_strcmp(p->key, k) == 0) {
return p;
} else {
h = hash(hashStr, 8) % pairs.size();
h = (h + 1) % pairs.size();
}
}
}
template<typename K, typename T>
constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, K k) {
constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, const K &k) {
auto h = hash(k) % pairs.size();
char hashStr[sizeof(h) + 1];
ox_memcpy(hashStr, &h, sizeof(h));
hashStr[sizeof(h)] = 0;
while (true) {
auto &p = pairs[h];
if (p == nullptr || ox_strcmp(p->key, k) == 0) {
return p;
} else {
h = hash(hashStr, 8) % pairs.size();
h = (h + 1) % pairs.size();
}
}
}
template<typename K, typename T>
constexpr void HashMap<K, T>::clear() {
for (std::size_t i = 0; i < m_pairs.size(); i++) {
delete m_pairs[i];
}
m_pairs.clear();
}
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -14,6 +14,8 @@
#else
#include "utility.hpp"
namespace std {
template<class T>

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -47,43 +47,43 @@ class MallocaPtr {
T *m_val = nullptr;
public:
inline MallocaPtr() noexcept = default;
constexpr MallocaPtr() noexcept = default;
inline MallocaPtr(MallocaPtr &other) = delete;
constexpr MallocaPtr(MallocaPtr &other) = delete;
inline MallocaPtr(const MallocaPtr &other) = delete;
constexpr MallocaPtr(const MallocaPtr &other) = delete;
inline MallocaPtr(MallocaPtr &&other) noexcept {
constexpr MallocaPtr(MallocaPtr &&other) noexcept {
m_onHeap = other.m_onHeap;
m_val = other.m_val;
other.m_onHeap = false;
other.m_val = nullptr;
}
inline MallocaPtr(bool onHeap, T *val) noexcept {
constexpr MallocaPtr(bool onHeap, T *val) noexcept {
m_onHeap = onHeap;
m_val = val;
}
inline ~MallocaPtr() noexcept {
constexpr ~MallocaPtr() noexcept {
if (m_onHeap && m_val) {
delete[] reinterpret_cast<uint8_t*>(m_val);
}
}
inline const T *get() const noexcept {
constexpr const T *get() const noexcept {
return reinterpret_cast<T*>(m_val);
}
inline T *get() noexcept {
constexpr T *get() noexcept {
return reinterpret_cast<T*>(m_val);
}
inline const T &operator=(MallocaPtr &other) = delete;
constexpr const T &operator=(MallocaPtr &other) = delete;
inline const T &operator=(const MallocaPtr &other) = delete;
constexpr const T &operator=(const MallocaPtr &other) = delete;
inline const T &operator=(MallocaPtr &&other) noexcept {
constexpr const T &operator=(MallocaPtr &&other) noexcept {
if (m_onHeap && m_val) {
delete[] reinterpret_cast<uint8_t*>(m_val);
}
@ -93,35 +93,35 @@ class MallocaPtr {
other.m_val = nullptr;
}
inline const T *operator->() const noexcept {
constexpr const T *operator->() const noexcept {
return reinterpret_cast<T*>(m_val);
}
inline T *operator->() noexcept {
constexpr T *operator->() noexcept {
return reinterpret_cast<T*>(m_val);
}
inline operator const T*() const noexcept {
constexpr operator const T*() const noexcept {
return reinterpret_cast<T*>(m_val);
}
inline operator T*() noexcept {
constexpr operator T*() noexcept {
return reinterpret_cast<T*>(m_val);
}
inline const T &operator*() const noexcept {
constexpr const T &operator*() const noexcept {
return *reinterpret_cast<T*>(m_val);
}
inline T &operator*() noexcept {
constexpr T &operator*() noexcept {
return *reinterpret_cast<T*>(m_val);
}
inline bool operator==(const MallocaPtr<T> &other) const noexcept {
constexpr bool operator==(const MallocaPtr<T> &other) const noexcept {
return m_val == other.m_val && m_onHeap == other.m_onHeap;
}
inline bool operator!=(const MallocaPtr<T> &other) const noexcept {
constexpr bool operator!=(const MallocaPtr<T> &other) const noexcept {
return m_val != other.m_val || m_onHeap != other.m_onHeap;
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -26,10 +26,10 @@ class Optional {
public:
constexpr Optional() noexcept = default;
template<typename ...Args>
constexpr Optional(Args &&... args);
constexpr Optional(const Optional &other) {
if (m_ptr) {
m_ptr->~T();
}
if (other.m_ptr) {
m_ptr = new(m_data) T(*other.m_ptr);
} else {
@ -149,4 +149,10 @@ class Optional {
};
template<typename T, std::size_t buffSize>
template<typename... Args>
constexpr Optional<T, buffSize>::Optional(Args &&... args) {
emplace(ox::forward<Args>(args)...);
}
}

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -13,6 +13,7 @@
#include "bit.hpp"
#include "bstring.hpp"
#include "byteswap.hpp"
#include "concepts.hpp"
#include "defer.hpp"
#include "def.hpp"
#include "defines.hpp"

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -134,8 +134,12 @@ class BasicString {
constexpr BasicString operator+(const BasicString &src) const noexcept;
constexpr bool operator==(const char *other) const noexcept;
constexpr bool operator==(const BasicString &other) const noexcept;
constexpr bool operator!=(const char *other) const noexcept;
constexpr bool operator!=(const BasicString &other) const noexcept;
constexpr bool operator<(const BasicString &other) const noexcept;
@ -404,8 +408,23 @@ constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::operator+(c
return cpy;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator==(const char *other) const noexcept {
bool retval = true;
for (auto i = 0u; i < m_buff.size() && (m_buff[i] || other[i]); ++i) {
if (m_buff[i] != other[i]) {
retval = false;
break;
}
}
return retval;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator==(const BasicString &other) const noexcept {
if (len() != other.len()) {
return false;
}
bool retval = true;
std::size_t i = 0;
while (i < m_buff.size() && (m_buff[i] || other.m_buff[i])) {
@ -418,6 +437,11 @@ constexpr bool BasicString<SmallStringSize>::operator==(const BasicString &other
return retval;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator!=(const char *other) const noexcept {
return !operator==(other);
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator!=(const BasicString &other) const noexcept {
return !operator==(other);

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -54,7 +54,7 @@ constexpr auto ox_strlen(T str1) noexcept {
template<typename T1, typename T2>
[[nodiscard]]
constexpr int ox_strcmp(T1 str1, T2 str2) noexcept {
constexpr int ox_strcmp(const T1 &str1, const T2 &str2) noexcept {
auto retval = 0;
auto i = 0u;
while (str1[i] || str2[i]) {

View File

@ -3,7 +3,7 @@
*
* 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/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
@ -138,6 +138,21 @@ constexpr bool is_class_v = is_class<T>();
template<typename T>
constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value;
template<typename T, std::size_t bits>
concept Signed_c = is_signed_v<T> && sizeof(T) == 8 * bits;
template<typename T, std::size_t bits>
concept Unsigned_c = !is_signed_v<T> && sizeof(T) == 8 * bits;
template<typename T, typename U>
struct is_same: false_type {};
template<typename T>
struct is_same<T, T>: true_type {};
template<typename T, typename U>
constexpr auto is_same_v = is_same<T, U>::value;
// enable_if ///////////////////////////////////////////////////////////////////
template<bool B, class T = void>