src/zserio/BitStreamWriter.h
Line | Count | Source |
1 | | #ifndef ZSERIO_BIT_STREAM_WRITER_H_INC |
2 | | #define ZSERIO_BIT_STREAM_WRITER_H_INC |
3 | | |
4 | | #include <algorithm> |
5 | | #include <cstddef> |
6 | | #include <cstring> |
7 | | |
8 | | #include "zserio/BitBuffer.h" |
9 | | #include "zserio/CppRuntimeException.h" |
10 | | #include "zserio/SizeConvertUtil.h" |
11 | | #include "zserio/Span.h" |
12 | | #include "zserio/StringView.h" |
13 | | #include "zserio/Types.h" |
14 | | |
15 | | namespace zserio |
16 | | { |
17 | | |
18 | | /** |
19 | | * Writer class which allows to write various data to the bit stream. |
20 | | */ |
21 | | class BitStreamWriter |
22 | | { |
23 | | public: |
24 | | /** Exception throw in case of insufficient capacity of the given buffer. */ |
25 | | class InsufficientCapacityException : public CppRuntimeException |
26 | | { |
27 | | public: |
28 | | using CppRuntimeException::CppRuntimeException; |
29 | | }; |
30 | | |
31 | | /** Type for bit position. */ |
32 | | using BitPosType = size_t; |
33 | | |
34 | | /** |
35 | | * Constructor from externally allocated byte buffer. |
36 | | * |
37 | | * \param buffer External byte buffer to create from. |
38 | | * \param bufferBitSize Size of the buffer in bits. |
39 | | */ |
40 | | explicit BitStreamWriter(uint8_t* buffer, size_t bufferBitSize, BitsTag); |
41 | | |
42 | | /** |
43 | | * Constructor from externally allocated byte buffer. |
44 | | * |
45 | | * \param buffer External byte buffer to create from. |
46 | | * \param bufferByteSize Size of the buffer in bytes. |
47 | | */ |
48 | | explicit BitStreamWriter(uint8_t* buffer, size_t bufferByteSize); |
49 | | |
50 | | /** |
51 | | * Constructor from externally allocated byte buffer. |
52 | | * |
53 | | * \param buffer External buffer to create from as a Span. |
54 | | */ |
55 | | explicit BitStreamWriter(Span<uint8_t> buffer); |
56 | | |
57 | | /** |
58 | | * Constructor from externally allocated byte buffer with exact bit size. |
59 | | * |
60 | | * \param buffer External buffer to create from as a Span. |
61 | | * \param bufferBitSize Size of the buffer in bits. |
62 | | */ |
63 | | explicit BitStreamWriter(Span<uint8_t> buffer, size_t bufferBitSize); |
64 | | |
65 | | /** |
66 | | * Constructor from externally allocated bit buffer. |
67 | | * |
68 | | * \param bitBuffer External bit buffer to create from. |
69 | | */ |
70 | | template <typename ALLOC> |
71 | | explicit BitStreamWriter(BasicBitBuffer<ALLOC>& bitBuffer) : |
72 | | BitStreamWriter(bitBuffer.getData(), bitBuffer.getBitSize()) |
73 | 469 | {} |
74 | | |
75 | | /** |
76 | | * Destructor. |
77 | | */ |
78 | | ~BitStreamWriter() = default; |
79 | | |
80 | | /** |
81 | | * Copying and moving is disallowed! |
82 | | * \{ |
83 | | */ |
84 | | BitStreamWriter(const BitStreamWriter&) = delete; |
85 | | BitStreamWriter& operator=(const BitStreamWriter&) = delete; |
86 | | |
87 | | BitStreamWriter(const BitStreamWriter&&) = delete; |
88 | | BitStreamWriter& operator=(BitStreamWriter&&) = delete; |
89 | | /** |
90 | | * \} |
91 | | */ |
92 | | |
93 | | /** |
94 | | * Writes unsigned bits up to 32 bits. |
95 | | * |
96 | | * \param data Data to write. |
97 | | * \param numBits Number of bits to write. |
98 | | */ |
99 | | void writeBits(uint32_t data, uint8_t numBits = 32); |
100 | | |
101 | | /** |
102 | | * Writes unsigned bits up to 64 bits. |
103 | | * |
104 | | * \param data Data to write. |
105 | | * \param numBits Number of bits to write. |
106 | | */ |
107 | | void writeBits64(uint64_t data, uint8_t numBits = 64); |
108 | | |
109 | | /** |
110 | | * Writes signed bits up to 32 bits. |
111 | | * |
112 | | * \param data Data to write. |
113 | | * \param numBits Number of bits to write. |
114 | | */ |
115 | | void writeSignedBits(int32_t data, uint8_t numBits = 32); |
116 | | |
117 | | /** |
118 | | * Writes signed bits up to 64 bits. |
119 | | * |
120 | | * \param data Data to write. |
121 | | * \param numBits Number of bits to write. |
122 | | */ |
123 | | void writeSignedBits64(int64_t data, uint8_t numBits = 64); |
124 | | |
125 | | /** |
126 | | * Writes signed variable integer up to 64 bits. |
127 | | * |
128 | | * \param data Varint64 to write. |
129 | | */ |
130 | | void writeVarInt64(int64_t data); |
131 | | |
132 | | /** |
133 | | * Writes signed variable integer up to 32 bits. |
134 | | * |
135 | | * \param data Varint32 to write. |
136 | | */ |
137 | | void writeVarInt32(int32_t data); |
138 | | |
139 | | /** |
140 | | * Writes signed variable integer up to 16 bits. |
141 | | * |
142 | | * \param data Varint16 to write. |
143 | | */ |
144 | | void writeVarInt16(int16_t data); |
145 | | |
146 | | /** |
147 | | * Writes unsigned variable integer up to 64 bits. |
148 | | * |
149 | | * \param data Varuint64 to write. |
150 | | */ |
151 | | void writeVarUInt64(uint64_t data); |
152 | | |
153 | | /** |
154 | | * Writes unsigned variable integer up to 32 bits. |
155 | | * |
156 | | * \param data Varuint32 to write. |
157 | | */ |
158 | | void writeVarUInt32(uint32_t data); |
159 | | |
160 | | /** |
161 | | * Writes unsigned variable integer up to 16 bits. |
162 | | * |
163 | | * \param data Varuint16 to write. |
164 | | */ |
165 | | void writeVarUInt16(uint16_t data); |
166 | | |
167 | | /** |
168 | | * Writes signed variable integer up to 72 bits. |
169 | | * |
170 | | * \param data Varuint64 to write. |
171 | | */ |
172 | | void writeVarInt(int64_t data); |
173 | | |
174 | | /** |
175 | | * Writes signed variable integer up to 72 bits. |
176 | | * |
177 | | * \param data Varuint64 to write. |
178 | | */ |
179 | | void writeVarUInt(uint64_t data); |
180 | | |
181 | | /** |
182 | | * Writes variable size integer up to 40 bits. |
183 | | * |
184 | | * \param data Varsize to write. |
185 | | */ |
186 | | void writeVarSize(uint32_t data); |
187 | | |
188 | | /** |
189 | | * Writes 16-bit float. |
190 | | * |
191 | | * \param data Float16 to write. |
192 | | */ |
193 | | void writeFloat16(float data); |
194 | | |
195 | | /** |
196 | | * Writes 32-bit float. |
197 | | * |
198 | | * \param data Float32 to write. |
199 | | */ |
200 | | void writeFloat32(float data); |
201 | | |
202 | | /** |
203 | | * Writes 64-bit float. |
204 | | * |
205 | | * \param data Float64 to write. |
206 | | */ |
207 | | void writeFloat64(double data); |
208 | | |
209 | | /** |
210 | | * Writes bytes. |
211 | | * |
212 | | * \param data Bytes to write. |
213 | | */ |
214 | | void writeBytes(Span<const uint8_t> data); |
215 | | |
216 | | /** |
217 | | * Writes UTF-8 string. |
218 | | * |
219 | | * \param data String view to write. |
220 | | */ |
221 | | void writeString(StringView data); |
222 | | |
223 | | /** |
224 | | * Writes bool as a single bit. |
225 | | * |
226 | | * \param data Bool to write. |
227 | | */ |
228 | | void writeBool(bool data); |
229 | | |
230 | | /** |
231 | | * Writes bit buffer. |
232 | | * |
233 | | * \param bitBuffer Bit buffer to write. |
234 | | */ |
235 | | template <typename ALLOC> |
236 | | void writeBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer) |
237 | 133 | { |
238 | 133 | const size_t bitSize = bitBuffer.getBitSize(); |
239 | 133 | writeVarSize(convertSizeToUInt32(bitSize)); |
240 | | |
241 | 133 | Span<const uint8_t> buffer = bitBuffer.getData(); |
242 | 133 | size_t numBytesToWrite = bitSize / 8; |
243 | 133 | const uint8_t numRestBits = static_cast<uint8_t>(bitSize - numBytesToWrite * 8); |
244 | 133 | const BitPosType beginBitPosition = getBitPosition(); |
245 | 133 | const Span<const uint8_t>::iterator itEnd = buffer.begin() + numBytesToWrite; |
246 | 133 | if ((beginBitPosition & 0x07U) != 0) |
247 | 67 | { |
248 | | // we are not aligned to byte |
249 | 147 | for (Span<const uint8_t>::iterator it = buffer.begin(); it != itEnd; ++it80 ) |
250 | 80 | { |
251 | 80 | writeUnsignedBits(*it, 8); |
252 | 80 | } |
253 | 67 | } |
254 | 66 | else |
255 | 66 | { |
256 | | // we are aligned to byte |
257 | 66 | setBitPosition(beginBitPosition + numBytesToWrite * 8); |
258 | 66 | if (hasWriteBuffer()) |
259 | 64 | { |
260 | 64 | std::copy(buffer.begin(), buffer.begin() + numBytesToWrite, |
261 | 64 | m_buffer.data() + beginBitPosition / 8); |
262 | 64 | } |
263 | 66 | } |
264 | | |
265 | 133 | if (numRestBits > 0) |
266 | 128 | { |
267 | 128 | writeUnsignedBits(static_cast<uint32_t>(*itEnd) >> (8U - numRestBits), numRestBits); |
268 | 128 | } |
269 | 133 | } |
270 | | |
271 | | /** |
272 | | * Gets current bit position. |
273 | | * |
274 | | * \return Current bit position. |
275 | | */ |
276 | | BitPosType getBitPosition() const |
277 | 17.3k | { |
278 | 17.3k | return m_bitIndex; |
279 | 17.3k | } |
280 | | |
281 | | /** |
282 | | * Sets current bit position. Use with caution! |
283 | | * |
284 | | * \param position New bit position. |
285 | | */ |
286 | | void setBitPosition(BitPosType position); |
287 | | |
288 | | /** |
289 | | * Moves current bit position to perform the requested bit alignment. |
290 | | * |
291 | | * \param alignment Size of the alignment in bits. |
292 | | */ |
293 | | void alignTo(size_t alignment); |
294 | | |
295 | | /** |
296 | | * Gets whether the writer has assigned a write buffer. |
297 | | * |
298 | | * \return True when a buffer is assigned. False otherwise. |
299 | | */ |
300 | | bool hasWriteBuffer() const |
301 | 105k | { |
302 | 105k | return m_buffer.data() != nullptr; |
303 | 105k | } |
304 | | |
305 | | /** |
306 | | * Gets the write buffer. |
307 | | * |
308 | | * \return Pointer to the beginning of write buffer. |
309 | | */ |
310 | | const uint8_t* getWriteBuffer() const; |
311 | | |
312 | | /** |
313 | | * Gets the write buffer as span. |
314 | | * |
315 | | * \return Span which represents the write buffer. |
316 | | */ |
317 | | Span<const uint8_t> getBuffer() const; |
318 | | |
319 | | /** |
320 | | * Gets size of the underlying buffer in bits. |
321 | | * |
322 | | * \return Buffer bit size. |
323 | | */ |
324 | | size_t getBufferBitSize() const |
325 | 5 | { |
326 | 5 | return m_bufferBitSize; |
327 | 5 | } |
328 | | |
329 | | private: |
330 | | void writeUnsignedBits(uint32_t data, uint8_t numBits); |
331 | | void writeUnsignedBits64(uint64_t data, uint8_t numBits); |
332 | | void writeSignedVarNum(int64_t value, size_t maxVarBytes, size_t numVarBytes); |
333 | | void writeUnsignedVarNum(uint64_t value, size_t maxVarBytes, size_t numVarBytes); |
334 | | void writeVarNum(uint64_t value, bool hasSign, bool isNegative, size_t maxVarBytes, size_t numVarBytes); |
335 | | |
336 | | void checkCapacity(size_t bitSize) const; |
337 | | void throwInsufficientCapacityException() const; |
338 | | |
339 | | Span<uint8_t> m_buffer; |
340 | | size_t m_bitIndex; |
341 | | size_t m_bufferBitSize; |
342 | | }; |
343 | | |
344 | | } // namespace zserio |
345 | | |
346 | | #endif // ifndef ZSERIO_BIT_STREAM_WRITER_H_INC |