2 * UCW Library -- Coding of u64 into variable length bytecode.
4 * (c) 2013 Tomas Valla <tom@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
13 #ifdef CONFIG_UCW_CLEAN_ABI
14 #define varint_get_big ucw_varint_get_big
15 #define varint_put_big ucw_varint_put_big
19 * The encoding works in the following way:
21 * First byte Stored values
24 * 10xxxxxx +1 byte 14 bits, value shifted by 2^7
25 * 110xxxxx +2 bytes 21 bits, value shifted by 2^7+2^14
26 * 1110xxxx +3 bytes 28 bits, value shifted by 2^7+2^14+2^21
28 * 11111110 +7 bytes 56 bits, value shifted by 2^7+2^14+2^21+2^28+2^35+2^42
29 * 11111111 +8 bytes full 64 bits, value shifted by 2^7+2^14+2^21+2^28+2^35+2^42+2^56
31 * The values are stored in bigendian to allow lexicographic sorting.
32 * The encoding and algorithms are aimed to be optimised for storing shorter numbers.
34 * There is an invalid combination: if the first two bytes are 0xff 0xff.
38 #define VARINT_SHIFT_L1 0x80
39 #define VARINT_SHIFT_L2 0x4080
40 #define VARINT_SHIFT_L3 0x204080
41 #define VARINT_SHIFT_L4 0x10204080
42 #define VARINT_SHIFT_L5 0x0810204080
43 #define VARINT_SHIFT_L6 0x040810204080
44 #define VARINT_SHIFT_L7 0x02040810204080
45 #define VARINT_SHIFT_L8 0x0102040810204080
48 * The following code is already unrolled, to maximize the speed.
52 #define PUTB(j,i) p[j] = (byte)((u >> (8*(i))));
53 #define PUTB4(b) PUTB(0,b-1) PUTB(1,b-2) PUTB(2,b-3) PUTB(3,b-4)
55 /* for internal use only, need the length > 4 */
56 uns varint_put_big(byte *p, u64 u);
57 const byte *varint_get_big(const byte *p, u64 *r);
60 * Encode u64 value u into byte sequence p.
61 * Returns the number of bytes used (at least 1 and at most 9).
63 static inline uns varint_put(byte *p, u64 u)
65 if (u < VARINT_SHIFT_L1) {
69 if (u < VARINT_SHIFT_L2) {
76 if (u < VARINT_SHIFT_L3) {
83 if (u < VARINT_SHIFT_L4) {
89 return varint_put_big(p, u);
95 * Decode u64 value from a byte sequence p into res.
96 * The invalid combination is not detected.
97 * Returns pointer to the next position after the sequence.
99 static inline const byte *varint_get(const byte *p, u64 *res)
108 *res = (p[0] & 0x3f)<<8 | p[1];
109 *res += VARINT_SHIFT_L1;
113 *res = (p[0] & 0x1f)<<16 | p[1]<<8 | p[2];
114 *res += VARINT_SHIFT_L2;
118 *res = (p[0] & 0xf)<<24 | p[1]<<16 | p[2]<<8 | p[3];
119 *res += VARINT_SHIFT_L3;
122 return varint_get_big(p, res);
126 * Decode at most u32 value from a byte sequence p into u32 res.
127 * The invalid combination is not detected.
128 * Returns pointer to the next position after the sequence.
129 * If the stored number cannot fit into u32, fill res by 0xffffffff and returns p.
131 static inline const byte *varint_get32(const byte *p, u32 *res)
140 *res = (p[0] & 0x3f)<<8 | p[1];
141 *res += VARINT_SHIFT_L1;
145 *res = (p[0] & 0x1f)<<16 | p[1]<<8 | p[2];
146 *res += VARINT_SHIFT_L2;
150 *res = (p[0] & 0xf)<<24 | p[1]<<16 | p[2]<<8 | p[3];
151 *res += VARINT_SHIFT_L3;
154 u64 r = (u64)(p[0] & 7)<<32 | (u64)p[1]<<24 | (u64)p[2]<<16 | (u64)p[3]<<8 | (u64)p[4];
155 r += VARINT_SHIFT_L4;
156 if (r > 0xffffffff) {
164 /** Does the byte sequence p code the invalid sequence? **/
165 static inline int varint_invalid(const byte *p)
167 return p[0] == 0xff && p[1] == 0xff;
171 * Store the invalid sequence.
172 * Returns always 2 (2 bytes were used, to be consistent with varint_put).
174 static inline uns varint_put_invalid(byte *p)
180 /** Compute the length of encoding in bytes from the first byte hdr of the encoding. **/
181 static inline uns varint_len(const byte hdr)
189 if (b & 0xf0) { l += 4; b &= 0xf0; }
190 if (b & 0xcc) { l += 2; b &= 0xcc; }
196 /** Compute the number of bytes needed to store the value u. **/
197 static inline uns varint_space(u64 u)
199 if (u < VARINT_SHIFT_L1)
201 if (u < VARINT_SHIFT_L2)
203 if (u < VARINT_SHIFT_L3)
205 if (u < VARINT_SHIFT_L4)
207 if (u < VARINT_SHIFT_L5)
209 if (u < VARINT_SHIFT_L6)
211 if (u < VARINT_SHIFT_L7)
213 if (u < VARINT_SHIFT_L8)