[ox] Add Reader_c and make MetalClawReader use it

This commit is contained in:
Gary Talent 2023-10-22 16:37:08 -05:00
parent 4ab710b155
commit 1f78ea1f37
16 changed files with 533 additions and 285 deletions

View File

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

View File

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

View File

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

View File

@ -11,9 +11,9 @@
namespace ox {
enum {
MC_PRESENCEMASKOUTBOUNDS = 1,
MC_BUFFENDED = 2,
MC_OUTBUFFENDED = 4
McPresenceMapOverflow = 1,
McBuffEnded = 2,
McOutputBuffEnded = 4
};
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@
namespace ox {
using StringLength = uint32_t;
using ArrayLength = uint32_t;
using StringLength = std::size_t;
using ArrayLength = std::size_t;
}

View File

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

View File

@ -30,6 +30,7 @@ add_library(
math.cpp
memops.cpp
random.cpp
reader.cpp
substitutes.cpp
stacktrace.cpp
string.cpp

View File

@ -13,6 +13,7 @@ namespace ox {
template class Vector<char>;
template class ReaderT<BufferReader>;
template class WriterT<BufferWriter>;
template class WriterT<CharBuffWriter>;

View File

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