]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/varint.c
Update bcachefs sources to bed61fae3b bcachefs: Delete a faulty assertion
[bcachefs-tools-debian] / libbcachefs / varint.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/bitops.h>
4 #include <linux/math.h>
5 #include <linux/string.h>
6 #include <asm/unaligned.h>
7
8 #ifdef CONFIG_VALGRIND
9 #include <valgrind/memcheck.h>
10 #endif
11
12 #include "varint.h"
13
14 /**
15  * bch2_varint_encode - encode a variable length integer
16  * @out - destination to encode to
17  * @v   - unsigned integer to encode
18  *
19  * Returns the size in bytes of the encoded integer - at most 9 bytes
20  */
21 int bch2_varint_encode(u8 *out, u64 v)
22 {
23         unsigned bits = fls64(v|1);
24         unsigned bytes = DIV_ROUND_UP(bits, 7);
25         __le64 v_le;
26
27         if (likely(bytes < 9)) {
28                 v <<= bytes;
29                 v |= ~(~0 << (bytes - 1));
30                 v_le = cpu_to_le64(v);
31                 memcpy(out, &v_le, bytes);
32         } else {
33                 *out++ = 255;
34                 bytes = 9;
35                 put_unaligned_le64(v, out);
36         }
37
38         return bytes;
39 }
40
41 /**
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
46  *
47  * Returns the size in bytes of the decoded integer - or -1 on failure (would
48  * have read past the end of the buffer)
49  */
50 int bch2_varint_decode(const u8 *in, const u8 *end, u64 *out)
51 {
52         unsigned bytes = likely(in < end)
53                 ? ffz(*in & 255) + 1
54                 : 1;
55         u64 v;
56
57         if (unlikely(in + bytes > end))
58                 return -1;
59
60         if (likely(bytes < 9)) {
61                 __le64 v_le = 0;
62
63                 memcpy(&v_le, in, bytes);
64                 v = le64_to_cpu(v_le);
65                 v >>= bytes;
66         } else {
67                 v = get_unaligned_le64(++in);
68         }
69
70         *out = v;
71         return bytes;
72 }
73
74 /**
75  * bch2_varint_encode_fast - fast version of bch2_varint_encode
76  *
77  * This version assumes it's always safe to write 8 bytes to @out, even if the
78  * encoded integer would be smaller.
79  */
80 int bch2_varint_encode_fast(u8 *out, u64 v)
81 {
82         unsigned bits = fls64(v|1);
83         unsigned bytes = DIV_ROUND_UP(bits, 7);
84
85         if (likely(bytes < 9)) {
86                 v <<= bytes;
87                 v |= ~(~0 << (bytes - 1));
88         } else {
89                 *out++ = 255;
90                 bytes = 9;
91         }
92
93         put_unaligned_le64(v, out);
94         return bytes;
95 }
96
97 /**
98  * bch2_varint_decode_fast - fast version of bch2_varint_decode
99  *
100  * This version assumes that it is safe to read at most 8 bytes past the end of
101  * @end (we still return an error if the varint extends past @end).
102  */
103 int bch2_varint_decode_fast(const u8 *in, const u8 *end, u64 *out)
104 {
105 #ifdef CONFIG_VALGRIND
106         VALGRIND_MAKE_MEM_DEFINED(in, 8);
107 #endif
108         u64 v = get_unaligned_le64(in);
109         unsigned bytes = ffz(*in) + 1;
110
111         if (unlikely(in + bytes > end))
112                 return -1;
113
114         if (likely(bytes < 9)) {
115                 v >>= bytes;
116                 v &= ~(~0ULL << (7 * bytes));
117         } else {
118                 v = get_unaligned_le64(++in);
119         }
120
121         *out = v;
122         return bytes;
123 }