]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/varint.c
Update bcachefs sources to ed6b7f81a7 six locks: Disable percpu read lock mode in...
[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
26         if (likely(bytes < 9)) {
27                 v <<= bytes;
28                 v |= ~(~0 << (bytes - 1));
29                 v = cpu_to_le64(v);
30                 memcpy(out, &v, bytes);
31         } else {
32                 *out++ = 255;
33                 bytes = 9;
34                 put_unaligned_le64(v, out);
35         }
36
37         return bytes;
38 }
39
40 /**
41  * bch2_varint_decode - encode a variable length integer
42  * @in  - varint to decode
43  * @end - end of buffer to decode from
44  * @out - on success, decoded integer
45  *
46  * Returns the size in bytes of the decoded integer - or -1 on failure (would
47  * have read past the end of the buffer)
48  */
49 int bch2_varint_decode(const u8 *in, const u8 *end, u64 *out)
50 {
51         unsigned bytes = likely(in < end)
52                 ? ffz(*in & 255) + 1
53                 : 1;
54         u64 v;
55
56         if (unlikely(in + bytes > end))
57                 return -1;
58
59         if (likely(bytes < 9)) {
60                 v = 0;
61                 memcpy(&v, in, bytes);
62                 v = le64_to_cpu(v);
63                 v >>= bytes;
64         } else {
65                 v = get_unaligned_le64(++in);
66         }
67
68         *out = v;
69         return bytes;
70 }
71
72 /**
73  * bch2_varint_encode_fast - fast version of bch2_varint_encode
74  *
75  * This version assumes it's always safe to write 8 bytes to @out, even if the
76  * encoded integer would be smaller.
77  */
78 int bch2_varint_encode_fast(u8 *out, u64 v)
79 {
80         unsigned bits = fls64(v|1);
81         unsigned bytes = DIV_ROUND_UP(bits, 7);
82
83         if (likely(bytes < 9)) {
84                 v <<= bytes;
85                 v |= ~(~0 << (bytes - 1));
86         } else {
87                 *out++ = 255;
88                 bytes = 9;
89         }
90
91         put_unaligned_le64(v, out);
92         return bytes;
93 }
94
95 /**
96  * bch2_varint_decode_fast - fast version of bch2_varint_decode
97  *
98  * This version assumes that it is safe to read at most 8 bytes past the end of
99  * @end (we still return an error if the varint extends past @end).
100  */
101 int bch2_varint_decode_fast(const u8 *in, const u8 *end, u64 *out)
102 {
103 #ifdef CONFIG_VALGRIND
104         VALGRIND_MAKE_MEM_DEFINED(in, 8);
105 #endif
106         u64 v = get_unaligned_le64(in);
107         unsigned bytes = ffz(*in) + 1;
108
109         if (unlikely(in + bytes > end))
110                 return -1;
111
112         if (likely(bytes < 9)) {
113                 v >>= bytes;
114                 v &= ~(~0ULL << (7 * bytes));
115         } else {
116                 v = get_unaligned_le64(++in);
117         }
118
119         *out = v;
120         return bytes;
121 }