[ox/mc] Make MC Write use Writer_c

This commit is contained in:
Gary Talent 2023-06-08 00:56:02 -05:00
parent ae3f0bb5db
commit ce4dcdcd18
6 changed files with 150 additions and 137 deletions

View File

@ -158,12 +158,10 @@ static std::map<std::string_view, ox::Error(*)()> tests = {
testIn.Struct.Bool = false;
testIn.Struct.Int = 300;
testIn.Struct.String = "Test String 2";
auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal);
oxAssert(err, "writeMC failed");
oxAssert(ox::readClaw(buff.data(), buff.size(), &testOut), "readMC failed");
const auto [buff, err] = ox::writeMC(&testIn);
oxAssert(err, "writeClaw failed");
oxAssert(ox::readMC(buff.data(), buff.size(), &testOut), "readClaw failed");
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch");

View File

@ -24,6 +24,8 @@ class FieldBitmapReader {
public:
constexpr FieldBitmapReader(T map, std::size_t maxLen) noexcept;
constexpr auto setBuffer(T map, std::size_t maxLen) noexcept;
constexpr Result<bool> get(std::size_t i) const noexcept;
constexpr void setFields(int) noexcept;
@ -41,6 +43,12 @@ constexpr FieldBitmapReader<T>::FieldBitmapReader(T map, std::size_t maxLen) noe
m_mapLen = maxLen;
}
template<typename T>
constexpr auto FieldBitmapReader<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 {
if (i / 8 < m_mapLen) {

View File

@ -122,8 +122,6 @@ std::map<ox::String, ox::Error(*)()> tests = {
"MetalClawReader",
[] {
// setup for tests
static constexpr size_t buffLen = 1024;
char buff[buffLen];
TestStruct testIn, testOut;
testIn.Bool = true;
testIn.Int = 42;
@ -140,8 +138,9 @@ std::map<ox::String, ox::Error(*)()> tests = {
testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 2";
// run tests
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed");
oxAssert(ox::readMC(buff, buffLen, &testOut), "readMC failed");
const auto [buff, err] = ox::writeMC(&testIn);
oxAssert(err, "writeMC failed");
oxAssert(ox::readMC(buff.data(), buff.size(), &testOut), "readMC failed");
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");

View File

@ -15,6 +15,7 @@
namespace ox {
template class ModelHandlerInterface<MetalClawWriter>;
template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
}

View File

@ -27,19 +27,19 @@
namespace ox {
template<Writer_c Writer>
class MetalClawWriter {
private:
ox::Vector<uint8_t, 16> m_presenceMapBuff;
FieldBitmap m_fieldPresence;
int m_fields = 0;
int m_field = 0;
int m_unionIdx = -1;
std::size_t m_buffIt = 0;
std::size_t m_buffLen = 0;
uint8_t *m_buff = nullptr;
std::size_t m_writerBeginP{};
Writer &m_writer;
public:
constexpr MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept;
constexpr explicit MetalClawWriter(Writer &writer, int unionIdx = -1) noexcept;
constexpr ~MetalClawWriter() noexcept = default;
@ -122,77 +122,81 @@ class MetalClawWriter {
return 0;
}
[[nodiscard]]
constexpr std::size_t size() const noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Write;
}
ox::Error finalize() noexcept;
private:
constexpr Error appendInteger(Integer_c auto val) noexcept {
bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
if (mi.length < m_buffLen) {
fieldSet = true;
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
m_buffIt += mi.length;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data), mi.length));
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
++m_field;
return OxError(0);
}
};
extern template class ModelHandlerInterface<MetalClawWriter>;
extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
constexpr MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
m_fieldPresence(buff, buffLen),
template<Writer_c Writer>
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, int unionIdx) noexcept:
m_fieldPresence(m_presenceMapBuff.data(), m_presenceMapBuff.size()),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff) {
m_writerBeginP(writer.tellp()),
m_writer(writer) {
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int8_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int8_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int16_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int16_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int32_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int32_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int64_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int64_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<bool> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<bool> auto *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
}
@ -200,108 +204,97 @@ constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<bool> auto *va
return OxError(0);
}
template<Writer_c Writer>
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false;
if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto strLen = mc::encodeInteger(val->len());
if (m_buffIt + strLen.length + static_cast<std::size_t>(val->len()) < m_buffLen) {
memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
m_buffIt += strLen.length;
// write the string
memcpy(&m_buff[m_buffIt], val->c_str(), static_cast<std::size_t>(val->len()));
m_buffIt += static_cast<std::size_t>(val->len());
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLen.data), strLen.length));
// write the string
oxReturnError(m_writer.write(val->c_str(), static_cast<std::size_t>(val->len())));
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
template<Writer_c Writer>
template<std::size_t L>
constexpr Error MetalClawWriter::field(const char *name, const BString<L> *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char *name, const BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
template<Writer_c Writer>
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter::field(const char *name, BasicString<SmallStringSize> *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char *name, BasicString<SmallStringSize> *val) noexcept {
return field(name, const_cast<const BasicString<SmallStringSize>*>(val));
}
template<Writer_c Writer>
template<std::size_t L>
constexpr Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
constexpr Error MetalClawWriter::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
bool fieldSet = false;
if (m_unionIdx == -1 || m_unionIdx == m_field) {
const auto strLen = *val ? ox_strlen(*val) : 0;
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], *val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
// write the string
oxReturnError(m_writer.write(*val, static_cast<std::size_t>(strLen)));
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
constexpr Error MetalClawWriter::fieldCString(const char *name, const char **val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char *name, const char **val) noexcept {
return fieldCString(name, val, {});
}
constexpr Error MetalClawWriter::fieldCString(const char *name, const char *const*val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char *name, const char *const*val) noexcept {
return fieldCString(name, val, {});
}
constexpr Error MetalClawWriter::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
bool fieldSet = false;
if (strLen && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
// write the string
oxReturnError(m_writer.write(val, static_cast<std::size_t>(strLen)));
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter::field(const char*, T *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, T *val) noexcept {
if constexpr(isVector_v<T> || isArray_v<T>) {
return field(nullptr, val->data(), val->size());
} else {
bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
ModelHandlerInterface<MetalClawWriter> handler{&writer};
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer};
oxReturnError(model(&handler, val));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
}
oxReturnError(writer.finalize());
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
@ -309,70 +302,57 @@ constexpr Error MetalClawWriter::field(const char*, T *val) noexcept {
}
}
template<Writer_c Writer>
template<typename U, bool force>
constexpr Error MetalClawWriter::field(const char*, UnionView<U, force> val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept {
bool fieldSet = false;
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt, val.idx());
MetalClawWriter<Writer> writer(m_writer, val.idx());
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val.get()));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
}
oxReturnError(writer.finalize());
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
++m_field;
return OxError(0);
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, T *val, std::size_t len) noexcept {
bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto arrLen = mc::encodeInteger(len);
if (m_buffIt + arrLen.length < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length);
m_buffIt += arrLen.length;
} else {
return OxError(MC_BUFFENDED);
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer};
handler.setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len));
handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len));
// write the array
for (std::size_t i = 0; i < len; i++) {
oxReturnError(handler.field("", &val[i]));
}
m_buffIt += writer.m_buffIt;
oxReturnError(writer.finalize());
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
++m_field;
return OxError(0);
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter::field(const char*, const HashMap<String, T> *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String, T> *val) noexcept {
const auto &keys = val->keys();
const auto len = keys.size();
bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto arrLen = mc::encodeInteger(len);
if (m_buffIt + arrLen.length < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length);
m_buffIt += arrLen.length;
} else {
return OxError(MC_BUFFENDED);
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
// write map
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer};
// double len for both key and value
handler.setTypeInfo("Map", 0, {}, len * 2);
@ -386,48 +366,69 @@ constexpr Error MetalClawWriter::field(const char*, const HashMap<String, T> *va
oxRequireM(value, val->at(key));
oxReturnError(handler.field("", value));
}
m_buffIt += writer.m_buffIt;
oxReturnError(writer.finalize());
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
++m_field;
return OxError(0);
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter::field(const char *name, HashMap<String, T> *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char *name, HashMap<String, T> *val) noexcept {
return field(name, const_cast<const HashMap<String, T>*>(val));
}
template<Writer_c Writer>
template<typename T>
constexpr void MetalClawWriter::setTypeInfo(const char*, int, const Vector<String>&, std::size_t fields) noexcept {
m_fields = static_cast<int>(fields);
constexpr void MetalClawWriter<Writer>::setTypeInfo(
const char*,
int,
const Vector<String>&,
std::size_t fields) noexcept {
// TODO: change all setTypeInfo signatures to return Errors
const auto fieldPresenceLen = (fields - 1) / 8 + 1;
oxIgnoreError(m_writer.write(nullptr, fieldPresenceLen));
m_presenceMapBuff.resize(fieldPresenceLen);
m_fieldPresence.setBuffer(m_presenceMapBuff.data(), m_presenceMapBuff.size());
m_fieldPresence.setFields(static_cast<int>(fields));
m_buffIt = static_cast<std::size_t>(m_fieldPresence.getMaxLen());
ox_memset(m_buff, 0, m_buffIt);
}
constexpr std::size_t MetalClawWriter::size() const noexcept {
return m_buffIt;
template<Writer_c Writer>
ox::Error MetalClawWriter<Writer>::finalize() noexcept {
const auto end = m_writer.tellp();
oxReturnError(m_writer.seekp(m_writerBeginP));
oxReturnError(m_writer.write(
reinterpret_cast<const char*>(m_presenceMapBuff.data()),
m_presenceMapBuff.size()));
oxReturnError(m_writer.seekp(end));
return {};
}
Result<Buffer> writeMC(auto *val) noexcept {
Buffer buff(10 * units::MB);
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff.data()), buff.size());
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val));
buff.resize(writer.size());
Result<Buffer> writeMC(Writer_c auto &writer, auto &val) noexcept {
MetalClawWriter mcWriter(writer);
ModelHandlerInterface handler{&mcWriter};
oxReturnError(model(&handler, &val));
oxReturnError(mcWriter.finalize());
return {};
}
Result<Buffer> writeMC(auto *val, std::size_t buffReserveSz = 2 * units::KB) noexcept {
Buffer buff(buffReserveSz);
BufferWriter bw(&buff, 0);
oxReturnError(writeMC(bw, *val));
buff.resize(bw.tellp());
return buff;
}
Error writeMC(char *buff, std::size_t buffLen, auto *val, std::size_t *sizeOut = nullptr) noexcept {
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff), buffLen);
ModelHandlerInterface handler(&writer);
auto err = model(&handler, val);
CharBuffWriter bw(buff, buffLen);
oxReturnError(writeMC(bw, *val));
if (sizeOut) {
*sizeOut = writer.size();
*sizeOut = bw.tellp();
}
return err;
return {};
}
}

View File

@ -66,6 +66,12 @@ class WriterT: public Writer_v {
}
};
/**
* Allocates the specified amount of data at the end of the current write stream.
* @param writer
* @param sz
* @return
*/
constexpr ox::Result<std::size_t> allocate(Writer_c auto *writer, std::size_t sz) noexcept {
const auto p = writer->tellp();
oxReturnError(writer->seekp(0, ios_base::end));