22
33#include < sourcemeta/core/numeric.h>
44
5- #include " varint.h"
6-
75#include < cassert> // assert
8- #include < ios> // std::ios_base
6+ #include < cstddef> // std::size_t
7+ #include < cstdint> // std::uint8_t, std::uint64_t, std::int64_t
98
109namespace sourcemeta ::jsonbinpack {
1110
12- InputStream::InputStream (Stream &input) : stream{input} {
13- this ->stream .exceptions (std::ios_base::badbit | std::ios_base::failbit |
14- std::ios_base::eofbit);
15- }
16-
17- auto InputStream::position () const noexcept -> std::uint64_t {
18- return static_cast <std::uint64_t >(this ->stream .tellg ());
19- }
20-
21- auto InputStream::seek (const std::uint64_t offset) -> void {
22- this ->stream .seekg (static_cast <std::streamoff>(offset));
23- }
11+ InputStream::InputStream (Stream &input)
12+ : sourcemeta::core::BinaryReader{input} {}
2413
2514auto InputStream::rewind (const std::uint64_t relative_offset,
2615 const std::uint64_t position) -> std::uint64_t {
@@ -32,33 +21,33 @@ auto InputStream::rewind(const std::uint64_t relative_offset,
3221 return current;
3322}
3423
35- auto InputStream::get_byte () -> std::uint8_t {
36- return static_cast <std::uint8_t >(this ->stream .get ());
37- }
38-
39- auto InputStream::get_word () -> std::uint16_t {
40- std::uint16_t word;
41- this ->stream .read (reinterpret_cast <char *>(&word), sizeof word);
42- return word;
43- }
44-
4524auto InputStream::get_varint () -> std::uint64_t {
46- return varint_decode (this ->stream );
47- }
25+ constexpr std::uint8_t LEAST_SIGNIFICANT_BITS {0b01111111 };
26+ constexpr std::uint8_t MOST_SIGNIFICANT_BIT {0b10000000 };
27+ constexpr std::uint8_t SHIFT {7 };
28+ std::uint64_t result{0 };
29+ std::size_t cursor{0 };
30+ while (true ) {
31+ const std::uint8_t byte{this ->get_byte ()};
32+ const std::uint64_t value{
33+ static_cast <std::uint64_t >(byte & LEAST_SIGNIFICANT_BITS )};
34+ #ifndef NDEBUG
35+ const std::uint64_t current = result;
36+ #endif
37+ result += static_cast <std::uint64_t >(value << SHIFT * cursor);
38+ // Try to catch potential overflows from the above addition
39+ assert (result >= current);
40+ cursor += 1 ;
41+ if ((byte & MOST_SIGNIFICANT_BIT ) == 0 ) {
42+ break ;
43+ }
44+ }
4845
49- auto InputStream::get_varint_zigzag () -> std::int64_t {
50- const std::uint64_t value = varint_decode (this ->stream );
51- return sourcemeta::core::zigzag_decode (value);
46+ return result;
5247}
5348
54- auto InputStream::has_more_data () const noexcept -> bool {
55- // A way to check if the stream is empty without using `.peek()`,
56- // which throws given we set exceptions on the EOF bit.
57- // However, `in_avail()` works on characters and will return zero
58- // if all that's remaining is 0x00 (null), so we need to handle
59- // that case separately.
60- return this ->stream .rdbuf ()->in_avail () > 0 ||
61- this ->stream .rdbuf ()->sgetc () == ' \0 ' ;
49+ auto InputStream::get_varint_zigzag () -> std::int64_t {
50+ return sourcemeta::core::zigzag_decode (this ->get_varint ());
6251}
6352
6453auto InputStream::get_string_utf8 (const std::uint64_t length)
0 commit comments