1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2023 Ericsson AB 3 */ 4 5 #ifndef _RTE_BITSET_H_ 6 #define _RTE_BITSET_H_ 7 8 /** 9 * @file 10 * RTE Bitset 11 * 12 * This file provides functions and macros for querying and 13 * manipulating sets of bits kept in arrays of @c uint64_t-sized 14 * elements. 15 * 16 * The bits in a bitset are numbered from 0 to @c size - 1, with the 17 * lowest index being the least significant bit. 18 * 19 * The bitset array must be properly aligned. 20 * 21 * For optimal performance, the @c size parameter, required by 22 * many of the API's functions, should be a compile-time constant. 23 * 24 * For large bitsets, the rte_bitmap.h API may be more appropriate. 25 * 26 * @warning 27 * All functions modifying a bitset may overwrite any unused bits of 28 * the last word. Such unused bits are ignored by all functions reading 29 * bits. 30 * 31 */ 32 33 #include <limits.h> 34 #include <stdbool.h> 35 #include <stddef.h> 36 #include <stdint.h> 37 38 #include <rte_bitops.h> 39 #include <rte_branch_prediction.h> 40 #include <rte_common.h> 41 #include <rte_compat.h> 42 #include <rte_debug.h> 43 #include <rte_memcpy.h> 44 45 #ifdef __cplusplus 46 extern "C" { 47 #endif 48 49 /** 50 * The size (in bytes) of each element in the array used to represent 51 * a bitset. 52 */ 53 #define RTE_BITSET_WORD_SIZE (sizeof(uint64_t)) 54 55 /** 56 * The size (in bits) of each element in the array used to represent 57 * a bitset. 58 */ 59 #define RTE_BITSET_WORD_BITS (RTE_BITSET_WORD_SIZE * CHAR_BIT) 60 61 /** 62 * Computes the number of words required to store @c size bits. 63 */ 64 #define RTE_BITSET_NUM_WORDS(size) \ 65 ((size + RTE_BITSET_WORD_BITS - 1) / RTE_BITSET_WORD_BITS) 66 67 /** 68 * Computes the amount of memory (in bytes) required to fit a bitset 69 * holding @c size bits. 70 */ 71 #define RTE_BITSET_SIZE(size) \ 72 ((size_t)(RTE_BITSET_NUM_WORDS(size) * RTE_BITSET_WORD_SIZE)) 73 74 #define __RTE_BITSET_WORD_IDX(bit_num) ((bit_num) / RTE_BITSET_WORD_BITS) 75 #define __RTE_BITSET_BIT_OFFSET(bit_num) ((bit_num) % RTE_BITSET_WORD_BITS) 76 #define __RTE_BITSET_UNUSED(size) \ 77 ((RTE_BITSET_NUM_WORDS(size) * RTE_BITSET_WORD_BITS) - (size)) 78 #define __RTE_BITSET_USED_MASK(size) \ 79 (UINT64_MAX >> __RTE_BITSET_UNUSED(size)) 80 81 #define __RTE_BITSET_DELEGATE_N(fun, bitset, bit_num, ...) \ 82 fun(&(bitset)[__RTE_BITSET_WORD_IDX(bit_num)], __RTE_BITSET_BIT_OFFSET(bit_num), \ 83 __VA_ARGS__) 84 85 /* MSVC doesn't have ##__VA_ARGS__, so argument-less -> special case */ 86 #define __RTE_BITSET_DELEGATE(fun, bitset, bit_num) \ 87 fun(&(bitset)[__RTE_BITSET_WORD_IDX(bit_num)], __RTE_BITSET_BIT_OFFSET(bit_num)) 88 89 /** 90 * @warning 91 * @b EXPERIMENTAL: this API may change without prior notice. 92 * 93 * Declare a bitset. 94 * 95 * Declare (e.g., as a struct field) or define (e.g., as a stack 96 * variable) a bitset of the specified size. 97 * 98 * @param size 99 * The number of bits the bitset must be able to represent. Must be 100 * a compile-time constant. 101 * @param name 102 * The field or variable name of the resulting definition. 103 */ 104 #define RTE_BITSET_DECLARE(name, size) \ 105 uint64_t name[RTE_BITSET_NUM_WORDS(size)] 106 107 #define __RTE_BITSET_FOREACH_LEFT(var, size, start_bit, len) \ 108 ((len) - 1 - ((var) >= (start_bit) ? (var) - (start_bit) : (size) - (start_bit) + (var))) 109 110 #define __RTE_BITSET_FOREACH(var, bitset, size, start_bit, len, flags) \ 111 for ((var) = __rte_bitset_find(bitset, size, start_bit, len, flags); \ 112 (var) != -1; \ 113 (var) = __RTE_BITSET_FOREACH_LEFT(var, size, start_bit, len) > 0 ? \ 114 __rte_bitset_find(bitset, size, ((var) + 1) % (size), \ 115 __RTE_BITSET_FOREACH_LEFT(var, size, start_bit, len), flags) : -1) 116 117 /** 118 * @warning 119 * @b EXPERIMENTAL: this API may change without prior notice. 120 * 121 * Iterate over all bits set. 122 * 123 * This macro iterates over all bits set (i.e., all ones) in the 124 * bitset, in the forward direction (i.e., starting with the least 125 * significant '1'). 126 * 127 * @param var 128 * An iterator variable of type @c ssize_t. For each successive 129 * iteration, this variable will hold the bit index of a set bit. 130 * @param bitset 131 * A <tt>const uint64_t *</tt> pointer to the bitset array. 132 * @param size 133 * The size of the bitset (in bits). 134 */ 135 #define RTE_BITSET_FOREACH_SET(var, bitset, size) \ 136 __RTE_BITSET_FOREACH(var, bitset, size, 0, size, 0) 137 138 /** 139 * @warning 140 * @b EXPERIMENTAL: this API may change without prior notice. 141 * 142 * Iterate over all bits cleared. 143 * 144 * This macro iterates over all bits cleared in the bitset, in the 145 * forward direction (i.e., starting with the lowest-indexed set bit). 146 * 147 * @param var 148 * An iterator variable of type @c ssize_t. For each successive iteration, 149 * this variable will hold the bit index of a cleared bit. 150 * @param bitset 151 * A <tt>const uint64_t *</tt> pointer to the bitset array. 152 * @param size 153 * The size of the bitset (in bits). 154 */ 155 #define RTE_BITSET_FOREACH_CLEAR(var, bitset, size) \ 156 __RTE_BITSET_FOREACH(var, bitset, size, 0, size, __RTE_BITSET_FIND_FLAG_FIND_CLEAR) 157 158 /** 159 * @warning 160 * @b EXPERIMENTAL: this API may change without prior notice. 161 * 162 * Iterate over all bits set within a range. 163 * 164 * This macro iterates over all bits set (i.e., all ones) in the 165 * specified range, in the forward direction (i.e., starting with the 166 * least significant '1'). 167 * 168 * @param var 169 * An iterator variable of type @c ssize_t. For each successive iteration, 170 * this variable will hold the bit index of a set bit. 171 * @param bitset 172 * A <tt>const uint64_t *</tt> pointer to the bitset array. 173 * @param size 174 * The size of the bitset (in bits). 175 * @param start_bit 176 * The index of the first bit to check. Must be less than @c size. 177 * @param len 178 * The length (in bits) of the range. @c start_bit + @c len must be less 179 * than or equal to @c size. 180 */ 181 #define RTE_BITSET_FOREACH_SET_RANGE(var, bitset, size, start_bit, len) \ 182 __RTE_BITSET_FOREACH(var, bitset, size, start_bit, len, 0) 183 184 /** 185 * @warning 186 * @b EXPERIMENTAL: this API may change without prior notice. 187 * 188 * Iterate over all cleared bits within a range. 189 * 190 * This macro iterates over all bits cleared (i.e., all zeroes) in the 191 * specified range, in the forward direction (i.e., starting with the 192 * least significant '0'). 193 * 194 * @param var 195 * An iterator variable of type @c ssize_t. For each successive iteration, 196 * this variable will hold the bit index of a set bit. 197 * @param bitset 198 * A <tt>const uint64_t *</tt> pointer to the bitset array. 199 * @param size 200 * The size of the bitset (in bits). 201 * @param start_bit 202 * The index of the first bit to check. Must be less than @c size. 203 * @param len 204 * The length (in bits) of the range. @c start_bit + @c len must be less 205 * than or equal to @c size. 206 */ 207 #define RTE_BITSET_FOREACH_CLEAR_RANGE(var, bitset, size, start_bit, len) \ 208 __RTE_BITSET_FOREACH(var, bitset, size, start_bit, len, __RTE_BITSET_FIND_FLAG_FIND_CLEAR) 209 210 #define RTE_BITSET_FOREACH_SET_WRAP(var, bitset, size, start_bit, len) \ 211 __RTE_BITSET_FOREACH(var, bitset, size, start_bit, len, __RTE_BITSET_FIND_FLAG_WRAP) 212 213 #define RTE_BITSET_FOREACH_CLEAR_WRAP(var, bitset, size, start_bit, len) \ 214 __RTE_BITSET_FOREACH(var, bitset, size, start_bit, len, \ 215 __RTE_BITSET_FIND_FLAG_WRAP | __RTE_BITSET_FIND_FLAG_FIND_CLEAR) 216 217 /** 218 * @warning 219 * @b EXPERIMENTAL: this API may change without prior notice. 220 * 221 * Initializes a bitset. 222 * 223 * All bits are cleared. 224 * 225 * In case all words in the bitset array are already set to zero by 226 * other means (e.g., at the time of memory allocation), this function 227 * need not be called. 228 * 229 * @param bitset 230 * A pointer to the array of bitset 64-bit words. 231 * @param size 232 * The size of the bitset (in bits). 233 */ 234 __rte_experimental 235 static inline void 236 rte_bitset_init(uint64_t *bitset, size_t size) 237 { 238 memset(bitset, 0, RTE_BITSET_SIZE(size)); 239 } 240 241 /** 242 * @warning 243 * @b EXPERIMENTAL: this API may change without prior notice. 244 * 245 * Test if a bit is set. 246 * 247 * @param bitset 248 * A pointer to the array of words making up the bitset. 249 * @param bit_num 250 * Index of the bit to test. Index 0 is the least significant bit. 251 * @return 252 * Returns true if the bit is '1', and false if the bit is '0'. 253 */ 254 __rte_experimental 255 static inline bool 256 rte_bitset_test(const uint64_t *bitset, size_t bit_num) 257 { 258 return __RTE_BITSET_DELEGATE(rte_bit_test, bitset, bit_num); 259 } 260 261 /** 262 * @warning 263 * @b EXPERIMENTAL: this API may change without prior notice. 264 * 265 * Set a bit in the bitset. 266 * 267 * Bits are numbered from 0 to (size - 1) (inclusive). 268 * 269 * The operation is not guaranteed to be atomic. 270 * 271 * @param bitset 272 * A pointer to the array of words making up the bitset. 273 * @param bit_num 274 * The index of the bit to be set. 275 */ 276 __rte_experimental 277 static inline void 278 rte_bitset_set(uint64_t *bitset, size_t bit_num) 279 { 280 __RTE_BITSET_DELEGATE(rte_bit_set, bitset, bit_num); 281 } 282 283 /** 284 * @warning 285 * @b EXPERIMENTAL: this API may change without prior notice. 286 * 287 * Clear a bit in the bitset. 288 * 289 * Bits are numbered 0 to (size - 1) (inclusive). 290 * 291 * The operation is not guaranteed to be atomic. 292 * 293 * @param bitset 294 * A pointer to the array of words making up the bitset. 295 * @param bit_num 296 * The index of the bit to be cleared. 297 */ 298 __rte_experimental 299 static inline void 300 rte_bitset_clear(uint64_t *bitset, size_t bit_num) 301 { 302 __RTE_BITSET_DELEGATE(rte_bit_clear, bitset, bit_num); 303 } 304 305 /** 306 * @warning 307 * @b EXPERIMENTAL: this API may change without prior notice. 308 * 309 * Set or clear a bit in the bitset. 310 * 311 * Bits are numbered 0 to (size - 1) (inclusive). 312 * 313 * The operation is not guaranteed to be atomic. 314 * 315 * @param bitset 316 * A pointer to the array of words making up the bitset. 317 * @param bit_num 318 * The index of the bit to be set or cleared. 319 * @param bit_value 320 * Control if the bit should be set or cleared. 321 */ 322 __rte_experimental 323 static inline void 324 rte_bitset_assign(uint64_t *bitset, size_t bit_num, bool bit_value) 325 { 326 __RTE_BITSET_DELEGATE_N(rte_bit_assign, bitset, bit_num, bit_value); 327 } 328 329 /** 330 * @warning 331 * @b EXPERIMENTAL: this API may change without prior notice. 332 * 333 * Change the value of a bit in the bitset. 334 * 335 * Bits are numbered 0 to (size - 1) (inclusive). 336 * 337 * The operation is not guaranteed to be atomic. 338 * 339 * @param bitset 340 * A pointer to the array of words making up the bitset. 341 * @param bit_num 342 * The index of the bit to be flipped. 343 */ 344 __rte_experimental 345 static inline void 346 rte_bitset_flip(uint64_t *bitset, size_t bit_num) 347 { 348 __RTE_BITSET_DELEGATE(rte_bit_flip, bitset, bit_num); 349 } 350 351 /** 352 * @warning 353 * @b EXPERIMENTAL: this API may change without prior notice. 354 * 355 * Atomically test if a bit is set. 356 * 357 * Atomically test if a bit in a bitset is set with the specified 358 * memory ordering. 359 * 360 * @param bitset 361 * A pointer to the array of words making up the bitset. 362 * @param bit_num 363 * Index of the bit to test. Index 0 is the least significant bit. 364 * @param memory_order 365 * The memory order to use. 366 * @return 367 * Returns true if the bit is '1', and false if the bit is '0'. 368 */ 369 __rte_experimental 370 static inline bool 371 rte_bitset_atomic_test(const uint64_t *bitset, size_t bit_num, int memory_order) 372 { 373 return __RTE_BITSET_DELEGATE_N(rte_bit_atomic_test, bitset, bit_num, memory_order); 374 } 375 376 /** 377 * @warning 378 * @b EXPERIMENTAL: this API may change without prior notice. 379 * 380 * Atomically set a bit in the bitset. 381 * 382 * Set a bit in a bitset as an atomic operation, with the specified 383 * memory ordering. 384 * 385 * rte_bitset_atomic_set() is multi-thread safe, provided all threads 386 * acting in parallel on the same bitset does so through 387 * @c rte_bitset_atomic_*() functions. 388 * 389 * Bits are numbered from 0 to (size - 1) (inclusive). 390 * 391 * @param bitset 392 * A pointer to the array of words making up the bitset. 393 * @param bit_num 394 * The index of the bit to be set. 395 * @param memory_order 396 * The memory order to use. 397 */ 398 __rte_experimental 399 static inline void 400 rte_bitset_atomic_set(uint64_t *bitset, size_t bit_num, int memory_order) 401 { 402 __RTE_BITSET_DELEGATE_N(rte_bit_atomic_set, bitset, bit_num, memory_order); 403 } 404 405 /** 406 * @warning 407 * @b EXPERIMENTAL: this API may change without prior notice. 408 * 409 * Atomically clear a bit in the bitset. 410 * 411 * Clear a bit in a bitset as an atomic operation, with the specified 412 * memory ordering. 413 * 414 * rte_bitset_atomic_clear() is multi-thread safe, provided all 415 * threads acting in parallel on the same bitset does so through @c 416 * rte_bitset_atomic_*() functions. 417 * 418 * Bits are numbered from 0 to (size - 1) (inclusive). 419 * 420 * @param bitset 421 * A pointer to the array of words making up the bitset. 422 * @param bit_num 423 * The index of the bit to be cleared. 424 * @param memory_order 425 * The memory order to use. 426 */ 427 __rte_experimental 428 static inline void 429 rte_bitset_atomic_clear(uint64_t *bitset, size_t bit_num, int memory_order) 430 { 431 __RTE_BITSET_DELEGATE_N(rte_bit_atomic_clear, bitset, bit_num, memory_order); 432 } 433 434 /** 435 * @warning 436 * @b EXPERIMENTAL: this API may change without prior notice. 437 * 438 * Atomically set or clear a bit in the bitset. 439 * 440 * Assign a value to a bit in a bitset as an atomic operation, with 441 * the specified memory ordering. 442 * 443 * rte_bitset_atomic_assign() is multi-thread safe, provided all 444 * threads acting in parallel on the same bitset does so through 445 * @c rte_bitset_atomic_*() functions. 446 * 447 * Bits are numbered from 0 to (size - 1) (inclusive). 448 * 449 * @param bitset 450 * A pointer to the array of words making up the bitset. 451 * @param bit_num 452 * The index of the bit to be set or cleared. 453 * @param bit_value 454 * Control if the bit should be set or cleared. 455 * @param memory_order 456 * The memory order to use. 457 */ 458 __rte_experimental 459 static inline void 460 rte_bitset_atomic_assign(uint64_t *bitset, size_t bit_num, bool bit_value, int memory_order) 461 { 462 __RTE_BITSET_DELEGATE_N(rte_bit_atomic_assign, bitset, bit_num, bit_value, memory_order); 463 } 464 465 /** 466 * @warning 467 * @b EXPERIMENTAL: this API may change without prior notice. 468 * 469 * Atomically change the value of a bit in the bitset. 470 * 471 * Flip a bit in a bitset as an atomic operation, with the specified 472 * memory ordering. 473 * 474 * rte_bitset_atomic_flip() is multi-thread safe, provided all threads 475 * acting in parallel on the same bitset does so through 476 * @c rte_bitset_atomic_*() functions. 477 * 478 * Bits are numbered from 0 to (size - 1) (inclusive). 479 * 480 * @param bitset 481 * A pointer to the array of words making up the bitset. 482 * @param bit_num 483 * The index of the bit to be flipped. 484 * @param memory_order 485 * The memory order to use. 486 */ 487 __rte_experimental 488 static inline void 489 rte_bitset_atomic_flip(uint64_t *bitset, size_t bit_num, int memory_order) 490 { 491 __RTE_BITSET_DELEGATE_N(rte_bit_atomic_flip, bitset, bit_num, memory_order); 492 } 493 494 /** 495 * @warning 496 * @b EXPERIMENTAL: this API may change without prior notice. 497 * 498 * Set all bits in the bitset. 499 * 500 * @param bitset 501 * A pointer to the array of words making up the bitset. 502 * @param size 503 * The size of the bitset (in bits). 504 */ 505 __rte_experimental 506 static inline void 507 rte_bitset_set_all(uint64_t *bitset, size_t size) 508 { 509 memset(bitset, 0xFF, RTE_BITSET_SIZE(size)); 510 } 511 512 /** 513 * @warning 514 * @b EXPERIMENTAL: this API may change without prior notice. 515 * 516 * Clear all bits in the bitset. 517 * 518 * @param bitset 519 * A pointer to the array of words making up the bitset. 520 * @param size 521 * The size of the bitset (in bits). 522 */ 523 __rte_experimental 524 static inline void 525 rte_bitset_clear_all(uint64_t *bitset, size_t size) 526 { 527 rte_bitset_init(bitset, size); 528 } 529 530 /** 531 * @warning 532 * @b EXPERIMENTAL: this API may change without prior notice. 533 * 534 * Count all set bits (also known as the @e weight). 535 * 536 * @param bitset 537 * A pointer to the array of words making up the bitset. 538 * @param size 539 * The size of the bitset (in bits). 540 * @return 541 * Returns the number of '1' bits in the bitset. 542 */ 543 __rte_experimental 544 static inline size_t 545 rte_bitset_count_set(const uint64_t *bitset, size_t size) 546 { 547 size_t i; 548 size_t total = 0; 549 550 /* 551 * Unused bits in a rte_bitset are always '0', and thus are 552 * not included in this count. 553 */ 554 for (i = 0; i < RTE_BITSET_NUM_WORDS(size) - 1; i++) 555 total += rte_popcount64(bitset[i]); 556 557 total += rte_popcount64(bitset[i] & __RTE_BITSET_USED_MASK(size)); 558 559 return total; 560 } 561 562 /** 563 * @warning 564 * @b EXPERIMENTAL: this API may change without prior notice. 565 * 566 * Count all cleared bits. 567 * 568 * @param bitset 569 * A pointer to the array of words making up the bitset. 570 * @param size 571 * The size of the bitset (in bits). 572 * @return 573 * Returns the number of '0' bits in the bitset. 574 */ 575 __rte_experimental 576 static inline size_t 577 rte_bitset_count_clear(const uint64_t *bitset, size_t size) 578 { 579 return size - rte_bitset_count_set(bitset, size); 580 } 581 582 #define __RTE_BITSET_FIND_FLAG_FIND_CLEAR (1U << 0) 583 #define __RTE_BITSET_FIND_FLAG_WRAP (1U << 1) 584 585 __rte_experimental 586 static inline ssize_t 587 __rte_bitset_find_nowrap(const uint64_t *bitset, size_t __rte_unused size, size_t start_bit, 588 size_t len, bool find_clear) 589 { 590 size_t word_idx; 591 size_t offset; 592 size_t end_bit = start_bit + len; 593 594 RTE_ASSERT(end_bit <= size); 595 596 if (unlikely(len == 0)) 597 return -1; 598 599 word_idx = __RTE_BITSET_WORD_IDX(start_bit); 600 offset = __RTE_BITSET_BIT_OFFSET(start_bit); 601 602 while (word_idx <= __RTE_BITSET_WORD_IDX(end_bit - 1)) { 603 uint64_t word; 604 int word_ffs; 605 606 word = bitset[word_idx]; 607 if (find_clear) 608 word = ~word; 609 610 word >>= offset; 611 612 word_ffs = __builtin_ffsll(word); 613 614 if (word_ffs != 0) { 615 ssize_t ffs = start_bit + word_ffs - 1; 616 617 /* 618 * Check if set bit were among the last, 619 * unused bits, in the last word. 620 */ 621 if (unlikely(ffs >= (ssize_t)end_bit)) 622 return -1; 623 624 return ffs; 625 } 626 627 start_bit += (RTE_BITSET_WORD_BITS - offset); 628 word_idx++; 629 offset = 0; 630 } 631 632 return -1; 633 634 } 635 636 __rte_experimental 637 static inline ssize_t 638 __rte_bitset_find(const uint64_t *bitset, size_t size, size_t start_bit, size_t len, 639 unsigned int flags) 640 { 641 bool find_clear = flags & __RTE_BITSET_FIND_FLAG_FIND_CLEAR; 642 bool may_wrap = flags & __RTE_BITSET_FIND_FLAG_WRAP; 643 bool does_wrap = (start_bit + len) > size; 644 ssize_t rc; 645 646 RTE_ASSERT(len <= size); 647 if (!may_wrap) 648 RTE_ASSERT(!does_wrap); 649 650 if (may_wrap && does_wrap) { 651 size_t len0 = size - start_bit; 652 size_t len1 = len - len0; 653 654 rc = __rte_bitset_find_nowrap(bitset, size, start_bit, len0, find_clear); 655 if (rc < 0) 656 rc = __rte_bitset_find_nowrap(bitset, size, 0, len1, find_clear); 657 } else 658 rc = __rte_bitset_find_nowrap(bitset, size, start_bit, len, find_clear); 659 660 return rc; 661 } 662 663 /** 664 * @warning 665 * @b EXPERIMENTAL: this API may change without prior notice. 666 * 667 * Find first bit set. 668 * 669 * Scans the bitset in the forward direction (i.e., starting at the 670 * least significant bit), and returns the index of the first '1'. 671 * 672 * @param bitset 673 * A pointer to the array of words making up the bitset. 674 * @param size 675 * The size of the bitset (in bits). 676 * @return 677 * Returns the index of the least significant '1', or -1 if all 678 * bits are '0'. 679 */ 680 __rte_experimental 681 static inline ssize_t 682 rte_bitset_find_first_set(const uint64_t *bitset, size_t size) 683 { 684 return __rte_bitset_find(bitset, size, 0, size, 0); 685 } 686 687 /** 688 * @warning 689 * @b EXPERIMENTAL: this API may change without prior notice. 690 * 691 * Find first bit set at offset. 692 * 693 * Scans the bitset in the forward direction (i.e., starting at the 694 * least significant bit), starting at an offset @c start_bit into the 695 * bitset, and returns the index of the first '1' encountered. 696 * 697 * @param bitset 698 * A pointer to the array of words making up the bitset. 699 * @param size 700 * The size of the bitset (in bits). 701 * @param start_bit 702 * The index of the first bit to check. Must be less than @c size. 703 * @param len 704 * The number of bits to scan. @c start_bit + @c len must be less 705 * than or equal to @c size. 706 * @return 707 * Returns the index of the least significant '1', or -1 if all 708 * bits are '0'. 709 */ 710 __rte_experimental 711 static inline ssize_t 712 rte_bitset_find_set(const uint64_t *bitset, size_t size, size_t start_bit, size_t len) 713 { 714 return __rte_bitset_find(bitset, size, start_bit, len, 0); 715 } 716 717 /** 718 * @warning 719 * @b EXPERIMENTAL: this API may change without prior notice. 720 * 721 * Find first bit set at offset, with wrap-around. 722 * 723 * Scans the bitset in the forward direction (i.e., starting at the 724 * least significant bit), starting at an offset @c start_bit into the 725 * bitset. If no '1' is encountered before the end of the bitset, the search 726 * will continue at index 0. 727 * 728 * @param bitset 729 * A pointer to the array of words making up the bitset. 730 * @param size 731 * The size of the bitset (in bits). 732 * @param start_bit 733 * The index of the first bit to check. Must be less than @c size. 734 * @param len 735 * The number of bits to scan. @c start_bit + @c len must be less 736 * than or equal to @c size. 737 * @return 738 * Returns the index of the least significant '1', or -1 if all 739 * bits are '0'. 740 */ 741 __rte_experimental 742 static inline ssize_t 743 rte_bitset_find_set_wrap(const uint64_t *bitset, size_t size, size_t start_bit, size_t len) 744 { 745 return __rte_bitset_find(bitset, size, start_bit, len, __RTE_BITSET_FIND_FLAG_WRAP); 746 } 747 748 /** 749 * @warning 750 * @b EXPERIMENTAL: this API may change without prior notice. 751 * 752 * Find first cleared bit. 753 * 754 * Scans the bitset in the forward direction (i.e., starting at the 755 * least significant bit), and returns the index of the first '0'. 756 * 757 * @param bitset 758 * A pointer to the array of words making up the bitset. 759 * @param size 760 * The size of the bitset (in bits). 761 * @return 762 * Returns the index of the least significant '0', or -1 if all 763 * bits are '1'. 764 */ 765 __rte_experimental 766 static inline ssize_t 767 rte_bitset_find_first_clear(const uint64_t *bitset, size_t size) 768 { 769 return __rte_bitset_find(bitset, size, 0, size, __RTE_BITSET_FIND_FLAG_FIND_CLEAR); 770 } 771 772 /** 773 * @warning 774 * @b EXPERIMENTAL: this API may change without prior notice. 775 * 776 * Find first cleared bit at offset. 777 * 778 * Scans the bitset in the forward direction (i.e., starting at the 779 * least significant bit), starting at an offset @c start_bit into the 780 * bitset, and returns the index of the first '0' encountered. 781 * 782 * @param bitset 783 * A pointer to the array of words making up the bitset. 784 * @param size 785 * The size of the bitset (in bits). 786 * @param start_bit 787 * The index of the first bit to check. Must be less than @c size. 788 * @param len 789 * The number of bits to scan. @c start_bit + @c len must be less 790 * than or equal to @c size. 791 * @return 792 * Returns the index of the least significant '0', or -1 if all 793 * bits are '1'. 794 */ 795 __rte_experimental 796 static inline ssize_t 797 rte_bitset_find_clear(const uint64_t *bitset, size_t size, size_t start_bit, size_t len) 798 { 799 return __rte_bitset_find(bitset, size, start_bit, len, __RTE_BITSET_FIND_FLAG_FIND_CLEAR); 800 } 801 802 /** 803 * @warning 804 * @b EXPERIMENTAL: this API may change without prior notice. 805 * 806 * Find first cleared bit at offset, with wrap-around. 807 * 808 * Scans the bitset in the forward direction (i.e., starting at the 809 * least significant bit), starting at an offset @c start_bit into the 810 * bitset. If no '0' is encountered before the end of the bitset, the 811 * search will continue at index 0. 812 * 813 * @param bitset 814 * A pointer to the array of words making up the bitset. 815 * @param size 816 * The size of the bitset (in bits). 817 * @param start_bit 818 * The index of the first bit to check. Must be less than @c size. 819 * @param len 820 * The number of bits to scan. @c start_bit + @c len must be less 821 * than or equal to @c size. 822 * @return 823 * Returns the index of the least significant '0', or -1 if all 824 * bits are '1'. 825 */ 826 __rte_experimental 827 static inline ssize_t 828 rte_bitset_find_clear_wrap(const uint64_t *bitset, size_t size, size_t start_bit, size_t len) 829 { 830 return __rte_bitset_find(bitset, size, start_bit, len, 831 __RTE_BITSET_FIND_FLAG_FIND_CLEAR | __RTE_BITSET_FIND_FLAG_WRAP); 832 } 833 834 /** 835 * @warning 836 * @b EXPERIMENTAL: this API may change without prior notice. 837 * 838 * Copy bitset. 839 * 840 * Copy the bits of the @c src_bitset to the @c dst_bitset. 841 * 842 * The bitsets may not overlap and must be of equal size. 843 * 844 * @param dst_bitset 845 * A pointer to the array of words making up the bitset. 846 * @param src_bitset 847 * A pointer to the array of words making up the bitset. 848 * @param size 849 * The size of the bitsets (in bits). 850 */ 851 __rte_experimental 852 static inline void 853 rte_bitset_copy(uint64_t *__rte_restrict dst_bitset, const uint64_t *__rte_restrict src_bitset, 854 size_t size) 855 { 856 rte_memcpy(dst_bitset, src_bitset, RTE_BITSET_SIZE(size)); 857 } 858 859 /** 860 * @warning 861 * @b EXPERIMENTAL: this API may change without prior notice. 862 * 863 * Bitwise or two bitsets. 864 * 865 * Perform a bitwise OR operation on all bits in the two equal-size 866 * bitsets @c src_bitset0 and @c src_bitset1, and store the results in 867 * @c dst_bitset. 868 * 869 * @param dst_bitset 870 * A pointer to the destination bitset. 871 * @param src_bitset0 872 * A pointer to the first source bitset. 873 * @param src_bitset1 874 * A pointer to the second source bitset. 875 * @param size 876 * The size of the bitsets (in bits). 877 */ 878 __rte_experimental 879 static inline void 880 rte_bitset_or(uint64_t *dst_bitset, const uint64_t *src_bitset0, const uint64_t *src_bitset1, 881 size_t size) 882 { 883 size_t i; 884 885 for (i = 0; i < RTE_BITSET_NUM_WORDS(size); i++) 886 dst_bitset[i] = src_bitset0[i] | src_bitset1[i]; 887 } 888 889 /** 890 * @warning 891 * @b EXPERIMENTAL: this API may change without prior notice. 892 * 893 * Bitwise and two bitsets. 894 * 895 * Perform a bitwise AND operation on all bits in the two equal-size 896 * bitsets @c src_bitset0 and @c src_bitset1, and store the result in 897 * @c dst_bitset. 898 * 899 * @param dst_bitset 900 * A pointer to the destination bitset. 901 * @param src_bitset0 902 * A pointer to the first source bitset. 903 * @param src_bitset1 904 * A pointer to the second source bitset. 905 * @param size 906 * The size of the bitsets (in bits). 907 */ 908 __rte_experimental 909 static inline void 910 rte_bitset_and(uint64_t *dst_bitset, const uint64_t *src_bitset0, const uint64_t *src_bitset1, 911 size_t size) 912 { 913 size_t i; 914 915 for (i = 0; i < RTE_BITSET_NUM_WORDS(size); i++) 916 dst_bitset[i] = src_bitset0[i] & src_bitset1[i]; 917 } 918 919 /** 920 * @warning 921 * @b EXPERIMENTAL: this API may change without prior notice. 922 * 923 * Bitwise xor two bitsets. 924 * 925 * Perform a bitwise XOR operation on all bits in the two equal-size 926 * bitsets @c src_bitset0 and @c src_bitset1, and store the result in 927 * @c dst_bitset. 928 * 929 * @param dst_bitset 930 * A pointer to the destination bitset. 931 * @param src_bitset0 932 * A pointer to the first source bitset. 933 * @param src_bitset1 934 * A pointer to the second source bitset. 935 * @param size 936 * The size of the bitsets (in bits). 937 */ 938 __rte_experimental 939 static inline void 940 rte_bitset_xor(uint64_t *dst_bitset, const uint64_t *src_bitset0, const uint64_t *src_bitset1, 941 size_t size) 942 { 943 size_t i; 944 945 for (i = 0; i < RTE_BITSET_NUM_WORDS(size); i++) 946 dst_bitset[i] = src_bitset0[i] ^ src_bitset1[i]; 947 } 948 949 /** 950 * @warning 951 * @b EXPERIMENTAL: this API may change without prior notice. 952 * 953 * Compute the bitwise complement of a bitset. 954 * 955 * Flip every bit in the @c src_bitset, and store the result in @c 956 * dst_bitset. 957 * 958 * @param dst_bitset 959 * A pointer to the destination bitset. 960 * @param src_bitset 961 * A pointer to the source bitset. 962 * @param size 963 * The size of the bitsets (in bits). 964 */ 965 __rte_experimental 966 static inline void 967 rte_bitset_complement(uint64_t *dst_bitset, const uint64_t *src_bitset, size_t size) 968 { 969 size_t i; 970 971 for (i = 0; i < RTE_BITSET_NUM_WORDS(size); i++) 972 dst_bitset[i] = ~src_bitset[i]; 973 } 974 975 /** 976 * @warning 977 * @b EXPERIMENTAL: this API may change without prior notice. 978 * 979 * Shift bitset left. 980 * 981 * Perform a logical shift left of (multiply) @c src_bitset, and store 982 * the result in @c dst_bitset. 983 * 984 * @param dst_bitset 985 * A pointer to the destination bitset. 986 * @param src_bitset 987 * A pointer to the source bitset. 988 * @param size 989 * The size of the bitsets (in bits). 990 * @param shift_bits 991 * The number of bits to shift the bitset. 992 */ 993 __rte_experimental 994 static inline void 995 rte_bitset_shift_left(uint64_t *dst_bitset, const uint64_t *src_bitset, size_t size, 996 size_t shift_bits) 997 { 998 const int src_word_offset = shift_bits / RTE_BITSET_WORD_BITS; 999 const int src_bit_offset = shift_bits % RTE_BITSET_WORD_BITS; 1000 unsigned int dst_idx; 1001 1002 for (dst_idx = 0; dst_idx < RTE_BITSET_NUM_WORDS(size); dst_idx++) { 1003 int src_high_idx = dst_idx - src_word_offset; 1004 uint64_t low_bits = 0; 1005 uint64_t high_bits = 0; 1006 1007 if (src_high_idx >= 0) { 1008 int src_low_idx = src_high_idx - 1; 1009 1010 high_bits = src_bitset[src_high_idx] << src_bit_offset; 1011 1012 if (src_bit_offset > 0 && src_low_idx >= 0) 1013 low_bits = src_bitset[src_low_idx] >> 1014 (RTE_BITSET_WORD_BITS - src_bit_offset); 1015 } 1016 dst_bitset[dst_idx] = low_bits | high_bits; 1017 } 1018 } 1019 1020 /** 1021 * @warning 1022 * @b EXPERIMENTAL: this API may change without prior notice. 1023 * 1024 * Shift bitset right. 1025 * 1026 * Perform a logical shift right of (divide) @c src_bitset, and store 1027 * the result in @c dst_bitset. 1028 * 1029 * @param dst_bitset 1030 * A pointer to the destination bitset. 1031 * @param src_bitset 1032 * A pointer to the source bitset. 1033 * @param size 1034 * The size of the bitsets (in bits). 1035 * @param shift_bits 1036 * The number of bits to shift the bitset. 1037 */ 1038 __rte_experimental 1039 static inline void 1040 rte_bitset_shift_right(uint64_t *dst_bitset, const uint64_t *src_bitset, size_t size, 1041 size_t shift_bits) 1042 { 1043 const int num_words = RTE_BITSET_NUM_WORDS(size); 1044 const uint64_t used_mask = __RTE_BITSET_USED_MASK(size); 1045 const int src_word_offset = shift_bits / RTE_BITSET_WORD_BITS; 1046 const int src_bit_offset = shift_bits % RTE_BITSET_WORD_BITS; 1047 int dst_idx; 1048 1049 for (dst_idx = 0; dst_idx < num_words; dst_idx++) { 1050 int src_low_idx = src_word_offset + dst_idx; 1051 int src_high_idx = src_low_idx + 1; 1052 uint64_t src_low_word_bits = 0; 1053 uint64_t src_high_word_bits = 0; 1054 1055 if (src_low_idx < num_words) { 1056 src_low_word_bits = src_bitset[src_low_idx]; 1057 1058 if (src_low_idx == (num_words - 1)) 1059 src_low_word_bits &= used_mask; 1060 1061 src_low_word_bits >>= src_bit_offset; 1062 1063 if (src_bit_offset > 0 && src_high_idx < num_words) { 1064 src_high_word_bits = src_bitset[src_high_idx]; 1065 1066 if (src_high_idx == (num_words - 1)) 1067 src_high_word_bits &= used_mask; 1068 1069 src_high_word_bits <<= (RTE_BITSET_WORD_BITS - src_bit_offset); 1070 } 1071 } 1072 dst_bitset[dst_idx] = src_low_word_bits | src_high_word_bits; 1073 } 1074 } 1075 1076 /** 1077 * @warning 1078 * @b EXPERIMENTAL: this API may change without prior notice. 1079 * 1080 * Compare two bitsets. 1081 * 1082 * Compare two bitsets for equality. 1083 * 1084 * @param bitset_a 1085 * A pointer to the destination bitset. 1086 * @param bitset_b 1087 * A pointer to the source bitset. 1088 * @param size 1089 * The size of the bitsets (in bits). 1090 */ 1091 __rte_experimental 1092 static inline bool 1093 rte_bitset_equal(const uint64_t *bitset_a, const uint64_t *bitset_b, size_t size) 1094 { 1095 size_t i; 1096 uint64_t last_a, last_b; 1097 1098 for (i = 0; i < RTE_BITSET_NUM_WORDS(size) - 1; i++) 1099 if (bitset_a[i] != bitset_b[i]) 1100 return false; 1101 1102 last_a = bitset_a[i] << __RTE_BITSET_UNUSED(size); 1103 last_b = bitset_b[i] << __RTE_BITSET_UNUSED(size); 1104 1105 return last_a == last_b; 1106 } 1107 1108 /** 1109 * @warning 1110 * @b EXPERIMENTAL: this API may change without prior notice. 1111 * 1112 * Converts a bitset to a string. 1113 * 1114 * This function prints a string representation of the bitstring to 1115 * the supplied buffer. 1116 * 1117 * Each bit is represented either by '0' or '1' in the output, with 1118 * the first (left-most) character in the output being the most 1119 * significant bit. The resulting string is NUL terminated. 1120 * 1121 * @param bitset 1122 * A pointer to the array of bitset 64-bit words. 1123 * @param size 1124 * The number of bits the bitset represent. 1125 * @param buf 1126 * A buffer to hold the output. 1127 * @param capacity 1128 * The size of the buffer. Must be @c size + 1 or larger. 1129 * @return 1130 * Returns the number of bytes written (i.e., @c size + 1), or -EINVAL 1131 * in case the buffer capacity was too small. 1132 */ 1133 __rte_experimental 1134 ssize_t 1135 rte_bitset_to_str(const uint64_t *bitset, size_t size, char *buf, size_t capacity); 1136 1137 #ifdef __cplusplus 1138 } 1139 #endif 1140 1141 #endif /* _RTE_BITSET_H_ */ 1142