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