protozero  1.6.8
Minimalistic protocol buffer decoder and encoder in C++.
varint.hpp
Go to the documentation of this file.
1 #ifndef PROTOZERO_VARINT_HPP
2 #define PROTOZERO_VARINT_HPP
3 
4 /*****************************************************************************
5 
6 protozero - Minimalistic protocol buffer decoder and encoder in C++.
7 
8 This file is from https://github.com/mapbox/protozero where you can find more
9 documentation.
10 
11 *****************************************************************************/
12 
19 #include <protozero/exception.hpp>
20 
21 #include <cstdint>
22 
23 namespace protozero {
24 
28 constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
29 
30 namespace detail {
31 
32  // from https://github.com/facebook/folly/blob/master/folly/Varint.h
33  inline uint64_t decode_varint_impl(const char** data, const char* end) {
34  const auto begin = reinterpret_cast<const int8_t*>(*data);
35  const auto iend = reinterpret_cast<const int8_t*>(end);
36  const int8_t* p = begin;
37  uint64_t val = 0;
38 
39  if (iend - begin >= max_varint_length) { // fast path
40  do {
41  int64_t b;
42  b = *p++; val = ((uint64_t(b) & 0x7fU) ); if (b >= 0) { break; }
43  b = *p++; val |= ((uint64_t(b) & 0x7fU) << 7U); if (b >= 0) { break; }
44  b = *p++; val |= ((uint64_t(b) & 0x7fU) << 14U); if (b >= 0) { break; }
45  b = *p++; val |= ((uint64_t(b) & 0x7fU) << 21U); if (b >= 0) { break; }
46  b = *p++; val |= ((uint64_t(b) & 0x7fU) << 28U); if (b >= 0) { break; }
47  b = *p++; val |= ((uint64_t(b) & 0x7fU) << 35U); if (b >= 0) { break; }
48  b = *p++; val |= ((uint64_t(b) & 0x7fU) << 42U); if (b >= 0) { break; }
49  b = *p++; val |= ((uint64_t(b) & 0x7fU) << 49U); if (b >= 0) { break; }
50  b = *p++; val |= ((uint64_t(b) & 0x7fU) << 56U); if (b >= 0) { break; }
51  b = *p++; val |= ((uint64_t(b) & 0x01U) << 63U); if (b >= 0) { break; }
53  } while (false);
54  } else {
55  unsigned int shift = 0;
56  while (p != iend && *p < 0) {
57  val |= (uint64_t(*p++) & 0x7fU) << shift;
58  shift += 7;
59  }
60  if (p == iend) {
62  }
63  val |= uint64_t(*p++) << shift;
64  }
65 
66  *data = reinterpret_cast<const char*>(p);
67  return val;
68  }
69 
70 } // end namespace detail
71 
89 inline uint64_t decode_varint(const char** data, const char* end) {
90  // If this is a one-byte varint, decode it here.
91  if (end != *data && ((static_cast<uint64_t>(**data) & 0x80U) == 0)) {
92  const auto val = static_cast<uint64_t>(**data);
93  ++(*data);
94  return val;
95  }
96  // If this varint is more than one byte, defer to complete implementation.
97  return detail::decode_varint_impl(data, end);
98 }
99 
112 inline void skip_varint(const char** data, const char* end) {
113  const auto begin = reinterpret_cast<const int8_t*>(*data);
114  const auto iend = reinterpret_cast<const int8_t*>(end);
115  const int8_t* p = begin;
116 
117  while (p != iend && *p < 0) {
118  ++p;
119  }
120 
121  if (p - begin >= max_varint_length) {
123  }
124 
125  if (p == iend) {
126  throw end_of_buffer_exception{};
127  }
128 
129  ++p;
130 
131  *data = reinterpret_cast<const char*>(p);
132 }
133 
144 template <typename T>
145 inline int write_varint(T data, uint64_t value) {
146  int n = 1;
147 
148  while (value >= 0x80U) {
149  *data++ = char((value & 0x7fU) | 0x80U);
150  value >>= 7U;
151  ++n;
152  }
153  *data++ = char(value);
154 
155  return n;
156 }
157 
164 inline int length_of_varint(uint64_t value) noexcept {
165  int n = 1;
166 
167  while (value >= 0x80U) {
168  value >>= 7U;
169  ++n;
170  }
171 
172  return n;
173 }
174 
178 inline constexpr uint32_t encode_zigzag32(int32_t value) noexcept {
179  return (static_cast<uint32_t>(value) << 1U) ^ static_cast<uint32_t>(-static_cast<int32_t>(static_cast<uint32_t>(value) >> 31U));
180 }
181 
185 inline constexpr uint64_t encode_zigzag64(int64_t value) noexcept {
186  return (static_cast<uint64_t>(value) << 1U) ^ static_cast<uint64_t>(-static_cast<int64_t>(static_cast<uint64_t>(value) >> 63U));
187 }
188 
192 inline constexpr int32_t decode_zigzag32(uint32_t value) noexcept {
193  return static_cast<int32_t>((value >> 1U) ^ static_cast<uint32_t>(-static_cast<int32_t>(value & 1U)));
194 }
195 
199 inline constexpr int64_t decode_zigzag64(uint64_t value) noexcept {
200  return static_cast<int64_t>((value >> 1U) ^ static_cast<uint64_t>(-static_cast<int64_t>(value & 1U)));
201 }
202 
203 } // end namespace protozero
204 
205 #endif // PROTOZERO_VARINT_HPP
protozero::varint_too_long_exception
Definition: exception.hpp:41
protozero
All parts of the protozero header-only library are in this namespace.
Definition: byteswap.hpp:23
protozero::length_of_varint
int length_of_varint(uint64_t value) noexcept
Definition: varint.hpp:164
protozero::max_varint_length
constexpr const int8_t max_varint_length
Definition: varint.hpp:28
protozero::encode_zigzag64
constexpr uint64_t encode_zigzag64(int64_t value) noexcept
Definition: varint.hpp:185
protozero::decode_zigzag64
constexpr int64_t decode_zigzag64(uint64_t value) noexcept
Definition: varint.hpp:199
protozero::write_varint
int write_varint(T data, uint64_t value)
Definition: varint.hpp:145
protozero::encode_zigzag32
constexpr uint32_t encode_zigzag32(int32_t value) noexcept
Definition: varint.hpp:178
protozero::decode_zigzag32
constexpr int32_t decode_zigzag32(uint32_t value) noexcept
Definition: varint.hpp:192
exception.hpp
Contains the exceptions used in the protozero library.
protozero::decode_varint
uint64_t decode_varint(const char **data, const char *end)
Definition: varint.hpp:89
protozero::end_of_buffer_exception
Definition: exception.hpp:67
protozero::skip_varint
void skip_varint(const char **data, const char *end)
Definition: varint.hpp:112