varint.hpp
Go to the documentation of this file.
#ifndef PROTOZERO_VARINT_HPP
#define PROTOZERO_VARINT_HPP
/*****************************************************************************
protozero - Minimalistic protocol buffer decoder and encoder in C++.
This file is from https://github.com/mapbox/protozero where you can find more
documentation.
*****************************************************************************/
#include <protozero/exception.hpp>
#include <cstdint>
namespace protozero {
constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
namespace detail {
// from https://github.com/facebook/folly/blob/master/folly/Varint.h
inline uint64_t decode_varint_impl(const char** data, const char* end) {
const auto begin = reinterpret_cast<const int8_t*>(*data);
const auto iend = reinterpret_cast<const int8_t*>(end);
const int8_t* p = begin;
uint64_t val = 0;
if (iend - begin >= max_varint_length) { // fast path
do {
int64_t b;
b = *p++; val = ((uint64_t(b) & 0x7fu) ); if (b >= 0) { break; }
b = *p++; val |= ((uint64_t(b) & 0x7fu) << 7u); if (b >= 0) { break; }
b = *p++; val |= ((uint64_t(b) & 0x7fu) << 14u); if (b >= 0) { break; }
b = *p++; val |= ((uint64_t(b) & 0x7fu) << 21u); if (b >= 0) { break; }
b = *p++; val |= ((uint64_t(b) & 0x7fu) << 28u); if (b >= 0) { break; }
b = *p++; val |= ((uint64_t(b) & 0x7fu) << 35u); if (b >= 0) { break; }
b = *p++; val |= ((uint64_t(b) & 0x7fu) << 42u); if (b >= 0) { break; }
b = *p++; val |= ((uint64_t(b) & 0x7fu) << 49u); if (b >= 0) { break; }
b = *p++; val |= ((uint64_t(b) & 0x7fu) << 56u); if (b >= 0) { break; }
b = *p++; val |= ((uint64_t(b) & 0x01u) << 63u); if (b >= 0) { break; }
throw varint_too_long_exception{};
} while (false);
} else {
unsigned int shift = 0;
while (p != iend && *p < 0) {
val |= (uint64_t(*p++) & 0x7fu) << shift;
shift += 7;
}
if (p == iend) {
throw end_of_buffer_exception{};
}
val |= uint64_t(*p++) << shift;
}
*data = reinterpret_cast<const char*>(p);
return val;
}
} // end namespace detail
inline uint64_t decode_varint(const char** data, const char* end) {
// If this is a one-byte varint, decode it here.
if (end != *data && ((static_cast<uint64_t>(**data) & 0x80u) == 0)) {
const auto val = static_cast<uint64_t>(**data);
++(*data);
return val;
}
// If this varint is more than one byte, defer to complete implementation.
return detail::decode_varint_impl(data, end);
}
inline void skip_varint(const char** data, const char* end) {
const auto begin = reinterpret_cast<const int8_t*>(*data);
const auto iend = reinterpret_cast<const int8_t*>(end);
const int8_t* p = begin;
while (p != iend && *p < 0) {
++p;
}
if (p - begin >= max_varint_length) {
throw varint_too_long_exception{};
}
if (p == iend) {
throw end_of_buffer_exception{};
}
++p;
*data = reinterpret_cast<const char*>(p);
}
template <typename T>
inline int write_varint(T data, uint64_t value) {
int n = 1;
while (value >= 0x80u) {
*data++ = char((value & 0x7fu) | 0x80u);
value >>= 7u;
++n;
}
*data++ = char(value);
return n;
}
inline int length_of_varint(uint64_t value) noexcept {
int n = 1;
while (value >= 0x80u) {
value >>= 7u;
++n;
}
return n;
}
inline constexpr uint32_t encode_zigzag32(int32_t value) noexcept {
return (static_cast<uint32_t>(value) << 1u) ^ static_cast<uint32_t>(-static_cast<int32_t>(static_cast<uint32_t>(value) >> 31u));
}
inline constexpr uint64_t encode_zigzag64(int64_t value) noexcept {
return (static_cast<uint64_t>(value) << 1u) ^ static_cast<uint64_t>(-static_cast<int64_t>(static_cast<uint64_t>(value) >> 63u));
}
inline constexpr int32_t decode_zigzag32(uint32_t value) noexcept {
return static_cast<int32_t>((value >> 1u) ^ static_cast<uint32_t>(-static_cast<int32_t>(value & 1u)));
}
inline constexpr int64_t decode_zigzag64(uint64_t value) noexcept {
return static_cast<int64_t>((value >> 1u) ^ static_cast<uint64_t>(-static_cast<int64_t>(value & 1u)));
}
} // end namespace protozero
#endif // PROTOZERO_VARINT_HPP
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::max_varint_length
constexpr const int8_t max_varint_length
Definition: varint.hpp:28
protozero::encode_zigzag32
constexpr uint32_t encode_zigzag32(int32_t value) noexcept
Definition: varint.hpp:178
protozero::write_varint
int write_varint(T data, uint64_t value)
Definition: varint.hpp:145
protozero::skip_varint
void skip_varint(const char **data, const char *end)
Definition: varint.hpp:112
protozero::length_of_varint
int length_of_varint(uint64_t value) noexcept
Definition: varint.hpp:164
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::varint_too_long_exception
Definition: exception.hpp:41
protozero::end_of_buffer_exception
Definition: exception.hpp:67
protozero::decode_varint
uint64_t decode_varint(const char **data, const char *end)
Definition: varint.hpp:89
protozero
All parts of the protozero header-only library are in this namespace.
Definition: byteswap.hpp:23