[ox/mc] Use VLI encoding for integers

This commit is contained in:
Gary Talent 2019-03-17 03:03:21 -05:00
parent 817e3fcef1
commit e0605edb6e
6 changed files with 53 additions and 65 deletions

View File

@ -66,15 +66,15 @@ Error MetalClawReader::op(const char*, bool *val) {
}
Error MetalClawReader::op(const char*, SerStr val) {
if (m_fieldPresence.get(m_field)) {
if (m_fieldPresence.get(m_field++)) {
// read the length
StringLength size = 0;
if (m_buffIt + sizeof(StringLength) < m_buffLen) {
size = *reinterpret_cast<LittleEndian<StringLength>*>(&m_buff[m_buffIt]);
m_buffIt += sizeof(StringLength);
} else {
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto size = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(size.error);
// read the string
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
@ -90,7 +90,6 @@ Error MetalClawReader::op(const char*, SerStr val) {
} else {
val.data()[0] = 0;
}
m_field++;
return OxError(0);
}
@ -98,25 +97,25 @@ Error MetalClawReader::op(const char*, SerStr val) {
std::size_t len = 0;
if (m_fieldPresence.get(m_field)) {
// read the length
if (m_buffIt + sizeof(ArrayLength) < m_buffLen) {
len = *reinterpret_cast<LittleEndian<ArrayLength>*>(&m_buff[m_buffIt]);
if (pass) {
m_buffIt += sizeof(ArrayLength);
}
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
if (pass) {
m_buffIt += sizeof(ArrayLength);
}
}
return len;
}
[[nodiscard]] StringLength MetalClawReader::stringLength() {
std::size_t len = 0;
if (m_fieldPresence.get(m_field)) {
// read the length
if (m_buffIt + sizeof(StringLength) < m_buffLen) {
len = *reinterpret_cast<LittleEndian<StringLength>*>(&m_buff[m_buffIt]);
}
std::size_t bytesRead = 0;
return mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
}
return len;
return 0;
}
void MetalClawReader::setTypeInfo(const char*, int fields) {

View File

@ -15,6 +15,7 @@
#include <ox/std/vector.hpp>
#include "err.hpp"
#include "intops.hpp"
#include "presenceindicator.hpp"
#include "types.hpp"
@ -106,11 +107,10 @@ class MetalClawReader {
template<typename T>
Error MetalClawReader::op(const char*, T *val) {
Error err = 0;
if (val && m_fieldPresence.get(m_field)) {
if (val && m_fieldPresence.get(m_field++)) {
auto reader = child();
err |= ioOp(&reader, val);
}
m_field++;
return err;
};
@ -121,34 +121,34 @@ Error MetalClawReader::op(const char *name, ox::BString<L> *val) {
template<typename I>
Error MetalClawReader::readInteger(I *val) {
Error err = 0;
if (m_fieldPresence.get(m_field)) {
if (m_buffIt + sizeof(I) < m_buffLen) {
*val = *reinterpret_cast<LittleEndian<I>*>(&m_buff[m_buffIt]);
m_buffIt += sizeof(I);
} else {
err = OxError(MC_BUFFENDED);
if (m_fieldPresence.get(m_field++)) {
std::size_t bytesRead = 0;
if (m_buffIt >= m_buffLen) {
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;
} else {
*val = 0;
}
m_field++;
return err;
return OxError(0);
};
// array handler
template<typename T>
Error MetalClawReader::op(const char*, T *val, std::size_t valLen) {
Error err = 0;
if (m_fieldPresence.get(m_field)) {
if (m_fieldPresence.get(m_field++)) {
// read the length
ArrayLength len = 0;
if (m_buffIt + sizeof(ArrayLength) < m_buffLen) {
len = *reinterpret_cast<LittleEndian<ArrayLength>*>(&m_buff[m_buffIt]);
m_buffIt += sizeof(ArrayLength);
} else {
err = OxError(MC_BUFFENDED);
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(len.error);
// read the list
if (valLen >= len) {
@ -161,7 +161,6 @@ Error MetalClawReader::op(const char*, T *val, std::size_t valLen) {
err = OxError(MC_OUTBUFFENDED);
}
}
m_field++;
return err;
};

View File

@ -10,5 +10,6 @@ target_link_libraries(
add_test("Test\\ McTest\\ Writer" McTest MetalClawWriter)
add_test("Test\\ McTest\\ Reader" McTest MetalClawReader)
add_test("Test\\ McTest\\ MetalClawDef" McTest MetalClawDef)
add_test("Test\\ McTest\\ encodeInteger" McTest encodeInteger)
add_test("Test\\ McTest\\ decodeInteger" McTest decodeInteger)

View File

@ -107,6 +107,7 @@ std::map<std::string, ox::Error(*)()> tests = {
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed");
oxAssert(ox::readMC(buff, buffLen, &testOut), "writeMC failed");
std::cout << testIn.Int << " " << testOut.Int << '\n';
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
@ -217,12 +218,15 @@ std::map<std::string, ox::Error(*)()> tests = {
}
return OxError(result.value != val);
};
oxAssert(check(uint32_t(14)), "Decode of 14 failed.");
oxAssert(check(int64_t(1)), "Decode of 1 failed.");
oxAssert(check(int64_t(2)), "Decode of 2 failed.");
oxAssert(check(int64_t(42)), "Decode of 42 failed.");
oxAssert(check(int64_t(130)), "Decode of 130 failed.");
oxAssert(check(int64_t(131)), "Decode of 131 failed.");
oxAssert(check(uint64_t(1)), "Decode of 1 failed.");
oxAssert(check(uint64_t(2)), "Decode of 2 failed.");
oxAssert(check(uint64_t(42)), "Decode of 42 failed.");
oxAssert(check(uint64_t(130)), "Decode of 130 failed.");
oxAssert(check(uint64_t(131)), "Decode of 131 failed.");
oxAssert(check(0xffffffff), "Decode of 0xffffffff failed.");
@ -262,7 +266,7 @@ std::map<std::string, ox::Error(*)()> tests = {
auto fieldName = f.fieldName.c_str();
switch (f.type->primitiveType) {
case ox::PrimitiveType::UnsignedInteger:
std::cout << fieldName << ":\tuint" << f.type->length << "_t:\t";
std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t";
switch (f.type->length) {
case 1: {
uint8_t i = {};
@ -292,7 +296,7 @@ std::map<std::string, ox::Error(*)()> tests = {
std::cout << '\n';
break;
case ox::PrimitiveType::SignedInteger:
std::cout << fieldName << ":\tint" << f.type->length << "_t:\t";
std::cout << fieldName << ":\tint" << f.type->length * 8 << "_t:\t";
switch (f.type->length) {
case 1: {
int8_t i = {};

View File

@ -65,9 +65,10 @@ Error MetalClawWriter::op(const char*, SerStr val) {
bool fieldSet = false;
if (val.cap()) {
// write the length
if (m_buffIt + sizeof(StringLength) + val.bytes() < m_buffLen) {
*reinterpret_cast<LittleEndian<StringLength>*>(&m_buff[m_buffIt]) = static_cast<StringLength>(val.bytes());
m_buffIt += sizeof(StringLength);
const auto strLen = mc::encodeInteger(val.bytes());
if (m_buffIt + strLen.length + val.bytes() < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
m_buffIt += strLen.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], val.c_str(), val.bytes());

View File

@ -111,9 +111,10 @@ Error MetalClawWriter::op(const char*, T *val, std::size_t len) {
if (len) {
// write the length
if (m_buffIt + sizeof(ArrayLength) < m_buffLen) {
*reinterpret_cast<LittleEndian<ArrayLength>*>(&m_buff[m_buffIt]) = static_cast<ArrayLength>(len);
m_buffIt += sizeof(ArrayLength);
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 {
err = MC_BUFFENDED;
}
@ -140,28 +141,11 @@ Error MetalClawWriter::appendInteger(I val) {
Error err = 0;
bool fieldSet = false;
if (val) {
if (m_buffIt + sizeof(I) < m_buffLen) {
LittleEndian<I> leVal = val;
// bits needed to represent number factoring in space possibly needed
// for signed bit
const auto bits = mc::highestBit(val) + (ox::is_signed<I> ? 1 : 0) / 8;
// bytes needed to store value
std::size_t bytes = bits / 8 + (bits % 8 != 0);
const auto bytesIndicator = onMask<uint8_t>(bytes - 1) << (7 - bytes);
// factor in bits needed for bytesIndicator (does not affect bytesIndicator)
// bits for integer + bits needed to represent bytes > bits available
if (bits + bytes > bytes * 8) {
++bytes;
}
if (bytes == 9) {
m_buff[m_buffIt++] = bytesIndicator;
} else {
}
*reinterpret_cast<LittleEndian<I>*>(&m_buff[m_buffIt]) = leVal;
auto mi = mc::encodeInteger(val);
if (mi.length < m_buffLen) {
fieldSet = true;
m_buffIt += sizeof(I);
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
m_buffIt += mi.length;
} else {
err |= MC_BUFFENDED;
}