protozero  1.8.0
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 "buffer_tmpl.hpp"
20 #include "exception.hpp"
21 
22 #include <cstdint>
23 
24 namespace protozero {
25 
29 constexpr const int8_t max_varint_length = (sizeof(uint64_t) * 8 / 7) + 1;
30 
31 namespace detail {
32 
33  // from https://github.com/facebook/folly/blob/master/folly/Varint.h
34  inline uint64_t decode_varint_impl(const char** data, const char* end) {
35  const auto* begin = reinterpret_cast<const int8_t*>(*data);
36  const auto* iend = reinterpret_cast<const int8_t*>(end);
37  const int8_t* p = begin;
38  uint64_t val = 0;
39 
40  if (iend - begin >= max_varint_length) { // fast path
41  do {
42  int64_t b = *p++;
43  val = ((static_cast<uint64_t>(b) & 0x7fU) ); if (b >= 0) { break; }
44  b = *p++; val |= ((static_cast<uint64_t>(b) & 0x7fU) << 7U); if (b >= 0) { break; }
45  b = *p++; val |= ((static_cast<uint64_t>(b) & 0x7fU) << 14U); if (b >= 0) { break; }
46  b = *p++; val |= ((static_cast<uint64_t>(b) & 0x7fU) << 21U); if (b >= 0) { break; }
47  b = *p++; val |= ((static_cast<uint64_t>(b) & 0x7fU) << 28U); if (b >= 0) { break; }
48  b = *p++; val |= ((static_cast<uint64_t>(b) & 0x7fU) << 35U); if (b >= 0) { break; }
49  b = *p++; val |= ((static_cast<uint64_t>(b) & 0x7fU) << 42U); if (b >= 0) { break; }
50  b = *p++; val |= ((static_cast<uint64_t>(b) & 0x7fU) << 49U); if (b >= 0) { break; }
51  b = *p++; val |= ((static_cast<uint64_t>(b) & 0x7fU) << 56U); if (b >= 0) { break; }
52  b = *p++; val |= ((static_cast<uint64_t>(b) & 0x01U) << 63U); if (b >= 0) { break; }
54  } while (false);
55  } else {
56  unsigned int shift = 0;
57  while (p != iend && *p < 0) {
58  val |= (static_cast<uint64_t>(*p++) & 0x7fU) << shift;
59  shift += 7;
60  }
61  if (p == iend) {
63  }
64  val |= static_cast<uint64_t>(*p++) << shift;
65  }
66 
67  *data = reinterpret_cast<const char*>(p);
68  return val;
69  }
70 
71 } // end namespace detail
72 
90 inline uint64_t decode_varint(const char** data, const char* end) {
91  // If this is a one-byte varint, decode it here.
92  if (end != *data && ((static_cast<uint64_t>(**data) & 0x80U) == 0)) {
93  const auto val = static_cast<uint64_t>(**data);
94  ++(*data);
95  return val;
96  }
97  // If this varint is more than one byte, defer to complete implementation.
98  return detail::decode_varint_impl(data, end);
99 }
100 
113 inline void skip_varint(const char** data, const char* end) {
114  const auto* begin = reinterpret_cast<const int8_t*>(*data);
115  const auto* iend = reinterpret_cast<const int8_t*>(end);
116  const int8_t* p = begin;
117 
118  while (p != iend && *p < 0) {
119  ++p;
120  }
121 
122  if (p - begin >= max_varint_length) {
124  }
125 
126  if (p == iend) {
127  throw end_of_buffer_exception{};
128  }
129 
130  ++p;
131 
132  *data = reinterpret_cast<const char*>(p);
133 }
134 
146 template <typename T>
147 inline int write_varint(T data, uint64_t value) {
148  int n = 1;
149 
150  while (value >= 0x80U) {
151  *data++ = static_cast<char>((value & 0x7fU) | 0x80U);
152  value >>= 7U;
153  ++n;
154  }
155  *data = static_cast<char>(value);
156 
157  return n;
158 }
159 
168 template <typename TBuffer>
169 inline void add_varint_to_buffer(TBuffer* buffer, uint64_t value) {
170  while (value >= 0x80U) {
171  buffer_customization<TBuffer>::push_back(buffer, static_cast<char>((value & 0x7fU) | 0x80U));
172  value >>= 7U;
173  }
174  buffer_customization<TBuffer>::push_back(buffer, static_cast<char>(value));
175 }
176 
184 inline int add_varint_to_buffer(char* data, uint64_t value) noexcept {
185  int n = 1;
186 
187  while (value >= 0x80U) {
188  *data++ = static_cast<char>((value & 0x7fU) | 0x80U);
189  value >>= 7U;
190  ++n;
191  }
192  *data = static_cast<char>(value);
193 
194  return n;
195 }
196 
203 inline int length_of_varint(uint64_t value) noexcept {
204  int n = 1;
205 
206  while (value >= 0x80U) {
207  value >>= 7U;
208  ++n;
209  }
210 
211  return n;
212 }
213 
217 constexpr uint32_t encode_zigzag32(int32_t value) noexcept {
218  return (static_cast<uint32_t>(value) << 1U) ^ static_cast<uint32_t>(-static_cast<int32_t>(static_cast<uint32_t>(value) >> 31U));
219 }
220 
224 constexpr uint64_t encode_zigzag64(int64_t value) noexcept {
225  return (static_cast<uint64_t>(value) << 1U) ^ static_cast<uint64_t>(-static_cast<int64_t>(static_cast<uint64_t>(value) >> 63U));
226 }
227 
231 constexpr int32_t decode_zigzag32(uint32_t value) noexcept {
232  return static_cast<int32_t>((value >> 1U) ^ static_cast<uint32_t>(-static_cast<int32_t>(value & 1U)));
233 }
234 
238 constexpr int64_t decode_zigzag64(uint64_t value) noexcept {
239  return static_cast<int64_t>((value >> 1U) ^ static_cast<uint64_t>(-static_cast<int64_t>(value & 1U)));
240 }
241 
242 } // end namespace protozero
243 
244 #endif // PROTOZERO_VARINT_HPP
Contains the customization points for buffer implementations.
Contains the exceptions used in the protozero library.
All parts of the protozero header-only library are in this namespace.
Definition: basic_pbf_builder.hpp:24
constexpr int32_t decode_zigzag32(uint32_t value) noexcept
Definition: varint.hpp:231
void add_varint_to_buffer(TBuffer *buffer, uint64_t value)
Definition: varint.hpp:169
int length_of_varint(uint64_t value) noexcept
Definition: varint.hpp:203
constexpr uint32_t encode_zigzag32(int32_t value) noexcept
Definition: varint.hpp:217
constexpr int64_t decode_zigzag64(uint64_t value) noexcept
Definition: varint.hpp:238
constexpr uint64_t encode_zigzag64(int64_t value) noexcept
Definition: varint.hpp:224
constexpr const int8_t max_varint_length
Definition: varint.hpp:29
void skip_varint(const char **data, const char *end)
Definition: varint.hpp:113
uint64_t decode_varint(const char **data, const char *end)
Definition: varint.hpp:90
int write_varint(T data, uint64_t value)
Definition: varint.hpp:147
Definition: exception.hpp:67
Definition: exception.hpp:41