src/zserio/BitStreamReader.h
Line | Count | Source |
1 | | #ifndef ZSERIO_BIT_STREAM_READER_H_INC |
2 | | #define ZSERIO_BIT_STREAM_READER_H_INC |
3 | | |
4 | | #include <algorithm> |
5 | | #include <cstring> |
6 | | #include <string> |
7 | | |
8 | | #include "zserio/BitBuffer.h" |
9 | | #include "zserio/RebindAlloc.h" |
10 | | #include "zserio/Span.h" |
11 | | #include "zserio/String.h" |
12 | | #include "zserio/Types.h" |
13 | | #include "zserio/Vector.h" |
14 | | |
15 | | namespace zserio |
16 | | { |
17 | | |
18 | | /** |
19 | | * Wrapper class to specify maximum initial array allocation. |
20 | | */ |
21 | | class ArrayPreallocation |
22 | | { |
23 | | public: |
24 | | static constexpr size_t MAX_INITIAL_ARRAY_ALLOCATION = 128 * 1024; |
25 | | |
26 | | /** |
27 | | * Default constructor sets default array preallocation. |
28 | | */ |
29 | | ArrayPreallocation() : |
30 | | allocation(MAX_INITIAL_ARRAY_ALLOCATION) |
31 | 4.64k | {} |
32 | | /** |
33 | | * Constructor. |
34 | | * |
35 | | * \param alloc Sets custom maximum preallocation for arrays. |
36 | | */ |
37 | | explicit ArrayPreallocation(size_t alloc) : |
38 | | allocation(alloc) |
39 | 12 | {} |
40 | | /** |
41 | | * Gets the value for maximum array preallocation. |
42 | | */ |
43 | | operator size_t() const |
44 | 4.65k | { |
45 | 4.65k | return allocation; |
46 | 4.65k | } |
47 | | |
48 | | private: |
49 | | size_t allocation; |
50 | | }; |
51 | | |
52 | | /** |
53 | | * Reader class which allows to read various data from the bit stream. |
54 | | */ |
55 | | class BitStreamReader |
56 | | { |
57 | | public: |
58 | | /** Type for bit position. */ |
59 | | using BitPosType = size_t; |
60 | | |
61 | | /** |
62 | | * Context of the reader defining its state. |
63 | | */ |
64 | | struct ReaderContext |
65 | | { |
66 | | /** |
67 | | * Constructor. |
68 | | * |
69 | | * \param readBuffer Span to the buffer to read. |
70 | | * \param readBufferBitSize Size of the buffer in bits. |
71 | | */ |
72 | | explicit ReaderContext( |
73 | | Span<const uint8_t> readBuffer, size_t readBufferBitSize, size_t maxArrayPrealloc); |
74 | | |
75 | | /** |
76 | | * Destructor. |
77 | | */ |
78 | | ~ReaderContext() = default; |
79 | | |
80 | | /** |
81 | | * Copying and moving is disallowed! |
82 | | * \{ |
83 | | */ |
84 | | ReaderContext(const ReaderContext&) = delete; |
85 | | ReaderContext& operator=(const ReaderContext&) = delete; |
86 | | |
87 | | ReaderContext(const ReaderContext&&) = delete; |
88 | | ReaderContext& operator=(const ReaderContext&&) = delete; |
89 | | /** |
90 | | * \} |
91 | | */ |
92 | | |
93 | | Span<const uint8_t> buffer; /**< Buffer to read from. */ |
94 | | const BitPosType bufferBitSize; /**< Size of the buffer in bits. */ |
95 | | |
96 | | uintptr_t cache; /**< Bit cache to optimize bit reading. */ |
97 | | uint8_t cacheNumBits; /**< Num bits available in the bit cache. */ |
98 | | |
99 | | BitPosType bitIndex; /**< Current bit index. */ |
100 | | |
101 | | const size_t maxArrayPreallocation; /**< Maximum initial array allocation. */ |
102 | | }; |
103 | | |
104 | | /** |
105 | | * Constructor from raw buffer. |
106 | | * |
107 | | * \param buffer Pointer to the buffer to read. |
108 | | * \param bufferByteSize Size of the buffer in bytes. |
109 | | * \param maxArrayPrealloc Maximum preallocation for arrays. |
110 | | */ |
111 | | explicit BitStreamReader( |
112 | | const uint8_t* buffer, size_t bufferByteSize, ArrayPreallocation maxArrayPrealloc = {}); |
113 | | |
114 | | /** |
115 | | * Constructor from buffer passed as a Span. |
116 | | * |
117 | | * \param buffer Buffer to read. |
118 | | * \param maxArrayPrealloc Maximum preallocation for arrays. |
119 | | */ |
120 | | explicit BitStreamReader(Span<const uint8_t> buffer, ArrayPreallocation maxArrayPrealloc = {}); |
121 | | |
122 | | /** |
123 | | * Constructor from buffer passed as a Span with exact bit size. |
124 | | * |
125 | | * \param buffer Buffer to read. |
126 | | * \param bufferBitSize Size of the buffer in bits. |
127 | | * \param maxArrayPrealloc Maximum preallocation for arrays. |
128 | | */ |
129 | | explicit BitStreamReader( |
130 | | Span<const uint8_t> buffer, size_t bufferBitSize, ArrayPreallocation maxArrayPrealloc = {}); |
131 | | |
132 | | /** |
133 | | * Constructor from raw buffer with exact bit size. |
134 | | * |
135 | | * \param buffer Pointer to buffer to read. |
136 | | * \param bufferBitSize Size of the buffer in bits. |
137 | | * \param maxArrayPrealloc Maximum preallocation for arrays. |
138 | | */ |
139 | | explicit BitStreamReader( |
140 | | const uint8_t* buffer, size_t bufferBitSize, BitsTag, ArrayPreallocation maxArrayPrealloc = {}); |
141 | | |
142 | | /** |
143 | | * Constructor from bit buffer. |
144 | | * |
145 | | * \param bitBuffer Bit buffer to read from. |
146 | | * \param maxArrayPrealloc Maximum preallocation for arrays. |
147 | | */ |
148 | | template <typename ALLOC> |
149 | | explicit BitStreamReader(const BasicBitBuffer<ALLOC>& bitBuffer, ArrayPreallocation maxArrayPrealloc = {}) : |
150 | | BitStreamReader(bitBuffer.getData(), bitBuffer.getBitSize(), maxArrayPrealloc) |
151 | 396 | {} |
152 | | |
153 | | /** |
154 | | * Destructor. |
155 | | */ |
156 | | ~BitStreamReader() = default; |
157 | | |
158 | | /** |
159 | | * Reads unsigned bits up to 32-bits. |
160 | | * |
161 | | * \param numBits Number of bits to read. |
162 | | * |
163 | | * \return Read bits. |
164 | | */ |
165 | | uint32_t readBits(uint8_t numBits = 32); |
166 | | |
167 | | /** |
168 | | * Reads unsigned bits up to 64-bits. |
169 | | * |
170 | | * \param numBits Number of bits to read. |
171 | | * |
172 | | * \return Read bits. |
173 | | */ |
174 | | uint64_t readBits64(uint8_t numBits = 64); |
175 | | |
176 | | /** |
177 | | * Reads signed bits up to 32-bits. |
178 | | * |
179 | | * \param numBits Number of bits to read. |
180 | | * |
181 | | * \return Read bits. |
182 | | */ |
183 | | int32_t readSignedBits(uint8_t numBits = 32); |
184 | | |
185 | | /** |
186 | | * Reads signed bits up to 64-bits. |
187 | | * |
188 | | * \param numBits Number of bits to read. |
189 | | * |
190 | | * \return Read bits. |
191 | | */ |
192 | | int64_t readSignedBits64(uint8_t numBits = 64); |
193 | | |
194 | | /** |
195 | | * Reads signed variable integer up to 64 bits. |
196 | | * |
197 | | * \return Read varint64. |
198 | | */ |
199 | | int64_t readVarInt64(); |
200 | | |
201 | | /** |
202 | | * Reads signed variable integer up to 32 bits. |
203 | | * |
204 | | * \return Read varint32. |
205 | | */ |
206 | | int32_t readVarInt32(); |
207 | | |
208 | | /** |
209 | | * Reads signed variable integer up to 16 bits. |
210 | | * |
211 | | * \return Read varint16. |
212 | | */ |
213 | | int16_t readVarInt16(); |
214 | | |
215 | | /** |
216 | | * Read unsigned variable integer up to 64 bits. |
217 | | * |
218 | | * \return Read varuint64. |
219 | | */ |
220 | | uint64_t readVarUInt64(); |
221 | | |
222 | | /** |
223 | | * Read unsigned variable integer up to 32 bits. |
224 | | * |
225 | | * \return Read varuint32. |
226 | | */ |
227 | | uint32_t readVarUInt32(); |
228 | | |
229 | | /** |
230 | | * Read unsigned variable integer up to 16 bits. |
231 | | * |
232 | | * \return Read varuint16. |
233 | | */ |
234 | | uint16_t readVarUInt16(); |
235 | | |
236 | | /** |
237 | | * Reads signed variable integer up to 72 bits. |
238 | | * |
239 | | * \return Read varint. |
240 | | */ |
241 | | int64_t readVarInt(); |
242 | | |
243 | | /** |
244 | | * Read unsigned variable integer up to 72 bits. |
245 | | * |
246 | | * \return Read varuint. |
247 | | */ |
248 | | uint64_t readVarUInt(); |
249 | | |
250 | | /** |
251 | | * Read variable size integer up to 40 bits. |
252 | | * |
253 | | * \return Read varsize. |
254 | | */ |
255 | | uint32_t readVarSize(); |
256 | | |
257 | | /** |
258 | | * Reads 16-bit float. |
259 | | * |
260 | | * \return Read float16. |
261 | | */ |
262 | | float readFloat16(); |
263 | | |
264 | | /** |
265 | | * Reads 32-bit float. |
266 | | * |
267 | | * \return Read float32. |
268 | | */ |
269 | | float readFloat32(); |
270 | | |
271 | | /** |
272 | | * Reads 64-bit float double. |
273 | | * |
274 | | * \return Read float64. |
275 | | */ |
276 | | double readFloat64(); |
277 | | |
278 | | /** |
279 | | * Reads bytes. |
280 | | * |
281 | | * \param alloc Allocator to use. |
282 | | * |
283 | | * \return Read bytes as a vector. |
284 | | */ |
285 | | template <typename ALLOC = std::allocator<uint8_t>> |
286 | | vector<uint8_t, ALLOC> readBytes(const ALLOC& alloc = ALLOC()) |
287 | 478 | { |
288 | 478 | const size_t len = static_cast<size_t>(readVarSize()); |
289 | 478 | const BitPosType beginBitPosition = getBitPosition(); |
290 | 478 | if (beginBitPosition + 8ULL * len > getBufferBitSize()) |
291 | 5 | { |
292 | 5 | throw CppRuntimeException("BitStreamReader: Byte array size exceeds available buffer!"); |
293 | 5 | } |
294 | 473 | if ((beginBitPosition & 0x07U) != 0) |
295 | 40 | { |
296 | | // we are not aligned to byte |
297 | 40 | vector<uint8_t, ALLOC> value{alloc}; |
298 | 40 | value.reserve(len); |
299 | 132 | for (size_t i = 0; i < len; ++i92 ) |
300 | 92 | { |
301 | 92 | value.push_back(readByte()); |
302 | 92 | } |
303 | 40 | return value; |
304 | 40 | } |
305 | 433 | else |
306 | 433 | { |
307 | | // we are aligned to byte |
308 | 433 | setBitPosition(beginBitPosition + len * 8); |
309 | 433 | Span<const uint8_t>::iterator beginIt = m_context.buffer.begin() + beginBitPosition / 8; |
310 | 433 | return vector<uint8_t, ALLOC>(beginIt, beginIt + len, alloc); |
311 | 433 | } |
312 | 473 | } |
313 | | |
314 | | /** |
315 | | * Reads an UTF-8 string. |
316 | | * |
317 | | * \param alloc Allocator to use. |
318 | | * |
319 | | * \return Read string. |
320 | | */ |
321 | | template <typename ALLOC = std::allocator<char>> |
322 | | string<ALLOC> readString(const ALLOC& alloc = ALLOC()) |
323 | 532 | { |
324 | 532 | const size_t len = static_cast<size_t>(readVarSize()); |
325 | 532 | const BitPosType beginBitPosition = getBitPosition(); |
326 | 532 | if (beginBitPosition + 8ULL * len > getBufferBitSize()) |
327 | 5 | { |
328 | 5 | throw CppRuntimeException("BitStreamReader: String size exceeds available buffer!"); |
329 | 5 | } |
330 | 527 | if ((beginBitPosition & 0x07U) != 0) |
331 | 60 | { |
332 | | // we are not aligned to byte |
333 | 60 | string<ALLOC> value{alloc}; |
334 | 60 | value.reserve(len); |
335 | 942 | for (size_t i = 0; i < len; ++i882 ) |
336 | 882 | { |
337 | 882 | using char_traits = std::char_traits<char>; |
338 | 882 | const char readCharacter = |
339 | 882 | char_traits::to_char_type(static_cast<char_traits::int_type>(readByte())); |
340 | 882 | value.push_back(readCharacter); |
341 | 882 | } |
342 | 60 | return value; |
343 | 60 | } |
344 | 467 | else |
345 | 467 | { |
346 | | // we are aligned to byte |
347 | 467 | setBitPosition(beginBitPosition + len * 8); |
348 | 467 | Span<const uint8_t>::iterator beginIt = m_context.buffer.begin() + beginBitPosition / 8; |
349 | 467 | return string<ALLOC>(beginIt, beginIt + len, alloc); |
350 | 467 | } |
351 | 527 | } |
352 | | |
353 | | /** |
354 | | * Reads bool as a single bit. |
355 | | * |
356 | | * \return Read bool value. |
357 | | */ |
358 | | bool readBool(); |
359 | | |
360 | | /** |
361 | | * Reads a bit buffer. |
362 | | * |
363 | | * \param alloc Allocator to use. |
364 | | * |
365 | | * \return Read bit buffer. |
366 | | */ |
367 | | template <typename ALLOC = std::allocator<uint8_t>> |
368 | | BasicBitBuffer<RebindAlloc<ALLOC, uint8_t>> readBitBuffer(const ALLOC& allocator = ALLOC()) |
369 | 510 | { |
370 | 510 | const size_t bitSize = static_cast<size_t>(readVarSize()); |
371 | 510 | const BitPosType beginBitPosition = getBitPosition(); |
372 | 510 | if (beginBitPosition + static_cast<uint64_t>(bitSize) > getBufferBitSize()) |
373 | 5 | { |
374 | 5 | throw CppRuntimeException("BitStreamReader: Bit buffer size exceeds available buffer!"); |
375 | 5 | } |
376 | | |
377 | 505 | const size_t numBytesToRead = bitSize / 8; |
378 | 505 | const uint8_t numRestBits = static_cast<uint8_t>(bitSize - numBytesToRead * 8); |
379 | 505 | BasicBitBuffer<RebindAlloc<ALLOC, uint8_t>> bitBuffer(bitSize, allocator); |
380 | 505 | Span<uint8_t> buffer = bitBuffer.getData(); |
381 | 505 | const Span<uint8_t>::iterator itEnd = buffer.begin() + numBytesToRead; |
382 | 505 | if ((beginBitPosition & 0x07U) != 0) |
383 | 54 | { |
384 | | // we are not aligned to byte |
385 | 114 | for (Span<uint8_t>::iterator it = buffer.begin(); it != itEnd; ++it60 ) |
386 | 60 | { |
387 | 60 | *it = static_cast<uint8_t>(readBits(8)); |
388 | 60 | } |
389 | 54 | } |
390 | 451 | else |
391 | 451 | { |
392 | | // we are aligned to byte |
393 | 451 | setBitPosition(beginBitPosition + numBytesToRead * 8); |
394 | 451 | Span<const uint8_t>::const_iterator sourceIt = m_context.buffer.begin() + beginBitPosition / 8; |
395 | 451 | (void)std::copy(sourceIt, sourceIt + numBytesToRead, buffer.begin()); |
396 | 451 | } |
397 | | |
398 | 505 | if (numRestBits > 0) |
399 | 114 | { |
400 | 114 | *itEnd = static_cast<uint8_t>(readBits(numRestBits) << (8U - numRestBits)); |
401 | 114 | } |
402 | | |
403 | 505 | return bitBuffer; |
404 | 510 | } |
405 | | |
406 | | /** |
407 | | * Gets current bit position. |
408 | | * |
409 | | * \return Current bit position. |
410 | | */ |
411 | | BitPosType getBitPosition() const |
412 | 27.4k | { |
413 | 27.4k | return m_context.bitIndex; |
414 | 27.4k | } |
415 | | |
416 | | /** |
417 | | * Sets current bit position. Use with caution! |
418 | | * |
419 | | * \param position New bit position. |
420 | | */ |
421 | | void setBitPosition(BitPosType position); |
422 | | |
423 | | /** |
424 | | * Moves current bit position to perform the requested bit alignment. |
425 | | * |
426 | | * \param alignment Size of the alignment in bits. |
427 | | */ |
428 | | void alignTo(size_t alignment); |
429 | | |
430 | | /** |
431 | | * Gets size of the underlying buffer in bits. |
432 | | * |
433 | | * \return Buffer bit size. |
434 | | */ |
435 | | size_t getBufferBitSize() const |
436 | 3.24k | { |
437 | 3.24k | return m_context.bufferBitSize; |
438 | 3.24k | } |
439 | | |
440 | | /** |
441 | | * Gets the maximum initial array capacity in bytes. |
442 | | * |
443 | | * \return Maximum array preallocation. |
444 | | */ |
445 | | size_t getMaxArrayPreallocation() const |
446 | 3.78k | { |
447 | 3.78k | return m_context.maxArrayPreallocation; |
448 | 3.78k | } |
449 | | |
450 | | private: |
451 | | uint8_t readByte(); |
452 | | |
453 | | ReaderContext m_context; |
454 | | }; |
455 | | |
456 | | } // namespace zserio |
457 | | |
458 | | #endif // ifndef ZSERIO_BIT_STREAM_READER_H_INC |