2 #include "../utility/assert.h"
3 #include "../utility/crc.h"
4 #include "../utility/endian.h"
5 #include "../utility/meta.h"
14 #include <type_traits>
22 template<
typename Policy>
33 template<
typename... Ts,
34 typename = std::enable_if_t<std::is_constructible_v<Policy, Ts...>>>
36 noexcept(std::is_nothrow_constructible_v<Policy, Ts...>) :
37 m_Policy(std::forward<Ts>(args) ...),
45 m_Policy(std::move(other.m_Policy)),
46 m_Scratch(other.m_Scratch),
47 m_ScratchBits(other.m_ScratchBits),
48 m_WordIndex(other.m_WordIndex)
51 other.m_ScratchBits = 0;
52 other.m_WordIndex = 0;
59 m_Policy = std::move(rhs.m_Policy);
60 m_Scratch = rhs.m_Scratch;
61 m_ScratchBits = rhs.m_ScratchBits;
62 m_WordIndex = rhs.m_WordIndex;
65 rhs.m_ScratchBits = 0;
75 [[nodiscard]] uint8_t*
get_buffer() const noexcept {
return reinterpret_cast<uint8_t*
>(m_Policy.get_buffer()); }
94 [[nodiscard]]
bool can_serialize_bits(uint32_t num_bits)
const noexcept {
return m_Policy.can_serialize_bits(num_bits); }
107 [[nodiscard]] uint32_t
get_total_bits() const noexcept {
return m_Policy.get_total_bits(); }
115 if (m_ScratchBits > 0U)
117 uint32_t* ptr = m_Policy.get_buffer() + m_WordIndex;
118 uint32_t ptr_value =
static_cast<uint32_t
>(m_Scratch >> 32U);
152 uint32_t num_bits =
flush();
157 uint32_t* buffer = m_Policy.get_buffer();
158 *buffer = protocol_version;
178 BS_ASSERT(num_bytes * 8U >= num_bits_written);
182 if (num_bits_written == 0)
184 BS_ASSERT(m_Policy.extend(num_bytes * 8U - num_bits_written));
186 std::memset(m_Policy.get_buffer(), 0, num_bytes);
190 m_WordIndex = num_bytes / 4;
195 uint32_t remainder = (num_bytes * 8U - num_bits_written) % 32U;
203 uint32_t max = num_bytes / 4;
206 for (uint32_t i = offset; i < max; i++)
217 [[nodiscard]]
bool pad(uint32_t num_bytes) noexcept
228 uint32_t remainder = m_ScratchBits % 8U;
247 BS_ASSERT(num_bits > 0U && num_bits <= 32U);
252 if (num_bits == 32U && m_ScratchBits == 0U)
254 uint32_t* ptr = m_Policy.get_buffer() + m_WordIndex;
263 uint32_t offset = 64U - num_bits - m_ScratchBits;
264 uint64_t ls_value =
static_cast<uint64_t
>(value) << offset;
266 m_Scratch |= ls_value;
267 m_ScratchBits += num_bits;
269 if (m_ScratchBits >= 32U)
271 uint32_t* ptr = m_Policy.get_buffer() + m_WordIndex;
272 uint32_t ptr_value =
static_cast<uint32_t
>(m_Scratch >> 32U);
275 m_ScratchBits -= 32U;
295 const uint32_t* word_buffer =
reinterpret_cast<const uint32_t*
>(bytes);
296 uint32_t num_words = num_bits / 32U;
298 if (m_ScratchBits % 32U == 0U && num_words > 0U)
300 BS_ASSERT(m_Policy.extend(num_words * 32U));
303 std::memcpy(m_Policy.get_buffer() + m_WordIndex, word_buffer, num_words * 4U);
305 m_WordIndex += num_words;
310 for (uint32_t i = 0U; i < num_words; i++)
320 if (num_bits % 32U == 0U)
323 uint32_t remaining_bits = num_bits - num_words * 32U;
325 uint32_t num_bytes = (remaining_bits - 1U) / 8U + 1U;
326 for (uint32_t i = 0U; i < num_bytes; i++)
328 uint32_t value =
static_cast<uint32_t
>(bytes[num_words * 4U + i]);
342 uint8_t* buffer =
reinterpret_cast<uint8_t*
>(m_Policy.get_buffer());
344 uint32_t remainder_bits = num_bits % 8U;
346 BS_ASSERT(writer.serialize_bytes(buffer, num_bits - remainder_bits));
348 if (remainder_bits > 0U)
350 uint32_t byte_value = buffer[num_bits / 8U] >> (8U - remainder_bits);
351 BS_ASSERT(writer.serialize_bits(byte_value, remainder_bits));
366 [[nodiscard]]
bool serialize(Args&&... args) noexcept(utility::is_serialize_noexcept_v<Trait, bit_writer, Args...>)
382 [[nodiscard]]
bool serialize(Trait&& arg, Args&&... args) noexcept(utility::is_deduce_serialize_noexcept_v<Trait, bit_writer, Args...>)
391 uint32_t m_ScratchBits;
392 uint32_t m_WordIndex;
#define BS_ASSERT(x)
Definition: assert.h:15
A stream for writing objects tightly into a buffer.
Definition: bit_writer.h:24
uint8_t * get_buffer() const noexcept
Returns the buffer that this writer is currently serializing into.
Definition: bit_writer.h:75
bool serialize(Trait &&arg, Args &&... args) noexcept(utility::is_deduce_serialize_noexcept_v< Trait, bit_writer, Args... >)
Writes to the buffer, by trying to deduce the trait.
Definition: bit_writer.h:382
bit_writer & operator=(bit_writer &&rhs) noexcept
Definition: bit_writer.h:57
bool serialize_bits(uint32_t value, uint32_t num_bits) noexcept
Writes the first num_bits bits of value into the buffer.
Definition: bit_writer.h:245
uint32_t get_total_bits() const noexcept
Returns the size of the buffer, in bits.
Definition: bit_writer.h:107
uint32_t get_num_bytes_serialized() const noexcept
Returns the number of bytes which have been written to the buffer.
Definition: bit_writer.h:87
bool prepend_checksum() noexcept
Instructs the writer that you intend to use serialize_checksum() later on, and to reserve the first 3...
Definition: bit_writer.h:133
bit_writer & operator=(const bit_writer &)=delete
uint32_t get_remaining_bits() const noexcept
Returns the number of bits which have not been written yet.
Definition: bit_writer.h:101
uint32_t flush() noexcept
Flushes any remaining bits into the buffer. Use this when you no longer intend to write anything to t...
Definition: bit_writer.h:113
bool serialize_bytes(const uint8_t *bytes, uint32_t num_bits) noexcept
Writes the first num_bits bits of the given byte array, 32 bits at a time.
Definition: bit_writer.h:288
bit_writer(bit_writer &&other) noexcept
Definition: bit_writer.h:44
bool align() noexcept
Pads the buffer with up to 8 zeros, so that the next write is byte-aligned.
Definition: bit_writer.h:226
uint32_t serialize_checksum(uint32_t protocol_version) noexcept
Writes a checksum of the protocol_version and the rest of the buffer as the first 32 bits.
Definition: bit_writer.h:150
bool serialize(Args &&... args) noexcept(utility::is_serialize_noexcept_v< Trait, bit_writer, Args... >)
Writes to the buffer, using the given Trait.
Definition: bit_writer.h:366
static constexpr bool reading
Definition: bit_writer.h:27
bool serialize_into(bit_writer &writer) const noexcept
Writes the contents of the buffer into the given writer. Essentially copies the entire buffer without...
Definition: bit_writer.h:340
bool pad_to_size(uint32_t num_bytes) noexcept
Pads the buffer up to the given number of bytes with zeros.
Definition: bit_writer.h:174
static constexpr bool writing
Definition: bit_writer.h:26
bit_writer(const bit_writer &)=delete
bit_writer(Ts &&... args) noexcept(std::is_nothrow_constructible_v< Policy, Ts... >)
Construct a writer with the parameters passed to the underlying policy.
Definition: bit_writer.h:35
bool pad(uint32_t num_bytes) noexcept
Pads the buffer up with the given number of bytes.
Definition: bit_writer.h:217
bool can_serialize_bits(uint32_t num_bits) const noexcept
Returns whether the num_bits can fit in the buffer.
Definition: bit_writer.h:94
uint32_t get_num_bits_serialized() const noexcept
Returns the number of bits which have been written to the buffer.
Definition: bit_writer.h:81
constexpr uint32_t crc_uint32(const uint8_t *bytes, uint32_t size)
Definition: crc.h:25
has_serialize_t< deduce_trait_t< Trait, Stream, Args... >, Stream, Trait, Args... > has_deduce_serialize_t
Definition: meta.h:101
uint32_t to_big_endian32(uint32_t value)
Definition: endian.h:82
typename deduce_trait< void, Trait, Stream, Args... >::type deduce_trait_t
Definition: meta.h:96
std::void_t< decltype(serialize_traits< T >::serialize(std::declval< Stream & >(), std::declval< Args >()...))> has_serialize_t
Definition: meta.h:17
Definition: bounded_range.h:28
A class for specializing trait serialization functions.
Definition: serialize_traits.h:11