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