/src/s2geometry/src/s2/util/coding/varint.h
Line | Count | Source |
1 | | // Copyright 2001 Google Inc. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS-IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | |
16 | | // |
17 | | // Raw support for varint encoding. Higher level interfaces are |
18 | | // provided by Encoder/Decoder/IOBuffer. Clients should typically use |
19 | | // those interfaces, unless speed is paramount. |
20 | | // |
21 | | // If decoding speed is very important, consider using PrefixVarint instead. |
22 | | // It has the same compression ratio, but generally faster decoding. |
23 | | // |
24 | | // Provided routines: |
25 | | // vi_parse32_unchecked |
26 | | // vi_parse64_unchecked |
27 | | // vi_encode32_unchecked |
28 | | // vi_encode64_unchecked |
29 | | |
30 | | #ifndef S2_UTIL_CODING_VARINT_H_ |
31 | | #define S2_UTIL_CODING_VARINT_H_ |
32 | | |
33 | | // Avoid adding expensive includes here. |
34 | | #include <cassert> |
35 | | #include <cstddef> |
36 | | #include <cstdint> |
37 | | #include <limits> |
38 | | #include <string> |
39 | | #include <utility> |
40 | | |
41 | | #include "absl/base/macros.h" |
42 | | #include "absl/numeric/bits.h" |
43 | | |
44 | | // Just a namespace, not a real class |
45 | | class Varint { |
46 | | public: |
47 | | // Maximum lengths of varint encoding of uint32 and uint64 |
48 | | static constexpr int kMax32 = 5; |
49 | | static constexpr int kMax64 = 10; |
50 | | |
51 | | // The decoder does not read past the end of the encoded data. |
52 | | static constexpr int kSlopBytes = 0; |
53 | | |
54 | | // REQUIRES "ptr" points to a buffer of length at least kMaxXX |
55 | | // EFFECTS Scan next varint from "ptr" and store in OUTPUT. |
56 | | // Returns pointer just past last read byte. Returns |
57 | | // nullptr if a valid varint value was not found. |
58 | | static const char* Parse32(const char* ptr, uint32_t* OUTPUT); |
59 | | static const char* Parse64(const char* ptr, uint64_t* OUTPUT); |
60 | | |
61 | | // A fully inlined version of Parse32: useful in the most time critical |
62 | | // routines, but its code size is large |
63 | | static const char* Parse32Inline(const char* ptr, uint32_t* OUTPUT); |
64 | | |
65 | | // REQUIRES "ptr" points just past the last byte of a varint-encoded value. |
66 | | // REQUIRES A second varint must be encoded just before the one we parse, |
67 | | // OR "base" must point to the first byte of the one we parse. |
68 | | // REQUIRES Bytes [base, ptr-1] are readable |
69 | | // |
70 | | // EFFECTS Scan backwards from "ptr" and store in OUTPUT. Stop at the last |
71 | | // byte of the previous varint, OR at "base", whichever one comes |
72 | | // first. Returns pointer to the first byte of the decoded varint |
73 | | // nullptr if a valid varint value was not found. |
74 | | static const char* Parse32Backward(const char* ptr, const char* base, |
75 | | uint32_t* OUTPUT); |
76 | | static const char* Parse64Backward(const char* ptr, const char* base, |
77 | | uint64_t* OUTPUT); |
78 | | |
79 | | // Attempts to parse a varint32 from a prefix of the bytes in [ptr,limit-1]. |
80 | | // Never reads a character at or beyond limit. If a valid/terminated varint32 |
81 | | // was found in the range, stores it in *OUTPUT and returns a pointer just |
82 | | // past the last byte of the varint32. Else returns nullptr. On success, |
83 | | // "result <= limit". |
84 | | static const char* Parse32WithLimit(const char* ptr, const char* limit, |
85 | | uint32_t* OUTPUT); |
86 | | static const char* Parse64WithLimit(const char* ptr, const char* limit, |
87 | | uint64_t* OUTPUT); |
88 | | |
89 | | // REQUIRES "ptr" points to the first byte of a varint-encoded value. |
90 | | // EFFECTS Scans until the end of the varint and returns a pointer just |
91 | | // past the last byte. Returns nullptr if "ptr" does not point to |
92 | | // a valid varint value. |
93 | | static const char* Skip32(const char* ptr); |
94 | | static const char* Skip64(const char* ptr); |
95 | | |
96 | | // REQUIRES "ptr" points just past the last byte of a varint-encoded value. |
97 | | // REQUIRES A second varint must be encoded just before the one we parse, |
98 | | // OR "base" must point to the first byte of the one we parse. |
99 | | // REQUIRES Bytes [base, ptr-1] are readable |
100 | | // |
101 | | // EFFECTS Scan backwards from "ptr" and stop at the last byte of the |
102 | | // previous varint, OR at "base", whichever one comes first. |
103 | | // Returns pointer to the first byte of the skipped varint or |
104 | | // nullptr if a valid varint value was not found. |
105 | | static const char* Skip32Backward(const char* ptr, const char* base); |
106 | | static const char* Skip64Backward(const char* ptr, const char* base); |
107 | | |
108 | | // REQUIRES "ptr" points to a buffer of length sufficient to hold "v". |
109 | | // EFFECTS Encodes "v" into "ptr" and returns a pointer to the |
110 | | // byte just past the last encoded byte. |
111 | | static char* Encode32(char* ptr, uint32_t v); |
112 | | static char* Encode64(char* ptr, uint64_t v); |
113 | | |
114 | | // A fully inlined version of Encode32: useful in the most time critical |
115 | | // routines, but its code size is large |
116 | | static char* Encode32Inline(char* ptr, uint32_t v); |
117 | | |
118 | | // EFFECTS Returns the encoding length of the specified value. |
119 | | static int Length32(uint32_t v); |
120 | | static int Length64(uint64_t v); |
121 | | |
122 | | // EFFECTS Appends the varint representation of "value" to "*s". |
123 | | static void Append32(std::string* s, uint32_t value); |
124 | | static void Append64(std::string* s, uint64_t value); |
125 | | |
126 | | // Decode and sum up a sequence of deltas until the sum >= goal. |
127 | | // It is significantly faster than calling ParseXXInline in a loop. |
128 | | // NOTE(user): The code does NO error checking, it assumes all the |
129 | | // deltas are valid and the sum of deltas will never exceed |
130 | | // numeric_limits<int64>::max(). The code works for both 32bits and |
131 | | // 64bits varint, and on 64 bits machines, the 64 bits version is |
132 | | // almost always faster. Thus we only have a 64 bits interface here. |
133 | | // The interface is slightly different from the other functions in that |
134 | | // it requires *signed* integers. |
135 | | // REQUIRES "ptr" points to the first byte of a varint-encoded delta. |
136 | | // The sum of deltas >= goal (the code does NO boundary check). |
137 | | // goal is positive and fit into a signed int64. |
138 | | // EFFECTS Returns a pointer just past last read byte. |
139 | | // "out" stores the actual sum. |
140 | | static const char* FastDecodeDeltas(const char* ptr, int64_t goal, |
141 | | int64_t* out); |
142 | | |
143 | | private: |
144 | | static const char* Parse32FallbackInline(const char* p, uint32_t* val); |
145 | | static const char* Parse32Fallback(const char* p, uint32_t* val); |
146 | | #if defined(__x86_64__) |
147 | | static std::pair<const char*, uint64_t> Parse64FallbackPair(const char* p, |
148 | | int64_t res1); |
149 | | #else |
150 | | static const char* Parse64Fallback(const char* p, uint64_t* val); |
151 | | #endif |
152 | | template <typename T> |
153 | | static int LengthImpl(T); |
154 | | |
155 | | static const char* Parse32BackwardSlow(const char* ptr, const char* base, |
156 | | uint32_t* OUTPUT); |
157 | | static const char* Parse64BackwardSlow(const char* ptr, const char* base, |
158 | | uint64_t* OUTPUT); |
159 | | static const char* Skip32BackwardSlow(const char* ptr, const char* base); |
160 | | static const char* Skip64BackwardSlow(const char* ptr, const char* base); |
161 | | |
162 | | static void Append32Slow(std::string* s, uint32_t value); |
163 | | static void Append64Slow(std::string* s, uint64_t value); |
164 | | }; |
165 | | |
166 | | /***** Implementation details; clients should ignore *****/ |
167 | | |
168 | | // NOLINTBEGIN(readability/braces) Many false positives. |
169 | | |
170 | | inline const char* Varint::Parse32FallbackInline(const char* p, |
171 | 0 | uint32_t* OUTPUT) { |
172 | | // Fast path |
173 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
174 | 0 | uint32_t byte, result; |
175 | 0 | byte = *(ptr++); result = byte & 127; |
176 | 0 | assert(byte >= 128); // Already checked in inlined prelude |
177 | 0 | byte = *(ptr++); result |= (byte & 127) << 7; if (byte < 128) goto done; |
178 | 0 | byte = *(ptr++); result |= (byte & 127) << 14; if (byte < 128) goto done; |
179 | 0 | byte = *(ptr++); result |= (byte & 127) << 21; if (byte < 128) goto done; |
180 | 0 | byte = *(ptr++); result |= (byte & 127) << 28; if (byte < 16) goto done; |
181 | 0 | return nullptr; // Value is too long to be a varint32 |
182 | 0 | done: |
183 | 0 | *OUTPUT = result; |
184 | 0 | return reinterpret_cast<const char*>(ptr); |
185 | 0 | } |
186 | | |
187 | 0 | inline const char* Varint::Parse32(const char* p, uint32_t* OUTPUT) { |
188 | | // Fast path for inlining |
189 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
190 | 0 | uint32_t byte = *ptr; |
191 | 0 | if (byte < 128) { |
192 | 0 | *OUTPUT = byte; |
193 | 0 | return reinterpret_cast<const char*>(ptr) + 1; |
194 | 0 | } else { |
195 | 0 | return Parse32Fallback(p, OUTPUT); |
196 | 0 | } |
197 | 0 | } |
198 | | |
199 | 0 | inline const char* Varint::Parse32Inline(const char* p, uint32_t* OUTPUT) { |
200 | 0 | // Fast path for inlining |
201 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
202 | 0 | uint32_t byte = *ptr; |
203 | 0 | if (byte < 128) { |
204 | 0 | *OUTPUT = byte; |
205 | 0 | return reinterpret_cast<const char*>(ptr) + 1; |
206 | 0 | } else { |
207 | 0 | return Parse32FallbackInline(p, OUTPUT); |
208 | 0 | } |
209 | 0 | } |
210 | | |
211 | 0 | inline const char* Varint::Skip32(const char* p) { |
212 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
213 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
214 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
215 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
216 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
217 | 0 | if (*ptr++ < 16) return reinterpret_cast<const char*>(ptr); |
218 | 0 | return nullptr; // value is too long to be a varint32 |
219 | 0 | } |
220 | | |
221 | | inline const char* Varint::Parse32Backward(const char* p, const char* base, |
222 | 0 | uint32_t* OUTPUT) { |
223 | 0 | if (p > base + kMax32) { |
224 | 0 | // Fast path |
225 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
226 | 0 | uint32_t byte, result; |
227 | 0 | byte = *(--ptr); if (byte > 127) return nullptr; |
228 | 0 | result = byte; |
229 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
230 | 0 | result <<= 7; result |= (byte & 127); |
231 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
232 | 0 | result <<= 7; result |= (byte & 127); |
233 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
234 | 0 | result <<= 7; result |= (byte & 127); |
235 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
236 | 0 | result <<= 7; result |= (byte & 127); |
237 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
238 | 0 | return nullptr; // Value is too long to be a varint32 |
239 | 0 | done: |
240 | 0 | *OUTPUT = result; |
241 | 0 | return reinterpret_cast<const char*>(ptr+1); |
242 | 0 | } else { |
243 | 0 | return Parse32BackwardSlow(p, base, OUTPUT); |
244 | 0 | } |
245 | 0 | } |
246 | | |
247 | 0 | inline const char* Varint::Skip32Backward(const char* p, const char* base) { |
248 | 0 | if (p > base + kMax32) { |
249 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
250 | 0 | if (*(--ptr) > 127) return nullptr; |
251 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
252 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
253 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
254 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
255 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
256 | 0 | return nullptr; // value is too long to be a varint32 |
257 | 0 | } else { |
258 | 0 | return Skip32BackwardSlow(p, base); |
259 | 0 | } |
260 | 0 | } |
261 | | |
262 | | inline const char* Varint::Parse32WithLimit(const char* p, const char* l, |
263 | 0 | uint32_t* OUTPUT) { |
264 | | // Version with bounds checks. |
265 | | // This formerly had an optimization to inline the non-bounds checking Parse32 |
266 | | // but it was found to be slower than the straightforward implementation. |
267 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
268 | 0 | const unsigned char* limit = reinterpret_cast<const unsigned char*>(l); |
269 | 0 | uint32_t b, result; |
270 | 0 | if (ptr >= limit) return nullptr; |
271 | 0 | b = *(ptr++); result = b & 127; if (b < 128) goto done; |
272 | 0 | if (ptr >= limit) return nullptr; |
273 | 0 | b = *(ptr++); result |= (b & 127) << 7; if (b < 128) goto done; |
274 | 0 | if (ptr >= limit) return nullptr; |
275 | 0 | b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done; |
276 | 0 | if (ptr >= limit) return nullptr; |
277 | 0 | b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done; |
278 | 0 | if (ptr >= limit) return nullptr; |
279 | 0 | b = *(ptr++); result |= (b & 127) << 28; if (b < 16) goto done; |
280 | 0 | return nullptr; // Value is too long to be a varint32 |
281 | 0 | done: |
282 | 0 | *OUTPUT = result; |
283 | 0 | return reinterpret_cast<const char*>(ptr); |
284 | 0 | } |
285 | | |
286 | 0 | inline const char* Varint::Parse64(const char* p, uint64_t* OUTPUT) { |
287 | 0 | #if defined(__x86_64__) |
288 | 0 | auto ptr = reinterpret_cast<const int8_t*>(p); |
289 | 0 | int64_t byte = *ptr; |
290 | 0 | if (byte >= 0) { |
291 | 0 | *OUTPUT = static_cast<uint64_t>(byte); |
292 | 0 | return reinterpret_cast<const char*>(ptr) + 1; |
293 | 0 | } else { |
294 | 0 | auto tmp = Parse64FallbackPair(p, byte); |
295 | 0 | if (ABSL_PREDICT_TRUE(tmp.first)) *OUTPUT = tmp.second; |
296 | 0 | return tmp.first; |
297 | 0 | } |
298 | | #else |
299 | | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
300 | | uint32_t byte = *ptr; |
301 | | if (byte < 128) { |
302 | | *OUTPUT = byte; |
303 | | return reinterpret_cast<const char*>(ptr) + 1; |
304 | | } else { |
305 | | return Parse64Fallback(p, OUTPUT); |
306 | | } |
307 | | #endif |
308 | 0 | } |
309 | | |
310 | 0 | inline const char* Varint::Skip64(const char* p) { |
311 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
312 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
313 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
314 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
315 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
316 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
317 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
318 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
319 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
320 | 0 | if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr); |
321 | 0 | if (*ptr++ < 2) return reinterpret_cast<const char*>(ptr); |
322 | 0 | return nullptr; // value is too long to be a varint64 |
323 | 0 | } |
324 | | |
325 | | inline const char* Varint::Parse64Backward(const char* p, const char* b, |
326 | 0 | uint64_t* OUTPUT) { |
327 | 0 | if (p > b + kMax64) { |
328 | 0 | // Fast path |
329 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
330 | 0 | uint32_t byte; |
331 | 0 | uint64_t res; |
332 | 0 |
|
333 | 0 | byte = *(--ptr); if (byte > 127) return nullptr; |
334 | 0 |
|
335 | 0 | res = byte; |
336 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
337 | 0 | res <<= 7; res |= (byte & 127); |
338 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
339 | 0 | res <<= 7; res |= (byte & 127); |
340 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
341 | 0 | res <<= 7; res |= (byte & 127); |
342 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
343 | 0 | res <<= 7; res |= (byte & 127); |
344 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
345 | 0 | res <<= 7; res |= (byte & 127); |
346 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
347 | 0 | res <<= 7; res |= (byte & 127); |
348 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
349 | 0 | res <<= 7; res |= (byte & 127); |
350 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
351 | 0 | res <<= 7; res |= (byte & 127); |
352 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
353 | 0 | res <<= 7; res |= (byte & 127); |
354 | 0 | byte = *(--ptr); if (byte < 128) goto done; |
355 | 0 |
|
356 | 0 | return nullptr; // Value is too long to be a varint64 |
357 | 0 |
|
358 | 0 | done: |
359 | 0 | *OUTPUT = res; |
360 | 0 | return reinterpret_cast<const char*>(ptr + 1); |
361 | 0 | } else { |
362 | 0 | return Parse64BackwardSlow(p, b, OUTPUT); |
363 | 0 | } |
364 | 0 | } |
365 | | |
366 | 0 | inline const char* Varint::Skip64Backward(const char* p, const char* b) { |
367 | 0 | if (p > b + kMax64) { |
368 | 0 | // Fast path |
369 | 0 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); |
370 | 0 | if (*(--ptr) > 127) return nullptr; |
371 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
372 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
373 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
374 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
375 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
376 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
377 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
378 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
379 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
380 | 0 | if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1); |
381 | 0 | return nullptr; // value is too long to be a varint64 |
382 | 0 | } else { |
383 | 0 | return Skip64BackwardSlow(p, b); |
384 | 0 | } |
385 | 0 | } |
386 | | |
387 | | template <typename T> |
388 | 0 | int Varint::LengthImpl(T v) { |
389 | 0 | static_assert(std::numeric_limits<T>::digits == 32 || |
390 | 0 | std::numeric_limits<T>::digits == 64, |
391 | 0 | "Unexpected length. This implementation works up to 448 bits, " |
392 | 0 | "but performance has not been tested other than 32 and 64."); |
393 | | // X86 CPUs lacking the lzcnt instruction are faster with the bit_width-based |
394 | | // implementation. Both absl::bit_width and absl::count_lzero will use lzcnt |
395 | | // when available, and bsr otherwise. For K8 (no lzcnt), bit_width produces |
396 | | // better code; for Haswell and AArch64, countl_zero does. MSVC and clang do |
397 | | // not define __LZCNT__, the nearest option that they interpret as lzcnt |
398 | | // availability is __AVX2__. |
399 | 0 | #if (defined(__x86__) || defined(__x86_64__) || defined(_M_IX86) || \ |
400 | 0 | defined(_M_X64)) && \ |
401 | 0 | !(defined(__LZCNT__) || defined(__AVX2__)) |
402 | 0 | return (absl::bit_width(v | T{1}) * 9 + 64) / 64; |
403 | | #else |
404 | | // This computes value == 0 ? 1 : floor(log2(v)) / 7 + 1 |
405 | | // Rather than using division by 7 to accomplish this, we use multiplication |
406 | | // by 9/64. This has a number of important properties: |
407 | | // * It's roughly 1/7.111111. This makes the 0 bits set case have the same |
408 | | // value as the 7 bits set case, so offsetting by 1 gives us the correct |
409 | | // value for integers up to 448 bits. |
410 | | // * Multiplying by 9 is special. x * 9 = x << 3 + x, and so this |
411 | | // multiplication can be done by a single shifted add on arm: |
412 | | // add w0, w0, w0, lsl #3 |
413 | | // or a single lea instruction on x86/64: |
414 | | // leal (%rax,%rax,8), %eax) |
415 | | // * Dividing by 64 is a 6 bit right shift. |
416 | | // |
417 | | // Summarized: |
418 | | // |
419 | | // value == 0 ? 1 : (floor(log2(v)) / 7 + 1) |
420 | | // floor((32 - clz) / 7.1111) + 1 |
421 | | // ((32 - clz) * 9) / 64 + 1 |
422 | | // (((32 - clz) * 9) >> 6) + 1 |
423 | | // ((32 - clz) * 9 + (1 << 6)) >> 6 |
424 | | // (32 * 9 + 64 - clz * 9) >> 6 |
425 | | // (352 - clz * 9) >> 6 |
426 | | // on arm: |
427 | | // (352 - (clz + (clz << 3))) >> 6 |
428 | | // on x86: |
429 | | // (352 - lea(clz, clz, 8)) >> 6 |
430 | | const int clz = absl::countl_zero(v); |
431 | | return ((std::numeric_limits<T>::digits * 9 + 64) - (clz * 9)) >> 6; |
432 | | #endif |
433 | 0 | } Unexecuted instantiation: int Varint::LengthImpl<unsigned int>(unsigned int) Unexecuted instantiation: int Varint::LengthImpl<unsigned long>(unsigned long) |
434 | | |
435 | 0 | inline int Varint::Length32(uint32_t v) { return LengthImpl(v); } |
436 | 0 | inline int Varint::Length64(uint64_t v) { return LengthImpl(v); } |
437 | | |
438 | 0 | inline void Varint::Append32(std::string* s, uint32_t value) { |
439 | 0 | // Inline the fast-path for single-character output, but fall back to the .cc |
440 | 0 | // file for the full version. The size<capacity check is so the compiler can |
441 | 0 | // optimize out the string resize code. |
442 | 0 | if (value < 128 && s->size() < s->capacity()) { |
443 | 0 | s->push_back(static_cast<unsigned char>(value)); |
444 | 0 | } else { |
445 | 0 | Append32Slow(s, value); |
446 | 0 | } |
447 | 0 | } |
448 | | |
449 | 0 | inline void Varint::Append64(std::string* s, uint64_t value) { |
450 | 0 | // Inline the fast-path for single-character output, but fall back to the .cc |
451 | 0 | // file for the full version. The size<capacity check is so the compiler can |
452 | 0 | // optimize out the string resize code. |
453 | 0 | if (value < 128 && s->size() < s->capacity()) { |
454 | 0 | s->push_back(static_cast<unsigned char>(value)); |
455 | 0 | } else { |
456 | 0 | Append64Slow(s, value); |
457 | 0 | } |
458 | 0 | } |
459 | | |
460 | 0 | inline char* Varint::Encode32Inline(char* sptr, uint32_t v) { |
461 | | // Operate on characters as unsigneds |
462 | 0 | uint8_t* ptr = reinterpret_cast<uint8_t*>(sptr); |
463 | 0 | static const uint32_t B = 128; |
464 | 0 | if (v < (1<<7)) { |
465 | 0 | *(ptr++) = static_cast<uint8_t>(v); |
466 | 0 | } else if (v < (1<<14)) { |
467 | 0 | *(ptr++) = static_cast<uint8_t>(v | B); |
468 | 0 | *(ptr++) = static_cast<uint8_t>(v >> 7); |
469 | 0 | } else if (v < (1<<21)) { |
470 | 0 | *(ptr++) = static_cast<uint8_t>(v | B); |
471 | 0 | *(ptr++) = static_cast<uint8_t>((v >> 7) | B); |
472 | 0 | *(ptr++) = static_cast<uint8_t>(v >> 14); |
473 | 0 | } else if (v < (1<<28)) { |
474 | 0 | *(ptr++) = static_cast<uint8_t>(v | B); |
475 | 0 | *(ptr++) = static_cast<uint8_t>((v >> 7) | B); |
476 | 0 | *(ptr++) = static_cast<uint8_t>((v >> 14) | B); |
477 | 0 | *(ptr++) = static_cast<uint8_t>(v >> 21); |
478 | 0 | } else { |
479 | 0 | *(ptr++) = static_cast<uint8_t>(v | B); |
480 | 0 | *(ptr++) = static_cast<uint8_t>((v >> 7) | B); |
481 | 0 | *(ptr++) = static_cast<uint8_t>((v >> 14) | B); |
482 | 0 | *(ptr++) = static_cast<uint8_t>((v >> 21) | B); |
483 | 0 | *(ptr++) = static_cast<uint8_t>(v >> 28); |
484 | 0 | } |
485 | 0 | return reinterpret_cast<char*>(ptr); |
486 | 0 | } |
487 | | |
488 | | #if (-1 >> 1) != -1 |
489 | | #error FastDecodeDeltas() needs right-shift to sign-extend. |
490 | | #endif |
491 | | inline const char* Varint::FastDecodeDeltas(const char* ptr, int64_t goal, |
492 | 0 | int64_t* out) { |
493 | 0 | int64_t value; |
494 | 0 | int64_t sum = -goal; |
495 | 0 | int64_t shift = 0; |
496 | 0 | // Make decoding faster by eliminating unpredictable branching. |
497 | 0 | do { |
498 | 0 | value = static_cast<int8_t>(*ptr++); // sign extend one byte of data |
499 | 0 | sum += (value & 0x7F) << shift; |
500 | 0 | shift += 7; |
501 | 0 | // (value >> 7) is either -1(continuation byte) or 0 (stop byte) |
502 | 0 | shift &= value >> 7; |
503 | 0 | // Loop if we haven't reached goal (sum < 0) or we haven't finished |
504 | 0 | // parsing current delta (value < 0). We write it in the form of |
505 | 0 | // (a | b) < 0 as opposed to (a < 0 || b < 0) as the former one is |
506 | 0 | // usually as fast as a test for (a < 0). |
507 | 0 | } while ((sum | value) < 0); |
508 | 0 |
|
509 | 0 | *out = goal + sum; |
510 | 0 | return ptr; |
511 | 0 | } |
512 | | |
513 | | // NOLINTEND(readability/braces) |
514 | | |
515 | | #endif // S2_UTIL_CODING_VARINT_H_ |