/src/tarantool/src/lib/bit/bit.h
Line | Count | Source |
1 | | #ifndef TARANTOOL_LIB_BIT_BIT_H_INCLUDED |
2 | | #define TARANTOOL_LIB_BIT_BIT_H_INCLUDED |
3 | | /* |
4 | | * Copyright 2010-2016, Tarantool AUTHORS, please see AUTHORS file. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or |
7 | | * without modification, are permitted provided that the following |
8 | | * conditions are met: |
9 | | * |
10 | | * 1. Redistributions of source code must retain the above |
11 | | * copyright notice, this list of conditions and the |
12 | | * following disclaimer. |
13 | | * |
14 | | * 2. Redistributions in binary form must reproduce the above |
15 | | * copyright notice, this list of conditions and the following |
16 | | * disclaimer in the documentation and/or other materials |
17 | | * provided with the distribution. |
18 | | * |
19 | | * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND |
20 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
23 | | * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
24 | | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
27 | | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
28 | | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
30 | | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | | * SUCH DAMAGE. |
32 | | */ |
33 | | |
34 | | /** |
35 | | * @file |
36 | | * @brief Bit manipulation library |
37 | | */ |
38 | | #include "trivia/util.h" |
39 | | |
40 | | #include <stddef.h> |
41 | | #include <stdint.h> |
42 | | #include <stdbool.h> |
43 | | #include <string.h> |
44 | | #if defined(HAVE_FFSL) || defined(HAVE_FFSLL) |
45 | | #include <strings.h> |
46 | | #endif /* defined(HAVE_FFSL) || defined(HAVE_FFSLL) */ |
47 | | #include <limits.h> |
48 | | |
49 | | #if defined(__cplusplus) |
50 | | extern "C" { |
51 | | #endif /* defined(__cplusplus) */ |
52 | | |
53 | | /** |
54 | | * @brief Unaligned load from memory. |
55 | | * @param p pointer |
56 | | * @return number |
57 | | */ |
58 | | inline uint8_t |
59 | | load_u8(const void *p) |
60 | 0 | { |
61 | 0 | uint8_t res; |
62 | 0 | memcpy(&res, p, sizeof(res)); |
63 | 0 | return res; |
64 | 0 | } |
65 | | |
66 | | /** @copydoc load_u8 */ |
67 | | inline uint16_t |
68 | | load_u16(const void *p) |
69 | 0 | { |
70 | 0 | uint16_t res; |
71 | 0 | memcpy(&res, p, sizeof(res)); |
72 | 0 | return res; |
73 | 0 | } |
74 | | |
75 | | /** @copydoc load_u8 */ |
76 | | inline uint32_t |
77 | | load_u32(const void *p) |
78 | 0 | { |
79 | 0 | uint32_t res; |
80 | 0 | memcpy(&res, p, sizeof(res)); |
81 | 0 | return res; |
82 | 0 | } |
83 | | |
84 | | /** @copydoc load_u8 */ |
85 | | inline uint64_t |
86 | | load_u64(const void *p) |
87 | 247 | { |
88 | 247 | uint64_t res; |
89 | 247 | memcpy(&res, p, sizeof(res)); |
90 | 247 | return res; |
91 | 247 | } |
92 | | |
93 | | /** @copydoc load_u8 */ |
94 | | inline float |
95 | | load_float(const void *p) |
96 | 0 | { |
97 | 0 | float res; |
98 | 0 | memcpy(&res, p, sizeof(res)); |
99 | 0 | return res; |
100 | 0 | } |
101 | | |
102 | | /** @copydoc load_u8 */ |
103 | | inline double |
104 | | load_double(const void *p) |
105 | 0 | { |
106 | 0 | double res; |
107 | 0 | memcpy(&res, p, sizeof(res)); |
108 | 0 | return res; |
109 | 0 | } |
110 | | |
111 | | /** @copydoc load_u8 */ |
112 | | inline bool |
113 | | load_bool(const void *p) |
114 | 0 | { |
115 | 0 | bool res; |
116 | 0 | memcpy(&res, p, sizeof(res)); |
117 | 0 | return res; |
118 | 0 | } |
119 | | |
120 | | /** |
121 | | * @brief Unaligned store to memory. |
122 | | * @param p pointer |
123 | | * @param v number |
124 | | */ |
125 | | inline void |
126 | | store_u8(void *p, uint8_t v) |
127 | 0 | { |
128 | 0 | memcpy(p, &v, sizeof(v)); |
129 | 0 | } |
130 | | |
131 | | /** @copydoc store_u8 */ |
132 | | inline void |
133 | | store_u16(void *p, uint16_t v) |
134 | 0 | { |
135 | 0 | memcpy(p, &v, sizeof(v)); |
136 | 0 | } |
137 | | |
138 | | /** @copydoc store_u8 */ |
139 | | inline void |
140 | | store_u32(void *p, uint32_t v) |
141 | 0 | { |
142 | 0 | memcpy(p, &v, sizeof(v)); |
143 | 0 | } |
144 | | |
145 | | /** @copydoc store_u8 */ |
146 | | inline void |
147 | | store_u64(void *p, uint64_t v) |
148 | 0 | { |
149 | 0 | memcpy(p, &v, sizeof(v)); |
150 | 0 | } |
151 | | |
152 | | /** @copydoc store_u8 */ |
153 | | inline void |
154 | | store_float(void *p, float v) |
155 | 0 | { |
156 | 0 | memcpy(p, &v, sizeof(v)); |
157 | 0 | } |
158 | | |
159 | | /** @copydoc store_u8 */ |
160 | | inline void |
161 | | store_double(void *p, double v) |
162 | 0 | { |
163 | 0 | memcpy(p, &v, sizeof(v)); |
164 | 0 | } |
165 | | |
166 | | /** @copydoc store_bool */ |
167 | | inline void |
168 | | store_bool(void *p, bool v) |
169 | 0 | { |
170 | 0 | memcpy(p, &v, sizeof(v)); |
171 | 0 | } |
172 | | |
173 | | /** |
174 | | * @brief Returns the size of memory needed to store a bitmap |
175 | | * of \a bit_count bits. |
176 | | * The function rounds the size up to a multiple of the word |
177 | | * size, which is required by bit_set() and bit_clear(). |
178 | | * @param bit_count number of bits in the bitmap |
179 | | * @retval bitmap size, in bytes |
180 | | */ |
181 | | #define BITMAP_SIZE(bit_count) \ |
182 | 0 | (DIV_ROUND_UP((bit_count), CHAR_BIT * sizeof(long)) * sizeof(long)) |
183 | | |
184 | | /** |
185 | | * @brief Test bit \a pos in memory chunk \a data |
186 | | * @param data memory chunk |
187 | | * @param pos bit number (zero-based) |
188 | | * @retval true bit \a pos is set in \a data |
189 | | * @retval false otherwise |
190 | | */ |
191 | | inline bool |
192 | | bit_test(const void *data, size_t pos) |
193 | 0 | { |
194 | 0 | size_t chunk = pos / CHAR_BIT; |
195 | 0 | size_t offset = pos % CHAR_BIT; |
196 | |
|
197 | 0 | const uint8_t *ldata = (const uint8_t *)data; |
198 | 0 | return (ldata[chunk] >> offset) & 0x1; |
199 | 0 | } |
200 | | |
201 | | /** |
202 | | * @brief Set bit \a pos in a memory chunk \a data |
203 | | * @param data memory chunk |
204 | | * @param pos bit number (zero-based) |
205 | | * @return previous value |
206 | | * @see bit_test |
207 | | * @see bit_clear |
208 | | */ |
209 | | inline bool |
210 | | bit_set(void *data, size_t pos) |
211 | 1.55M | { |
212 | 1.55M | size_t chunk = pos / CHAR_BIT; |
213 | 1.55M | size_t offset = pos % CHAR_BIT; |
214 | | |
215 | 1.55M | uint8_t *ldata = (uint8_t *)data; |
216 | 1.55M | bool prev = (ldata[chunk] >> offset) & 0x1; |
217 | 1.55M | ldata[chunk] |= (1UL << offset); |
218 | 1.55M | return prev; |
219 | 1.55M | } |
220 | | |
221 | | /** |
222 | | * @brief Clear bit \a pos in memory chunk \a data |
223 | | * @param data memory chunk |
224 | | * @param pos bit number (zero-based) |
225 | | * @return previous value |
226 | | * @see bit_test |
227 | | * @see bit_set |
228 | | */ |
229 | | inline bool |
230 | | bit_clear(void *data, size_t pos) |
231 | 0 | { |
232 | 0 | size_t chunk = pos / CHAR_BIT; |
233 | 0 | size_t offset = pos % CHAR_BIT; |
234 | |
|
235 | 0 | uint8_t *ldata = (uint8_t *)data; |
236 | 0 | bool prev = (ldata[chunk] >> offset) & 0x1; |
237 | 0 | ldata[chunk] &= ~(1UL << offset); |
238 | 0 | return prev; |
239 | 0 | } |
240 | | |
241 | | /** |
242 | | * @brief Set \a count bits in a memory chunk \a data starting from bit \a pos |
243 | | * to the value \a val. |
244 | | * @param data - memory chunk |
245 | | * @param pos - the first bit number (zero-based) |
246 | | * @param count - the amount of bits to set |
247 | | * @param val - the new value of bits |
248 | | */ |
249 | | inline void |
250 | | bit_set_range(void *data, size_t pos, size_t count, bool val) |
251 | 0 | { |
252 | 0 | if (count == 0) |
253 | 0 | return; |
254 | | /* |
255 | | * We can have: |
256 | | * - a head of bits in the start; |
257 | | * - a bunch of whole bytes in the middle; |
258 | | * - a tail of bits in the end. |
259 | | */ |
260 | 0 | size_t pos_byte = pos / CHAR_BIT; |
261 | 0 | size_t pos_bit = pos % CHAR_BIT; |
262 | | /* |
263 | | * The head may be the only byte to copy to. |
264 | | */ |
265 | 0 | size_t head_size = pos_bit + count < CHAR_BIT ? |
266 | 0 | count : CHAR_BIT - pos_bit; |
267 | 0 | size_t rest_size = count - head_size; /* Can be 0. */ |
268 | 0 | size_t body_size = rest_size / CHAR_BIT; /* In bytes. */ |
269 | 0 | size_t tail_size = rest_size % CHAR_BIT; /* In bits. */ |
270 | |
|
271 | 0 | size_t head_mask = ((1ULL << head_size) - 1) << pos_bit; |
272 | 0 | size_t tail_mask = ((1ULL << tail_size) - 1); |
273 | |
|
274 | 0 | uint8_t value = val ? 0xFF : 0x00; |
275 | 0 | uint8_t *head = (uint8_t *)data + pos_byte; |
276 | 0 | uint8_t *body = head + 1; |
277 | 0 | uint8_t *tail = body + body_size; |
278 | | /* |
279 | | * Set the head bits. |
280 | | */ |
281 | 0 | *head = (*head & ~head_mask) | (value & head_mask); |
282 | | /* |
283 | | * Set the body bytes. |
284 | | */ |
285 | 0 | memset(body, value, body_size); |
286 | | /* |
287 | | * Set the tail bits. The if-statement is required to avoid overwriting |
288 | | * a byte beyond the buffer even if `tail_mask' is empty. |
289 | | */ |
290 | 0 | if (tail_size > 0) |
291 | 0 | *tail = (*tail & ~tail_mask) | (value & tail_mask); |
292 | | /* |
293 | | * Once you are done trying to "optimize" this routine, and have |
294 | | * realized what a terrible mistake that was, please increment |
295 | | * the following counter as a warning to the next guy: |
296 | | * |
297 | | * total_hours_wasted_here = 8 |
298 | | */ |
299 | 0 | } |
300 | | |
301 | | /** |
302 | | * @brief Copy \a count bits from memory chunk \a src starting from bit \a src_i |
303 | | * into \a dst starting from bit \a dst_i. |
304 | | * @param dst - the memory chunk to copy bits into. |
305 | | * @param dst_i - the position to copy bits into. |
306 | | * @param count - the amount of bits to copy. |
307 | | * @param src - the memory chunk to copy bits from. |
308 | | * @param src_i - the position to copy bits from. |
309 | | * @pre the bit buffers do not overlap. |
310 | | */ |
311 | | void |
312 | | bit_copy_range(uint8_t *restrict dst, size_t dst_i, const uint8_t *restrict src, |
313 | | size_t src_i, size_t count); |
314 | | |
315 | | /** |
316 | | * @brief Copy \a count bits from memory chunk \a src starting from bit \a src_i |
317 | | * in backward order into \a dst starting from bit \a dst_i in forward order. |
318 | | * @param dst - the memory chunk to copy bits into. |
319 | | * @param dst_i - the position to copy bits into. |
320 | | * @param count - the amount of bits to copy. |
321 | | * @param src - the memory chunk to copy bits from. |
322 | | * @param src_i - the position to copy bits from. |
323 | | * @pre the bit buffers do not overlap. |
324 | | */ |
325 | | void |
326 | | bit_copy_range_reverse(uint8_t *restrict dst, size_t dst_i, |
327 | | const uint8_t *restrict src, size_t src_i, size_t count); |
328 | | |
329 | | /** |
330 | | * @cond false |
331 | | * @brief Naive implementation of ctz. |
332 | | */ |
333 | | #define CTZ_NAIVE(x, bitsize) { \ |
334 | | if (x == 0) { \ |
335 | | return (bitsize); \ |
336 | | } \ |
337 | | \ |
338 | | int r = 0; \ |
339 | | for (; (x & 1) == 0; r++) { \ |
340 | | x >>= 1; \ |
341 | | } \ |
342 | | \ |
343 | | return r; \ |
344 | | } |
345 | | /** @endcond */ |
346 | | |
347 | | /** |
348 | | * @brief Count Trailing Zeros. |
349 | | * Returns the number of trailing 0-bits in @a x, starting at the least |
350 | | * significant bit position. If @a x is 0, the result is undefined. |
351 | | * @param x integer |
352 | | * @see __builtin_ctz() |
353 | | * @return the number trailing 0-bits |
354 | | */ |
355 | | inline int |
356 | | bit_ctz_u32(uint32_t x) |
357 | 0 | { |
358 | 0 | #if defined(HAVE_BUILTIN_CTZ) |
359 | 0 | return __builtin_ctz(x); |
360 | | #elif defined(HAVE_FFSL) |
361 | | return ffsl(x) - 1; |
362 | | #else |
363 | | CTZ_NAIVE(x, sizeof(uint32_t) * CHAR_BIT); |
364 | | #endif |
365 | 0 | } |
366 | | |
367 | | /** |
368 | | * @copydoc bit_ctz_u32 |
369 | | */ |
370 | | inline int |
371 | | bit_ctz_u64(uint64_t x) |
372 | 535 | { |
373 | 535 | #if defined(HAVE_BUILTIN_CTZLL) |
374 | 535 | return __builtin_ctzll(x); |
375 | | #elif defined(HAVE_FFSLL) |
376 | | return ffsll(x) - 1; |
377 | | #else |
378 | | CTZ_NAIVE(x, sizeof(uint64_t) * CHAR_BIT); |
379 | | #endif |
380 | 535 | } |
381 | | |
382 | | #undef CTZ_NAIVE |
383 | | |
384 | | /** |
385 | | * @cond false |
386 | | * @brief Naive implementation of clz. |
387 | | */ |
388 | | #define CLZ_NAIVE(x, bitsize) { \ |
389 | | if (x == 0) { \ |
390 | | return (bitsize); \ |
391 | | } \ |
392 | | \ |
393 | | int r = (bitsize); \ |
394 | | for (; x; r--) { \ |
395 | | x >>= 1; \ |
396 | | } \ |
397 | | \ |
398 | | return r; \ |
399 | | } |
400 | | /** @endcond */ |
401 | | |
402 | | /** |
403 | | * @brief Count Leading Zeros. |
404 | | * Returns the number of leading 0-bits in @a x, starting at the most |
405 | | * significant bit position. If @a x is 0, the result is undefined. |
406 | | * @param x integer |
407 | | * @see __builtin_clz() |
408 | | * @return the number of leading 0-bits |
409 | | */ |
410 | | inline int |
411 | | bit_clz_u32(uint32_t x) |
412 | 0 | { |
413 | 0 | #if defined(HAVE_BUILTIN_CLZ) |
414 | 0 | return __builtin_clz(x); |
415 | | #else /* !defined(HAVE_BUILTIN_CLZ) */ |
416 | | CLZ_NAIVE(x, sizeof(uint32_t) * CHAR_BIT); |
417 | | #endif |
418 | 0 | } |
419 | | |
420 | | /** |
421 | | * @copydoc bit_clz_u32 |
422 | | */ |
423 | | inline int |
424 | | bit_clz_u64(uint64_t x) |
425 | 0 | { |
426 | 0 | #if defined(HAVE_BUILTIN_CLZLL) |
427 | 0 | return __builtin_clzll(x); |
428 | | #else /* !defined(HAVE_BUILTIN_CLZLL) */ |
429 | | CLZ_NAIVE(x, sizeof(uint64_t) * CHAR_BIT); |
430 | | #endif |
431 | 0 | } |
432 | | |
433 | | #undef CLZ_NAIVE |
434 | | |
435 | | /** |
436 | | * @cond false |
437 | | * @brief Naive implementation of popcount. |
438 | | */ |
439 | | #define POPCOUNT_NAIVE(x, bitsize) { \ |
440 | | int r; \ |
441 | | for (r = 0; x; r++) { \ |
442 | | x &= (x-1); \ |
443 | | } \ |
444 | | \ |
445 | | return r; \ |
446 | | } |
447 | | /** @endcond */ |
448 | | |
449 | | /** |
450 | | * @brief Returns the number of 1-bits in @a x. |
451 | | * @param x integer |
452 | | * @see __builtin_popcount() |
453 | | * @return the number of 1-bits in @a x |
454 | | */ |
455 | | inline int |
456 | | bit_count_u32(uint32_t x) |
457 | 0 | { |
458 | 0 | #if defined(HAVE_BUILTIN_POPCOUNT) |
459 | 0 | return __builtin_popcount(x); |
460 | | #else /* !defined(HAVE_BUILTIN_POPCOUNT) */ |
461 | | POPCOUNT_NAIVE(x, sizeof(uint32_t) * CHAR_BIT); |
462 | | #endif |
463 | 0 | } |
464 | | |
465 | | /** |
466 | | * @copydoc bit_count_u32 |
467 | | */ |
468 | | inline int |
469 | | bit_count_u64(uint64_t x) |
470 | 0 | { |
471 | 0 | #if defined(HAVE_BUILTIN_POPCOUNTLL) |
472 | 0 | return __builtin_popcountll(x); |
473 | | #else /* !defined(HAVE_BUILTIN_POPCOUNTLL) */ |
474 | | POPCOUNT_NAIVE(x, sizeof(uint64_t) * CHAR_BIT); |
475 | | #endif |
476 | 0 | } |
477 | | |
478 | | #undef POPCOUNT_NAIVE |
479 | | |
480 | | /** |
481 | | * @brief Returns the number of 1-bits in @a data vector starting from |
482 | | * @a bit_offset. |
483 | | * @param data byte vector of length @a length bits. |
484 | | * @param bit_offset offset within the byte vector from where to start |
485 | | * counting 1-bits. |
486 | | * @param length length in bits of byte vector @a data. |
487 | | * @return the number of 1-bits in @a data. |
488 | | * |
489 | | * Implementation adopted from the internals of the Apache |
490 | | * Arrow C++ library. |
491 | | */ |
492 | | size_t |
493 | | bit_count(const uint8_t *data, size_t bit_offset, size_t length); |
494 | | |
495 | | /** |
496 | | * @brief Rotate @a x left by @a r bits |
497 | | * @param x integer |
498 | | * @param r number for bits to rotate |
499 | | * @return @a x rotated left by @a r bits |
500 | | */ |
501 | | inline uint32_t |
502 | | bit_rotl_u32(uint32_t x, int r) |
503 | 0 | { |
504 | 0 | assert(r > 0 && r < 32); |
505 | | /* gcc recognises this code and generates a rotate instruction */ |
506 | 0 | return ((x << r) | (x >> (32 - r))); |
507 | 0 | } |
508 | | |
509 | | /** |
510 | | * @copydoc bit_rotl_u32 |
511 | | */ |
512 | | inline uint64_t |
513 | | bit_rotl_u64(uint64_t x, int r) |
514 | 0 | { |
515 | 0 | assert(r > 0 && r < 64); |
516 | | /* gcc recognises this code and generates a rotate instruction */ |
517 | 0 | return ((x << r) | (x >> (64 - r))); |
518 | 0 | } |
519 | | |
520 | | /** |
521 | | * @copydoc bit_rotl_u32 |
522 | | */ |
523 | | __attribute__ ((const)) inline uintmax_t |
524 | | bit_rotl_umax(uintmax_t x, int r) |
525 | 0 | { |
526 | 0 | assert(r > 0 && r < (int)(sizeof(uintmax_t) * CHAR_BIT)); |
527 | 0 | /* gcc recognises this code and generates a rotate instruction */ |
528 | 0 | return ((x << r) | (x >> (sizeof(uintmax_t) * CHAR_BIT - r))); |
529 | 0 | } |
530 | | /** |
531 | | * @brief Rotate @a x right by @a r bits |
532 | | * @param x integer |
533 | | * @param r number for bits to rotate |
534 | | * @return @a x rotated right by @a r bits |
535 | | * @todo Move this method to bit.h |
536 | | */ |
537 | | inline uint32_t |
538 | | bit_rotr_u32(uint32_t x, int r) |
539 | 0 | { |
540 | 0 | assert(r > 0 && r < 32); |
541 | | /* gcc recognises this code and generates a rotate instruction */ |
542 | 0 | return ((x >> r) | (x << (32 - r))); |
543 | 0 | } |
544 | | |
545 | | /** |
546 | | * @copydoc bit_rotr_u32 |
547 | | */ |
548 | | inline uint64_t |
549 | | bit_rotr_u64(uint64_t x, int r) |
550 | 0 | { |
551 | 0 | assert(r > 0 && r < 64); |
552 | | /* gcc recognises this code and generates a rotate instruction */ |
553 | 0 | return ((x >> r) | (x << (64 - r))); |
554 | 0 | } |
555 | | |
556 | | /** |
557 | | * @copydoc bswap_u32 |
558 | | */ |
559 | | inline uint16_t |
560 | | bswap_u16(uint16_t x) |
561 | 0 | { |
562 | | #if defined(HAVE_BUILTIN_BSWAP16) |
563 | | return __builtin_bswap16(x); |
564 | | #else /* !defined(HAVE_BUILTIN_BSWAP16) */ |
565 | 0 | return ((x << 8) & UINT16_C(0xff00)) | |
566 | 0 | ((x >> 8) & UINT16_C(0x00ff)); |
567 | 0 | #endif |
568 | 0 | } |
569 | | |
570 | | /** |
571 | | * @brief Returns a byte order swapped integer @a x. |
572 | | * This function does not take into account host architecture |
573 | | * (as it done by htonl / ntohl functions) and always returns @a x |
574 | | * with byte order swapped (BE -> LE if @a x is in BE and vice versa). |
575 | | * @param x integer |
576 | | * @return @a x with swapped bytes |
577 | | */ |
578 | | inline uint32_t |
579 | | bswap_u32(uint32_t x) |
580 | 0 | { |
581 | 0 | #if defined(HAVE_BUILTIN_BSWAP32) |
582 | 0 | return __builtin_bswap32(x); |
583 | | #else /* !defined(HAVE_BUILTIN_BSWAP32) */ |
584 | | return ((x << 24) & UINT32_C(0xff000000)) | |
585 | | ((x << 8) & UINT32_C(0x00ff0000)) | |
586 | | ((x >> 8) & UINT32_C(0x0000ff00)) | |
587 | | ((x >> 24) & UINT32_C(0x000000ff)); |
588 | | #endif |
589 | 0 | } |
590 | | |
591 | | /** |
592 | | * @copydoc bswap_u32 |
593 | | */ |
594 | | inline uint64_t |
595 | | bswap_u64(uint64_t x) |
596 | 0 | { |
597 | 0 | #if defined(HAVE_BUILTIN_BSWAP64) |
598 | 0 | return __builtin_bswap64(x); |
599 | | #else /* !defined(HAVE_BUILTIN_BSWAP64) */ |
600 | | return ( (x << 56) & UINT64_C(0xff00000000000000)) | |
601 | | ( (x << 40) & UINT64_C(0x00ff000000000000)) | |
602 | | ( (x << 24) & UINT64_C(0x0000ff0000000000)) | |
603 | | ( (x << 8) & UINT64_C(0x000000ff00000000)) | |
604 | | ( (x >> 8) & UINT64_C(0x00000000ff000000)) | |
605 | | ( (x >> 24) & UINT64_C(0x0000000000ff0000)) | |
606 | | ( (x >> 40) & UINT64_C(0x000000000000ff00)) | |
607 | | ( (x >> 56) & UINT64_C(0x00000000000000ff)); |
608 | | #endif |
609 | 0 | } |
610 | | |
611 | | /** |
612 | | * @brief Reverse bits in \a x. |
613 | | * @param x value |
614 | | * @return value with bits reversed |
615 | | */ |
616 | | static inline uint8_t |
617 | | bit_reverse_u8(uint8_t x) |
618 | 0 | { |
619 | 0 | x = ((x & 0x55) << 1) | ((x >> 1) & 0x55); |
620 | 0 | x = ((x & 0x33) << 2) | ((x >> 2) & 0x33); |
621 | 0 | x = (x << 4) | (x >> 4); |
622 | 0 | return x; |
623 | 0 | } Unexecuted instantiation: xrow_decode_error_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: xrow.c:bit_reverse_u8 Unexecuted instantiation: iproto_features.c:bit_reverse_u8 Unexecuted instantiation: error.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: vclock.c:bit_reverse_u8 Unexecuted instantiation: mpstream.c:bit_reverse_u8 Unexecuted instantiation: error_payload.c:bit_reverse_u8 Unexecuted instantiation: tt_uuid.c:bit_reverse_u8 Unexecuted instantiation: mp_uuid.c:bit_reverse_u8 Unexecuted instantiation: mp_datetime.c:bit_reverse_u8 Unexecuted instantiation: random.c:bit_reverse_u8 Unexecuted instantiation: bit.c:bit_reverse_u8 Unexecuted instantiation: xrow_decode_auth_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: xrow_greeting_decode_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: xrow_decode_id_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: xrow_decode_raft_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: xrow_decode_dml_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: xrow_decode_sql_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: vclock_from_string_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: xrow_decode_call_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: xrow_decode_watch_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: swim_proto_member_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: swim_proto.c:bit_reverse_u8 Unexecuted instantiation: swim_proto_meta_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: xrow_header_decode_fuzzer.c:bit_reverse_u8 Unexecuted instantiation: box.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: gc.c:bit_reverse_u8 Unexecuted instantiation: user.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: authentication.c:bit_reverse_u8 Unexecuted instantiation: replication.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: recovery.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: applier.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: relay.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: journal.c:bit_reverse_u8 Unexecuted instantiation: sql.c:bit_reverse_u8 Unexecuted instantiation: wal.c:bit_reverse_u8 Unexecuted instantiation: call.c:bit_reverse_u8 Unexecuted instantiation: alter.c:bit_reverse_u8 Unexecuted instantiation: build.c:bit_reverse_u8 Unexecuted instantiation: expr.c:bit_reverse_u8 Unexecuted instantiation: func.c:bit_reverse_u8 Unexecuted instantiation: global.c:bit_reverse_u8 Unexecuted instantiation: main.c:bit_reverse_u8 Unexecuted instantiation: malloc.c:bit_reverse_u8 Unexecuted instantiation: mem.c:bit_reverse_u8 Unexecuted instantiation: os.c:bit_reverse_u8 Unexecuted instantiation: os_unix.c:bit_reverse_u8 Unexecuted instantiation: parse_def.c:bit_reverse_u8 Unexecuted instantiation: prepare.c:bit_reverse_u8 Unexecuted instantiation: printf.c:bit_reverse_u8 Unexecuted instantiation: resolve.c:bit_reverse_u8 Unexecuted instantiation: port.c:bit_reverse_u8 Unexecuted instantiation: select.c:bit_reverse_u8 Unexecuted instantiation: tokenize.c:bit_reverse_u8 Unexecuted instantiation: treeview.c:bit_reverse_u8 Unexecuted instantiation: trigger.c:bit_reverse_u8 Unexecuted instantiation: update.c:bit_reverse_u8 Unexecuted instantiation: util.c:bit_reverse_u8 Unexecuted instantiation: vdbe.c:bit_reverse_u8 Unexecuted instantiation: vdbeapi.c:bit_reverse_u8 Unexecuted instantiation: vdbeaux.c:bit_reverse_u8 Unexecuted instantiation: vdbesort.c:bit_reverse_u8 Unexecuted instantiation: walker.c:bit_reverse_u8 Unexecuted instantiation: where.c:bit_reverse_u8 Unexecuted instantiation: wherecode.c:bit_reverse_u8 Unexecuted instantiation: whereexpr.c:bit_reverse_u8 Unexecuted instantiation: console.c:bit_reverse_u8 Unexecuted instantiation: serialize_lua.c:bit_reverse_u8 Unexecuted instantiation: tuple.c:bit_reverse_u8 Unexecuted instantiation: misc.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: execute.c:bit_reverse_u8 Unexecuted instantiation: tuple_format.c:bit_reverse_u8 Unexecuted instantiation: msgpack.c:bit_reverse_u8 Unexecuted instantiation: iproto.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: xrow_io.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: tuple_convert.c:bit_reverse_u8 Unexecuted instantiation: index.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: index_def.c:bit_reverse_u8 Unexecuted instantiation: index_weak_ref.c:bit_reverse_u8 Unexecuted instantiation: memtx_bitset.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: memtx_tx.c:bit_reverse_u8 Unexecuted instantiation: memtx_engine.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: memtx_space.c:bit_reverse_u8 Unexecuted instantiation: memtx_sort_data.c:bit_reverse_u8 Unexecuted instantiation: sysview.c:bit_reverse_u8 Unexecuted instantiation: blackhole.c:bit_reverse_u8 Unexecuted instantiation: service_engine.c:bit_reverse_u8 Unexecuted instantiation: session_settings.c:bit_reverse_u8 Unexecuted instantiation: vinyl.c:bit_reverse_u8 Unexecuted instantiation: vy_stmt.c:bit_reverse_u8 Unexecuted instantiation: vy_mem.c:bit_reverse_u8 Unexecuted instantiation: vy_run.c:bit_reverse_u8 Unexecuted instantiation: vy_lsm.c:bit_reverse_u8 Unexecuted instantiation: vy_tx.c:bit_reverse_u8 Unexecuted instantiation: vy_read_iterator.c:bit_reverse_u8 Unexecuted instantiation: vy_point_lookup.c:bit_reverse_u8 Unexecuted instantiation: vy_cache.c:bit_reverse_u8 Unexecuted instantiation: vy_log.c:bit_reverse_u8 Unexecuted instantiation: vy_upsert.c:bit_reverse_u8 Unexecuted instantiation: vy_history.c:bit_reverse_u8 Unexecuted instantiation: vy_read_set.c:bit_reverse_u8 Unexecuted instantiation: vy_scheduler.c:bit_reverse_u8 Unexecuted instantiation: vy_regulator.c:bit_reverse_u8 Unexecuted instantiation: space.c:bit_reverse_u8 Unexecuted instantiation: space_cache.c:bit_reverse_u8 Unexecuted instantiation: space_def.c:bit_reverse_u8 Unexecuted instantiation: sequence.c:bit_reverse_u8 Unexecuted instantiation: field_default_func.c:bit_reverse_u8 Unexecuted instantiation: tuple_constraint_func.c:bit_reverse_u8 Unexecuted instantiation: tuple_constraint_fkey.c:bit_reverse_u8 Unexecuted instantiation: key_list.c:bit_reverse_u8 Unexecuted instantiation: alter.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: schema.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: session.c:bit_reverse_u8 Unexecuted instantiation: checkpoint.c:bit_reverse_u8 Unexecuted instantiation: txn.c:bit_reverse_u8 Unexecuted instantiation: txn_limbo.c:bit_reverse_u8 Unexecuted instantiation: txn_event_trigger.c:bit_reverse_u8 Unexecuted instantiation: raft.c:bit_reverse_u8 Unexecuted instantiation: bind.c:bit_reverse_u8 Unexecuted instantiation: read_view.c:bit_reverse_u8 Unexecuted instantiation: xlog_reader.c:bit_reverse_u8 Unexecuted instantiation: opcodes.c:bit_reverse_u8 Unexecuted instantiation: parse.c:bit_reverse_u8 Unexecuted instantiation: cursor.c:bit_reverse_u8 Unexecuted instantiation: delete.c:bit_reverse_u8 Unexecuted instantiation: hash.c:bit_reverse_u8 Unexecuted instantiation: insert.c:bit_reverse_u8 Unexecuted instantiation: pragma.c:bit_reverse_u8 Unexecuted instantiation: show.c:bit_reverse_u8 Unexecuted instantiation: iproto.c:bit_reverse_u8 Unexecuted instantiation: space_upgrade.c:bit_reverse_u8 Unexecuted instantiation: memtx_space_upgrade.c:bit_reverse_u8 Unexecuted instantiation: memtx_allocator.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: memtx_hash.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: memtx_tree.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: memtx_rtree.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: vy_range.c:bit_reverse_u8 Unexecuted instantiation: vy_write_iterator.c:bit_reverse_u8 Unexecuted instantiation: request.c:bit_reverse_u8 Unexecuted instantiation: func_adapter.c:bit_reverse_u8 Unexecuted instantiation: field_map.c:bit_reverse_u8 Unexecuted instantiation: tuple_format_map.c:bit_reverse_u8 Unexecuted instantiation: tuple_constraint.c:bit_reverse_u8 Unexecuted instantiation: tuple_builder.c:bit_reverse_u8 Unexecuted instantiation: xrow_update.c:bit_reverse_u8 Unexecuted instantiation: xrow_update_field.c:bit_reverse_u8 Unexecuted instantiation: xrow_update_array.c:bit_reverse_u8 Unexecuted instantiation: xrow_update_bar.c:bit_reverse_u8 Unexecuted instantiation: xrow_update_route.c:bit_reverse_u8 Unexecuted instantiation: xrow_update_map.c:bit_reverse_u8 Unexecuted instantiation: tuple_compare.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: tuple_extract_key.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: tuple_hash.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: tuple_bloom.c:bit_reverse_u8 Unexecuted instantiation: key_def.c:bit_reverse_u8 Unexecuted instantiation: field_def.c:bit_reverse_u8 Unexecuted instantiation: opt_def.c:bit_reverse_u8 Unexecuted instantiation: mp_tuple.c:bit_reverse_u8 Unexecuted instantiation: xlog.c:bit_reverse_u8 Unexecuted instantiation: utils.c:bit_reverse_u8 Unexecuted instantiation: pickle.c:bit_reverse_u8 Unexecuted instantiation: lyaml.cc:bit_reverse_u8(unsigned char) Unexecuted instantiation: lua_cjson.c:bit_reverse_u8 Unexecuted instantiation: iterator.c:bit_reverse_u8 Unexecuted instantiation: index.c:bit_reverse_u8 Unexecuted instantiation: bitset.c:bit_reverse_u8 Unexecuted instantiation: page.c:bit_reverse_u8 Unexecuted instantiation: swim.c:bit_reverse_u8 Unexecuted instantiation: swim_io.c:bit_reverse_u8 Unexecuted instantiation: fio.c:bit_reverse_u8 Unexecuted instantiation: bloom.c:bit_reverse_u8 Unexecuted instantiation: xrow_decode_begin_fuzzer.c:bit_reverse_u8 |
624 | | |
625 | | /** |
626 | | * @brief Index bits in the @a x, i.e. find all positions where bits are set. |
627 | | * This method fills @a indexes array with found positions in increasing order. |
628 | | * @a offset is added to each index before putting it into @a indexes. |
629 | | * @param x integer |
630 | | * @param indexes memory array where found indexes are stored |
631 | | * @param offset a number added to each index |
632 | | * @return pointer to last+1 element in indexes array |
633 | | */ |
634 | | int * |
635 | | bit_index_u32(uint32_t x, int *indexes, int offset); |
636 | | |
637 | | /** |
638 | | * @copydoc bit_index_u32 |
639 | | */ |
640 | | int * |
641 | | bit_index_u64(uint64_t x, int *indexes, int offset); |
642 | | |
643 | | /** @cond false **/ |
644 | | #if defined(__x86_64__) |
645 | | /* Use bigger words on x86_64 */ |
646 | | #define ITER_UINT uint64_t |
647 | 535 | #define ITER_CTZ bit_ctz_u64 |
648 | 0 | #define ITER_LOAD load_u64 |
649 | | #else |
650 | | #define ITER_UINT uint32_t |
651 | | #define ITER_CTZ bit_ctz_u32 |
652 | | #define ITER_LOAD load_u32 |
653 | | #endif |
654 | | /** @endcond **/ |
655 | | |
656 | | /** |
657 | | * @brief The Bit Iterator |
658 | | */ |
659 | | struct bit_iterator { |
660 | | /** @cond false **/ |
661 | | /** Current word to process using ctz **/ |
662 | | ITER_UINT word; |
663 | | /** A bitmask that XORed with word (for set = false iteration) **/ |
664 | | ITER_UINT word_xor; |
665 | | /** A base offset of the word in bits **/ |
666 | | size_t word_base; |
667 | | /** A pointer to the start of a memory chunk **/ |
668 | | const char *start; |
669 | | /** A pointer to the next part of a memory chunk */ |
670 | | const char *next; |
671 | | /** A pointer to the end of a memory chunk */ |
672 | | const char *end; |
673 | | /** @endcond **/ |
674 | | }; |
675 | | |
676 | | /** |
677 | | * @brief Initialize bit iterator \a it |
678 | | * @param it bit iterator |
679 | | * @param data memory chunk |
680 | | * @param size size of the memory chunk \a data |
681 | | * @param set true to iterate over set bits or false to iterate over clear bits |
682 | | */ |
683 | | inline void |
684 | | bit_iterator_init(struct bit_iterator *it, const void *data, size_t size, |
685 | | bool set) |
686 | 49 | { |
687 | 49 | it->start = (const char *) data; |
688 | 49 | it->next = it->start; |
689 | 49 | it->end = it->next + size; |
690 | 49 | if (unlikely(size == 0)) { |
691 | 0 | it->word = 0; |
692 | 0 | return; |
693 | 0 | } |
694 | | |
695 | 49 | it->word_xor = set ? 0 : (ITER_UINT) -1; |
696 | 49 | it->word_base = 0; |
697 | | |
698 | | /* Check if size is a multiple of sizeof(ITER_UINT) */ |
699 | 49 | if (likely(size % sizeof(ITER_UINT) == 0)) { |
700 | 0 | it->word = ITER_LOAD(it->next); |
701 | 0 | it->next += sizeof(ITER_UINT); |
702 | 49 | } else { |
703 | 49 | const char *e = it->next + size % sizeof(ITER_UINT); |
704 | 49 | it->word = it->word_xor; |
705 | 49 | char *w = (char *) &it->word; |
706 | 245 | while (it->next < e) |
707 | 196 | *w++ = *it->next++; |
708 | 49 | } |
709 | 49 | it->word ^= it->word_xor; |
710 | 49 | } |
711 | | |
712 | | /** |
713 | | * @brief Return a number of a next set bit in \a it or \a SIZE_MAX |
714 | | * if no bits are remain in \a it |
715 | | * @param it bit iterator |
716 | | * @retval a zero-based number of a next set bit in iterator \a it |
717 | | * @retval SIZE_MAX if \a it does not have more set bits |
718 | | */ |
719 | | inline size_t |
720 | | bit_iterator_next(struct bit_iterator *it) |
721 | 584 | { |
722 | 584 | while (unlikely(it->word == 0)) { |
723 | 49 | if (unlikely(it->next >= it->end)) |
724 | 49 | return SIZE_MAX; |
725 | | |
726 | | /* Extract the next word from memory */ |
727 | 0 | it->word = ITER_LOAD(it->next); |
728 | 0 | it->word ^= it->word_xor; |
729 | 0 | it->word_base = (it->next - it->start) * CHAR_BIT; |
730 | 0 | it->next += sizeof(ITER_UINT); |
731 | 0 | } |
732 | | |
733 | | /* Find the position of a first trailing bit in the current word */ |
734 | 535 | int bit = ITER_CTZ(it->word); |
735 | | /* Remove the first trailing bit from the current word */ |
736 | 535 | it->word &= it->word - 1; |
737 | | /* Add start position if the current word to the found bit */ |
738 | 535 | return it->word_base + bit; |
739 | 584 | } |
740 | | |
741 | | #undef ITER_LOAD |
742 | | #undef ITER_CTZ |
743 | | #undef ITER_UINT |
744 | | |
745 | | #if defined(__cplusplus) |
746 | | } /* extern "C" */ |
747 | | #endif /* defined(__cplusplus) */ |
748 | | |
749 | | #endif /* TARANTOOL_LIB_BIT_BIT_H_INCLUDED */ |