BitStream
bit_measure.h
Go to the documentation of this file.
1 #pragma once
2 #include "../utility/assert.h"
3 #include "../utility/crc.h"
4 #include "../utility/endian.h"
5 #include "../utility/meta.h"
6 
7 #include "byte_buffer.h"
8 #include "serialize_traits.h"
9 
10 #include <cstdint>
11 #include <cstring>
12 #include <limits>
13 #include <memory>
14 #include <type_traits>
15 
16 namespace bitstream
17 {
23  {
24  public:
25  static constexpr bool writing = true;
26  static constexpr bool reading = false;
27 
31  bit_measure() noexcept :
32  m_NumBitsWritten(0),
33  m_TotalBits((std::numeric_limits<uint32_t>::max)()) {}
34 
39  bit_measure(uint32_t num_bytes) noexcept :
40  m_NumBitsWritten(0),
41  m_TotalBits(num_bytes * 8) {}
42 
43  bit_measure(const bit_measure&) = delete;
44 
45  bit_measure(bit_measure&& other) noexcept :
46  m_NumBitsWritten(other.m_NumBitsWritten),
47  m_TotalBits(other.m_TotalBits)
48  {
49  other.m_NumBitsWritten = 0;
50  other.m_TotalBits = 0;
51  }
52 
53  bit_measure& operator=(const bit_measure&) = delete;
54 
56  {
57  m_NumBitsWritten = rhs.m_NumBitsWritten;
58  m_TotalBits = rhs.m_TotalBits;
59 
60  rhs.m_NumBitsWritten = 0;
61  rhs.m_TotalBits = 0;
62 
63  return *this;
64  }
65 
70  [[nodiscard]] uint8_t* get_buffer() const noexcept { return nullptr; }
71 
76  [[nodiscard]] uint32_t get_num_bits_serialized() const noexcept { return m_NumBitsWritten; }
77 
82  [[nodiscard]] uint32_t get_num_bytes_serialized() const noexcept { return m_NumBitsWritten > 0U ? ((m_NumBitsWritten - 1U) / 8U + 1U) : 0U; }
83 
89  [[nodiscard]] bool can_serialize_bits(uint32_t num_bits) const noexcept { return m_NumBitsWritten + num_bits <= m_TotalBits; }
90 
96  [[nodiscard]] uint32_t get_remaining_bits() const noexcept { return m_TotalBits - m_NumBitsWritten; }
97 
102  [[nodiscard]] uint32_t get_total_bits() const noexcept { return m_TotalBits; }
103 
108  [[nodiscard]] bool prepend_checksum() noexcept
109  {
110  BS_ASSERT(m_NumBitsWritten == 0);
111 
113 
114  m_NumBitsWritten += 32U;
115 
116  return true;
117  }
118 
124  uint32_t serialize_checksum(uint32_t protocol_version) noexcept
125  {
126  return m_NumBitsWritten;
127  }
128 
134  [[nodiscard]] bool pad_to_size(uint32_t num_bytes) noexcept
135  {
136  BS_ASSERT(num_bytes * 8U <= m_TotalBits);
137 
138  BS_ASSERT(num_bytes * 8U >= m_NumBitsWritten);
139 
140  m_NumBitsWritten = num_bytes * 8U;
141 
142  return true;
143  }
144 
150  [[nodiscard]] bool pad(uint32_t num_bytes) noexcept
151  {
152  return pad_to_size(get_num_bytes_serialized() + num_bytes);
153  }
154 
159  [[nodiscard]] bool align() noexcept
160  {
161  uint32_t remainder = m_NumBitsWritten % 8U;
162  if (remainder != 0U)
163  m_NumBitsWritten += 8U - remainder;
164  return true;
165  }
166 
173  [[nodiscard]] bool serialize_bits(uint32_t value, uint32_t num_bits) noexcept
174  {
175  BS_ASSERT(num_bits > 0U && num_bits <= 32U);
176 
177  BS_ASSERT(can_serialize_bits(num_bits));
178 
179  m_NumBitsWritten += num_bits;
180 
181  return true;
182  }
183 
190  [[nodiscard]] bool serialize_bytes(const uint8_t* bytes, uint32_t num_bits) noexcept
191  {
192  BS_ASSERT(num_bits > 0U);
193 
194  BS_ASSERT(can_serialize_bits(num_bits));
195 
196  m_NumBitsWritten += num_bits;
197 
198  return true;
199  }
200 
209  template<typename Trait, typename... Args, typename = utility::has_serialize_t<Trait, bit_measure, Args...>>
210  [[nodiscard]] bool serialize(Args&&... args) noexcept(utility::is_serialize_noexcept_v<Trait, bit_measure, Args...>)
211  {
212  return serialize_traits<Trait>::serialize(*this, std::forward<Args>(args)...);
213  }
214 
225  template<typename... Args, typename Trait, typename = utility::has_deduce_serialize_t<Trait, bit_measure, Args...>>
226  [[nodiscard]] bool serialize(Trait&& arg, Args&&... args) noexcept(utility::is_deduce_serialize_noexcept_v<Trait, bit_measure, Args...>)
227  {
228  return serialize_traits<utility::deduce_trait_t<Trait, bit_measure, Args...>>::serialize(*this, std::forward<Trait>(arg), std::forward<Args>(args)...);
229  }
230 
231  private:
232  uint32_t m_NumBitsWritten;
233  uint32_t m_TotalBits;
234  };
235 }
#define BS_ASSERT(x)
Definition: assert.h:15
A stream for writing objects tightly into a buffer.
Definition: bit_measure.h:23
bool serialize_bits(uint32_t value, uint32_t num_bits) noexcept
Writes the first num_bits bits of value into the buffer.
Definition: bit_measure.h:173
bit_measure(bit_measure &&other) noexcept
Definition: bit_measure.h:45
uint32_t get_num_bytes_serialized() const noexcept
Returns the number of bytes which have been written to the buffer.
Definition: bit_measure.h:82
bit_measure & operator=(bit_measure &&rhs) noexcept
Definition: bit_measure.h:55
bit_measure(uint32_t num_bytes) noexcept
Construct a writer pointing to the given byte array with num_bytes size.
Definition: bit_measure.h:39
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_measure.h:190
bool align() noexcept
Pads the buffer with up to 8 zeros, so that the next write is byte-aligned.
Definition: bit_measure.h:159
uint32_t get_remaining_bits() const noexcept
Returns the number of bits which have not been written yet.
Definition: bit_measure.h:96
uint8_t * get_buffer() const noexcept
Returns the buffer that this writer is currently serializing into.
Definition: bit_measure.h:70
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_measure.h:124
bit_measure & operator=(const bit_measure &)=delete
bool pad(uint32_t num_bytes) noexcept
Pads the buffer up with the given number of bytes.
Definition: bit_measure.h:150
uint32_t get_total_bits() const noexcept
Returns the size of the buffer, in bits.
Definition: bit_measure.h:102
static constexpr bool reading
Definition: bit_measure.h:26
uint32_t get_num_bits_serialized() const noexcept
Returns the number of bits which have been written to the buffer.
Definition: bit_measure.h:76
bool can_serialize_bits(uint32_t num_bits) const noexcept
Returns whether the num_bits can fit in the buffer.
Definition: bit_measure.h:89
static constexpr bool writing
Definition: bit_measure.h:25
bool serialize(Args &&... args) noexcept(utility::is_serialize_noexcept_v< Trait, bit_measure, Args... >)
Writes to the buffer, using the given Trait.
Definition: bit_measure.h:210
bool prepend_checksum() noexcept
Instructs the writer that you intend to use serialize_checksum() later on, and to reserve the first 3...
Definition: bit_measure.h:108
bit_measure() noexcept
Default construct a writer pointing to a null buffer.
Definition: bit_measure.h:31
bool pad_to_size(uint32_t num_bytes) noexcept
Pads the buffer up to the given number of bytes with zeros.
Definition: bit_measure.h:134
bit_measure(const bit_measure &)=delete
bool serialize(Trait &&arg, Args &&... args) noexcept(utility::is_deduce_serialize_noexcept_v< Trait, bit_measure, Args... >)
Writes to the buffer, by trying to deduce the trait.
Definition: bit_measure.h:226
has_serialize_t< deduce_trait_t< Trait, Stream, Args... >, Stream, Trait, Args... > has_deduce_serialize_t
Definition: meta.h:101
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