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