[ox] Add Reader_c and make MetalClawReader use it
This commit is contained in:
parent
4ab710b155
commit
1f78ea1f37
12
deps/ox/src/ox/claw/CMakeLists.txt
vendored
12
deps/ox/src/ox/claw/CMakeLists.txt
vendored
@ -5,7 +5,6 @@ add_library(
|
||||
write.cpp
|
||||
)
|
||||
|
||||
|
||||
if(NOT MSVC)
|
||||
target_compile_options(OxClaw PRIVATE -Wsign-conversion)
|
||||
target_compile_options(OxClaw PRIVATE -Wconversion)
|
||||
@ -17,6 +16,17 @@ target_link_libraries(
|
||||
$<$<BOOL:${OX_USE_STDLIB}>:OxOrganicClaw>
|
||||
)
|
||||
|
||||
if(OX_USE_STDLIB)
|
||||
add_executable(
|
||||
readclaw
|
||||
readclaw.cpp
|
||||
)
|
||||
target_link_libraries(
|
||||
readclaw PUBLIC
|
||||
OxClaw
|
||||
)
|
||||
endif()
|
||||
|
||||
install(TARGETS OxClaw
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
|
3
deps/ox/src/ox/claw/read.cpp
vendored
3
deps/ox/src/ox/claw/read.cpp
vendored
@ -80,7 +80,8 @@ Result<ModelObject> readClaw(TypeStore *ts, const char *buff, std::size_t buffSz
|
||||
switch (header.fmt) {
|
||||
case ClawFormat::Metal:
|
||||
{
|
||||
MetalClawReader reader(reinterpret_cast<const uint8_t*>(header.data), header.dataSize);
|
||||
ox::BufferReader br(header.data, header.dataSize);
|
||||
MetalClawReader reader(br);
|
||||
ModelHandlerInterface handler(&reader);
|
||||
oxReturnError(model(&handler, &obj));
|
||||
return obj;
|
||||
|
3
deps/ox/src/ox/claw/read.hpp
vendored
3
deps/ox/src/ox/claw/read.hpp
vendored
@ -51,7 +51,8 @@ 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), header.dataSize);
|
||||
ox::BufferReader br(header.data, header.dataSize);
|
||||
MetalClawReader reader(br);
|
||||
ModelHandlerInterface handler(&reader);
|
||||
return model(&handler, val);
|
||||
}
|
||||
|
6
deps/ox/src/ox/mc/err.hpp
vendored
6
deps/ox/src/ox/mc/err.hpp
vendored
@ -11,9 +11,9 @@
|
||||
namespace ox {
|
||||
|
||||
enum {
|
||||
MC_PRESENCEMASKOUTBOUNDS = 1,
|
||||
MC_BUFFENDED = 2,
|
||||
MC_OUTBUFFENDED = 4
|
||||
McPresenceMapOverflow = 1,
|
||||
McBuffEnded = 2,
|
||||
McOutputBuffEnded = 4
|
||||
};
|
||||
|
||||
}
|
||||
|
28
deps/ox/src/ox/mc/intops.hpp
vendored
28
deps/ox/src/ox/mc/intops.hpp
vendored
@ -14,6 +14,7 @@
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/math.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
#include <ox/std/reader.hpp>
|
||||
|
||||
namespace ox::mc {
|
||||
|
||||
@ -114,7 +115,7 @@ constexpr McInt encodeInteger(I input) noexcept {
|
||||
* length integer.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
static constexpr std::size_t countBytes(unsigned b) noexcept {
|
||||
constexpr std::size_t countBytes(unsigned b) noexcept {
|
||||
std::size_t i = 0;
|
||||
while ((b >> i) & 1) ++i;
|
||||
return i + 1;
|
||||
@ -131,17 +132,21 @@ static_assert(countBytes(0b0111'1111) == 8);
|
||||
static_assert(countBytes(0b1111'1111) == 9);
|
||||
|
||||
template<typename I>
|
||||
constexpr Result<I> decodeInteger(const uint8_t buff[9], std::size_t buffLen, std::size_t *bytesRead) noexcept {
|
||||
const auto bytes = countBytes(buff[0]);
|
||||
constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noexcept {
|
||||
uint8_t firstByte = 0;
|
||||
oxReturnError(rdr.read(&firstByte, 1));
|
||||
oxReturnError(rdr.seekg(-1, ox::ios_base::cur));
|
||||
const auto bytes = countBytes(firstByte);
|
||||
if (bytes == 9) {
|
||||
*bytesRead = bytes;
|
||||
I out = 0;
|
||||
ox_memcpy(&out, &buff[1], sizeof(I));
|
||||
oxReturnError(rdr.seekg(1, ox::ios_base::cur));
|
||||
oxReturnError(rdr.read(&out, sizeof(I)));
|
||||
return fromLittleEndian<I>(out);
|
||||
} else if (buffLen >= bytes) {
|
||||
}
|
||||
*bytesRead = bytes;
|
||||
uint64_t decoded = 0;
|
||||
ox_memcpy(&decoded, &buff[0], bytes);
|
||||
oxReturnError(rdr.read(&decoded, bytes));
|
||||
decoded >>= bytes;
|
||||
// move sign bit
|
||||
if constexpr(is_signed_v<I>) {
|
||||
@ -152,6 +157,8 @@ constexpr Result<I> decodeInteger(const uint8_t buff[9], std::size_t buffLen, st
|
||||
// fill in all bits between encoded sign and real sign with 1s
|
||||
// split it up because the 32-bit ARM can't shift more than 32 bits
|
||||
ox::Array<uint32_t, 2> d = {};
|
||||
//d[0] = decoded & 0xffff'ffff;
|
||||
//d[1] = decoded >> 32;
|
||||
ox_memcpy(d.data(), &decoded, sizeof(decoded));
|
||||
auto bit = negBit;
|
||||
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) {
|
||||
@ -172,14 +179,13 @@ constexpr Result<I> decodeInteger(const uint8_t buff[9], std::size_t buffLen, st
|
||||
}
|
||||
}
|
||||
return static_cast<I>(decoded);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr Result<I> decodeInteger(McInt m) noexcept {
|
||||
std::size_t bytesRead;
|
||||
return decodeInteger<I>(m.data, 9, &bytesRead);
|
||||
Result<I> decodeInteger(McInt m) noexcept {
|
||||
std::size_t bytesRead{};
|
||||
BufferReader br(reinterpret_cast<const char*>(m.data), 9);
|
||||
return decodeInteger<I>(br, &bytesRead);
|
||||
}
|
||||
|
||||
}
|
||||
|
4
deps/ox/src/ox/mc/presenceindicator.cpp
vendored
4
deps/ox/src/ox/mc/presenceindicator.cpp
vendored
@ -11,7 +11,7 @@
|
||||
|
||||
namespace ox {
|
||||
|
||||
template class FieldBitmapReader<uint8_t*>;
|
||||
template class FieldBitmapReader<const uint8_t*>;
|
||||
template class FieldBitmapWriterBase<uint8_t*>;
|
||||
template class FieldBitmapWriterBase<const uint8_t*>;
|
||||
|
||||
}
|
||||
|
85
deps/ox/src/ox/mc/presenceindicator.hpp
vendored
85
deps/ox/src/ox/mc/presenceindicator.hpp
vendored
@ -8,21 +8,77 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/array.hpp>
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/reader.hpp>
|
||||
|
||||
#include "err.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename T>
|
||||
template<Reader_c Reader>
|
||||
class FieldBitmapReader {
|
||||
protected:
|
||||
mutable std::size_t m_mapBlockIdx = ~std::size_t{0};
|
||||
mutable uint64_t m_mapBlock = 0;
|
||||
std::size_t m_mapStart = 0;
|
||||
Reader &m_reader;
|
||||
|
||||
public:
|
||||
explicit constexpr FieldBitmapReader(Reader &reader) noexcept;
|
||||
|
||||
constexpr Result<bool> get(std::size_t i) const noexcept;
|
||||
|
||||
private:
|
||||
constexpr ox::Error loadMapBlock(std::size_t id) const noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr FieldBitmapReader<Reader>::FieldBitmapReader(Reader &reader) noexcept:
|
||||
m_mapStart(reader.tellg()),
|
||||
m_reader(reader) {
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Result<bool> FieldBitmapReader<Reader>::get(std::size_t idx) const noexcept {
|
||||
constexpr auto blockBits = sizeof(m_mapBlock);
|
||||
auto const blockIdx = idx / blockBits;
|
||||
if (m_mapBlockIdx != blockIdx) [[unlikely]] {
|
||||
oxReturnError(loadMapBlock(blockIdx));
|
||||
}
|
||||
idx %= blockBits;
|
||||
return (m_mapBlock >> idx) & 1;
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr ox::Error FieldBitmapReader<Reader>::loadMapBlock(std::size_t idx) const noexcept {
|
||||
oxRequire(g, m_reader.tellg());
|
||||
oxReturnError(m_reader.seekg(static_cast<int>(m_mapStart + idx), ox::ios_base::beg));
|
||||
ox::Array<char, sizeof(m_mapBlock)> mapBlock{};
|
||||
oxReturnError(m_reader.read(mapBlock.data(), sizeof(m_mapBlock)));
|
||||
// Warning: narrow-conv
|
||||
oxReturnError(m_reader.seekg(static_cast<int>(g), ox::ios_base::beg));
|
||||
m_mapBlock = 0;
|
||||
for (auto i = 0ull; auto b : mapBlock) {
|
||||
m_mapBlock |= static_cast<uint64_t>(std::bit_cast<uint8_t>(b)) << i;
|
||||
i += 8;
|
||||
}
|
||||
m_mapBlockIdx = idx;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
class FieldBitmapWriterBase {
|
||||
protected:
|
||||
T m_map = nullptr;
|
||||
std::size_t m_mapLen = 0;
|
||||
|
||||
public:
|
||||
constexpr FieldBitmapReader(T map, std::size_t maxLen) noexcept;
|
||||
constexpr FieldBitmapWriterBase(T map, std::size_t maxLen) noexcept;
|
||||
|
||||
constexpr auto setBuffer(T map, std::size_t maxLen) noexcept;
|
||||
|
||||
@ -38,45 +94,45 @@ class FieldBitmapReader {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr FieldBitmapReader<T>::FieldBitmapReader(T map, std::size_t maxLen) noexcept {
|
||||
constexpr FieldBitmapWriterBase<T>::FieldBitmapWriterBase(T map, std::size_t maxLen) noexcept {
|
||||
m_map = map;
|
||||
m_mapLen = maxLen;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr auto FieldBitmapReader<T>::setBuffer(T map, std::size_t maxLen) noexcept {
|
||||
constexpr auto FieldBitmapWriterBase<T>::setBuffer(T map, std::size_t maxLen) noexcept {
|
||||
m_map = map;
|
||||
m_mapLen = maxLen;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Result<bool> FieldBitmapReader<T>::get(std::size_t i) const noexcept {
|
||||
constexpr Result<bool> FieldBitmapWriterBase<T>::get(std::size_t i) const noexcept {
|
||||
if (i / 8 < m_mapLen) {
|
||||
return (m_map[i / 8] >> (i % 8)) & 1;
|
||||
} else {
|
||||
return OxError(MC_PRESENCEMASKOUTBOUNDS);
|
||||
return OxError(McPresenceMapOverflow);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr void FieldBitmapReader<T>::setFields(int fields) noexcept {
|
||||
constexpr void FieldBitmapWriterBase<T>::setFields(int fields) noexcept {
|
||||
m_mapLen = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr void FieldBitmapReader<T>::setMaxLen(int maxLen) noexcept {
|
||||
constexpr void FieldBitmapWriterBase<T>::setMaxLen(int maxLen) noexcept {
|
||||
m_mapLen = static_cast<std::size_t>(maxLen);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr int64_t FieldBitmapReader<T>::getMaxLen() const noexcept {
|
||||
constexpr int64_t FieldBitmapWriterBase<T>::getMaxLen() const noexcept {
|
||||
return static_cast<int64_t>(m_mapLen);
|
||||
}
|
||||
|
||||
extern template class FieldBitmapReader<uint8_t*>;
|
||||
extern template class FieldBitmapReader<const uint8_t*>;
|
||||
extern template class FieldBitmapWriterBase<uint8_t*>;
|
||||
extern template class FieldBitmapWriterBase<const uint8_t*>;
|
||||
|
||||
class FieldBitmap: public FieldBitmapReader<uint8_t*> {
|
||||
class FieldBitmap: public FieldBitmapWriterBase<uint8_t*> {
|
||||
|
||||
public:
|
||||
constexpr FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept;
|
||||
@ -85,7 +141,8 @@ class FieldBitmap: public FieldBitmapReader<uint8_t*> {
|
||||
|
||||
};
|
||||
|
||||
constexpr FieldBitmap::FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept: FieldBitmapReader<uint8_t*>(map, maxLen) {
|
||||
constexpr FieldBitmap::FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept:
|
||||
FieldBitmapWriterBase<uint8_t*>(map, maxLen) {
|
||||
}
|
||||
|
||||
constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept {
|
||||
@ -97,7 +154,7 @@ constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept {
|
||||
}
|
||||
return {};
|
||||
} else {
|
||||
return OxError(MC_PRESENCEMASKOUTBOUNDS);
|
||||
return OxError(McPresenceMapOverflow);
|
||||
}
|
||||
}
|
||||
|
||||
|
328
deps/ox/src/ox/mc/read.hpp
vendored
328
deps/ox/src/ox/mc/read.hpp
vendored
@ -26,22 +26,22 @@
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<auto HandlerMaker>
|
||||
class MetalClawReaderTemplate {
|
||||
template<Reader_c Reader>
|
||||
class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<Reader>> {
|
||||
|
||||
private:
|
||||
FieldBitmapReader<const uint8_t*> m_fieldPresence;
|
||||
FieldBitmapReader<Reader> m_fieldPresence;
|
||||
std::size_t m_fields = 0;
|
||||
std::size_t m_field = 0;
|
||||
int m_unionIdx = -1;
|
||||
std::size_t m_buffIt = 0;
|
||||
std::size_t m_buffLen = 0;
|
||||
const uint8_t *m_buff = nullptr;
|
||||
MetalClawReaderTemplate<HandlerMaker> *m_parent = nullptr;
|
||||
Reader &m_reader;
|
||||
MetalClawReaderTemplate<Reader> *m_parent = nullptr;
|
||||
|
||||
public:
|
||||
constexpr MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen, int unionIdx = -1,
|
||||
MetalClawReaderTemplate<HandlerMaker> *parent = nullptr) noexcept;
|
||||
explicit constexpr MetalClawReaderTemplate(
|
||||
Reader &reader,
|
||||
int unionIdx = -1,
|
||||
MetalClawReaderTemplate<Reader> *parent = nullptr) noexcept;
|
||||
|
||||
constexpr ~MetalClawReaderTemplate() noexcept;
|
||||
|
||||
@ -95,8 +95,7 @@ class MetalClawReaderTemplate {
|
||||
/**
|
||||
* Reads an string length from the current location in the buffer.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
constexpr StringLength stringLength(const char *name) noexcept;
|
||||
constexpr Result<StringLength> stringLength(const char *name) noexcept;
|
||||
|
||||
template<typename T = std::nullptr_t>
|
||||
constexpr ox::Error setTypeInfo(
|
||||
@ -109,7 +108,7 @@ class MetalClawReaderTemplate {
|
||||
* Returns a MetalClawReader to parse a child object.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
constexpr MetalClawReaderTemplate<HandlerMaker> child(const char *name, int unionIdx = -1) noexcept;
|
||||
constexpr MetalClawReaderTemplate<Reader> child(const char *name, int unionIdx = -1) noexcept;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the next field to be read is present.
|
||||
@ -139,127 +138,118 @@ class MetalClawReaderTemplate {
|
||||
|
||||
};
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr MetalClawReaderTemplate<HandlerMaker>::MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen,
|
||||
template<Reader_c Reader>
|
||||
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
|
||||
Reader &reader,
|
||||
int unionIdx,
|
||||
MetalClawReaderTemplate *parent) noexcept:
|
||||
m_fieldPresence(buff, buffLen),
|
||||
m_fieldPresence(reader),
|
||||
m_unionIdx(unionIdx),
|
||||
m_buffLen(buffLen),
|
||||
m_buff(buff),
|
||||
m_reader(reader),
|
||||
m_parent(parent) {
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr MetalClawReaderTemplate<HandlerMaker>::~MetalClawReaderTemplate() noexcept {
|
||||
if (m_parent) {
|
||||
m_parent->m_buffIt += m_buffIt;
|
||||
}
|
||||
template<Reader_c Reader>
|
||||
constexpr MetalClawReaderTemplate<Reader>::~MetalClawReaderTemplate() noexcept {
|
||||
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 {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int8_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int16_t *val) noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int16_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int32_t *val) noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int32_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int64_t *val) noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int64_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint8_t *val) noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint8_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint16_t *val) noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint16_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint32_t *val) noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint32_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint64_t *val) noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint64_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, bool *val) noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
||||
auto valErr = m_fieldPresence.get(static_cast<std::size_t>(m_field));
|
||||
*val = valErr.value;
|
||||
oxReturnError(valErr.error);
|
||||
auto const result = m_fieldPresence.get(static_cast<std::size_t>(m_field));
|
||||
*val = result.value;
|
||||
oxReturnError(result);
|
||||
}
|
||||
++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 {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *val, std::size_t valLen) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(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;
|
||||
oxRequire(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
|
||||
// read the list
|
||||
if (valLen >= len) {
|
||||
auto reader = child("");
|
||||
auto handler = HandlerMaker(&reader);
|
||||
auto reader = child({});
|
||||
auto &handler = *reader.interface();
|
||||
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
oxReturnError(handler.field("", &val[i]));
|
||||
oxReturnError(handler.field({}, &val[i]));
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
oxTracef("ox::mc::read::field(T)", "{}, length: {}", name, valLen);
|
||||
return OxError(McOutputBuffEnded);
|
||||
}
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
template<Reader_c Reader>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, HashMap<String, T> *val) noexcept {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<String, T> *val) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(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);
|
||||
}
|
||||
oxRequire(g, m_reader.tellg());
|
||||
std::size_t bytesRead = 0;
|
||||
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
|
||||
m_buffIt += bytesRead;
|
||||
oxRequire(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
|
||||
oxReturnError(m_reader.seekg(g));
|
||||
// read the list
|
||||
auto reader = child("");
|
||||
auto handler = HandlerMaker(&reader);
|
||||
auto &handler = *reader.interface();
|
||||
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
const auto keyLen = handler.stringLength(nullptr);
|
||||
oxRequire(keyLen, handler.stringLength(nullptr));
|
||||
auto wkey = ox_malloca(keyLen + 1, char, 0);
|
||||
auto wkeyPtr = wkey.get();
|
||||
oxReturnError(handler.fieldCString("", &wkeyPtr, keyLen + 1));
|
||||
@ -271,18 +261,19 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, HashMa
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
template<Reader_c Reader>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, T *val) noexcept {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
|
||||
if constexpr(isVector_v<T>) {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
||||
// set size of val if the field is present, don't worry about it if not
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
oxRequire(len, arrayLength(name, false));
|
||||
val->resize(len);
|
||||
}
|
||||
return field(name, val->data(), val->size());
|
||||
}
|
||||
}
|
||||
val->resize(0);
|
||||
++m_field;
|
||||
return {};
|
||||
} else if constexpr(isArray_v<T>) {
|
||||
@ -302,8 +293,7 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, T
|
||||
if ((m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) && val) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
auto reader = child("");
|
||||
auto handler = HandlerMaker(&reader);
|
||||
oxReturnError(model(&handler, val));
|
||||
oxReturnError(model(reader.interface(), val));
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
@ -311,44 +301,35 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, T
|
||||
}
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
template<Reader_c Reader>
|
||||
template<typename U, bool force>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, UnionView<U, force> val) noexcept {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept {
|
||||
if ((m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) && val.get()) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
auto reader = child("", val.idx());
|
||||
auto handler = HandlerMaker(&reader);
|
||||
oxReturnError(model(&handler, val.get()));
|
||||
oxReturnError(model(reader.interface(), val.get()));
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
template<Reader_c Reader>
|
||||
template<std::size_t SmallStringSize>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(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(size, mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
|
||||
m_buffIt += bytesRead;
|
||||
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||
const auto cap = size;
|
||||
*val = BasicString<SmallStringSize>(cap);
|
||||
auto data = val->data();
|
||||
// read the string
|
||||
if (static_cast<StringLength>(cap) < size) {
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
return OxError(McOutputBuffEnded);
|
||||
}
|
||||
if (m_buffIt + size > m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
ox_strncpy(data, &m_buff[m_buffIt], size);
|
||||
m_buffIt += size;
|
||||
oxReturnError(m_reader.read(data, size));
|
||||
} else {
|
||||
*val = "";
|
||||
}
|
||||
@ -357,81 +338,56 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicS
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
template<Reader_c Reader>
|
||||
template<std::size_t L>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, BString<L> *val) noexcept {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::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 {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::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);
|
||||
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||
if (size > buffLen) {
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
return OxError(McOutputBuffEnded);
|
||||
}
|
||||
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);
|
||||
oxReturnError(m_reader.read(data, 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 {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::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);
|
||||
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||
// 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);
|
||||
oxReturnError(m_reader.read(data, 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 {
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(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);
|
||||
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||
// re-allocate if too small
|
||||
if (buffLen < size + 1) {
|
||||
safeDelete(*val);
|
||||
@ -440,13 +396,8 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*,
|
||||
}
|
||||
auto data = *val;
|
||||
// read the string
|
||||
if (m_buffIt + size <= m_buffLen) {
|
||||
ox_memcpy(data, &m_buff[m_buffIt], size);
|
||||
oxReturnError(m_reader.read(data, size));
|
||||
data[size] = 0;
|
||||
m_buffIt += size;
|
||||
} else {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
} else {
|
||||
auto data = *val;
|
||||
if (data) {
|
||||
@ -458,18 +409,16 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*,
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr Result<ArrayLength> MetalClawReaderTemplate<HandlerMaker>::arrayLength(const char*, bool pass) noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const char*, bool pass) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(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;
|
||||
oxRequire(g, m_reader.tellg());
|
||||
oxRequire(out, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
|
||||
if (!pass) {
|
||||
oxReturnError(m_reader.seekg(g));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@ -477,20 +426,29 @@ constexpr Result<ArrayLength> MetalClawReaderTemplate<HandlerMaker>::arrayLength
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
template<Reader_c Reader>
|
||||
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(const char*) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(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_reader, &bytesRead);
|
||||
oxReturnError(m_reader.seekg(-static_cast<int64_t>(bytesRead), ox::ios_base::cur));
|
||||
return len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<typename I>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::readInteger(I *val) noexcept {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
std::size_t bytesRead = 0;
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
oxTrace("ox::MetalClaw::readInteger") << "Buffer ended";
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
auto valErr = mc::decodeInteger<I>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(valErr.error);
|
||||
*val = valErr.value;
|
||||
auto const result = mc::decodeInteger<I>(m_reader, &bytesRead);
|
||||
oxReturnError(result);
|
||||
*val = result.value;
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
@ -499,22 +457,17 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::readInteger(I *val) noexc
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
template<Reader_c Reader>
|
||||
template<typename T, typename CB>
|
||||
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, CB cb) noexcept {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(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;
|
||||
|
||||
oxRequire(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
|
||||
// read the list
|
||||
auto reader = child("");
|
||||
auto handler = HandlerMaker(&reader);
|
||||
auto &handler = *reader.interface();
|
||||
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
T val;
|
||||
@ -527,50 +480,36 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, CB cb)
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr StringLength MetalClawReaderTemplate<HandlerMaker>::stringLength(const char*) noexcept {
|
||||
if (m_unionIdx == -1 || static_cast<std::size_t>(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<Reader_c Reader>
|
||||
template<typename T>
|
||||
constexpr ox::Error MetalClawReaderTemplate<HandlerMaker>::setTypeInfo(
|
||||
constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
|
||||
const char*, int, const Vector<String>&, std::size_t fields) noexcept {
|
||||
m_fields = fields;
|
||||
m_buffIt = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
|
||||
m_fieldPresence.setFields(static_cast<int>(fields));
|
||||
m_fieldPresence.setMaxLen(static_cast<int>(m_buffIt));
|
||||
return {};
|
||||
// Warning: narrow-conv
|
||||
return m_reader.seekg(
|
||||
static_cast<int>((fields / 8 + 1) - (fields % 8 == 0)),
|
||||
ox::ios_base::cur);
|
||||
}
|
||||
|
||||
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<Reader_c Reader>
|
||||
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(const char*, int unionIdx) noexcept {
|
||||
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx, this);
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr bool MetalClawReaderTemplate<HandlerMaker>::fieldPresent(const char*) const noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr bool MetalClawReaderTemplate<Reader>::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 {
|
||||
template<Reader_c Reader>
|
||||
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int fieldNo) const noexcept {
|
||||
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
template<Reader_c Reader>
|
||||
[[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(static_cast<int>(u.fieldCount()));
|
||||
constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept {
|
||||
FieldBitmapReader<Reader> p(m_reader);
|
||||
for (auto i = 0u; i < u.fieldCount(); ++i) {
|
||||
if (p.get(i)) {
|
||||
return static_cast<int>(i);
|
||||
@ -579,18 +518,17 @@ constexpr int MetalClawReaderTemplate<HandlerMaker>::whichFieldPresent(const cha
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<auto HandlerMaker>
|
||||
constexpr void MetalClawReaderTemplate<HandlerMaker>::nextField() noexcept {
|
||||
template<Reader_c Reader>
|
||||
constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
|
||||
++m_field;
|
||||
}
|
||||
|
||||
using MetalClawReader = MetalClawReaderTemplate<[](auto r) {
|
||||
return ModelHandlerInterface{r};
|
||||
}>;
|
||||
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
|
||||
|
||||
template<typename T>
|
||||
Error readMC(const char *buff, std::size_t buffLen, T *val) noexcept {
|
||||
MetalClawReader reader(reinterpret_cast<const uint8_t*>(buff), buffLen);
|
||||
BufferReader br(buff, buffLen);
|
||||
MetalClawReader reader(br);
|
||||
ModelHandlerInterface handler(&reader);
|
||||
return model(&handler, val);
|
||||
}
|
||||
|
39
deps/ox/src/ox/mc/test/tests.cpp
vendored
39
deps/ox/src/ox/mc/test/tests.cpp
vendored
@ -18,8 +18,8 @@ union TestUnion {
|
||||
static constexpr auto TypeName = "TestUnion";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
bool Bool;
|
||||
uint32_t Int = 5;
|
||||
char *CString;
|
||||
uint32_t Int;
|
||||
char *CString{};
|
||||
};
|
||||
|
||||
struct TestStructNest {
|
||||
@ -49,6 +49,7 @@ struct TestStruct {
|
||||
ox::BString<32> BString = "";
|
||||
uint32_t List[4] = {0, 0, 0, 0};
|
||||
ox::Vector<uint32_t> Vector = {1, 2, 3, 4, 5};
|
||||
ox::Vector<uint32_t> Vector2 = {1, 2, 3, 4, 5};
|
||||
ox::HashMap<ox::String, int> Map;
|
||||
TestStructNest EmptyStruct;
|
||||
TestStructNest Struct;
|
||||
@ -77,7 +78,6 @@ oxModelEnd()
|
||||
template<typename T>
|
||||
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept {
|
||||
oxReturnError(io->template setTypeInfo<TestStruct>());
|
||||
oxReturnError(io->field("Vector", &obj->Vector));
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("Int1", &obj->Int1));
|
||||
@ -97,9 +97,10 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexce
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
oxReturnError(io->field("BString", &obj->BString));
|
||||
oxReturnError(io->field("List", obj->List, 4));
|
||||
oxReturnError(io->field("Vector", &obj->Vector));
|
||||
oxReturnError(io->field("Map", &obj->Map));
|
||||
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
|
||||
oxReturnError(io->field("Struct", &obj->Struct));
|
||||
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
@ -110,10 +111,9 @@ std::map<ox::String, ox::Error(*)()> tests = {
|
||||
[] {
|
||||
// This test doesn't confirm much, but it does show that the writer
|
||||
// doesn't segfault
|
||||
static constexpr size_t buffLen = 1024;
|
||||
char buff[buffLen];
|
||||
ox::Array<char, 1024> buff;
|
||||
TestStruct ts;
|
||||
oxReturnError(ox::writeMC(buff, buffLen, ts));
|
||||
oxReturnError(ox::writeMC(buff.data(), buff.size(), ts));
|
||||
oxReturnError(ox::writeMC(ts));
|
||||
return OxError(0);
|
||||
}
|
||||
@ -126,18 +126,19 @@ std::map<ox::String, ox::Error(*)()> tests = {
|
||||
TestStruct testIn, testOut;
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.Union.Int = 42;
|
||||
testIn.String = "Test String 0";
|
||||
testIn.BString = "Test String 1";
|
||||
testIn.String = "Test String 2";
|
||||
testIn.Vector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, };
|
||||
testIn.Vector2 = {};
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Map["asdf"] = 93;
|
||||
testIn.Map["aoeu"] = 94;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Bool = true;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.BString = "Test String 2";
|
||||
testIn.Struct.BString = "Test String 3";
|
||||
testIn.unionIdx = 1;
|
||||
testIn.Union.Int = 93;
|
||||
// run tests
|
||||
const auto [buff, err] = ox::writeMC(testIn);
|
||||
oxAssert(err, "writeMC failed");
|
||||
@ -160,10 +161,11 @@ std::map<ox::String, ox::Error(*)()> tests = {
|
||||
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
||||
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
||||
oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch");
|
||||
oxAssert(testIn.Vector[0] == testOut.Vector[0], "Vector[0] value mismatch");
|
||||
oxAssert(testIn.Vector[1] == testOut.Vector[1], "Vector[1] value mismatch");
|
||||
oxAssert(testIn.Vector[2] == testOut.Vector[2], "Vector[2] value mismatch");
|
||||
oxAssert(testIn.Vector[3] == testOut.Vector[3], "Vector[3] value mismatch");
|
||||
oxAssert(testIn.Vector.size() == testOut.Vector.size(), "Vector size mismatch");
|
||||
for (auto i = 0u; i < testIn.Vector.size(); ++i) {
|
||||
oxAssert(testIn.Vector[i] == testOut.Vector[i], ox::sfmt("Vector[{}] value mismatch", i));
|
||||
}
|
||||
oxAssert(testIn.Vector2.size() == testOut.Vector2.size(), "Vector2 size mismatch");
|
||||
oxAssert(testIn.Map["asdf"] == testOut.Map["asdf"], "Map[\"asdf\"] value mismatch");
|
||||
oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
|
||||
@ -363,7 +365,8 @@ std::map<ox::String, ox::Error(*)()> tests = {
|
||||
ox::TypeStore typeStore;
|
||||
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
|
||||
oxAssert(typeErr, "Descriptor write failed");
|
||||
oxReturnError(ox::walkModel<ox::MetalClawReader>(type, dataBuff, dataBuffLen,
|
||||
ox::BufferReader br(dataBuff, dataBuffLen);
|
||||
oxReturnError(ox::walkModel<ox::MetalClawReader>(type, br,
|
||||
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
|
||||
//std::cout << f.fieldName.c_str() << '\n';
|
||||
auto fieldName = f.fieldName.c_str();
|
||||
|
4
deps/ox/src/ox/mc/types.hpp
vendored
4
deps/ox/src/ox/mc/types.hpp
vendored
@ -14,7 +14,7 @@
|
||||
|
||||
namespace ox {
|
||||
|
||||
using StringLength = uint32_t;
|
||||
using ArrayLength = uint32_t;
|
||||
using StringLength = std::size_t;
|
||||
using ArrayLength = std::size_t;
|
||||
|
||||
}
|
||||
|
7
deps/ox/src/ox/model/walk.hpp
vendored
7
deps/ox/src/ox/model/walk.hpp
vendored
@ -144,6 +144,13 @@ constexpr Error model(Reader *rdr, DataWalker<Reader, FH> *walker) noexcept {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename Reader, typename Handler>
|
||||
constexpr Error walkModel(DescriptorType *type, Reader_c auto &reader, Handler handler) noexcept {
|
||||
DataWalker<Reader, Handler> walker(type, handler);
|
||||
Reader rdr(reader);
|
||||
return model(&rdr, &walker);
|
||||
}
|
||||
|
||||
template<typename Reader, typename Handler>
|
||||
constexpr Error walkModel(DescriptorType *type, const char *data, std::size_t dataLen, Handler handler) noexcept {
|
||||
DataWalker<Reader, Handler> walker(type, handler);
|
||||
|
1
deps/ox/src/ox/std/CMakeLists.txt
vendored
1
deps/ox/src/ox/std/CMakeLists.txt
vendored
@ -30,6 +30,7 @@ add_library(
|
||||
math.cpp
|
||||
memops.cpp
|
||||
random.cpp
|
||||
reader.cpp
|
||||
substitutes.cpp
|
||||
stacktrace.cpp
|
||||
string.cpp
|
||||
|
1
deps/ox/src/ox/std/buffer.cpp
vendored
1
deps/ox/src/ox/std/buffer.cpp
vendored
@ -13,6 +13,7 @@ namespace ox {
|
||||
|
||||
template class Vector<char>;
|
||||
|
||||
template class ReaderT<BufferReader>;
|
||||
template class WriterT<BufferWriter>;
|
||||
template class WriterT<CharBuffWriter>;
|
||||
|
||||
|
70
deps/ox/src/ox/std/buffer.hpp
vendored
70
deps/ox/src/ox/std/buffer.hpp
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 - 2022 gary@drinkingtea.net
|
||||
* Copyright 2015 - 2023 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
|
||||
@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "error.hpp"
|
||||
#include "reader.hpp"
|
||||
#include "vector.hpp"
|
||||
#include "writer.hpp"
|
||||
|
||||
@ -166,6 +167,73 @@ class CharBuffWriter {
|
||||
}
|
||||
};
|
||||
|
||||
class BufferReader {
|
||||
private:
|
||||
std::size_t m_it = 0;
|
||||
std::size_t m_size = 0;
|
||||
char const* m_buff = nullptr;
|
||||
|
||||
public:
|
||||
constexpr explicit BufferReader(char const*buff, std::size_t sz) noexcept:
|
||||
m_size(sz), m_buff(buff) {}
|
||||
|
||||
constexpr explicit BufferReader(ox::Buffer const&buffer) noexcept:
|
||||
m_size(buffer.size()), m_buff(buffer.data()) {}
|
||||
|
||||
constexpr ox::Result<char> peek() const noexcept {
|
||||
if (m_it >= m_size) [[unlikely]] {
|
||||
return OxError(1, "Peek failed: buffer overrun");
|
||||
}
|
||||
return m_buff[m_it];
|
||||
}
|
||||
|
||||
constexpr ox::Result<std::size_t> read(void *v, std::size_t sz) noexcept {
|
||||
sz = ox::min(sz, m_size - m_it);
|
||||
if (m_it + sz > m_size) [[unlikely]] {
|
||||
return OxError(1, "Read failed: Buffer overrun");
|
||||
}
|
||||
ox_memcpy(v, &m_buff[m_it], sz);
|
||||
m_it += sz;
|
||||
return sz;
|
||||
}
|
||||
|
||||
constexpr ox::Error seekg(std::size_t p) noexcept {
|
||||
if (p > m_size) [[unlikely]] {
|
||||
return OxError(1, "Seek failed: Buffer overrun");
|
||||
}
|
||||
m_it = p;
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr ox::Error seekg(int64_t off, ios_base::seekdir dir) noexcept {
|
||||
ox::Signed<std::size_t> base = 0;
|
||||
switch (dir) {
|
||||
case ox::ios_base::beg:
|
||||
base = 0;
|
||||
break;
|
||||
case ox::ios_base::end:
|
||||
base = static_cast<ox::Signed<std::size_t>>(m_size);
|
||||
break;
|
||||
case ox::ios_base::cur:
|
||||
base = static_cast<ox::Signed<std::size_t>>(m_it);
|
||||
break;
|
||||
default:
|
||||
return OxError(1, "Invalid seekdir");
|
||||
}
|
||||
auto const newIt = static_cast<std::size_t>(base + off);
|
||||
if (newIt > m_size) [[unlikely]] {
|
||||
return OxError(1, "Seek failed: Buffer overrun");
|
||||
}
|
||||
m_it = newIt;
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr ox::Result<std::size_t> tellg() const noexcept {
|
||||
return m_it;
|
||||
}
|
||||
};
|
||||
|
||||
extern template class ReaderT<BufferReader>;
|
||||
extern template class WriterT<BufferWriter>;
|
||||
extern template class WriterT<CharBuffWriter>;
|
||||
|
||||
|
59
deps/ox/src/ox/std/reader.cpp
vendored
Normal file
59
deps/ox/src/ox/std/reader.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef OX_USE_STDLIB
|
||||
#include <cstdio>
|
||||
|
||||
#include "array.hpp"
|
||||
#include "reader.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr int sdMap(ox::ios_base::seekdir in) noexcept {
|
||||
switch (in) {
|
||||
case ox::ios_base::beg:
|
||||
return SEEK_SET;
|
||||
case ox::ios_base::end:
|
||||
return SEEK_END;
|
||||
case ox::ios_base::cur:
|
||||
return SEEK_CUR;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ox::Result<char> FileReader::peek() const noexcept {
|
||||
auto const c = fgetc(m_file);
|
||||
auto const ok = c != EOF;
|
||||
if (ok && ungetc(c, m_file)) [[unlikely]] {
|
||||
return OxError(1, "Unable to unget character");
|
||||
}
|
||||
return {static_cast<char>(c), OxError(!ok, "File peek failed")};
|
||||
}
|
||||
|
||||
ox::Result<std::size_t> FileReader::read(char *v, std::size_t cnt) noexcept {
|
||||
return fread(v, 1, cnt, m_file);
|
||||
}
|
||||
|
||||
ox::Error FileReader::seekg(std::size_t p) noexcept {
|
||||
return OxError(fseek(m_file, static_cast<int64_t>(p), SEEK_CUR) != 0);
|
||||
}
|
||||
|
||||
ox::Error FileReader::seekg(int64_t p, ios_base::seekdir sd) noexcept {
|
||||
return OxError(fseek(m_file, p, sdMap(sd)) != 0);
|
||||
}
|
||||
|
||||
ox::Result<std::size_t> FileReader::tellg() noexcept {
|
||||
const auto sz = ftell(m_file);
|
||||
return {static_cast<std::size_t>(sz), OxError(sz == -1)};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
96
deps/ox/src/ox/std/reader.hpp
vendored
Normal file
96
deps/ox/src/ox/std/reader.hpp
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef OX_USE_STDLIB
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#include "concepts.hpp"
|
||||
#include "error.hpp"
|
||||
#include "types.hpp"
|
||||
#include "writer.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename T>
|
||||
concept Reader_c = requires(T v) {
|
||||
{v.peek()} -> ox::same_as<ox::Result<char>>;
|
||||
{v.read(static_cast<char*>(nullptr), static_cast<std::size_t>(0))} -> ox::same_as<ox::Result<std::size_t>>;
|
||||
{v.seekg(static_cast<int64_t>(0))} -> ox::same_as<ox::Error>;
|
||||
{v.seekg(static_cast<std::size_t>(0), ios_base::beg)} -> ox::same_as<ox::Error>;
|
||||
{v.tellg()} -> ox::same_as<ox::Result<std::size_t>>;
|
||||
};
|
||||
|
||||
class Reader_v {
|
||||
public:
|
||||
virtual constexpr ~Reader_v() noexcept = default;
|
||||
[[nodiscard]]
|
||||
virtual constexpr ox::Result<char> peek() const noexcept = 0;
|
||||
virtual constexpr ox::Result<std::size_t> read(char*, std::size_t) noexcept = 0;
|
||||
virtual constexpr ox::Result<std::size_t> tellg() noexcept = 0;
|
||||
virtual constexpr ox::Error seekg(std::size_t) noexcept = 0;
|
||||
virtual constexpr ox::Error seekg(int64_t, ios_base::seekdir) = 0;
|
||||
};
|
||||
|
||||
template<Reader_c T>
|
||||
class ReaderT: public Reader_v {
|
||||
private:
|
||||
T m_reader{};
|
||||
public:
|
||||
template<typename ...Args>
|
||||
constexpr explicit ReaderT(Args&&... args) noexcept: m_reader(args...) {
|
||||
}
|
||||
constexpr ox::Result<char> peek() const noexcept override {
|
||||
return m_reader.peek();
|
||||
}
|
||||
constexpr ox::Result<std::size_t> read(char *v, std::size_t cnt) noexcept override {
|
||||
return m_reader.read(v, cnt);
|
||||
}
|
||||
constexpr ox::Error seekg(std::size_t p) noexcept override {
|
||||
return m_reader.seekg(p);
|
||||
}
|
||||
constexpr ox::Error seekg(int64_t p, ios_base::seekdir sd) noexcept override {
|
||||
return m_reader.seekg(p, sd);
|
||||
}
|
||||
constexpr ox::Result<std::size_t> tellg() noexcept override {
|
||||
return m_reader.tellg();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef OX_USE_STDLIB
|
||||
class FileReader: public Reader_v {
|
||||
private:
|
||||
FILE *m_file = nullptr;
|
||||
public:
|
||||
constexpr explicit FileReader(FILE *file) noexcept: m_file(file) {}
|
||||
ox::Result<char> peek() const noexcept override;
|
||||
ox::Result<std::size_t> read(char *v, std::size_t cnt) noexcept override;
|
||||
ox::Error seekg(std::size_t p) noexcept override;
|
||||
ox::Error seekg(int64_t p, ios_base::seekdir sd) noexcept override;
|
||||
ox::Result<std::size_t> tellg() noexcept override;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Allocates the specified amount of data at the end of the current read stream.
|
||||
* @param reader
|
||||
* @param sz
|
||||
* @return
|
||||
*/
|
||||
constexpr ox::Result<std::size_t> allocate(Reader_c auto *reader, std::size_t sz) noexcept {
|
||||
const auto p = reader->tellg();
|
||||
oxReturnError(reader->seekg(0, ios_base::end));
|
||||
const auto out = reader->tellg();
|
||||
oxReturnError(reader->read(nullptr, sz));
|
||||
oxReturnError(reader->seekg(p));
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user