Skip to content

Commit

Permalink
Merge pull request #9 from KredeGC/dev
Browse files Browse the repository at this point in the history
Constexpr and CRC correctness
  • Loading branch information
KredeGC authored Apr 22, 2023
2 parents ed26f51 + 6f389f7 commit 6eeae1a
Show file tree
Hide file tree
Showing 17 changed files with 142 additions and 108 deletions.
34 changes: 27 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ bool status_read = reader.serialize<bool>(out_value);
## Bounded integers - T
A trait that covers all signed and unsigned integers.<br/>
Takes the integer by reference and a lower and upper bound.<br/>
The upper and lower bounds will default to T's upper and lower bound if left unspecified, effectively making the object unbounded.
The upper and lower bounds will default to T's upper and lower bounds if left unspecified, effectively making the object unbounded.

The call signature can be seen below:
```cpp
Expand All @@ -115,7 +115,8 @@ bool status_read = reader.serialize<int16_t>(out_value, -512, 2098);
## Compile-time bounded integers - bounded_int\<T, T Min, T Max\>
A trait that covers all signed and unsigned integers within a `bounded_int` wrapper.<br/>
Takes the integer by reference and a lower and upper bound as template parameters.<br/>
This is preferable if you know the bounds at compile time as it skips having to calculate the number of bits required.
This is preferable if you know the bounds at compile time as it skips having to calculate the number of bits required.<br/>
The upper and lower bounds will default to T's upper and lower bounds if left unspecified, effectively making the object unbounded.

The call signature can be seen below:
```cpp
Expand Down Expand Up @@ -163,6 +164,22 @@ bool status_write = writer.serialize<std::string>(in_value, 32);
bool status_read = reader.serialize<std::string>(out_value, 32);
```

## Double-precision float - double
A trait that covers an entire double, with no quantization.<br/>
Takes a reference to the double.

The call signature can be seen below:
```cpp
bool serialize<double>(double& value);
```
As well as a short example of its usage:
```cpp
double in_value = 0.12345678652;
double out_value;
bool status_write = writer.serialize<double>(in_value);
bool status_read = reader.serialize<double>(out_value);
```

## Single-precision float - float
A trait that covers an entire float, with no quantization.<br/>
Takes a reference to the float.
Expand Down Expand Up @@ -256,7 +273,7 @@ writer.serialize_bits(value, 5);
// Flush the writer's remaining state into the buffer
uint32_t num_bits = writer.flush();
// Create a reader, referencing the buffer and bytes written
// Create a reader, referencing the buffer and bits written
bit_reader reader(buffer, num_bits);
// Read the value back
Expand All @@ -277,7 +294,7 @@ writer.serialize<int32_t>(value, -90, 40); // A lower and upper bound which the
// Flush the writer's remaining state into the buffer
uint32_t num_bits = writer.flush();

// Create a reader by moving and invalidating the writer
// Create a reader, referencing the buffer and bits written
bit_reader reader(buffer, num_bits);

// Read the value back
Expand All @@ -298,7 +315,7 @@ writer.serialize<const char*>(value, 32U); // The second argument is the maximum
// Flush the writer's remaining state into the buffer
uint32_t num_bits = writer.flush();
// Create a reader by moving and invalidating the writer
// Create a reader, referencing the buffer and bits written
bit_reader reader(buffer, num_bits);
// Read the value back
Expand All @@ -319,7 +336,7 @@ writer.serialize<std::string>(value, 32U); // The second argument is the maximum
// Flush the writer's remaining state into the buffer
uint32_t num_bits = writer.flush();

// Create a reader by moving and invalidating the writer
// Create a reader, referencing the buffer and bits written
bit_reader reader(buffer, num_bits);

// Read the value back
Expand All @@ -341,7 +358,7 @@ writer.serialize<bounded_range>(range, value);
// Flush the writer's remaining state into the buffer
uint32_t num_bits = writer.flush();
// Create a reader by moving and invalidating the writer
// Create a reader, referencing the buffer and bits written
bit_reader reader(buffer, num_bits);
// Read the value back
Expand Down Expand Up @@ -374,6 +391,9 @@ struct serialize_traits<TRAIT_TYPE> // The type to use when referencing this spe
};
```
As with any functions, you are free to overload them if you want to serialize an object differently, depending on any parameters you pass.
As long as their list of parameters starts with `bit_writer&` and `bit_reader&` respectively they will be able to be called.
## Unified serialization
The serialization can also be unified with templating, if writing and reading look similar.
If some parts of the serialization process don't match entirely you can query the `Stream::reading` or `Stream::writing` and branch depending on the value.
Expand Down
33 changes: 18 additions & 15 deletions include/bitstream/quantization/bounded_range.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,26 @@ namespace bitstream
class bounded_range
{
public:
bounded_range() = default;
constexpr bounded_range() noexcept :
m_Min(0),
m_Max(0),
m_Precision(0),
m_BitsRequired(0),
m_Mask(0) {}

bounded_range(float min, float max, float precision) :
constexpr bounded_range(float min, float max, float precision) noexcept :
m_Min(min),
m_Max(max),
m_Precision(precision)
{
m_BitsRequired = log2(static_cast<uint32_t>((m_Max - m_Min) * (1.0f / precision) + 0.5f)) + 1;
m_Mask = (1 << m_BitsRequired) - 1;
}
m_Precision(precision),
m_BitsRequired(log2(static_cast<uint32_t>((m_Max - m_Min) * (1.0f / precision) + 0.5f)) + 1),
m_Mask((1U << m_BitsRequired) - 1U) {}

inline float get_min() const { return m_Min; }
inline float get_max() const { return m_Max; }
inline float get_precision() const { return m_Precision; }
inline uint32_t get_bits_required() const { return m_BitsRequired; }
constexpr inline float get_min() const noexcept { return m_Min; }
constexpr inline float get_max() const noexcept { return m_Max; }
constexpr inline float get_precision() const noexcept { return m_Precision; }
constexpr inline uint32_t get_bits_required() const noexcept { return m_BitsRequired; }

inline uint32_t quantize(float value) const
constexpr inline uint32_t quantize(float value) const noexcept
{
if (value < m_Min)
value = m_Min;
Expand All @@ -58,7 +61,7 @@ namespace bitstream
return static_cast<uint32_t>(static_cast<float>((value - m_Min) * (1.0f / m_Precision)) + 0.5f) & m_Mask;
}

inline float dequantize(uint32_t data) const
constexpr inline float dequantize(uint32_t data) const noexcept
{
float adjusted = (static_cast<float>(data) * m_Precision) + m_Min;

Expand All @@ -71,7 +74,7 @@ namespace bitstream
}

private:
inline static constexpr uint32_t log2(uint32_t value)
constexpr inline static uint32_t log2(uint32_t value) noexcept
{
value |= value >> 1;
value |= value >> 2;
Expand All @@ -90,7 +93,7 @@ namespace bitstream
uint32_t m_BitsRequired;
uint32_t m_Mask;

inline static constexpr uint32_t DE_BRUIJN[32]
constexpr inline static uint32_t DE_BRUIJN[32]
{
0, 9, 1, 10, 13, 21, 2, 29,
11, 14, 16, 18, 22, 25, 3, 30,
Expand Down
24 changes: 12 additions & 12 deletions include/bitstream/quantization/half_precision.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace bitstream
class half_precision
{
public:
inline static uint16_t quantize(float value)
inline static uint16_t quantize(float value) noexcept
{
int32_t tmp;
std::memcpy(&tmp, &value, sizeof(float));
Expand All @@ -44,7 +44,7 @@ namespace bitstream

if (e <= 0) {
if (e < -10)
return (uint16_t)s;
return static_cast<uint16_t>(s);

m |= 0x00800000;

Expand All @@ -54,16 +54,16 @@ namespace bitstream

m = (m + a + b) >> t;

return (uint16_t)(s | m);
return static_cast<uint16_t>(s | m);
}

if (e == 0XFF - (127 - 15)) {
if (m == 0)
return (uint16_t)(s | 0X7C00);
return static_cast<uint16_t>(s | 0X7C00);

m >>= 13;

return (uint16_t)(s | 0X7C00 | m | ((m == 0) ? 1 : 0));
return static_cast<uint16_t>(s | 0X7C00 | m | ((m == 0) ? 1 : 0));
}

m = m + 0X00000FFF + ((m >> 13) & 1);
Expand All @@ -74,15 +74,15 @@ namespace bitstream
}

if (e > 30)
return (uint16_t)(s | 0X7C00);
return static_cast<uint16_t>(s | 0X7C00);

return (uint16_t)(s | (e << 10) | (m >> 13));
return static_cast<uint16_t>(s | (e << 10) | (m >> 13));
}

inline static float dequantize(uint16_t value)
inline static float dequantize(uint16_t value) noexcept
{
uint32_t tmp;
uint32_t mantissa = (uint32_t)(value & 1023);
uint32_t mantissa = static_cast<uint32_t>(value & 1023);
uint32_t exponent = 0XFFFFFFF2;

if ((value & -33792) == 0) {
Expand All @@ -93,16 +93,16 @@ namespace bitstream
}

mantissa &= 0XFFFFFBFF;
tmp = (((uint32_t)value & 0x8000) << 16) | ((exponent + 127) << 23) | (mantissa << 13);
tmp = ((static_cast<uint32_t>(value) & 0x8000) << 16) | ((exponent + 127) << 23) | (mantissa << 13);
}
else
{
tmp = (uint32_t)((value & 0x8000) << 16);
tmp = static_cast<uint32_t>((value & 0x8000) << 16);
}
}
else
{
tmp = ((((uint32_t)value & 0x8000) << 16) | ((((((uint32_t)value >> 10) & 0X1F) - 15) + 127) << 23)) | (mantissa << 13);
tmp = ((static_cast<uint32_t>(value) & 0x8000) << 16) | (((((static_cast<uint32_t>(value) >> 10) & 0X1F) - 15) + 127) << 23) | (mantissa << 13);
}

float result;
Expand Down
36 changes: 20 additions & 16 deletions include/bitstream/quantization/smallest_three.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ namespace bitstream
uint32_t b;
uint32_t c;

quantized_quaternion() = default;

quantized_quaternion(uint32_t m, uint32_t a, uint32_t b, uint32_t c)
: m(m), a(a), b(b), c(c) {}
constexpr quantized_quaternion() noexcept :
m(0),
a(0),
b(0),
c(0) {}

constexpr quantized_quaternion(uint32_t w, uint32_t x, uint32_t y, uint32_t z) noexcept :
m(w), a(x), b(y), c(z) {}
};

/**
Expand All @@ -55,7 +59,7 @@ namespace bitstream
static constexpr float SMALLEST_THREE_PACK = 1.0f / SMALLEST_THREE_UNPACK;

public:
inline static quantized_quaternion quantize(const T& quaternion)
inline static quantized_quaternion quantize(const T& quaternion) noexcept
{
constexpr float half_range = static_cast<float>(1 << (BitsPerElement - 1));
constexpr float packer = SMALLEST_THREE_PACK * half_range;
Expand All @@ -71,7 +75,7 @@ namespace bitstream
{
float element = quaternion[i];

float abs = std::abs(element);
float abs = element > 0.0f ? element : -element;

if (abs > max_value)
{
Expand Down Expand Up @@ -111,28 +115,28 @@ namespace bitstream

if (sign_minus)
{
a = (uint32_t)((-af * packer) + half_range);
b = (uint32_t)((-bf * packer) + half_range);
c = (uint32_t)((-cf * packer) + half_range);
a = static_cast<uint32_t>((-af * packer) + half_range);
b = static_cast<uint32_t>((-bf * packer) + half_range);
c = static_cast<uint32_t>((-cf * packer) + half_range);
}
else
{
a = (uint32_t)((af * packer) + half_range);
b = (uint32_t)((bf * packer) + half_range);
c = (uint32_t)((cf * packer) + half_range);
a = static_cast<uint32_t>((af * packer) + half_range);
b = static_cast<uint32_t>((bf * packer) + half_range);
c = static_cast<uint32_t>((cf * packer) + half_range);
}

return { m, a, b, c };
}

inline static T dequantize(const quantized_quaternion& data)
inline static T dequantize(const quantized_quaternion& data) noexcept
{
constexpr uint32_t half_range = (1 << (BitsPerElement - 1));
constexpr float unpacker = SMALLEST_THREE_UNPACK * (1.0f / half_range);

float a = data.a * unpacker - half_range * unpacker;
float b = data.b * unpacker - half_range * unpacker;
float c = data.c * unpacker - half_range * unpacker;
float a = static_cast<float>(data.a * unpacker - half_range * unpacker);
float b = static_cast<float>(data.b * unpacker - half_range * unpacker);
float c = static_cast<float>(data.c * unpacker - half_range * unpacker);

float d = std::sqrt(1.0f - ((a * a) + (b * b) + (c * c)));

Expand Down
Loading

0 comments on commit 6eeae1a

Please sign in to comment.