roo_io
API Documentation for roo_io
Loading...
Searching...
No Matches
read.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstring>
4#include <limits>
5#include <type_traits>
6
7#include "roo_backport.h"
8#include "roo_backport/string_view.h"
11#include "roo_io/data/ieee754.h"
13
14namespace roo_io {
15
16// Unsigned.
17
18// Reads an unsigned 8-bit int from the specified iterator.
19template <typename InputIterator>
21 return (uint8_t)in.read();
22}
23
24// Reads a big-endian unsigned 16-bit int from the specified iterator.
25template <typename InputIterator>
27 return ((uint16_t)in.read() << 8) | ((uint16_t)in.read() << 0);
28}
29
30// Reads a little-endian unsigned 16-bit int from the specified iterator.
31template <typename InputIterator>
33 return ((uint16_t)in.read() << 0) | ((uint16_t)in.read() << 8);
34}
35
36// Reads a big-endian unsigned 24-bit int from the specified iterator.
37template <typename InputIterator>
39 return ((uint32_t)in.read() << 16) | ((uint32_t)in.read() << 8) |
40 ((uint32_t)in.read() << 0);
41}
42
43// Reads a little-endian unsigned 24-bit int from the specified iterator.
44template <typename InputIterator>
46 return ((uint32_t)in.read() << 0) | ((uint32_t)in.read() << 8) |
47 ((uint32_t)in.read() << 16);
48}
49
50// Reads a big-endian unsigned 32-bit int from the specified iterator.
51template <typename InputIterator>
53 return ((uint32_t)in.read() << 24) | ((uint32_t)in.read() << 16) |
54 ((uint32_t)in.read() << 8) | ((uint32_t)in.read() << 0);
55}
56
57// Reads a little-endian unsigned 32-bit int from the specified iterator.
58template <typename InputIterator>
60 return ((uint32_t)in.read() << 0) | ((uint32_t)in.read() << 8) |
61 ((uint32_t)in.read() << 16) | ((uint32_t)in.read() << 24);
62}
63
64// Reads a big-endian unsigned 64-bit int from the specified iterator.
65template <typename InputIterator>
67 return ((uint64_t)ReadBeU32(in) << 32) | ReadBeU32(in);
68}
69
70// Reads a little-endian unsigned 64-bit int from the specified iterator.
71template <typename InputIterator>
73 return ReadLeU32(in) | ((uint64_t)ReadLeU32(in) << 32);
74}
75
76// Signed.
77
78// Reads a signed 8-bit int from the specified iterator.
79template <typename InputIterator>
81 return (int8_t)in.read();
82}
83
84// Reads a big-endian signed 16-bit int from the specified iterator.
85template <typename InputIterator>
87 return (int16_t)ReadBeU16(in);
88}
89
90// Reads a little-endian signed 16-bit int from the specified iterator.
91template <typename InputIterator>
93 return (int16_t)ReadLeU16(in);
94}
95
96namespace internal {
97
98// Copies the sign bit (23th bit) to the top 8 bits.
100 return v | (((v & 0x00800000) > 0) * 0xFF000000);
101}
102
103} // namespace internal
104
105// Reads a big-endian signed 24-bit int from the specified iterator.
106template <typename InputIterator>
110
111// Reads a little-endian signed 24-bit int from the specified iterator.
112template <typename InputIterator>
116
117// Reads a big-endian signed 32-bit int from the specified iterator.
118template <typename InputIterator>
120 return (int32_t)ReadBeU32(in);
121}
122
123// Reads a little-endian signed 32-bit int from the specified iterator.
124template <typename InputIterator>
126 return (int32_t)ReadLeU32(in);
127}
128
129// Reads a big-endian signed 64-bit int from the specified iterator.
130template <typename InputIterator>
132 return (int64_t)ReadBeU64(in);
133}
134
135// Reads a little-endian signed 64-bit int from the specified iterator.
136template <typename InputIterator>
138 return (int64_t)ReadLeU64(in);
139}
140
141#if ROO_IO_IEEE754
142// Reads a big-endian IEEE754 float from the specified iterator.
143template <typename InputIterator>
144inline float ReadBeFloat(InputIterator& in) {
145 static_assert(sizeof(float) == sizeof(uint32_t),
146 "ReadBeFloat requires 32-bit float.");
147 static_assert(std::numeric_limits<float>::is_iec559,
148 "ReadBeFloat requires IEEE754 float.");
150 float value;
151 memcpy(&value, &bits, sizeof(value));
152 return value;
153}
154
155// Reads a little-endian IEEE754 float from the specified iterator.
156template <typename InputIterator>
157inline float ReadLeFloat(InputIterator& in) {
158 static_assert(sizeof(float) == sizeof(uint32_t),
159 "ReadLeFloat requires 32-bit float.");
160 static_assert(std::numeric_limits<float>::is_iec559,
161 "ReadLeFloat requires IEEE754 float.");
163 float value;
164 memcpy(&value, &bits, sizeof(value));
165 return value;
166}
167
168// Reads a big-endian IEEE754 double from the specified iterator.
169template <typename InputIterator>
170inline double ReadBeDouble(InputIterator& in) {
171 static_assert(sizeof(double) == sizeof(uint64_t),
172 "ReadBeDouble requires 64-bit double.");
173 static_assert(std::numeric_limits<double>::is_iec559,
174 "ReadBeDouble requires IEEE754 double.");
176 double value;
177 memcpy(&value, &bits, sizeof(value));
178 return value;
179}
180
181// Reads a little-endian IEEE754 double from the specified iterator.
182template <typename InputIterator>
183inline double ReadLeDouble(InputIterator& in) {
184 static_assert(sizeof(double) == sizeof(uint64_t),
185 "ReadLeDouble requires 64-bit double.");
186 static_assert(std::numeric_limits<double>::is_iec559,
187 "ReadLeDouble requires IEEE754 double.");
189 double value;
190 memcpy(&value, &bits, sizeof(value));
191 return value;
192}
193#endif // ROO_IO_IEEE754
194
195// Reads `count` bytes from the input iterator, storing them in the result.
196// Returns the number of bytes successfully read. If the returned value is
197// smaller than `count`, it indicates that the end of stream has been reached,
198// or that an error was encountered. The `status()` of the underlying iterator
199// can be used to determine the cause.
200template <typename InputIterator>
201size_t ReadByteArray(InputIterator& in, byte* result, size_t count) {
202 size_t read_total = 0;
203 while (count > 0) {
204 size_t read_now = in.read(result, count);
205 if (read_now == 0) break;
206 result += read_now;
208 count -= read_now;
209 }
210 return read_total;
211}
212
213// Reads an unsigned 64-bit integer, encoded using variable-length encoding as
214// defined by Google protocol buffers. (Small numbers take little space; numbers
215// up to 127 take 1 byte).
216template <typename InputIterator>
218 uint64_t result = 0;
219 byte read;
220 int shift = 0;
221 do {
222 read = in.read();
223 if (in.status() != kOk) {
224 return 0;
225 }
226 result |= ((uint64_t)(read & byte{0x7F}) << shift);
227 shift += 7;
228 } while ((read & byte{0x80}) != byte{0});
229 return result;
230}
231
232// Helper to read integers templated on the byte order.
233template <ByteOrder byte_order>
235
236template <>
238 public:
239 template <typename InputIterator>
240 constexpr uint16_t readU16(InputIterator& in) const {
241 return ReadBeU16(in);
242 }
243
244 template <typename InputIterator>
245 constexpr uint32_t readU24(InputIterator& in) const {
246 return ReadBeU24(in);
247 }
248
249 template <typename InputIterator>
250 constexpr uint32_t readU32(InputIterator& in) const {
251 return ReadBeU32(in);
252 }
253
254 template <typename InputIterator>
255 constexpr uint64_t readU64(InputIterator& in) const {
256 return ReadBeU64(in);
257 }
258
259 template <typename InputIterator>
260 constexpr int16_t readS16(InputIterator& in) const {
261 return ReadBeS16(in);
262 }
263
264 template <typename InputIterator>
265 constexpr int32_t readS24(InputIterator& in) const {
266 return ReadBeS24(in);
267 }
268
269 template <typename InputIterator>
270 constexpr int32_t readS32(InputIterator& in) const {
271 return ReadBeS32(in);
272 }
273
274 template <typename InputIterator>
275 constexpr int64_t readS64(InputIterator& in) const {
276 return ReadBeS64(in);
277 }
278
279 // template <typename InputIterator>
280 // constexpr float read_float(InputIterator& in) const {
281 // return *reinterpret_cast<float*>(reinterpret_cast<char*>(&read_u32(in)));
282 // }
283};
284
285template <>
287 public:
288 template <typename InputIterator>
289 constexpr uint16_t readU16(InputIterator& in) const {
290 return ReadLeU16(in);
291 }
292
293 template <typename InputIterator>
294 constexpr uint32_t readU24(InputIterator& in) const {
295 return ReadLeU24(in);
296 }
297
298 template <typename InputIterator>
299 constexpr uint32_t readU32(InputIterator& in) const {
300 return ReadLeU32(in);
301 }
302
303 template <typename InputIterator>
304 constexpr uint64_t readU64(InputIterator& in) const {
305 return ReadLeU64(in);
306 }
307
308 template <typename InputIterator>
309 constexpr int16_t readS16(InputIterator& in) const {
310 return ReadLeS16(in);
311 }
312
313 template <typename InputIterator>
314 constexpr int32_t readS24(InputIterator& in) const {
315 return ReadLeS24(in);
316 }
317
318 template <typename InputIterator>
319 constexpr int32_t readS32(InputIterator& in) const {
320 return ReadLeS32(in);
321 }
322
323 template <typename InputIterator>
324 constexpr int64_t readS64(InputIterator& in) const {
325 return ReadLeS64(in);
326 }
327
328 // template <typename InputIterator>
329 // constexpr float read_float(InputIterator& in) const {
330 // return *reinterpret_cast<float*>(reinterpret_cast<char*>(&read_u32(in)));
331 // }
332};
333
334#if ROO_IO_IEEE754
335// Helper to read IEEE754 floats/doubles templated on byte order.
336template <ByteOrder byte_order>
337class FloatReader;
338
339template <>
340class FloatReader<kBigEndian> {
341 public:
342 template <typename InputIterator>
343 inline float readFloat(InputIterator& in) const {
344 return ReadBeFloat(in);
345 }
346
347 template <typename InputIterator>
348 inline double readDouble(InputIterator& in) const {
349 return ReadBeDouble(in);
350 }
351};
352
353template <>
355 public:
356 template <typename InputIterator>
357 inline float readFloat(InputIterator& in) const {
358 return ReadLeFloat(in);
359 }
360
361 template <typename InputIterator>
362 inline double readDouble(InputIterator& in) const {
363 return ReadLeDouble(in);
364 }
365};
366#endif // ROO_IO_IEEE754
367
368template <typename InputIterator, ByteOrder byte_order>
370 return IntegerReader<byte_order>().readU16(in);
371}
372
373template <typename InputIterator, ByteOrder byte_order>
375 return IntegerReader<byte_order>().readU24(in);
376}
377
378template <typename InputIterator, ByteOrder byte_order>
380 return IntegerReader<byte_order>().readU32(in);
381}
382
383template <typename InputIterator, ByteOrder byte_order>
385 return IntegerReader<byte_order>().readU64(in);
386}
387
388#if ROO_IO_IEEE754
389template <typename InputIterator, ByteOrder byte_order>
390inline float ReadFloat(InputIterator& in) {
391 return FloatReader<byte_order>().readFloat(in);
392}
393
394template <typename InputIterator, ByteOrder byte_order>
395inline double ReadDouble(InputIterator& in) {
396 return FloatReader<byte_order>().readDouble(in);
397}
398#endif // ROO_IO_IEEE754
399
400// Allows reading platform-native (implementation-dependent) data from an input
401// iterator. T must be default-constructible and have trivial destructor.
402template <typename T>
404 public:
405 // Reads T from the iterator. If T cannot be fully read, a default value is
406 // returned.
407 template <typename InputIterator>
409 T result;
410 if (ReadByteArray(in, (byte*)&result, sizeof(result)) == sizeof(result)) {
411 return result;
412 }
413 return default_value;
414 }
415};
416
417// Reads a string, represented in portable representation (varint length
418// followed by the character array), as a C string, into the specified buffer
419// `buf` of specified `capacity`, and returns the length of the returned C
420// string.
421//
422// If the string won't fit into the buffer, i.e. if the string's lengh plus 1
423// (to account for the terminating zero) is greater than `capacity`, the
424// returned string gets truncated. As long as `capacity` is greater than zero,
425// the result gets zero-terminated. The return value indicates the actual
426// returned length, not counting the terminal zero.
427//
428// Regardless whether the string gets truncated or not, it is always entirely
429// skipped in the input stream, so that subsequent reads can access the data
430// past the string.
431template <typename InputIterator>
432size_t ReadCString(InputIterator& in, char* buf, size_t capacity = SIZE_MAX) {
434 if (in.status() != kOk) return 0;
435 if (len + 1 <= capacity) {
436 // Common case.
437 size_t written = ReadByteArray(in, (byte*)buf, len);
438 buf[written] = 0;
439 return written;
440 }
441 if (capacity > 0) {
442 size_t written = ReadByteArray(in, (byte*)buf, capacity - 1);
443 buf[written] = 0;
444 in.skip(len - written);
445 return written;
446 }
447 in.skip(len);
448 return 0;
449}
450
451// Reads a string, represented in portable representation (varint length
452// followed by the character array), up to `max_size` length.
453//
454// If the string length exceeds `max_size`, the result gets truncated to
455// `max_size`, but the entire string gets skipped in the input stream.
456template <typename InputIterator>
457std::string ReadString(InputIterator& in, size_t max_size = SIZE_MAX) {
459 if (in.status() != kOk) return "";
460 std::string result;
461 if (len <= max_size) {
462 // Common case.
463 result.reserve(len);
464 for (size_t i = 0; i < len; ++i) {
465 char ch = (char)ReadU8(in);
466 if (in.status() != kOk) return result;
467 result.push_back(ch);
468 }
469 return result;
470 }
471 result.reserve(max_size);
472 for (size_t i = 0; i < max_size; ++i) {
473 char ch = (char)ReadU8(in);
474 if (in.status() != kOk) return result;
475 result.push_back(ch);
476 }
477 in.skip(len - max_size);
478 return result;
479}
480
481// For memory iterators only. Reads a string, represented in portable
482// representation (varint length followed by the character array), as
483// a string_view up to `max_size` length, without copying the underlying data.
484// (The returned string_view is backed by the underlying iterator's memory
485// buffer).
486//
487// If the string length exceeds `max_size`, the result gets truncated to
488// `max_size`, but the entire string gets skipped in the input stream.
489template <typename InputIterator,
490 typename std::enable_if<
491 internal::MemoryIteratorTraits<InputIterator>::is_memory,
492 bool>::type = true>
493roo::string_view ReadStringView(InputIterator& in, size_t max_size = SIZE_MAX) {
495 if (in.status() != kOk) return "";
496 typename InputIterator::PtrType start = in.ptr();
497 if (len <= max_size) {
498 // Common case.
499 in.skip(len);
500 return roo::string_view((const char*)start, in.ptr() - start);
501 }
502 in.skip(max_size);
503 roo::string_view result((const char*)start, in.ptr() - start);
504 in.skip(len - max_size);
505 return result;
506}
507
508} // namespace roo_io
constexpr int32_t readS32(InputIterator &in) const
Definition read.h:270
constexpr uint32_t readU32(InputIterator &in) const
Definition read.h:250
constexpr int32_t readS24(InputIterator &in) const
Definition read.h:265
constexpr uint64_t readU64(InputIterator &in) const
Definition read.h:255
constexpr uint32_t readU24(InputIterator &in) const
Definition read.h:245
constexpr int16_t readS16(InputIterator &in) const
Definition read.h:260
constexpr uint16_t readU16(InputIterator &in) const
Definition read.h:240
constexpr int64_t readS64(InputIterator &in) const
Definition read.h:275
constexpr int64_t readS64(InputIterator &in) const
Definition read.h:324
constexpr uint32_t readU24(InputIterator &in) const
Definition read.h:294
constexpr uint16_t readU16(InputIterator &in) const
Definition read.h:289
constexpr uint64_t readU64(InputIterator &in) const
Definition read.h:304
constexpr int32_t readS32(InputIterator &in) const
Definition read.h:319
constexpr uint32_t readU32(InputIterator &in) const
Definition read.h:299
constexpr int16_t readS16(InputIterator &in) const
Definition read.h:309
constexpr int32_t readS24(InputIterator &in) const
Definition read.h:314
constexpr int32_t sign_extend_24(int32_t v)
Definition read.h:99
Definition byte.h:6
constexpr uint32_t ReadBeU32(InputIterator &in)
Definition read.h:52
size_t ReadCString(InputIterator &in, char *buf, size_t capacity=SIZE_MAX)
Definition read.h:432
constexpr uint64_t ReadLeU64(InputIterator &in)
Definition read.h:72
constexpr uint16_t ReadBeU16(InputIterator &in)
Definition read.h:26
roo::basic_string_view< CharT, Traits > basic_string_view
Definition string_view.h:8
constexpr uint32_t ReadLeU24(InputIterator &in)
Definition read.h:45
constexpr int16_t ReadBeS16(InputIterator &in)
Definition read.h:86
constexpr uint16_t ReadU16(InputIterator &in)
Definition read.h:369
size_t ReadByteArray(InputIterator &in, byte *result, size_t count)
Definition read.h:201
constexpr uint32_t ReadBeU24(InputIterator &in)
Definition read.h:38
constexpr uint32_t ReadU32(InputIterator &in)
Definition read.h:379
constexpr uint32_t ReadU24(InputIterator &in)
Definition read.h:374
constexpr int64_t ReadBeS64(InputIterator &in)
Definition read.h:131
constexpr int64_t ReadLeS64(InputIterator &in)
Definition read.h:137
constexpr int32_t ReadBeS24(InputIterator &in)
Definition read.h:107
size_t count
Definition compare.h:45
constexpr int8_t ReadS8(InputIterator &in)
Definition read.h:80
constexpr uint64_t ReadU64(InputIterator &in)
Definition read.h:384
constexpr uint64_t ReadBeU64(InputIterator &in)
Definition read.h:66
roo::string_view ReadStringView(InputIterator &in, size_t max_size=SIZE_MAX)
Definition read.h:493
constexpr uint32_t ReadLeU32(InputIterator &in)
Definition read.h:59
constexpr int32_t ReadBeS32(InputIterator &in)
Definition read.h:119
@ kOk
Definition status.h:8
constexpr int16_t ReadLeS16(InputIterator &in)
Definition read.h:92
constexpr int32_t ReadLeS32(InputIterator &in)
Definition read.h:125
uint64_t ReadVarU64(InputIterator &in)
Definition read.h:217
constexpr int32_t ReadLeS24(InputIterator &in)
Definition read.h:113
constexpr uint8_t ReadU8(InputIterator &in)
Definition read.h:20
@ kLittleEndian
Definition byte_order.h:16
@ kBigEndian
Definition byte_order.h:17
constexpr uint16_t ReadLeU16(InputIterator &in)
Definition read.h:32
std::string ReadString(InputIterator &in, size_t max_size=SIZE_MAX)
Definition read.h:457
T read(InputIterator &in, T default_value=T()) const
Definition read.h:408