[ox/mc] Add VLI decode
This commit is contained in:
parent
341dbf14ae
commit
df44abc316
49
deps/ox/src/ox/mc/intops.hpp
vendored
49
deps/ox/src/ox/mc/intops.hpp
vendored
@ -96,4 +96,53 @@ template<typename I>
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes indicated by the bytes indicator of a variable
|
||||
* length integer.
|
||||
*/
|
||||
[[nodiscard]] static constexpr std::size_t countBytes(uint8_t b) noexcept {
|
||||
std::size_t i = 0;
|
||||
for (; (b >> i) & 1; i++);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static_assert(countBytes(0b00000000) == 1);
|
||||
static_assert(countBytes(0b00000001) == 2);
|
||||
static_assert(countBytes(0b00000011) == 3);
|
||||
static_assert(countBytes(0b00000111) == 4);
|
||||
static_assert(countBytes(0b00001111) == 5);
|
||||
static_assert(countBytes(0b00011111) == 6);
|
||||
static_assert(countBytes(0b00111111) == 7);
|
||||
static_assert(countBytes(0b01111111) == 8);
|
||||
static_assert(countBytes(0b11111111) == 9);
|
||||
|
||||
template<typename I>
|
||||
[[nodiscard]] ValErr<I> decodeInteger(uint8_t buff[9], std::size_t buffLen) noexcept {
|
||||
const auto bytes = countBytes(buff[0]);
|
||||
if (bytes == 9) {
|
||||
return {LittleEndian<I>(*reinterpret_cast<I*>(&buff[1])), 0};
|
||||
} else if (buffLen >= bytes) {
|
||||
uint64_t decoded = LittleEndian<uint64_t>(*reinterpret_cast<uint64_t*>(&buff[0]));
|
||||
decoded >>= bytes;
|
||||
auto out = static_cast<I>(decoded);
|
||||
// move sign bit
|
||||
if constexpr(ox::is_signed<I>) {
|
||||
const auto valBits = bytes << 3;
|
||||
// get sign
|
||||
uint64_t sign = decoded >> (valBits - 1);
|
||||
// remove sign
|
||||
decoded &= uint64_t(~0) ^ (uint64_t(1) << valBits);
|
||||
// set sign
|
||||
*reinterpret_cast<Unsigned<I>*>(&out) |= sign << (Bits<I> - 1);
|
||||
}
|
||||
return {out, 0};
|
||||
}
|
||||
return {0, OxError(1)};
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
[[nodiscard]] ValErr<I> decodeInteger(McInt m) noexcept {
|
||||
return decodeInteger<I>(m.data, 9);
|
||||
}
|
||||
|
||||
}
|
||||
|
1
deps/ox/src/ox/mc/test/CMakeLists.txt
vendored
1
deps/ox/src/ox/mc/test/CMakeLists.txt
vendored
@ -11,3 +11,4 @@ target_link_libraries(
|
||||
add_test("Test\\ McTest\\ Writer" McTest MetalClawWriter)
|
||||
add_test("Test\\ McTest\\ Reader" McTest MetalClawReader)
|
||||
add_test("Test\\ McTest\\ encodeInteger" McTest encodeInteger)
|
||||
add_test("Test\\ McTest\\ decodeInteger" McTest decodeInteger)
|
||||
|
32
deps/ox/src/ox/mc/test/tests.cpp
vendored
32
deps/ox/src/ox/mc/test/tests.cpp
vendored
@ -184,6 +184,7 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
oxAssert(check(encodeInteger(int64_t(-130)), {255, 126, 255, 255, 255, 255, 255, 255, 255}), "Encode -130 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-131)), {255, 125, 255, 255, 255, 255, 255, 255, 255}), "Encode -131 fail");
|
||||
|
||||
oxAssert(check(encodeInteger(uint32_t(0xffffffff)), {0b11101111, 255, 255, 255, 0b00011111}), "Encode 0xffffffff fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(1)), {0b0010}), "Encode 1 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(2)), {0b0100}), "Encode 2 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(3)), {0b0110}), "Encode 3 fail");
|
||||
@ -200,6 +201,37 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"decodeInteger",
|
||||
[] {
|
||||
using ox::MaxValue;
|
||||
using ox::mc::McInt;
|
||||
using ox::mc::encodeInteger;
|
||||
using ox::mc::decodeInteger;
|
||||
|
||||
constexpr auto check = [](auto val) {
|
||||
auto result = decodeInteger<decltype(val)>(encodeInteger(val));
|
||||
oxReturnError(result.error);
|
||||
if (result.value != val) {
|
||||
std::cout << "Bad value: " << result.value << ", expected: " << val << '\n';
|
||||
}
|
||||
return OxError(result.value != val);
|
||||
};
|
||||
oxAssert(check(int64_t(1)), "Decode of 1 failed.");
|
||||
oxAssert(check(int64_t(2)), "Decode of 2 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(130)), "Decode of 130 failed.");
|
||||
oxAssert(check(uint64_t(131)), "Decode of 131 failed.");
|
||||
oxAssert(check(0xffffffff), "Decode of 0xffffffff failed.");
|
||||
oxAssert(check(0xffffffffffff), "Decode of 0xffffffffffff failed.");
|
||||
oxAssert(check(0xffffffffffffffff), "Decode of U64 max failed.");
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"MetalClawDef",
|
||||
[] {
|
||||
|
Loading…
x
Reference in New Issue
Block a user