[ox] Fix MC negative int encoding and bump MC version to 2
This commit is contained in:
parent
bd2dd3f000
commit
6cebe52904
2
deps/ox/src/ox/claw/read.cpp
vendored
2
deps/ox/src/ox/claw/read.cpp
vendored
@ -41,7 +41,7 @@ Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcep
|
||||
buffLen -= s3Size + 1;
|
||||
|
||||
ClawHeader hdr;
|
||||
if (fmt == "M1") {
|
||||
if (fmt == "M2") {
|
||||
hdr.fmt = ClawFormat::Metal;
|
||||
} else if (fmt == "O1") {
|
||||
hdr.fmt = ClawFormat::Organic;
|
||||
|
1
deps/ox/src/ox/claw/read.hpp
vendored
1
deps/ox/src/ox/claw/read.hpp
vendored
@ -45,7 +45,6 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) {
|
||||
return OxError(Error_ClawTypeMismatch, "Claw Read: Type mismatch");
|
||||
}
|
||||
if (header.typeVersion != getModelTypeVersion<T>()) {
|
||||
oxDebugf("version: {}, {}", header.typeVersion, getModelTypeVersion<T>());
|
||||
return OxError(Error_ClawTypeVersionMismatch, "Claw Read: Type Version mismatch");
|
||||
}
|
||||
switch (header.fmt) {
|
||||
|
2
deps/ox/src/ox/claw/test/tests.cpp
vendored
2
deps/ox/src/ox/claw/test/tests.cpp
vendored
@ -116,7 +116,7 @@ std::map<std::string_view, ox::Error(*)()> tests = {
|
||||
{
|
||||
"ClawHeaderReader2",
|
||||
[] {
|
||||
ox::String hdr = "M1;com.drinkingtea.ox.claw.test.Header2;3;";
|
||||
ox::String hdr = "M2;com.drinkingtea.ox.claw.test.Header2;3;";
|
||||
auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1);
|
||||
oxAssert(err, "Error parsing header");
|
||||
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
|
||||
|
2
deps/ox/src/ox/claw/write.hpp
vendored
2
deps/ox/src/ox/claw/write.hpp
vendored
@ -62,7 +62,7 @@ Result<String> writeClawHeader(T *t, ClawFormat fmt) noexcept {
|
||||
String out;
|
||||
switch (fmt) {
|
||||
case ClawFormat::Metal:
|
||||
out += "M1;";
|
||||
out += "M2;";
|
||||
break;
|
||||
case ClawFormat::Organic:
|
||||
out += "O1;";
|
||||
|
6
deps/ox/src/ox/event/signal.cpp
vendored
6
deps/ox/src/ox/event/signal.cpp
vendored
@ -20,3 +20,9 @@ SignalHandler::~SignalHandler() noexcept {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. ProjectExplorer::fileOpened cannot notify StudioUI that it is being destroyed.
|
||||
* 2. StudioUI tries to unsubscribe from ProjectExplorer::fileOpened upon its destruction.
|
||||
* 3. Segfault
|
||||
*/
|
||||
|
24
deps/ox/src/ox/event/signal.hpp
vendored
24
deps/ox/src/ox/event/signal.hpp
vendored
@ -8,6 +8,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/assert.hpp>
|
||||
#include <ox/std/def.hpp>
|
||||
#include <ox/std/defines.hpp>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/memory.hpp>
|
||||
@ -36,10 +38,6 @@ struct isError<Error> {
|
||||
|
||||
template<class... Args>
|
||||
class Signal {
|
||||
private:
|
||||
template<typename T>
|
||||
static constexpr void ignoreValue(const T&) {}
|
||||
|
||||
protected:
|
||||
struct BaseSlot {
|
||||
virtual ~BaseSlot() = default;
|
||||
@ -85,7 +83,10 @@ class Signal {
|
||||
}
|
||||
|
||||
void cleanup(Signal *signal) noexcept final {
|
||||
oxIgnoreError(m_receiver->destruction.disconnectSignal(signal));
|
||||
auto err = m_receiver->destruction.disconnectSignal(signal);
|
||||
if (err) {
|
||||
oxErrorf("Signal could not notify receiver that it is being destroyed. Destruction of receiver will cause use-after-free. ({})", toStr(err));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
@ -196,7 +197,7 @@ Error Signal<Args...>::disconnectObject(const void *receiver) const noexcept {
|
||||
--i;
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
return OxError(1, "Signal::disconnectObject: Receiver was not found among this Signal's slots");
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
@ -263,7 +264,9 @@ class Signal<Error(Args...)> {
|
||||
}
|
||||
|
||||
void cleanup(Signal *signal) noexcept final {
|
||||
oxIgnoreError(m_receiver->destruction.disconnectSignal(signal));
|
||||
auto err = m_receiver->destruction.disconnectSignal(signal);
|
||||
oxErrorf("{}", toStr(err));
|
||||
//oxAssert(err, "Signal could not notify receiver that it is being destroyed. Destruction of receiver will cause use-after-free.");
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
@ -327,6 +330,11 @@ class SignalHandler {
|
||||
public:
|
||||
Signal<Error(const SignalHandler*)> destruction;
|
||||
|
||||
constexpr SignalHandler() noexcept = default;
|
||||
SignalHandler(const SignalHandler&) = delete;
|
||||
SignalHandler(SignalHandler&) = delete;
|
||||
SignalHandler(SignalHandler&&) = delete;
|
||||
|
||||
virtual ~SignalHandler() noexcept;
|
||||
};
|
||||
|
||||
@ -377,7 +385,7 @@ Error Signal<Error(Args...)>::disconnectObject(const void *receiver) const noexc
|
||||
--i;
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
return OxError(1, "Signal::disconnectObject: Receiver was not found among this Signal's slots");
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
|
77
deps/ox/src/ox/mc/intops.hpp
vendored
77
deps/ox/src/ox/mc/intops.hpp
vendored
@ -11,6 +11,7 @@
|
||||
#include <ox/std/assert.hpp>
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/math.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
|
||||
namespace ox::mc {
|
||||
@ -43,6 +44,9 @@ constexpr std::size_t highestBit(I val) noexcept {
|
||||
}
|
||||
|
||||
static_assert(highestBit(int8_t(0b10000000)) == 0);
|
||||
static_assert(highestBit(~static_cast<int8_t>(-1)) == 0);
|
||||
static_assert(highestBit(~static_cast<int8_t>(-2)) == 0);
|
||||
static_assert(highestBit(~static_cast<int8_t>(-3)) == 1);
|
||||
static_assert(highestBit(1) == 0);
|
||||
static_assert(highestBit(2) == 1);
|
||||
static_assert(highestBit(4) == 2);
|
||||
@ -60,6 +64,7 @@ template<typename I>
|
||||
[[nodiscard]]
|
||||
constexpr McInt encodeInteger(I input) noexcept {
|
||||
McInt out;
|
||||
auto inputNegative = is_signed_v<I> && input < 0;
|
||||
// move input to uint64_t to allow consistent bit manipulation, and to avoid
|
||||
// overflow concerns
|
||||
uint64_t val = 0;
|
||||
@ -67,26 +72,35 @@ constexpr McInt encodeInteger(I input) noexcept {
|
||||
if (val) {
|
||||
// bits needed to represent number factoring in space possibly
|
||||
// needed for signed bit
|
||||
const auto bits = highestBit(val) + 1 + (is_signed_v<I> ? 1 : 0);
|
||||
const auto highBit = inputNegative ? (highestBit(~val)) : highestBit(val);
|
||||
const auto bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
|
||||
// bytes needed to store value
|
||||
std::size_t bytes = bits / 8 + (bits % 8 != 0);
|
||||
const auto bitsAvailable = bytes * 8; // bits available to integer value
|
||||
const auto bitsNeeded = bits + bytes;
|
||||
// factor in bits needed for bytesIndicator (does not affect bytesIndicator)
|
||||
// bits for integer + bits neded to represent bytes > bits available
|
||||
// bits for integer + bits needed to represent bytes > bits available
|
||||
if (bitsNeeded > bitsAvailable && bytes != 9) {
|
||||
++bytes;
|
||||
}
|
||||
const auto bytesIndicator = onMask<uint8_t>(bytes - 1);
|
||||
|
||||
// ensure we are copying from little endian represenstation
|
||||
LittleEndian<I> leVal = static_cast<I>(val);
|
||||
// ensure we are copying from little endian representation
|
||||
LittleEndian<uint64_t> leVal = val;
|
||||
if (inputNegative) {
|
||||
leVal |= static_cast<uint64_t>(1 << (bitsNeeded - 1));
|
||||
}
|
||||
if (bytes == 9) {
|
||||
out.data[0] = bytesIndicator;
|
||||
ox_memcpy(&out.data[1], &leVal, sizeof(I));
|
||||
if (inputNegative) {
|
||||
out.data[1] |= 0b1000'0000;
|
||||
}
|
||||
} else {
|
||||
const auto valBits = bytes * 8;
|
||||
uint64_t negBit = inputNegative ? 1 : 0;
|
||||
auto intermediate =
|
||||
static_cast<uint64_t>(leVal.raw()) << bytes |
|
||||
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
|
||||
static_cast<uint64_t>(bytesIndicator);
|
||||
ox_memcpy(out.data, &intermediate, sizeof(intermediate));
|
||||
}
|
||||
@ -106,15 +120,15 @@ static constexpr std::size_t countBytes(uint8_t b) noexcept {
|
||||
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);
|
||||
static_assert(countBytes(0b0000'0000) == 1);
|
||||
static_assert(countBytes(0b0000'0001) == 2);
|
||||
static_assert(countBytes(0b0000'0011) == 3);
|
||||
static_assert(countBytes(0b0000'0111) == 4);
|
||||
static_assert(countBytes(0b0000'1111) == 5);
|
||||
static_assert(countBytes(0b0001'1111) == 6);
|
||||
static_assert(countBytes(0b0011'1111) == 7);
|
||||
static_assert(countBytes(0b0111'1111) == 8);
|
||||
static_assert(countBytes(0b1111'1111) == 9);
|
||||
|
||||
template<typename I>
|
||||
Result<I> decodeInteger(const uint8_t buff[9], std::size_t buffLen, std::size_t *bytesRead) noexcept {
|
||||
@ -122,26 +136,37 @@ Result<I> decodeInteger(const uint8_t buff[9], std::size_t buffLen, std::size_t
|
||||
if (bytes == 9) {
|
||||
*bytesRead = bytes;
|
||||
I out = 0;
|
||||
memcpy(&out, &buff[1], sizeof(I));
|
||||
ox_memcpy(&out, &buff[1], sizeof(I));
|
||||
return static_cast<I>(LittleEndian<I>(out));
|
||||
} else if (buffLen >= bytes) {
|
||||
*bytesRead = bytes;
|
||||
uint64_t decoded = 0;
|
||||
memcpy(&decoded, &buff[0], bytes);
|
||||
ox_memcpy(&decoded, &buff[0], bytes);
|
||||
decoded >>= bytes;
|
||||
auto out = static_cast<I>(decoded);
|
||||
// move sign bit
|
||||
if constexpr(is_signed_v<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
|
||||
decoded |= sign << (Bits<I> - 1);
|
||||
memcpy(&out, &decoded, sizeof(out));
|
||||
const auto negBit = bytes * 8 - bytes - 1;
|
||||
// move sign
|
||||
const auto negative = (decoded >> negBit) == 1;
|
||||
if (negative) {
|
||||
// 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
|
||||
uint32_t *d = reinterpret_cast<uint32_t*>(&decoded);
|
||||
auto bit = negBit;
|
||||
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) {
|
||||
d[0] |= 1 << bit;
|
||||
}
|
||||
for (; bit < Bits<I>; ++bit) {
|
||||
d[1] |= 1 << bit;
|
||||
}
|
||||
}
|
||||
I out = 0;
|
||||
ox_memcpy(&out, &decoded, sizeof(out));
|
||||
return out;
|
||||
} else {
|
||||
auto out = static_cast<I>(decoded);
|
||||
return out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
38
deps/ox/src/ox/mc/test/tests.cpp
vendored
38
deps/ox/src/ox/mc/test/tests.cpp
vendored
@ -196,23 +196,23 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
return OxError(0);
|
||||
};
|
||||
|
||||
oxAssert(check(encodeInteger(int64_t(1)), {0b00000010}), "Encode 1 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(2)), {0b00000100}), "Encode 2 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(3)), {0b00000110}), "Encode 3 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(4)), {0b00001000}), "Encode 4 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(128)), {0b00000001, 0b10}), "Encode 128 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(129)), {0b00000101, 0b10}), "Encode 129 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(130)), {0b00001001, 0b10}), "Encode 130 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(131)), {0b00001101, 0b10}), "Encode 131 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(1)), {0b000'0001'0}), "Encode 1 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(2)), {0b000'0010'0}), "Encode 2 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(3)), {0b000'0011'0}), "Encode 3 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(4)), {0b000'0100'0}), "Encode 4 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(128)), {0b00'0000'01, 0b10}), "Encode 128 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(129)), {0b00'0001'01, 0b10}), "Encode 129 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(130)), {0b00'0010'01, 0b10}), "Encode 130 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(131)), {0b00'0011'01, 0b10}), "Encode 131 fail");
|
||||
|
||||
oxAssert(check(encodeInteger(int64_t(-1)), {255, 255, 255, 255, 255, 255, 255, 255, 255}), "Encode -1 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-2)), {255, 254, 255, 255, 255, 255, 255, 255, 255}), "Encode -2 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-3)), {255, 253, 255, 255, 255, 255, 255, 255, 255}), "Encode -3 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-4)), {255, 252, 255, 255, 255, 255, 255, 255, 255}), "Encode -4 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-128)), {255, 128, 255, 255, 255, 255, 255, 255, 255}), "Encode -128 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-129)), {255, 127, 255, 255, 255, 255, 255, 255, 255}), "Encode -129 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(-1)), {0b111'1111'0}), "Encode -1 fail");
|
||||
oxAssert(check(encodeInteger( int64_t(-2)), {0b111'1110'0}), "Encode -2 fail");
|
||||
oxAssert(check(encodeInteger( int64_t(-3)), {0b111'1101'0}), "Encode -3 fail");
|
||||
oxAssert(check(encodeInteger( int64_t(-4)), {0b111'1100'0}), "Encode -4 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-128)), {0b00'0000'01, 0b11'1111'10}), "Encode -128 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-129)), {0b11'1111'01, 0b11'1111'01}), "Encode -129 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-130)), {0b11'1110'01, 0b11'1111'01}), "Encode -130 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-131)), {0b11'1101'01, 0b11'1111'01}), "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");
|
||||
@ -250,11 +250,17 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
};
|
||||
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(-127)), "Decode of -127 failed.");
|
||||
oxAssert(check(int64_t(-128)), "Decode of -128 failed.");
|
||||
oxAssert(check(int64_t(-129)), "Decode of -129 failed.");
|
||||
oxAssert(check(int64_t(-129000)), "Decode of -129000 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(int64_t(131000)), "Decode of 131000 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.");
|
||||
|
42
deps/ox/src/ox/std/memops.hpp
vendored
42
deps/ox/src/ox/std/memops.hpp
vendored
@ -8,7 +8,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "types.hpp"
|
||||
#include "typetraits.hpp"
|
||||
|
||||
#if __has_include(<cstring>)
|
||||
#include<cstring>
|
||||
@ -27,29 +29,41 @@ void *memset(void *ptr, int val, std::size_t size);
|
||||
int ox_memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept;
|
||||
|
||||
constexpr void *ox_memcpy(void *dest, const void *src, std::size_t size) noexcept {
|
||||
auto srcBuf = static_cast<const char*>(src);
|
||||
auto dstBuf = static_cast<char*>(dest);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
dstBuf[i] = static_cast<char>(srcBuf[i]);
|
||||
if (std::is_constant_evaluated() || !ox::defines::UseStdLib) {
|
||||
auto srcBuf = static_cast<const char *>(src);
|
||||
auto dstBuf = static_cast<char *>(dest);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
dstBuf[i] = static_cast<char>(srcBuf[i]);
|
||||
}
|
||||
return dest;
|
||||
} else {
|
||||
return memcpy(dest, src, size);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
constexpr void *ox_memmove(void *dest, const void *src, std::size_t size) noexcept {
|
||||
auto srcBuf = static_cast<const char*>(src);
|
||||
auto dstBuf = static_cast<char*>(dest);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
dstBuf[i] = static_cast<char>(srcBuf[i]);
|
||||
if (std::is_constant_evaluated() || !ox::defines::UseStdLib) {
|
||||
auto srcBuf = static_cast<const char *>(src);
|
||||
auto dstBuf = static_cast<char *>(dest);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
dstBuf[i] = static_cast<char>(srcBuf[i]);
|
||||
}
|
||||
return dest;
|
||||
} else {
|
||||
return memmove(dest, src, size);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
constexpr void *ox_memset(void *ptr, int val, std::size_t size) noexcept {
|
||||
auto buf = static_cast<uint8_t*>(ptr);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
buf[i] = static_cast<uint8_t>(val);
|
||||
if (std::is_constant_evaluated() || !ox::defines::UseStdLib) {
|
||||
auto buf = static_cast<uint8_t *>(ptr);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
buf[i] = static_cast<uint8_t>(val);
|
||||
}
|
||||
return ptr;
|
||||
} else {
|
||||
return memset(ptr, val, size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
namespace ox {
|
||||
|
Loading…
Reference in New Issue
Block a user