/Users/deen/code/yugabyte-db/src/yb/util/memcmpable_varint.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | // This file contains code derived from sqlite4, distributed in the public domain. |
33 | | // |
34 | | // A variable length integer is an encoding of 64-bit unsigned integers |
35 | | // into between 1 and 9 bytes. The encoding is designed so that small |
36 | | // (and common) values take much less space that larger values. Additional |
37 | | // properties: |
38 | | // |
39 | | // * The length of the varint can be determined after examining just |
40 | | // the first byte of the encoding. |
41 | | // |
42 | | // * Varints compare in numerical order using memcmp(). |
43 | | // |
44 | | //************************************************************************ |
45 | | // |
46 | | // Treat each byte of the encoding as an unsigned integer between 0 and 255. |
47 | | // Let the bytes of the encoding be called A0, A1, A2, ..., A8. |
48 | | // |
49 | | // DECODE |
50 | | // |
51 | | // If A0 is between 0 and 240 inclusive, then the result is the value of A0. |
52 | | // |
53 | | // If A0 is between 241 and 248 inclusive, then the result is |
54 | | // 240+256*(A0-241)+A1. |
55 | | // |
56 | | // If A0 is 249 then the result is 2288+256*A1+A2. |
57 | | // |
58 | | // If A0 is 250 then the result is A1..A3 as a 3-byte big-ending integer. |
59 | | // |
60 | | // If A0 is 251 then the result is A1..A4 as a 4-byte big-ending integer. |
61 | | // |
62 | | // If A0 is 252 then the result is A1..A5 as a 5-byte big-ending integer. |
63 | | // |
64 | | // If A0 is 253 then the result is A1..A6 as a 6-byte big-ending integer. |
65 | | // |
66 | | // If A0 is 254 then the result is A1..A7 as a 7-byte big-ending integer. |
67 | | // |
68 | | // If A0 is 255 then the result is A1..A8 as a 8-byte big-ending integer. |
69 | | // |
70 | | // ENCODE |
71 | | // |
72 | | // Let the input value be V. |
73 | | // |
74 | | // If V<=240 then output a single by A0 equal to V. |
75 | | // |
76 | | // If V<=2287 then output A0 as (V-240)/256 + 241 and A1 as (V-240)%256. |
77 | | // |
78 | | // If V<=67823 then output A0 as 249, A1 as (V-2288)/256, and A2 |
79 | | // as (V-2288)%256. |
80 | | // |
81 | | // If V<=16777215 then output A0 as 250 and A1 through A3 as a big-endian |
82 | | // 3-byte integer. |
83 | | // |
84 | | // If V<=4294967295 then output A0 as 251 and A1..A4 as a big-ending |
85 | | // 4-byte integer. |
86 | | // |
87 | | // If V<=1099511627775 then output A0 as 252 and A1..A5 as a big-ending |
88 | | // 5-byte integer. |
89 | | // |
90 | | // If V<=281474976710655 then output A0 as 253 and A1..A6 as a big-ending |
91 | | // 6-byte integer. |
92 | | // |
93 | | // If V<=72057594037927935 then output A0 as 254 and A1..A7 as a |
94 | | // big-ending 7-byte integer. |
95 | | // |
96 | | // Otherwise then output A0 as 255 and A1..A8 as a big-ending 8-byte integer. |
97 | | // |
98 | | // SUMMARY |
99 | | // |
100 | | // Bytes Max Value Digits |
101 | | // ------- --------- --------- |
102 | | // 1 240 2.3 |
103 | | // 2 2287 3.3 |
104 | | // 3 67823 4.8 |
105 | | // 4 2**24-1 7.2 |
106 | | // 5 2**32-1 9.6 |
107 | | // 6 2**40-1 12.0 |
108 | | // 7 2**48-1 14.4 |
109 | | // 8 2**56-1 16.8 |
110 | | // 9 2**64-1 19.2 |
111 | | // |
112 | | #include "yb/util/memcmpable_varint.h" |
113 | | |
114 | | #include <glog/logging.h> |
115 | | |
116 | | #include "yb/util/cast.h" |
117 | | #include "yb/util/faststring.h" |
118 | | #include "yb/util/slice.h" |
119 | | #include "yb/util/status.h" |
120 | | |
121 | | namespace yb { |
122 | | |
123 | | //////////////////////////////////////////////////////////// |
124 | | // Begin code ripped from sqlite4 |
125 | | //////////////////////////////////////////////////////////// |
126 | | |
127 | | // This function is borrowed from sqlite4/varint.c |
128 | 221k | static void varintWrite32(uint8_t *z, uint32_t y) { |
129 | 221k | z[0] = (uint8_t)(y>>24); |
130 | 221k | z[1] = (uint8_t)(y>>16); |
131 | 221k | z[2] = (uint8_t)(y>>8); |
132 | 221k | z[3] = (uint8_t)(y); |
133 | 221k | } |
134 | | |
135 | | |
136 | | // Write a varint into z[]. The buffer z[] must be at least 9 characters |
137 | | // long to accommodate the largest possible varint. Return the number of |
138 | | // bytes of z[] used. |
139 | | // |
140 | | // This function is borrowed from sqlite4/varint.c |
141 | 305k | static size_t sqlite4PutVarint64(uint8_t *z, uint64_t x) { |
142 | 305k | if (x <= 240) { |
143 | 21.2k | z[0] = (uint8_t)x; |
144 | 21.2k | return 1; |
145 | 21.2k | } |
146 | 284k | if (x <= 2287) { |
147 | 22.5k | auto y = x - 240; |
148 | 22.5k | z[0] = (uint8_t)(y/256 + 241); |
149 | 22.5k | z[1] = (uint8_t)(y%256); |
150 | 22.5k | return 2; |
151 | 22.5k | } |
152 | 261k | if (x <= 67823) { |
153 | 86.1k | auto y = x - 2288; |
154 | 86.1k | z[0] = 249; |
155 | 86.1k | z[1] = (uint8_t)(y/256); |
156 | 86.1k | z[2] = (uint8_t)(y%256); |
157 | 86.1k | return 3; |
158 | 86.1k | } |
159 | 175k | auto y = static_cast<uint32_t>(x); |
160 | 175k | auto w = static_cast<uint32_t>(x >> 32); |
161 | 175k | if (w == 0) { |
162 | 73.8k | if (y <= 16777215) { |
163 | 52.9k | z[0] = 250; |
164 | 52.9k | z[1] = (uint8_t)(y>>16); |
165 | 52.9k | z[2] = (uint8_t)(y>>8); |
166 | 52.9k | z[3] = (uint8_t)(y); |
167 | 52.9k | return 4; |
168 | 52.9k | } |
169 | 20.8k | z[0] = 251; |
170 | 20.8k | varintWrite32(z+1, y); |
171 | 20.8k | return 5; |
172 | 20.8k | } |
173 | 101k | if (w <= 255) { |
174 | 541 | z[0] = 252; |
175 | 541 | z[1] = (uint8_t)w; |
176 | 541 | varintWrite32(z+2, y); |
177 | 541 | return 6; |
178 | 541 | } |
179 | 101k | if (w <= 65535) { |
180 | 523 | z[0] = 253; |
181 | 523 | z[1] = (uint8_t)(w>>8); |
182 | 523 | z[2] = (uint8_t)w; |
183 | 523 | varintWrite32(z+3, y); |
184 | 523 | return 7; |
185 | 523 | } |
186 | 100k | if (w <= 16777215) { |
187 | 2.13k | z[0] = 254; |
188 | 2.13k | z[1] = (uint8_t)(w>>16); |
189 | 2.13k | z[2] = (uint8_t)(w>>8); |
190 | 2.13k | z[3] = (uint8_t)w; |
191 | 2.13k | varintWrite32(z+4, y); |
192 | 2.13k | return 8; |
193 | 2.13k | } |
194 | 98.6k | z[0] = 255; |
195 | 98.6k | varintWrite32(z+1, w); |
196 | 98.6k | varintWrite32(z+5, y); |
197 | 98.6k | return 9; |
198 | 98.6k | } |
199 | | |
200 | | // Decode the varint in the first n bytes z[]. Write the integer value |
201 | | // into *pResult and return the number of bytes in the varint. |
202 | | // |
203 | | // If the decode fails because there are not enough bytes in z[] then |
204 | | // return 0; |
205 | | // |
206 | | // Borrowed from sqlite4 varint.c |
207 | | static int sqlite4GetVarint64( |
208 | | const uint8_t *z, |
209 | | size_t n, |
210 | 200k | uint64_t *pResult) { |
211 | 200k | unsigned int x; |
212 | 200k | if ( n < 1) return 0; |
213 | 200k | if (z[0] <= 240) { |
214 | 241 | *pResult = z[0]; |
215 | 241 | return 1; |
216 | 241 | } |
217 | 199k | if (z[0] <= 248) { |
218 | 2.04k | if ( n < 2) return 0; |
219 | 2.04k | *pResult = (z[0]-241)*256 + z[1] + 240; |
220 | 2.04k | return 2; |
221 | 2.04k | } |
222 | 197k | if (n < z[0]-246U ) return 0; |
223 | 197k | if (z[0] == 249) { |
224 | 65.5k | *pResult = 2288 + 256*z[1] + z[2]; |
225 | 65.5k | return 3; |
226 | 65.5k | } |
227 | 132k | if (z[0] == 250) { |
228 | 32.1k | *pResult = (z[1] << 16) + (z[2] << 8) + z[3]; |
229 | 32.1k | return 4; |
230 | 32.1k | } |
231 | 100k | x = (z[1] << 24) + (z[2] << 16) + (z[3] << 8) + z[4]; |
232 | 100k | if (z[0] == 251) { |
233 | 0 | *pResult = x; |
234 | 0 | return 5; |
235 | 0 | } |
236 | 100k | if (z[0] == 252) { |
237 | 0 | *pResult = (((uint64_t)x) << 8) + z[5]; |
238 | 0 | return 6; |
239 | 0 | } |
240 | 100k | if (z[0] == 253) { |
241 | 6 | *pResult = (((uint64_t)x) << 16) + (z[5] << 8) + z[6]; |
242 | 6 | return 7; |
243 | 6 | } |
244 | 99.9k | if (z[0] == 254) { |
245 | 1.62k | *pResult = (((uint64_t)x) << 24) + (z[5] << 16) + (z[6] << 8) + z[7]; |
246 | 1.62k | return 8; |
247 | 1.62k | } |
248 | 98.3k | *pResult = (((uint64_t)x) << 32) + |
249 | 98.3k | (0xffffffff & ((z[5] << 24) + (z[6] << 16) + (z[7] << 8) + z[8])); |
250 | 98.3k | return 9; |
251 | 98.3k | } |
252 | | |
253 | | //////////////////////////////////////////////////////////// |
254 | | // End code ripped from sqlite4 |
255 | | //////////////////////////////////////////////////////////// |
256 | | |
257 | 305k | size_t PutVarint64ToBuf(uint8_t* buf, size_t bufsize, uint64_t value) { |
258 | 305k | auto used = sqlite4PutVarint64(buf, value); |
259 | 305k | DCHECK_LE(used, bufsize); |
260 | 305k | return used; |
261 | 305k | } |
262 | | |
263 | 0 | void PutMemcmpableVarint64(std::string *dst, uint64_t value) { |
264 | 0 | uint8_t buf[16]; |
265 | 0 | auto used = PutVarint64ToBuf(buf, sizeof(buf), value); |
266 | 0 | dst->append(to_char_ptr(buf), used); |
267 | 0 | } |
268 | | |
269 | 305k | void PutMemcmpableVarint64(faststring *dst, uint64_t value) { |
270 | 305k | uint8_t buf[16]; |
271 | 305k | auto used = PutVarint64ToBuf(buf, sizeof(buf), value); |
272 | 305k | dst->append(buf, used); |
273 | 305k | } |
274 | | |
275 | 200k | Status GetMemcmpableVarint64(Slice *input, uint64_t *value) { |
276 | 200k | size_t size = sqlite4GetVarint64(input->data(), input->size(), value); |
277 | 200k | input->remove_prefix(size); |
278 | 200k | if (size <= 0) { |
279 | 0 | return STATUS(InvalidArgument, "Valid varint couldn't be decoded"); |
280 | 0 | } |
281 | 200k | return Status::OK(); |
282 | 200k | } |
283 | | |
284 | | } // namespace yb |