C/C++ API Reference
Loading...
Searching...
No Matches
varint.h
Go to the documentation of this file.
1// Copyright 2023 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
33
34#include <stdbool.h>
35#include <stddef.h>
36#include <stdint.h>
37
38#include "pw_preprocessor/compiler.h"
39
40#ifdef __cplusplus
41extern "C" {
42#endif
43
45#define PW_VARINT_MAX_INT32_SIZE_BYTES 5
46
48#define PW_VARINT_MAX_INT64_SIZE_BYTES 10
49
53size_t pw_varint_Encode32(uint32_t integer,
54 void* output,
55 size_t output_size_bytes);
56
60size_t pw_varint_Encode64(uint64_t integer,
61 void* output,
62 size_t output_size_bytes);
63
65static inline uint32_t pw_varint_ZigZagEncode32(int32_t n) {
66 return (uint32_t)((uint32_t)n << 1) ^ (uint32_t)(n >> (sizeof(n) * 8 - 1));
67}
68
70static inline uint64_t pw_varint_ZigZagEncode64(int64_t n) {
71 return (uint64_t)((uint64_t)n << 1) ^ (uint64_t)(n >> (sizeof(n) * 8 - 1));
72}
73
76static inline uint8_t pw_varint_EncodeOneByte32(uint32_t* integer) {
77 const uint8_t bits = (uint8_t)((*integer & 0x7Fu) | 0x80u);
78 *integer >>= 7;
79 return bits;
80}
81
83static inline uint8_t pw_varint_EncodeOneByte64(uint64_t* integer) {
84 const uint8_t bits = (uint8_t)((*integer & 0x7Fu) | 0x80u);
85 *integer >>= 7;
86 return bits;
87}
88
90static inline int32_t pw_varint_ZigZagDecode32(uint32_t n)
91 PW_NO_SANITIZE("unsigned-integer-overflow") {
92 return (int32_t)((n >> 1) ^ (~(n & 1) + 1));
93}
94
96static inline int64_t pw_varint_ZigZagDecode64(uint64_t n)
97 PW_NO_SANITIZE("unsigned-integer-overflow") {
98 return (int64_t)((n >> 1) ^ (~(n & 1) + 1));
99}
100
103size_t pw_varint_Decode32(const void* input,
104 size_t input_size_bytes,
105 uint32_t* output);
106
109size_t pw_varint_Decode64(const void* input,
110 size_t input_size_bytes,
111 uint64_t* output);
112
115static inline bool pw_varint_DecodeOneByte32(uint8_t byte,
116 size_t count,
117 uint32_t* value) {
118 *value |= (uint32_t)(byte & 0x7fu) << (count * 7);
119 return (byte & 0x80u) != 0u;
120}
121
124static inline bool pw_varint_DecodeOneByte64(uint8_t byte,
125 size_t count,
126 uint64_t* value) {
127 *value |= (uint64_t)(byte & 0x7fu) << (count * 7);
128 return (byte & 0x80u) != 0u;
129}
130
134#define PW_VARINT_ENCODED_SIZE_BYTES(value) \
135 ((unsigned long long)value < (1u << 7) ? 1u \
136 : (unsigned long long)value < (1u << 14) ? 2u \
137 : (unsigned long long)value < (1u << 21) ? 3u \
138 : (unsigned long long)value < (1u << 28) ? 4u \
139 : (unsigned long long)value < (1llu << 35) ? 5u \
140 : (unsigned long long)value < (1llu << 42) ? 6u \
141 : (unsigned long long)value < (1llu << 49) ? 7u \
142 : (unsigned long long)value < (1llu << 56) ? 8u \
143 : (unsigned long long)value < (1llu << 63) ? 9u \
144 : 10u)
145
147size_t pw_varint_EncodedSizeBytes(uint64_t integer);
148
150typedef enum {
151 PW_VARINT_ZERO_TERMINATED_LEAST_SIGNIFICANT = 0,
152 PW_VARINT_ZERO_TERMINATED_MOST_SIGNIFICANT = 1,
153 PW_VARINT_ONE_TERMINATED_LEAST_SIGNIFICANT = 2,
154 PW_VARINT_ONE_TERMINATED_MOST_SIGNIFICANT = 3,
156
158size_t pw_varint_EncodeCustom(uint64_t integer,
159 void* output,
160 size_t output_size,
161 pw_varint_Format format);
162
164size_t pw_varint_DecodeCustom(const void* input,
165 size_t input_size,
166 uint64_t* output,
167 pw_varint_Format format);
168
169#ifdef __cplusplus
170
171} // extern "C"
172
173#include <limits>
174#include <type_traits>
175
176#include "lib/stdcompat/bit.h"
177#include "pw_span/span.h"
178
179namespace pw {
182namespace varint {
183
186
189
203template <typename T>
204constexpr std::make_unsigned_t<T> ZigZagEncode(T n) {
205 static_assert(std::is_signed<T>(), "Zig-zag encoding is for signed integers");
206 using U = std::make_unsigned_t<T>;
207 return static_cast<U>(static_cast<U>(n) << 1) ^
208 static_cast<U>(n >> (sizeof(T) * 8 - 1));
209}
210
215template <typename T>
216constexpr std::make_signed_t<T> ZigZagDecode(T n)
217 PW_NO_SANITIZE("unsigned-integer-overflow") {
218 static_assert(std::is_unsigned<T>(),
219 "Zig-zag decoding is for unsigned integers");
220 return static_cast<std::make_signed_t<T>>((n >> 1) ^ (~(n & 1) + 1));
221}
222
229template <typename T,
230 typename = std::enable_if_t<std::is_integral<T>::value ||
231 std::is_convertible<T, uint64_t>::value>>
232constexpr size_t EncodedSize(T integer) {
233 if (integer == 0) {
234 return 1;
235 }
236 return static_cast<size_t>(
237 (64 - cpp20::countl_zero(static_cast<uint64_t>(integer)) + 6) / 7);
238}
239
242inline size_t EncodeLittleEndianBase128(uint64_t integer,
243 const span<std::byte>& output) {
244 return pw_varint_Encode64(integer, output.data(), output.size());
245}
246
257template <typename T>
258size_t Encode(T integer, const span<std::byte>& output) {
259 if (std::is_signed<T>()) {
260 using Signed =
261 std::conditional_t<std::is_signed<T>::value, T, std::make_signed_t<T>>;
262 return EncodeLittleEndianBase128(ZigZagEncode(static_cast<Signed>(integer)),
263 output);
264 } else {
265 using Unsigned = std::
266 conditional_t<std::is_signed<T>::value, std::make_unsigned_t<T>, T>;
267 return EncodeLittleEndianBase128(static_cast<Unsigned>(integer), output);
268 }
269}
270
294inline size_t Decode(const span<const std::byte>& input, int64_t* output) {
295 uint64_t value = 0;
296 size_t bytes_read = pw_varint_Decode64(input.data(), input.size(), &value);
297 *output = pw_varint_ZigZagDecode64(value);
298 return bytes_read;
299}
300
302inline size_t Decode(const span<const std::byte>& input, uint64_t* value) {
303 return pw_varint_Decode64(input.data(), input.size(), value);
304}
305
307enum class Format {
308 kZeroTerminatedLeastSignificant = PW_VARINT_ZERO_TERMINATED_LEAST_SIGNIFICANT,
309 kZeroTerminatedMostSignificant = PW_VARINT_ZERO_TERMINATED_MOST_SIGNIFICANT,
310 kOneTerminatedLeastSignificant = PW_VARINT_ONE_TERMINATED_LEAST_SIGNIFICANT,
311 kOneTerminatedMostSignificant = PW_VARINT_ONE_TERMINATED_MOST_SIGNIFICANT,
312};
313
315inline size_t Encode(uint64_t value, span<std::byte> output, Format format) {
316 return pw_varint_EncodeCustom(value,
317 output.data(),
318 output.size(),
319 static_cast<pw_varint_Format>(format));
320}
321
323inline size_t Decode(span<const std::byte> input,
324 uint64_t* value,
325 Format format) {
327 input.data(), input.size(), value, static_cast<pw_varint_Format>(format));
328}
329
352constexpr uint64_t MaxValueInBytes(size_t bytes) {
353 return bytes >= kMaxVarint64SizeBytes ? std::numeric_limits<uint64_t>::max()
354 : (uint64_t(1) << (7 * bytes)) - 1;
355}
356
357} // namespace varint
358} // namespace pw
359
360#endif // __cplusplus
Definition: span_impl.h:235
#define PW_NO_SANITIZE(check)
Definition: compiler.h:158
constexpr std::make_unsigned_t< T > ZigZagEncode(T n)
Definition: varint.h:204
Format
Describes a custom varint format.
Definition: varint.h:307
constexpr size_t kMaxVarint32SizeBytes
Maximum size of a varint (LEB128) encoded uint32_t.
Definition: varint.h:185
constexpr size_t kMaxVarint64SizeBytes
Maximum size of a varint (LEB128) encoded uint64_t.
Definition: varint.h:188
constexpr std::make_signed_t< T > ZigZagDecode(T n)
Definition: varint.h:216
size_t Encode(T integer, const span< std::byte > &output)
Definition: varint.h:258
size_t Decode(const span< const std::byte > &input, int64_t *output)
Definition: varint.h:294
constexpr size_t EncodedSize(T integer)
Computes the size of an integer when encoded as a varint.
Definition: varint.h:232
size_t EncodeLittleEndianBase128(uint64_t integer, const span< std::byte > &output)
Definition: varint.h:242
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:352
The Pigweed namespace.
Definition: alignment.h:27
pw_varint_Format
Describes a custom varint format.
Definition: varint.h:150
size_t pw_varint_Decode32(const void *input, size_t input_size_bytes, uint32_t *output)
size_t pw_varint_Encode64(uint64_t integer, void *output, size_t output_size_bytes)
static uint8_t pw_varint_EncodeOneByte64(uint64_t *integer)
Definition: varint.h:83
static uint8_t pw_varint_EncodeOneByte32(uint32_t *integer)
Definition: varint.h:76
static uint32_t pw_varint_ZigZagEncode32(int32_t n)
Zig-zag encodes an int32_t, returning it as a uint32_t.
Definition: varint.h:65
#define PW_VARINT_MAX_INT64_SIZE_BYTES
Maximum size of an LEB128-encoded uint64_t.
Definition: varint.h:48
static bool pw_varint_DecodeOneByte64(uint8_t byte, size_t count, uint64_t *value)
Definition: varint.h:124
size_t pw_varint_EncodeCustom(uint64_t integer, void *output, size_t output_size, pw_varint_Format format)
Encodes a uint64_t using a custom varint format.
#define PW_VARINT_MAX_INT32_SIZE_BYTES
Maximum size of an LEB128-encoded uint32_t.
Definition: varint.h:45
size_t pw_varint_EncodedSizeBytes(uint64_t integer)
Returns the size of a uint64_t when encoded as a varint (LEB128).
size_t pw_varint_Decode64(const void *input, size_t input_size_bytes, uint64_t *output)
static int32_t pw_varint_ZigZagDecode32(uint32_t n)
Zig-zag decodes a uint64_t, returning it as an int64_t.
Definition: varint.h:90
size_t pw_varint_DecodeCustom(const void *input, size_t input_size, uint64_t *output, pw_varint_Format format)
Decodes a uint64_t using a custom varint format.
static int64_t pw_varint_ZigZagDecode64(uint64_t n)
Zig-zag decodes a uint64_t, returning it as an int64_t.
Definition: varint.h:96
static bool pw_varint_DecodeOneByte32(uint8_t byte, size_t count, uint32_t *value)
Definition: varint.h:115
size_t pw_varint_Encode32(uint32_t integer, void *output, size_t output_size_bytes)
static uint64_t pw_varint_ZigZagEncode64(int64_t n)
Zig-zag encodes an int64_t, returning it as a uint64_t.
Definition: varint.h:70