1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/bitops.h>
4 #include <linux/math.h>
5 #include <linux/string.h>
6 #include <asm/unaligned.h>
9 #include <valgrind/memcheck.h>
15 * bch2_varint_encode - encode a variable length integer
16 * @out - destination to encode to
17 * @v - unsigned integer to encode
19 * Returns the size in bytes of the encoded integer - at most 9 bytes
21 int bch2_varint_encode(u8 *out, u64 v)
23 unsigned bits = fls64(v|1);
24 unsigned bytes = DIV_ROUND_UP(bits, 7);
27 if (likely(bytes < 9)) {
29 v |= ~(~0 << (bytes - 1));
30 v_le = cpu_to_le64(v);
31 memcpy(out, &v_le, bytes);
35 put_unaligned_le64(v, out);
42 * bch2_varint_decode - encode a variable length integer
43 * @in - varint to decode
44 * @end - end of buffer to decode from
45 * @out - on success, decoded integer
47 * Returns the size in bytes of the decoded integer - or -1 on failure (would
48 * have read past the end of the buffer)
50 int bch2_varint_decode(const u8 *in, const u8 *end, u64 *out)
52 unsigned bytes = likely(in < end)
57 if (unlikely(in + bytes > end))
60 if (likely(bytes < 9)) {
62 memcpy(&v_le, in, bytes);
63 v = le64_to_cpu(v_le);
66 v = get_unaligned_le64(++in);
74 * bch2_varint_encode_fast - fast version of bch2_varint_encode
76 * This version assumes it's always safe to write 8 bytes to @out, even if the
77 * encoded integer would be smaller.
79 int bch2_varint_encode_fast(u8 *out, u64 v)
81 unsigned bits = fls64(v|1);
82 unsigned bytes = DIV_ROUND_UP(bits, 7);
84 if (likely(bytes < 9)) {
86 v |= ~(~0 << (bytes - 1));
92 put_unaligned_le64(v, out);
97 * bch2_varint_decode_fast - fast version of bch2_varint_decode
99 * This version assumes that it is safe to read at most 8 bytes past the end of
100 * @end (we still return an error if the varint extends past @end).
102 int bch2_varint_decode_fast(const u8 *in, const u8 *end, u64 *out)
104 #ifdef CONFIG_VALGRIND
105 VALGRIND_MAKE_MEM_DEFINED(in, 8);
107 u64 v = get_unaligned_le64(in);
108 unsigned bytes = ffz(*in) + 1;
110 if (unlikely(in + bytes > end))
113 if (likely(bytes < 9)) {
115 v &= ~(~0ULL << (7 * bytes));
117 v = get_unaligned_le64(++in);