43#include "lib/stdcompat/bit.h"
44#include "pw_bytes/span.h"
45#include "pw_preprocessor/compiler.h"
53#define PW_VARINT_MAX_INT32_SIZE_BYTES 5
56#define PW_VARINT_MAX_INT64_SIZE_BYTES 10
60 PW_VARINT_ZERO_TERMINATED_LEAST_SIGNIFICANT = 0,
61 PW_VARINT_ZERO_TERMINATED_MOST_SIGNIFICANT = 1,
62 PW_VARINT_ONE_TERMINATED_LEAST_SIGNIFICANT = 2,
63 PW_VARINT_ONE_TERMINATED_MOST_SIGNIFICANT = 3,
81 kZeroTerminatedLeastSignificant = PW_VARINT_ZERO_TERMINATED_LEAST_SIGNIFICANT,
82 kZeroTerminatedMostSignificant = PW_VARINT_ZERO_TERMINATED_MOST_SIGNIFICANT,
83 kOneTerminatedLeastSignificant = PW_VARINT_ONE_TERMINATED_LEAST_SIGNIFICANT,
84 kOneTerminatedMostSignificant = PW_VARINT_ONE_TERMINATED_MOST_SIGNIFICANT,
111 : (uint64_t(1) << (7 * bytes)) - 1;
121 typename = std::enable_if_t<std::is_integral<T>::value ||
122 std::is_convertible<T, uint64_t>::value>>
126 :
static_cast<size_t>(
127 (64 - cpp20::countl_zero(
static_cast<uint64_t
>(value)) + 6) /
144constexpr size_t Encode(T value,
ByteSpan out_encoded);
145size_t Encode(uint64_t value,
ByteSpan out_encoded,
Format format);
230 size_t out_encoded_size);
235 size_t out_encoded_size);
240 size_t out_encoded_size,
258 uint32_t* out_value);
263 uint64_t* out_value);
274 uint32_t* out_value);
279 uint64_t* out_value);
290#define PW_VARINT_ENCODED_SIZE_BYTES(value) \
291 ((unsigned long long)value < (1u << 7) ? 1u \
292 : (unsigned long long)value < (1u << 14) ? 2u \
293 : (unsigned long long)value < (1u << 21) ? 3u \
294 : (unsigned long long)value < (1u << 28) ? 4u \
295 : (unsigned long long)value < (1llu << 35) ? 5u \
296 : (unsigned long long)value < (1llu << 42) ? 6u \
297 : (unsigned long long)value < (1llu << 49) ? 7u \
298 : (unsigned long long)value < (1llu << 56) ? 8u \
299 : (unsigned long long)value < (1llu << 63) ? 9u \
304namespace pw::varint {
312constexpr size_t DecodeUnsigned(ConstByteSpan encoded,
315 max_count = std::min(encoded.size(), max_count);
317 bool keep_going =
true;
319 if (count >= max_count) {
323 keep_going =
DecodeOneByte(encoded[count], count, out_uvalue);
330constexpr size_t EncodeUnsigned(U uvalue, ByteSpan out_encoded) {
333 if (written >= out_encoded.size()) {
337 }
while (uvalue != 0u);
339 out_encoded[written - 1] &=
static_cast<std::byte
>(0x7f);
346constexpr size_t Encode(T value, ByteSpan out_encoded) {
347 using U = std::conditional_t<
sizeof(T) <=
sizeof(uint32_t),
350 if constexpr (std::is_signed<T>()) {
351 return internal::EncodeUnsigned<U>(
ZigZagEncode(value), out_encoded);
353 return internal::EncodeUnsigned<U>(value, out_encoded);
359 const auto bits =
static_cast<std::byte
>((*value & 0x7Fu) | 0x80u);
366 static_assert(std::is_signed<T>(),
"Zig-zag encoding is for signed integers");
367 using U = std::make_unsigned_t<T>;
368 return static_cast<U
>(
static_cast<U
>(value) << 1) ^
369 static_cast<U
>(value >> (
sizeof(T) * 8 - 1));
374 return Encode(value, out_encoded);
378constexpr size_t Decode(
ConstByteSpan encoded, T* out_value) {
379 static_assert(
sizeof(T) >=
sizeof(uint32_t));
380 using U = std::conditional_t<
sizeof(T) ==
sizeof(uint32_t),
386 size_t count = internal::DecodeUnsigned(encoded, &uvalue, max_count);
387 if constexpr (std::is_signed_v<T>) {
390 *out_value =
static_cast<T
>(uvalue);
399 auto u8 =
static_cast<uint_fast8_t
>(encoded);
400 *out_value |=
static_cast<T
>(u8 & 0x7fu) << (count * 7);
401 return (u8 & 0x80u) != 0u;
407 static_assert(std::is_unsigned<T>(),
408 "Zig-zag decoding is for unsigned integers");
409 return static_cast<std::make_signed_t<T>
>((encoded >> 1) ^
410 (~(encoded & 1) + 1));
void Encode(span< const std::byte > binary, char *output)
Definition: base64.h:109
#define PW_NO_SANITIZE(check)
Definition: compiler.h:158
Format
Describes a custom varint format.
Definition: varint.h:80
constexpr size_t kMaxVarint32SizeBytes
Maximum size of a varint (LEB128) encoded uint32_t.
Definition: varint.h:74
constexpr std::make_unsigned_t< T > ZigZagEncode(T value)
Definition: varint.h:365
constexpr size_t kMaxVarint64SizeBytes
Maximum size of a varint (LEB128) encoded uint64_t.
Definition: varint.h:77
constexpr std::byte EncodeOneByte(T *value)
Definition: varint.h:358
constexpr std::make_signed_t< T > ZigZagDecode(T encoded)
Definition: varint.h:405
constexpr bool DecodeOneByte(std::byte encoded, size_t count, T *out_value)
Definition: varint.h:396
constexpr size_t EncodeLittleEndianBase128(uint64_t value, ByteSpan out_encoded)
Definition: varint.h:372
constexpr size_t EncodedSize(T value)
Computes the size of an integer when encoded as a varint.
Definition: varint.h:123
constexpr uint64_t MaxValueInBytes(size_t bytes)
Returns the maximum (max) integer value that can be encoded as a varint into the specified number of ...
Definition: varint.h:109
pw_varint_Format
Describes a custom varint format.
Definition: varint.h:59
size_t pw_varint_Decode64(const void *encoded, size_t encoded_size, uint64_t *out_value)
size_t pw_varint_Decode32(const void *encoded, size_t encoded_size, uint32_t *out_value)
bool pw_varint_DecodeOneByte64(uint8_t encoded, size_t count, uint64_t *out_value)
uint64_t pw_varint_ZigZagEncode64(int64_t value)
size_t pw_varint_EncodedSizeBytes(uint64_t value)
Computes the size of an integer when encoded as a varint.
#define PW_VARINT_MAX_INT64_SIZE_BYTES
Maximum size of an LEB128-encoded uint64_t.
Definition: varint.h:56
size_t pw_varint_Encode32(uint32_t value, void *out_encoded, size_t out_encoded_size)
size_t pw_varint_EncodeCustom(uint64_t value, void *out_encoded, size_t out_encoded_size, pw_varint_Format format)
#define PW_VARINT_MAX_INT32_SIZE_BYTES
Maximum size of an LEB128-encoded uint32_t.
Definition: varint.h:53
int64_t pw_varint_ZigZagDecode64(uint64_t encoded)
uint8_t pw_varint_EncodeOneByte64(uint64_t *value)
bool pw_varint_DecodeOneByte32(uint8_t encoded, size_t count, uint32_t *out_value)
int32_t pw_varint_ZigZagDecode32(uint32_t encoded)
uint8_t pw_varint_EncodeOneByte32(uint32_t *value)
size_t pw_varint_DecodeCustom(const void *encoded, size_t encoded_size, uint64_t *out_value, pw_varint_Format format)
uint32_t pw_varint_ZigZagEncode32(int32_t value)
size_t pw_varint_Encode64(uint64_t value, void *out_encoded, size_t out_encoded_size)