Skip to content

Commit 397fb80

Browse files
committed
Add multi function with deduced serialize trait
Add likely and unlikely Add stream_writing_t and stream_reading_t
1 parent 4cf8d2e commit 397fb80

File tree

17 files changed

+252
-86
lines changed

17 files changed

+252
-86
lines changed

include/bitstream/bitstream.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#pragma once
22

3+
// Possible defines
4+
// #define BS_DEBUG_BREAK // Stops execution when serialization fails (debug break, trap etc.)
5+
// #define BS_EQUAL_PATH // Stops optimization of the happy path
6+
37
// Quantization
48
#include "quantization/bounded_range.h"
59
#include "quantization/half_precision.h"
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#pragma once
2+
#include "../utility/meta.h"
3+
4+
#include "multi.h"
5+
#include "serialize_traits.h"
6+
#include "stream_traits.h"
7+
8+
#include <cstdint>
9+
#include <cstring>
10+
#include <type_traits>
11+
12+
namespace bitstream
13+
{
14+
/**
15+
* @brief A noop stream
16+
*/
17+
class bit_noop
18+
{
19+
public:
20+
static constexpr bool writing = true;
21+
static constexpr bool reading = false;
22+
23+
/**
24+
* @brief Returns the buffer that this reader is currently serializing from
25+
* @return The buffer
26+
*/
27+
[[nodiscard]] const uint8_t* get_buffer() const noexcept { return nullptr; }
28+
29+
/**
30+
* @brief Returns the number of bits which have been read from the buffer
31+
* @return The number of bits which have been read
32+
*/
33+
[[nodiscard]] uint32_t get_num_bits_serialized() const noexcept { return 0; }
34+
35+
/**
36+
* @brief Returns the number of bytes which have been read from the buffer
37+
* @return The number of bytes which have been read
38+
*/
39+
[[nodiscard]] uint32_t get_num_bytes_serialized() const noexcept { return 0; }
40+
41+
/**
42+
* @brief Returns whether the @p num_bits be read from the buffer
43+
* @param num_bits The number of bits to test
44+
* @return Whether the number of bits can be read from the buffer
45+
*/
46+
[[nodiscard]] bool can_serialize_bits(uint32_t num_bits) const noexcept { return false; }
47+
48+
/**
49+
* @brief Returns the number of bits which have not been read yet
50+
* @note The same as get_total_bits() - get_num_bits_serialized()
51+
* @return The remaining space in the buffer
52+
*/
53+
[[nodiscard]] uint32_t get_remaining_bits() const noexcept { return 0; }
54+
55+
/**
56+
* @brief Returns the size of the buffer, in bits
57+
* @return The size of the buffer, in bits
58+
*/
59+
[[nodiscard]] uint32_t get_total_bits() const noexcept { return 0; }
60+
61+
/**
62+
* @brief Pads the buffer up to the given number of bytes
63+
* @param num_bytes The byte number to pad to
64+
* @return Returns false if the current size of the buffer is bigger than @p num_bytes or if the padded bits are not zeros.
65+
*/
66+
[[nodiscard]] bool pad_to_size(uint32_t num_bytes) noexcept { return false; }
67+
68+
/**
69+
* @brief Pads the buffer up with the given number of bytes
70+
* @param num_bytes The amount of bytes to pad
71+
* @return Returns false if the current size of the buffer is bigger than @p num_bytes or if the padded bits are not zeros.
72+
*/
73+
[[nodiscard]] bool pad(uint32_t num_bytes) noexcept { return false; }
74+
75+
/**
76+
* @brief Pads the buffer with up to 8 zeros, so that the next read is byte-aligned
77+
* @notes Return false if the padded bits are not zeros
78+
* @return Returns false if the padded bits are not zeros
79+
*/
80+
[[nodiscard]] bool align() noexcept { return false; }
81+
82+
/**
83+
* @brief Reads the first @p num_bits bits of @p value from the buffer
84+
* @param value The value to serialize
85+
* @param num_bits The number of bits of the @p value to serialize
86+
* @return Returns false if @p num_bits is less than 1 or greater than 32 or if reading the given number of bits would overflow the buffer
87+
*/
88+
[[nodiscard]] bool serialize_bits(uint32_t& value, uint32_t num_bits) noexcept { return false; }
89+
90+
/**
91+
* @brief Reads the first @p num_bits bits of the given byte array, 32 bits at a time
92+
* @param bytes The bytes to serialize
93+
* @param num_bits The number of bits of the @p bytes to serialize
94+
* @return Returns false if @p num_bits is less than 1 or if reading the given number of bits would overflow the buffer
95+
*/
96+
[[nodiscard]] bool serialize_bytes(uint8_t* bytes, uint32_t num_bits) noexcept { return false; }
97+
98+
/**
99+
* @brief Reads from the buffer into mulitple variables.
100+
* @note Pass multi<T>(...) to this in place of multiple calls to the regular serialize functions.
101+
* @tparam ...Args The types of the arguments to pass to the serialize function
102+
* @param ...args The arguments to pass to the serialize function
103+
* @return Whether successful or not
104+
*/
105+
template<typename... Args, typename = std::enable_if_t<(utility::has_instance_serialize_v<Args, bit_noop> && ...)>>
106+
[[nodiscard]] bool serialize(Args&&... args)
107+
noexcept((noexcept(std::declval<Args&>().serialize(std::declval<bit_noop&>())) && ...))
108+
{
109+
return (std::forward<Args>(args).serialize(*this) && ...);
110+
}
111+
112+
/**
113+
* @brief Reads from the buffer, using the given @p Trait.
114+
* @note The Trait type in this function must always be explicitly declared
115+
* @tparam Trait A template specialization of serialize_trait<>
116+
* @tparam ...Args The types of the arguments to pass to the serialize function
117+
* @param ...args The arguments to pass to the serialize function
118+
* @return Whether successful or not
119+
*/
120+
template<typename Trait, typename... Args, typename = utility::has_serialize_t<Trait, bit_noop, Args...>>
121+
[[nodiscard]] bool serialize(Args&&... args) noexcept(utility::is_serialize_noexcept_v<Trait, bit_noop, Args...>)
122+
{
123+
return serialize_traits<Trait>::serialize(*this, std::forward<Args>(args)...);
124+
}
125+
126+
/**
127+
* @brief Reads from the buffer, by trying to deduce the trait.
128+
* @note The Trait type in this function is always implicit and will be deduced from the first argument if possible.
129+
* If the trait cannot be deduced it will not compile.
130+
* @tparam Trait The type of the first argument, which will be used to deduce the trait specialization
131+
* @tparam ...Args The types of the arguments to pass to the serialize function
132+
* @param arg The first argument to pass to the serialize function
133+
* @param ...args The rest of the arguments to pass to the serialize function
134+
* @return Whether successful or not
135+
*/
136+
template<typename... Args, typename Trait, typename = utility::has_deduce_serialize_t<Trait, bit_noop, Args...>>
137+
[[nodiscard]] bool serialize(Trait&& arg, Args&&... args) noexcept(utility::is_deduce_serialize_noexcept_v<Trait, bit_noop, Args...>)
138+
{
139+
return serialize_traits<utility::deduce_trait_t<Trait, bit_noop, Args...>>::serialize(*this, std::forward<Trait>(arg), std::forward<Args>(args)...);
140+
}
141+
};
142+
}

include/bitstream/stream/bit_reader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ namespace bitstream
159159
[[nodiscard]] bool align() noexcept
160160
{
161161
uint32_t remainder = get_num_bits_serialized() % 8U;
162-
if (remainder != 0U)
162+
if (remainder != 0U) BS_LIKELY
163163
{
164164
uint32_t zero;
165165
bool status = serialize_bits(zero, 8U - remainder);

include/bitstream/stream/bit_writer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ namespace bitstream
186186
[[nodiscard]] bool align() noexcept
187187
{
188188
uint32_t remainder = m_ScratchBits % 8U;
189-
if (remainder != 0U)
189+
if (remainder != 0U) BS_LIKELY
190190
{
191191
uint32_t zero = 0U;
192192
bool status = serialize_bits(zero, 8U - remainder);

include/bitstream/stream/multi.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#include "../utility/meta.h"
33
#include "../utility/parameter.h"
44

5+
#include "../stream/bit_noop.h"
6+
57
#include "serialize_traits.h"
68

79
#include <tuple>
@@ -14,15 +16,21 @@ namespace bitstream
1416
std::tuple<Ts...> Args;
1517

1618
template<typename Stream, typename = utility::has_serialize_t<T, Stream, Ts...>>
17-
bool serialize(Stream& stream) noexcept(utility::is_serialize_noexcept_v<T, Stream, Ts...>)
19+
[[nodiscard]] bool serialize(Stream& stream) noexcept(utility::is_serialize_noexcept_v<T, Stream, Ts...>)
1820
{
1921
return std::apply([&](auto&&... args) { return serialize_traits<T>::serialize(stream, args ...); }, std::move(Args));
2022
}
2123
};
2224

2325
template<typename T, typename... Args>
24-
multi_args<T, Args&&...> multi(Args&&... args) noexcept
26+
[[nodiscard]] multi_args<T, Args&&...> multi(Args&&... args) noexcept
2527
{
2628
return multi_args<T, Args&&...>{ std::forward_as_tuple(std::forward<Args>(args) ...) };
2729
}
30+
31+
template<typename... Args, typename Trait, typename = utility::has_deduce_serialize_t<Trait, bit_noop, Args...>>
32+
[[nodiscard]] multi_args<utility::deduce_trait_t<Trait, bit_noop, Args...>, Trait&&, Args&&...> multi(Trait&& arg, Args&&... args) noexcept
33+
{
34+
return multi_args<utility::deduce_trait_t<Trait, bit_noop, Args...>, Trait&&, Args&&...>{ std::forward_as_tuple(std::forward<Trait>(arg), std::forward<Args>(args) ...) };
35+
}
2836
}

include/bitstream/traits/array_traits.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ namespace bitstream
114114
* @return Success
115115
*/
116116
template<typename Stream, typename Compare, typename... Args>
117-
typename utility::is_writing_t<Stream>
118-
static serialize(Stream& writer, T* values, int max_size, Compare compare, Args&&... args) noexcept
117+
static stream_writing_t<Stream> serialize(Stream& writer, T* values, int max_size, Compare compare, Args&&... args) noexcept
119118
{
120119
int prev_index = -1;
121120
for (int index = 0; index < max_size; index++)
@@ -144,8 +143,7 @@ namespace bitstream
144143
* @return Success
145144
*/
146145
template<typename Stream, typename... Args>
147-
typename utility::is_reading_t<Stream>
148-
static serialize(Stream& reader, T* values, int max_size, Args&&... args) noexcept
146+
static stream_reading_t<Stream> serialize(Stream& reader, T* values, int max_size, Args&&... args) noexcept
149147
{
150148
int prev_index = -1;
151149
int index = 0;

include/bitstream/traits/bool_trait.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,15 @@ namespace bitstream
1414
struct serialize_traits<bool>
1515
{
1616
template<typename Stream>
17-
typename utility::is_writing_t<Stream>
18-
static serialize(Stream& writer, in<bool> value) noexcept
17+
static stream_writing_t<Stream> serialize(Stream& writer, in<bool> value) noexcept
1918
{
2019
uint32_t unsigned_value = value;
2120

2221
return writer.serialize_bits(unsigned_value, 1U);
2322
}
2423

2524
template<typename Stream>
26-
typename utility::is_reading_t<Stream>
27-
static serialize(Stream& reader, out<bool> value) noexcept
25+
static stream_reading_t<Stream> serialize(Stream& reader, out<bool> value) noexcept
2826
{
2927
uint32_t unsigned_value;
3028

@@ -43,8 +41,7 @@ namespace bitstream
4341
struct serialize_traits<bool[Size]>
4442
{
4543
template<typename Stream>
46-
typename utility::is_writing_t<Stream>
47-
static serialize(Stream& writer, const bool* values) noexcept
44+
static stream_writing_t<Stream> serialize(Stream& writer, const bool* values) noexcept
4845
{
4946
uint32_t unsigned_value;
5047
for (size_t i = 0; i < Size; i++)
@@ -57,8 +54,7 @@ namespace bitstream
5754
}
5855

5956
template<typename Stream>
60-
typename utility::is_reading_t<Stream>
61-
static serialize(Stream& reader, bool* values) noexcept
57+
static stream_reading_t<Stream> serialize(Stream& reader, bool* values) noexcept
6258
{
6359
uint32_t unsigned_value;
6460
for (size_t i = 0; i < Size; i++)

include/bitstream/traits/checksum_trait.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ namespace bitstream
2727
constexpr static uint32_t protocol_size = sizeof(uint32_t);
2828

2929
template<typename Stream>
30-
typename utility::is_writing_t<Stream>
31-
static serialize(Stream& writer) noexcept
30+
static stream_writing_t<Stream> serialize(Stream& writer) noexcept
3231
{
3332
if (writer.get_num_bits_serialized() == 0)
3433
return writer.pad_to_size(4);
@@ -52,8 +51,7 @@ namespace bitstream
5251
}
5352

5453
template<typename Stream>
55-
typename utility::is_reading_t<Stream>
56-
static serialize(Stream& reader) noexcept
54+
static stream_reading_t<Stream> serialize(Stream& reader) noexcept
5755
{
5856
if (reader.get_num_bits_serialized() > 0)
5957
return true;

include/bitstream/traits/enum_trait.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,15 @@ namespace bitstream
2525
using value_type = std::underlying_type_t<T>;
2626

2727
template<typename Stream>
28-
typename utility::is_writing_t<Stream>
29-
static serialize(Stream& writer, T value, value_type min = 0, value_type max = (std::numeric_limits<value_type>::max)()) noexcept
28+
static stream_writing_t<Stream> serialize(Stream& writer, T value, value_type min = 0, value_type max = (std::numeric_limits<value_type>::max)()) noexcept
3029
{
3130
value_type unsigned_value = static_cast<value_type>(value);
3231

3332
return writer.template serialize<value_type>(unsigned_value, min, max);
3433
}
3534

3635
template<typename Stream>
37-
typename utility::is_reading_t<Stream>
38-
static serialize(Stream& reader, T& value, value_type min = 0, value_type max = (std::numeric_limits<value_type>::max)()) noexcept
36+
static stream_reading_t<Stream> serialize(Stream& reader, T& value, value_type min = 0, value_type max = (std::numeric_limits<value_type>::max)()) noexcept
3937
{
4038
value_type unsigned_value;
4139

@@ -57,17 +55,15 @@ namespace bitstream
5755
using bound_type = bounded_int<value_type, Min, Max>;
5856

5957
template<typename Stream>
60-
typename utility::is_writing_t<Stream>
61-
static serialize(Stream& writer, T value) noexcept
58+
static stream_writing_t<Stream> serialize(Stream& writer, T value) noexcept
6259
{
6360
value_type unsigned_value = static_cast<value_type>(value);
6461

6562
return writer.template serialize<bound_type>(unsigned_value);
6663
}
6764

6865
template<typename Stream>
69-
typename utility::is_reading_t<Stream>
70-
static serialize(Stream& reader, T& value) noexcept
66+
static stream_reading_t<Stream> serialize(Stream& reader, T& value) noexcept
7167
{
7268
value_type unsigned_value;
7369

include/bitstream/traits/float_trait.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ namespace bitstream
2323
* @return Success
2424
*/
2525
template<typename Stream>
26-
typename utility::is_writing_t<Stream>
27-
static serialize(Stream& writer, in<float> value) noexcept
26+
static stream_writing_t<Stream> serialize(Stream& writer, in<float> value) noexcept
2827
{
2928
uint32_t tmp;
3029
std::memcpy(&tmp, &value, sizeof(float));
@@ -41,8 +40,7 @@ namespace bitstream
4140
* @return Success
4241
*/
4342
template<typename Stream>
44-
typename utility::is_reading_t<Stream>
45-
static serialize(Stream& reader, float& value) noexcept
43+
static stream_reading_t<Stream> serialize(Stream& reader, float& value) noexcept
4644
{
4745
uint32_t tmp;
4846

@@ -67,8 +65,7 @@ namespace bitstream
6765
* @return Success
6866
*/
6967
template<typename Stream>
70-
typename utility::is_writing_t<Stream>
71-
static serialize(Stream& writer, in<double> value) noexcept
68+
static stream_writing_t<Stream> serialize(Stream& writer, in<double> value) noexcept
7269
{
7370
uint32_t tmp[2];
7471
std::memcpy(tmp, &value, sizeof(double));
@@ -86,8 +83,7 @@ namespace bitstream
8683
* @return Success
8784
*/
8885
template<typename Stream>
89-
typename utility::is_reading_t<Stream>
90-
static serialize(Stream& reader, double& value) noexcept
86+
static stream_reading_t<Stream> serialize(Stream& reader, double& value) noexcept
9187
{
9288
uint32_t tmp[2];
9389

0 commit comments

Comments
 (0)