[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;
|
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\\ Writer" McTest MetalClawWriter)
|
||||||
add_test("Test\\ McTest\\ Reader" McTest MetalClawReader)
|
add_test("Test\\ McTest\\ Reader" McTest MetalClawReader)
|
||||||
add_test("Test\\ McTest\\ encodeInteger" McTest encodeInteger)
|
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(-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(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(1)), {0b0010}), "Encode 1 fail");
|
||||||
oxAssert(check(encodeInteger(uint64_t(2)), {0b0100}), "Encode 2 fail");
|
oxAssert(check(encodeInteger(uint64_t(2)), {0b0100}), "Encode 2 fail");
|
||||||
oxAssert(check(encodeInteger(uint64_t(3)), {0b0110}), "Encode 3 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);
|
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",
|
"MetalClawDef",
|
||||||
[] {
|
[] {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user