LCOV - code coverage report
Current view: top level - source/flat_bitset.c (source / functions) Coverage Total Hit
Test: CCC Test Suite Coverage Report Lines: 99.2 % 870 863
Test Date: 2026-08-22 15:52:04 Functions: 100.0 % 80 80

            Line data    Source code
       1              : /** Copyright 2025 Alexander G. Lopez
       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              : This file implements a Bit Set using blocks of platform defined integers
      16              : for speed and efficiency. The implementation aims for constant and linear time
      17              : operations at all times, specifically when implementing more complicated range
      18              : based operations over the set.
      19              : 
      20              : It is also important to avoid modulo and division operations whenever possible.
      21              : This is why much of the code revolves around obtaining indices by processing
      22              : entire blocks at a time, rather than using mathematical operations to
      23              : conceptually iterate over individual bits.
      24              : 
      25              : Finally, the code is able to unite most functions for finding zeros or ones
      26              : into a single function that accepts true or false as an additional argument.
      27              : This is because every search for a zero can be solved by bitwise inverting a
      28              : block and searching for a 1 instead. This elimination of identical functions
      29              : costs a single branch in the function and is worth it to avoid code duplication
      30              : and bug doubling. */
      31              : /** C23 provided headers. */
      32              : #include <assert.h>
      33              : #include <limits.h>
      34              : #include <stdckdint.h>
      35              : #include <stddef.h>
      36              : #include <stdint.h>
      37              : 
      38              : /** CCC provided headers. */
      39              : #include "ccc/configuration.h" /* IWYU pragma: keep */
      40              : #include "ccc/flat_bitset.h"
      41              : #include "ccc/private/private_flat_bitset.h"
      42              : #include "ccc/types.h"
      43              : #include "source/compiler_utilities.h"
      44              : 
      45              : /*=========================   Type Declarations  ============================*/
      46              : 
      47              : /** @internal The type representing the word size used for each block of the
      48              : Flat_bitset. This type may vary depending on the platform in order to maximize
      49              : performance, so it is given a type. The implementation then should not concern
      50              : itself with the word size.
      51              : 
      52              : The implementation may assume that the block is a standard integer width on
      53              : the given platform that is compatible with all basic arithmetic and bitwise
      54              : operations. If SIMD is implemented then multiple blocks may be processed under
      55              : this same assumption. */
      56              : typedef typeof(*(struct CCC_Flat_bitset){}.blocks) Bit_block;
      57              : 
      58              : /** @internal Used frequently so call the builtin just once. */
      59              : enum : size_t {
      60              :     /** @internal Bytes of a bit block to help with byte calculations. */
      61              :     SIZEOF_BLOCK = sizeof(Bit_block),
      62              : };
      63              : 
      64              : /** @internal Various constants to support bit block size bit ops. */
      65              : enum : Bit_block {
      66              :     /** @internal A mask of a bit block with all bits on. */
      67              :     BLOCK_ON = (Bit_block)~0,
      68              :     /** @internal The Most Significant Bit of a bit block turned on to 1. */
      69              :     BLOCK_MSB = (Bit_block)1 << ((SIZEOF_BLOCK * CHAR_BIT) - 1),
      70              : };
      71              : 
      72              : /** @internal An index into the block array or count of bit blocks. The block
      73              : array is constructed by the number of blocks required to support the current bit
      74              : set capacity. Assume this index type has range [0, block count to support N
      75              : bits].
      76              : 
      77              : User input is given as a `size_t` so distinguish from that input with this type
      78              : to make it clear to the reader the index refers to a block not the given bit
      79              : index the user has provided. */
      80              : typedef size_t Block_count;
      81              : 
      82              : /** @internal An index within a block. A block is set to some number of bits
      83              : as determined by the type used for each block. This type is intended to count
      84              : bits in a block and therefore cannot count up to arbitrary indices. Assume its
      85              : range is `[0, BIT_BLOCK_BITS]`, for ease of use and clarity.
      86              : 
      87              : There are many types of indexing and counting that take place in a bit set so
      88              : use this type specifically for counting bits in a block so the reader is clear
      89              : on intent. */
      90              : typedef uint8_t Bit_count;
      91              : 
      92              : enum : Bit_count {
      93              :     /** @internal How many total bits that fit in a bit block. */
      94              :     BLOCK_BITS = SIZEOF_BLOCK * CHAR_BIT,
      95              :     /** @internal Used for static assert clarity. */
      96              :     U8_BLOCK_MAX = UINT8_MAX,
      97              :     /** @internal log2 of block bits to avoid division. */
      98              :     BLOCK_BITS_LOG2 = CCC_log2((Bit_count)BLOCK_BITS),
      99              : };
     100              : static_assert(
     101              :     (BLOCK_BITS & (BLOCK_BITS - 1)) == 0,
     102              :     "the number of bits in a block is always a power of two, "
     103              :     "helping avoid division and modulo operations when possible"
     104              : );
     105              : static_assert(
     106              :     BLOCK_BITS >> BLOCK_BITS_LOG2 == 1,
     107              :     "hand coded log2 of bitblock bits is always correct"
     108              : );
     109              : static_assert(
     110              :     (Bit_count) ~((Bit_count)0) >= (Bit_count)0, "Bit_count must be unsigned"
     111              : );
     112              : static_assert(UINT8_MAX >= BLOCK_BITS, "Bit_count counts all block bits.");
     113              : 
     114              : /*=========================      Prototypes      ============================*/
     115              : 
     116              : static size_t block_count_index(size_t);
     117              : static Bit_block *block_at(struct CCC_Flat_bitset const *, size_t);
     118              : static void set(Bit_block *, size_t, CCC_Tribool);
     119              : static Bit_block on(size_t);
     120              : static void fix_end(struct CCC_Flat_bitset *);
     121              : static CCC_Tribool status(Bit_block const *, size_t);
     122              : static size_t block_count(size_t);
     123              : static inline CCC_Tribool
     124              : checked_block_count(Block_count *result, size_t bit_count);
     125              : static CCC_Tribool
     126              : any_or_none_range(struct CCC_Flat_bitset const *, size_t, size_t, CCC_Tribool);
     127              : static CCC_Tribool all_range(struct CCC_Flat_bitset const *, size_t, size_t);
     128              : static CCC_Count first_trailing_bit_range(
     129              :     struct CCC_Flat_bitset const *, size_t, size_t, CCC_Tribool
     130              : );
     131              : static CCC_Count first_leading_bit_range(
     132              :     struct CCC_Flat_bitset const *, size_t, size_t, CCC_Tribool
     133              : );
     134              : static CCC_Count first_trailing_bits_range(
     135              :     struct CCC_Flat_bitset const *, size_t, size_t, size_t, CCC_Tribool
     136              : );
     137              : static CCC_Count first_leading_bits_range(
     138              :     struct CCC_Flat_bitset const *, size_t, size_t, size_t, CCC_Tribool
     139              : );
     140              : static CCC_Result
     141              : maybe_resize(struct CCC_Flat_bitset *, size_t, CCC_Allocator const *);
     142              : static CCC_Tribool is_mask_match(Bit_block, Bit_block);
     143              : static Bit_block trailing_ones_mask(Bit_count);
     144              : static Bit_block leading_ones_mask(Bit_count);
     145              : static void set_all(struct CCC_Flat_bitset *, CCC_Tribool);
     146              : static Bit_count bit_count_index(size_t);
     147              : static CCC_Tribool
     148              : is_subset_of(struct CCC_Flat_bitset const *, struct CCC_Flat_bitset const *);
     149              : static Bit_count popcount(Bit_block);
     150              : static Bit_count count_trailing_zeros(Bit_block);
     151              : static Bit_count count_leading_zeros(Bit_block);
     152              : 
     153              : /*=======================   Public Interface   ==============================*/
     154              : 
     155              : CCC_Tribool
     156            4 : CCC_flat_bitset_is_proper_subset(
     157              :     CCC_Flat_bitset const *const subset, CCC_Flat_bitset const *const set
     158              : ) {
     159            4 :     if (!set || !subset) {
     160            2 :         return CCC_TRIBOOL_ERROR;
     161              :     }
     162            2 :     if (set->count <= subset->count) {
     163            1 :         return CCC_FALSE;
     164              :     }
     165            1 :     return is_subset_of(subset, set);
     166            4 : }
     167              : 
     168              : CCC_Tribool
     169           11 : CCC_flat_bitset_is_subset(
     170              :     CCC_Flat_bitset const *const subset, CCC_Flat_bitset const *const set
     171              : ) {
     172           11 :     if (!set || !subset) {
     173            2 :         return CCC_TRIBOOL_ERROR;
     174              :     }
     175            9 :     if (set->count < subset->count) {
     176            1 :         return CCC_FALSE;
     177              :     }
     178            8 :     return is_subset_of(subset, set);
     179           11 : }
     180              : 
     181              : CCC_Result
     182            8 : CCC_flat_bitset_or(
     183              :     CCC_Flat_bitset *const destination, CCC_Flat_bitset const *const source
     184              : ) {
     185            8 :     if (!destination || !source) {
     186            2 :         return CCC_RESULT_ARGUMENT_ERROR;
     187              :     }
     188            6 :     if (!destination->count || !source->count) {
     189            4 :         return CCC_RESULT_OK;
     190              :     }
     191            4 :     Block_count const end_block
     192            2 :         = block_count(CCC_min(destination->count, source->count));
     193           26 :     for (size_t b = 0; b < end_block; ++b) {
     194           24 :         destination->blocks[b] |= source->blocks[b];
     195           24 :     }
     196            2 :     fix_end(destination);
     197            2 :     return CCC_RESULT_OK;
     198            8 : }
     199              : 
     200              : CCC_Result
     201            6 : CCC_flat_bitset_xor(
     202              :     CCC_Flat_bitset *const destination, CCC_Flat_bitset const *const source
     203              : ) {
     204            6 :     if (!destination || !source) {
     205            2 :         return CCC_RESULT_ARGUMENT_ERROR;
     206              :     }
     207            4 :     if (!destination->count || !source->count) {
     208            2 :         return CCC_RESULT_OK;
     209              :     }
     210            4 :     Block_count const end_block
     211            2 :         = block_count(CCC_min(destination->count, source->count));
     212           26 :     for (Block_count b = 0; b < end_block; ++b) {
     213           24 :         destination->blocks[b] ^= source->blocks[b];
     214           24 :     }
     215            2 :     fix_end(destination);
     216            2 :     return CCC_RESULT_OK;
     217            6 : }
     218              : 
     219              : CCC_Result
     220            6 : CCC_flat_bitset_and(
     221              :     CCC_Flat_bitset *destination, CCC_Flat_bitset const *source
     222              : ) {
     223            6 :     if (!destination || !source) {
     224            2 :         return CCC_RESULT_ARGUMENT_ERROR;
     225              :     }
     226            4 :     if (!source->count) {
     227            1 :         set_all(destination, CCC_FALSE);
     228            1 :         return CCC_RESULT_OK;
     229              :     }
     230            3 :     if (!destination->count) {
     231            1 :         return CCC_RESULT_OK;
     232              :     }
     233            4 :     Block_count const end_block
     234            2 :         = block_count(CCC_min(destination->count, source->count));
     235           26 :     for (Block_count b = 0; b < end_block; ++b) {
     236           24 :         destination->blocks[b] &= source->blocks[b];
     237           24 :     }
     238            2 :     if (destination->count <= source->count) {
     239            1 :         return CCC_RESULT_OK;
     240              :     }
     241              :     /* The source widens to align with destination as integers would; same
     242              :        consequences. */
     243            1 :     Block_count const destination_blocks = block_count(destination->count);
     244            1 :     Block_count const remain = destination_blocks - end_block;
     245            2 :     (void)memset(
     246            2 :         destination->blocks + end_block, CCC_FALSE, remain * SIZEOF_BLOCK
     247              :     );
     248            1 :     fix_end(destination);
     249            1 :     return CCC_RESULT_OK;
     250            6 : }
     251              : 
     252              : CCC_Result
     253            9 : CCC_flat_bitset_shift_left(
     254              :     CCC_Flat_bitset *const bitset, size_t const left_shifts
     255              : ) {
     256            9 :     if (!bitset) {
     257            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     258              :     }
     259            8 :     if (!bitset->count || !left_shifts) {
     260            1 :         return CCC_RESULT_OK;
     261              :     }
     262            7 :     if (left_shifts >= bitset->count) {
     263            1 :         set_all(bitset, CCC_FALSE);
     264            1 :         return CCC_RESULT_OK;
     265              :     }
     266            6 :     Block_count const end = block_count_index(bitset->count - 1);
     267            6 :     Block_count const blocks = block_count_index(left_shifts);
     268            6 :     Bit_count const split = bit_count_index(left_shifts);
     269            6 :     if (!split) {
     270           31 :         for (Block_count shift = end - blocks + 1, write = end; shift--;
     271           29 :              --write) {
     272           29 :             bitset->blocks[write] = bitset->blocks[shift];
     273           29 :         }
     274            2 :     } else {
     275            4 :         Bit_count const remain = BLOCK_BITS - split;
     276           32 :         for (Block_count shift = end - blocks, write = end; shift > 0;
     277           28 :              --shift, --write) {
     278           56 :             bitset->blocks[write] = (bitset->blocks[shift] << split)
     279           28 :                                   | (bitset->blocks[shift - 1] >> remain);
     280           28 :         }
     281            4 :         bitset->blocks[blocks] = bitset->blocks[0] << split;
     282            4 :     }
     283              :     /* Zero fills in lower bits just as an integer shift would. */
     284           26 :     for (Block_count i = 0; i < blocks; ++i) {
     285           20 :         bitset->blocks[i] = 0;
     286           20 :     }
     287            6 :     fix_end(bitset);
     288            6 :     return CCC_RESULT_OK;
     289            9 : }
     290              : 
     291              : CCC_Result
     292            9 : CCC_flat_bitset_shift_right(
     293              :     CCC_Flat_bitset *const bitset, size_t const right_shifts
     294              : ) {
     295            9 :     if (!bitset) {
     296            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     297              :     }
     298            8 :     if (!bitset->count || !right_shifts) {
     299            1 :         return CCC_RESULT_OK;
     300              :     }
     301            7 :     if (right_shifts >= bitset->count) {
     302            1 :         set_all(bitset, CCC_FALSE);
     303            1 :         return CCC_RESULT_OK;
     304              :     }
     305            6 :     Block_count const end = block_count_index(bitset->count - 1);
     306            6 :     Block_count const blocks = block_count_index(right_shifts);
     307            6 :     Bit_count const split = bit_count_index(right_shifts);
     308            6 :     if (!split) {
     309           31 :         for (Block_count shift = blocks, write = 0; shift < end + 1;
     310           29 :              ++shift, ++write) {
     311           29 :             bitset->blocks[write] = bitset->blocks[shift];
     312           29 :         }
     313            2 :     } else {
     314            4 :         Bit_count const remain = BLOCK_BITS - split;
     315           32 :         for (Block_count shift = blocks, write = 0; shift < end;
     316           28 :              ++shift, ++write) {
     317           56 :             bitset->blocks[write] = (bitset->blocks[shift + 1] << remain)
     318           28 :                                   | (bitset->blocks[shift] >> split);
     319           28 :         }
     320            4 :         bitset->blocks[end - blocks] = bitset->blocks[end] >> split;
     321            4 :     }
     322              :     /* This is safe for a few reasons:
     323              :        - If shifts equals count we set all to 0 and returned early.
     324              :        - If we only have one block i will be equal to end and we are done.
     325              :        - If end is the 0th block we will stop after 1. A meaningful shift
     326              :          occurred in the 0th block so zeroing would be a mistake.
     327              :        - All other cases ensure it is safe to decrease i (no underflow).
     328              :        This operation emulates the zeroing of high bits on a right shift and
     329              :        a bit set is considered unsigned so we don't sign bit fill. */
     330           26 :     for (Block_count i = end; i > end - blocks; --i) {
     331           20 :         bitset->blocks[i] = 0;
     332           20 :     }
     333            6 :     fix_end(bitset);
     334            6 :     return CCC_RESULT_OK;
     335            9 : }
     336              : 
     337              : CCC_Tribool
     338         4144 : CCC_flat_bitset_test(CCC_Flat_bitset const *const bitset, size_t const i) {
     339         4144 :     if (!bitset) {
     340            1 :         return CCC_TRIBOOL_ERROR;
     341              :     }
     342         4143 :     if (i >= bitset->count) {
     343            7 :         return CCC_TRIBOOL_ERROR;
     344              :     }
     345         4136 :     return status(block_at(bitset, i), i);
     346         4144 : }
     347              : 
     348              : CCC_Tribool
     349        13721 : CCC_flat_bitset_set(
     350              :     CCC_Flat_bitset *const bitset, size_t const i, CCC_Tribool const b
     351              : ) {
     352        13721 :     if (!bitset) {
     353            1 :         return CCC_TRIBOOL_ERROR;
     354              :     }
     355        13720 :     if (i >= bitset->count) {
     356            2 :         return CCC_TRIBOOL_ERROR;
     357              :     }
     358        13718 :     Bit_block *const block = block_at(bitset, i);
     359        13718 :     CCC_Tribool const was = status(block, i);
     360        13718 :     set(block, i, b);
     361        13718 :     return was;
     362        13721 : }
     363              : 
     364              : CCC_Result
     365           34 : CCC_flat_bitset_set_all(CCC_Flat_bitset *const bitset, CCC_Tribool const b) {
     366           34 :     if (!bitset) {
     367            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     368              :     }
     369           33 :     if (bitset->count) {
     370           33 :         set_all(bitset, b);
     371           33 :     }
     372           33 :     return CCC_RESULT_OK;
     373           34 : }
     374              : 
     375              : /** A naive implementation might just call set for every index between the
     376              : start and start + count. However, calculating the block and index within each
     377              : block for every call to set costs a division and a modulo operation. This also
     378              : loads and stores a block multiple times just to set each bit within a block to
     379              : the same value. We can avoid this by handling the first and last block with one
     380              : operations and then handling everything in between with a bulk memset. */
     381              : CCC_Result
     382        10452 : CCC_flat_bitset_set_range(
     383              :     CCC_Flat_bitset *const bitset,
     384              :     size_t const range_start_index,
     385              :     size_t const range_bit_count,
     386              :     CCC_Tribool const b
     387              : ) {
     388        10452 :     size_t range_end = 0;
     389        10452 :     if (ckd_add(&range_end, range_start_index, range_bit_count) || !bitset
     390        10452 :         || !range_bit_count || range_start_index >= bitset->count
     391        10452 :         || range_end > bitset->count) {
     392            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     393              :     }
     394        10451 :     Block_count start_block = block_count_index(range_start_index);
     395        10451 :     Bit_count const start_bit = bit_count_index(range_start_index);
     396        10451 :     Bit_block range_mask = leading_ones_mask(BLOCK_BITS - start_bit);
     397        10451 :     if (start_bit + range_bit_count < BLOCK_BITS) {
     398              :         range_mask
     399         1687 :             &= trailing_ones_mask((Bit_count)(start_bit + range_bit_count));
     400         1687 :     }
     401              : 
     402              :     /* Logic is uniform except for key lines to turn bits on or off. */
     403        10451 :     b ? (bitset->blocks[start_block] |= range_mask)
     404         4201 :       : (bitset->blocks[start_block] &= ~range_mask);
     405              : 
     406        10451 :     Block_count const end_block = block_count_index(range_end - 1);
     407        10451 :     if (end_block == start_block) {
     408         1972 :         fix_end(bitset);
     409         1972 :         return CCC_RESULT_OK;
     410              :     }
     411         8479 :     if (++start_block != end_block) {
     412         5766 :         int const v = b ? ~0 : 0;
     413        11532 :         (void)memset(
     414         5766 :             &bitset->blocks[start_block],
     415         5766 :             v,
     416         5766 :             (end_block - start_block) * SIZEOF_BLOCK
     417              :         );
     418         5766 :     }
     419              :     /* Need the final included bit position modulo block size but then feed to
     420              :        mask creation function as a count. */
     421        16958 :     Bit_block const last_block_mask
     422         8479 :         = trailing_ones_mask(bit_count_index(range_end - 1) + 1);
     423              : 
     424         8479 :     b ? (bitset->blocks[end_block] |= last_block_mask)
     425         3248 :       : (bitset->blocks[end_block] &= ~last_block_mask);
     426              : 
     427         8479 :     fix_end(bitset);
     428         8479 :     return CCC_RESULT_OK;
     429        10452 : }
     430              : 
     431              : CCC_Tribool
     432            4 : CCC_flat_bitset_reset(CCC_Flat_bitset *const bitset, size_t const i) {
     433            4 :     if (!bitset) {
     434            1 :         return CCC_TRIBOOL_ERROR;
     435              :     }
     436            3 :     if (i >= bitset->count) {
     437            1 :         return CCC_TRIBOOL_ERROR;
     438              :     }
     439            2 :     Bit_block *const block = block_at(bitset, i);
     440            2 :     CCC_Tribool const was = status(block, i);
     441            2 :     *block &= ~on(i);
     442            2 :     fix_end(bitset);
     443            2 :     return was;
     444            4 : }
     445              : 
     446              : CCC_Result
     447           11 : CCC_flat_bitset_reset_all(CCC_Flat_bitset *const bitset) {
     448           11 :     if (!bitset) {
     449            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     450              :     }
     451           10 :     if (bitset->count) {
     452           10 :         (void)memset(
     453           10 :             bitset->blocks, CCC_FALSE, block_count(bitset->count) * SIZEOF_BLOCK
     454              :         );
     455           10 :     }
     456           10 :     return CCC_RESULT_OK;
     457           11 : }
     458              : 
     459              : /** Same concept as set range but easier. Handle first and last then set
     460              : everything in between to false with memset. */
     461              : CCC_Result
     462         2050 : CCC_flat_bitset_reset_range(
     463              :     CCC_Flat_bitset *const bitset,
     464              :     size_t const range_start_index,
     465              :     size_t const range_bit_count
     466              : ) {
     467         2050 :     size_t range_end = 0;
     468         2050 :     if (ckd_add(&range_end, range_start_index, range_bit_count) || !bitset
     469         2050 :         || !range_bit_count || range_start_index >= bitset->count
     470         2049 :         || range_end > bitset->count) {
     471            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     472              :     }
     473         2049 :     Block_count start_block = block_count_index(range_start_index);
     474         2049 :     Bit_count const start_bit = bit_count_index(range_start_index);
     475         2049 :     Bit_block first_block_mask = leading_ones_mask(BLOCK_BITS - start_bit);
     476         2049 :     if (start_bit + range_bit_count < BLOCK_BITS) {
     477              :         first_block_mask
     478           33 :             &= trailing_ones_mask((Bit_count)(start_bit + range_bit_count));
     479           33 :     }
     480         2049 :     bitset->blocks[start_block] &= ~first_block_mask;
     481         2049 :     Block_count const end_block = block_count_index(range_end - 1);
     482         2049 :     if (end_block == start_block) {
     483           66 :         fix_end(bitset);
     484           66 :         return CCC_RESULT_OK;
     485              :     }
     486         1983 :     if (++start_block != end_block) {
     487         1792 :         (void)memset(
     488         1792 :             &bitset->blocks[start_block],
     489              :             CCC_FALSE,
     490         1792 :             (end_block - start_block) * SIZEOF_BLOCK
     491              :         );
     492         1792 :     }
     493         3966 :     Bit_block const last_block_mask
     494         1983 :         = trailing_ones_mask(bit_count_index(range_end - 1) + 1);
     495         1983 :     bitset->blocks[end_block] &= ~last_block_mask;
     496         1983 :     fix_end(bitset);
     497         1983 :     return CCC_RESULT_OK;
     498         2050 : }
     499              : 
     500              : CCC_Tribool
     501            4 : CCC_flat_bitset_flip(CCC_Flat_bitset *const bitset, size_t const i) {
     502            4 :     if (!bitset || i > bitset->count) {
     503            2 :         return CCC_TRIBOOL_ERROR;
     504              :     }
     505            2 :     Block_count const b_i = block_count_index(i);
     506            2 :     Bit_block *const block = &bitset->blocks[b_i];
     507            2 :     CCC_Tribool const was = status(block, i);
     508            2 :     *block ^= on(i);
     509            2 :     fix_end(bitset);
     510            2 :     return was;
     511            4 : }
     512              : 
     513              : CCC_Result
     514            3 : CCC_flat_bitset_flip_all(CCC_Flat_bitset *const bitset) {
     515            3 :     if (!bitset) {
     516            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     517              :     }
     518            2 :     if (!bitset->count) {
     519            1 :         return CCC_RESULT_OK;
     520              :     }
     521            1 :     Block_count const end = block_count(bitset->count);
     522            2 :     for (size_t i = 0; i < end; ++i) {
     523            1 :         bitset->blocks[i] = ~bitset->blocks[i];
     524            1 :     }
     525            1 :     fix_end(bitset);
     526            1 :     return CCC_RESULT_OK;
     527            3 : }
     528              : 
     529              : /** Maybe future SIMD vectorization could speed things up here because we use
     530              : the same strat of handling first and last which just leaves a simpler bulk
     531              : operation in the middle. But we don't benefit from memset here. */
     532              : CCC_Result
     533         2563 : CCC_flat_bitset_flip_range(
     534              :     CCC_Flat_bitset *const bitset,
     535              :     size_t const range_start_index,
     536              :     size_t const range_bit_count
     537              : ) {
     538         2563 :     size_t range_end = 0;
     539         2563 :     if (ckd_add(&range_end, range_start_index, range_bit_count) || !bitset
     540         2563 :         || !range_bit_count || range_start_index >= bitset->count
     541         2562 :         || range_end > bitset->count) {
     542            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     543              :     }
     544         2560 :     Block_count start_block = block_count_index(range_start_index);
     545         2560 :     Bit_count const start_bit = bit_count_index(range_start_index);
     546         2560 :     Bit_block first_block_on = leading_ones_mask(BLOCK_BITS - start_bit);
     547         2560 :     if (start_bit + range_bit_count < BLOCK_BITS) {
     548              :         first_block_on
     549           62 :             &= trailing_ones_mask((Bit_count)(start_bit + range_bit_count));
     550           62 :     }
     551         2560 :     bitset->blocks[start_block] ^= first_block_on;
     552         2560 :     Block_count const end_block = block_count_index(range_end - 1);
     553         2560 :     if (end_block == start_block) {
     554          128 :         fix_end(bitset);
     555          128 :         return CCC_RESULT_OK;
     556              :     }
     557        19456 :     while (++start_block < end_block) {
     558        17024 :         bitset->blocks[start_block] = ~bitset->blocks[start_block];
     559              :     }
     560         4864 :     Bit_block const last_block_mask
     561         2432 :         = trailing_ones_mask(bit_count_index(range_end - 1) + 1);
     562         2432 :     bitset->blocks[end_block] ^= last_block_mask;
     563         2432 :     fix_end(bitset);
     564         2432 :     return CCC_RESULT_OK;
     565         2563 : }
     566              : 
     567              : CCC_Count
     568           76 : CCC_flat_bitset_capacity(CCC_Flat_bitset const *const bitset) {
     569           76 :     if (!bitset) {
     570            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     571              :     }
     572           75 :     return (CCC_Count){.count = bitset->capacity};
     573           76 : }
     574              : 
     575              : CCC_Count
     576            2 : CCC_flat_bitset_blocks_capacity(CCC_Flat_bitset const *const bitset) {
     577            2 :     if (!bitset) {
     578            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     579              :     }
     580            2 :     return (CCC_Count){
     581            1 :         .count = block_count(bitset->capacity),
     582              :     };
     583            2 : }
     584              : 
     585              : CCC_Count
     586         1679 : CCC_flat_bitset_count(CCC_Flat_bitset const *const bitset) {
     587         1679 :     if (!bitset) {
     588            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     589              :     }
     590         1678 :     return (CCC_Count){.count = bitset->count};
     591         1679 : }
     592              : 
     593              : CCC_Count
     594            2 : CCC_flat_bitset_blocks_count(CCC_Flat_bitset const *const bitset) {
     595            2 :     if (!bitset) {
     596            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     597              :     }
     598            2 :     return (CCC_Count){
     599            1 :         .count = block_count(bitset->count),
     600              :     };
     601            2 : }
     602              : 
     603              : CCC_Tribool
     604         2304 : CCC_flat_bitset_is_empty(CCC_Flat_bitset const *const bitset) {
     605         2304 :     if (!bitset) {
     606            1 :         return CCC_TRIBOOL_ERROR;
     607              :     }
     608         2303 :     return !bitset->count;
     609         2304 : }
     610              : 
     611              : CCC_Count
     612         9297 : CCC_flat_bitset_popcount(CCC_Flat_bitset const *const bitset) {
     613         9297 :     if (!bitset) {
     614            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     615              :     }
     616         9296 :     if (!bitset->count) {
     617            9 :         return (CCC_Count){.count = 0};
     618              :     }
     619         9287 :     Block_count const end = block_count(bitset->count);
     620         9287 :     size_t count = 0;
     621       157390 :     for (Block_count i = 0; i < end; ++i) {
     622       148103 :         count += popcount(bitset->blocks[i]);
     623       148103 :     }
     624         9287 :     return (CCC_Count){.count = count};
     625         9297 : }
     626              : 
     627              : CCC_Count
     628         9220 : CCC_flat_bitset_popcount_range(
     629              :     CCC_Flat_bitset const *const bitset,
     630              :     size_t const range_start_index,
     631              :     size_t const range_bit_count
     632              : ) {
     633         9220 :     size_t range_end = 0;
     634         9220 :     if (ckd_add(&range_end, range_start_index, range_bit_count) || !bitset
     635         9220 :         || !range_bit_count || range_start_index >= bitset->count
     636         9218 :         || range_end > bitset->count) {
     637            2 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     638              :     }
     639         9218 :     size_t popped = 0;
     640         9218 :     Block_count start_block = block_count_index(range_start_index);
     641         9218 :     Bit_count const start_bit = bit_count_index(range_start_index);
     642         9218 :     Bit_block first_block_mask = leading_ones_mask(BLOCK_BITS - start_bit);
     643         9218 :     if (start_bit + range_bit_count < BLOCK_BITS) {
     644              :         first_block_mask
     645          188 :             &= trailing_ones_mask((Bit_count)(start_bit + range_bit_count));
     646          188 :     }
     647         9218 :     popped += popcount(first_block_mask & bitset->blocks[start_block]);
     648         9218 :     Block_count const end_block = block_count_index(range_end - 1);
     649         9218 :     if (end_block == start_block) {
     650          388 :         return (CCC_Count){.count = popped};
     651              :     }
     652        70640 :     while (++start_block < end_block) {
     653        61810 :         popped += popcount(bitset->blocks[start_block]);
     654              :     }
     655        17660 :     Bit_block const last_block_mask
     656         8830 :         = trailing_ones_mask(bit_count_index(range_end - 1) + 1);
     657         8830 :     popped += popcount(last_block_mask & bitset->blocks[end_block]);
     658         8830 :     return (CCC_Count){.count = popped};
     659         9220 : }
     660              : 
     661              : CCC_Result
     662         1700 : CCC_flat_bitset_push_back(
     663              :     CCC_Flat_bitset *const bitset,
     664              :     CCC_Tribool const b,
     665              :     CCC_Allocator const *const allocator
     666              : ) {
     667         1700 :     if (!bitset || !allocator || b > CCC_TRUE || b < CCC_FALSE) {
     668            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     669              :     }
     670         1697 :     CCC_Result const check_resize = maybe_resize(bitset, 1, allocator);
     671         1697 :     if (check_resize != CCC_RESULT_OK) {
     672            3 :         return check_resize;
     673              :     }
     674         1694 :     ++bitset->count;
     675         1694 :     set(block_at(bitset, bitset->count - 1), bitset->count - 1, b);
     676         1694 :     fix_end(bitset);
     677         1694 :     return CCC_RESULT_OK;
     678         1700 : }
     679              : 
     680              : CCC_Tribool
     681         2279 : CCC_flat_bitset_pop_back(CCC_Flat_bitset *const bitset) {
     682         2279 :     if (!bitset || !bitset->count) {
     683            1 :         return CCC_TRIBOOL_ERROR;
     684              :     }
     685         4556 :     CCC_Tribool const was
     686         2278 :         = status(block_at(bitset, bitset->count - 1), bitset->count - 1);
     687         2278 :     --bitset->count;
     688         2278 :     fix_end(bitset);
     689         2278 :     return was;
     690         2279 : }
     691              : 
     692              : CCC_Tribool
     693         1035 : CCC_flat_bitset_any_range(
     694              :     CCC_Flat_bitset const *const bitset,
     695              :     size_t const range_start_index,
     696              :     size_t const range_bit_count
     697              : ) {
     698         1035 :     return any_or_none_range(
     699         1035 :         bitset, range_start_index, range_bit_count, CCC_TRUE
     700              :     );
     701              : }
     702              : 
     703              : CCC_Tribool
     704          512 : CCC_flat_bitset_any(CCC_Flat_bitset const *const bitset) {
     705          512 :     return any_or_none_range(bitset, 0, bitset->count, CCC_TRUE);
     706              : }
     707              : 
     708              : CCC_Tribool
     709          512 : CCC_flat_bitset_none_range(
     710              :     CCC_Flat_bitset const *const bitset,
     711              :     size_t const range_start_index,
     712              :     size_t const range_bit_count
     713              : ) {
     714          512 :     return any_or_none_range(
     715          512 :         bitset, range_start_index, range_bit_count, CCC_FALSE
     716              :     );
     717              : }
     718              : 
     719              : CCC_Tribool
     720          512 : CCC_flat_bitset_none(CCC_Flat_bitset const *const bitset) {
     721          512 :     return any_or_none_range(bitset, 0, bitset->count, CCC_FALSE);
     722              : }
     723              : 
     724              : CCC_Tribool
     725          524 : CCC_flat_bitset_all_range(
     726              :     CCC_Flat_bitset const *const bitset,
     727              :     size_t const range_start_index,
     728              :     size_t const range_bit_count
     729              : ) {
     730          524 :     return all_range(bitset, range_start_index, range_bit_count);
     731              : }
     732              : 
     733              : CCC_Tribool
     734          513 : CCC_flat_bitset_all(CCC_Flat_bitset const *const bitset) {
     735          513 :     return all_range(bitset, 0, bitset->count);
     736              : }
     737              : 
     738              : CCC_Count
     739         1029 : CCC_flat_bitset_first_trailing_one_range(
     740              :     CCC_Flat_bitset const *const bitset,
     741              :     size_t const range_start_index,
     742              :     size_t const range_bit_count
     743              : ) {
     744         1029 :     return first_trailing_bit_range(
     745         1029 :         bitset, range_start_index, range_bit_count, CCC_TRUE
     746              :     );
     747         1029 : }
     748              : 
     749              : CCC_Count
     750          511 : CCC_flat_bitset_first_trailing_one(CCC_Flat_bitset const *const bitset) {
     751          511 :     return first_trailing_bit_range(bitset, 0, bitset->count, CCC_TRUE);
     752          511 : }
     753              : 
     754              : CCC_Count
     755         4289 : CCC_flat_bitset_first_trailing_ones(
     756              :     CCC_Flat_bitset const *const bitset, size_t const ones_count
     757              : ) {
     758         4289 :     return first_trailing_bits_range(
     759         4289 :         bitset, 0, bitset->count, ones_count, CCC_TRUE
     760              :     );
     761         4289 : }
     762              : 
     763              : CCC_Count
     764         4325 : CCC_flat_bitset_first_trailing_ones_range(
     765              :     CCC_Flat_bitset const *const bitset,
     766              :     size_t const range_start_index,
     767              :     size_t const range_bit_count,
     768              :     size_t const ones_count
     769              : ) {
     770         4325 :     return first_trailing_bits_range(
     771         4325 :         bitset, range_start_index, range_bit_count, ones_count, CCC_TRUE
     772              :     );
     773         4325 : }
     774              : 
     775              : CCC_Count
     776         1022 : CCC_flat_bitset_first_trailing_zero_range(
     777              :     CCC_Flat_bitset const *const bitset,
     778              :     size_t const range_start_index,
     779              :     size_t const range_bit_count
     780              : ) {
     781         1022 :     return first_trailing_bit_range(
     782         1022 :         bitset, range_start_index, range_bit_count, CCC_FALSE
     783              :     );
     784         1022 : }
     785              : 
     786              : CCC_Count
     787          511 : CCC_flat_bitset_first_trailing_zero(CCC_Flat_bitset const *const bitset) {
     788          511 :     return first_trailing_bit_range(bitset, 0, bitset->count, CCC_FALSE);
     789          511 : }
     790              : 
     791              : CCC_Count
     792         4289 : CCC_flat_bitset_first_trailing_zeros(
     793              :     CCC_Flat_bitset const *const bitset, size_t const zeros_count
     794              : ) {
     795         4289 :     return first_trailing_bits_range(
     796         4289 :         bitset, 0, bitset->count, zeros_count, CCC_FALSE
     797              :     );
     798         4289 : }
     799              : 
     800              : CCC_Count
     801         4322 : CCC_flat_bitset_first_trailing_zeros_range(
     802              :     CCC_Flat_bitset const *const bitset,
     803              :     size_t const range_start_index,
     804              :     size_t const range_bit_count,
     805              :     size_t const zeros_count
     806              : ) {
     807         4322 :     return first_trailing_bits_range(
     808         4322 :         bitset, range_start_index, range_bit_count, zeros_count, CCC_FALSE
     809              :     );
     810         4322 : }
     811              : 
     812              : CCC_Count
     813         1035 : CCC_flat_bitset_first_leading_one_range(
     814              :     CCC_Flat_bitset const *const bitset,
     815              :     size_t const range_start_index,
     816              :     size_t const range_bit_count
     817              : ) {
     818         1035 :     return first_leading_bit_range(
     819         1035 :         bitset, range_start_index, range_bit_count, CCC_TRUE
     820              :     );
     821         1035 : }
     822              : 
     823              : CCC_Count
     824          512 : CCC_flat_bitset_first_leading_one(CCC_Flat_bitset const *const bitset) {
     825          512 :     return first_leading_bit_range(bitset, 0, bitset->count, CCC_TRUE);
     826          512 : }
     827              : 
     828              : CCC_Count
     829         4280 : CCC_flat_bitset_first_leading_ones(
     830              :     CCC_Flat_bitset const *const bitset, size_t const ones_count
     831              : ) {
     832         4280 :     return first_leading_bits_range(
     833         4280 :         bitset, 0, bitset->count, ones_count, CCC_TRUE
     834              :     );
     835         4280 : }
     836              : 
     837              : CCC_Count
     838         4316 : CCC_flat_bitset_first_leading_ones_range(
     839              :     CCC_Flat_bitset const *const bitset,
     840              :     size_t const range_start_index,
     841              :     size_t const range_bit_count,
     842              :     size_t const ones_count
     843              : ) {
     844         4316 :     return first_leading_bits_range(
     845         4316 :         bitset, range_start_index, range_bit_count, ones_count, CCC_TRUE
     846              :     );
     847         4316 : }
     848              : 
     849              : CCC_Count
     850         1029 : CCC_flat_bitset_first_leading_zero_range(
     851              :     CCC_Flat_bitset const *const bitset,
     852              :     size_t const range_start_index,
     853              :     size_t const range_bit_count
     854              : ) {
     855         1029 :     return first_leading_bit_range(
     856         1029 :         bitset, range_start_index, range_bit_count, CCC_FALSE
     857              :     );
     858         1029 : }
     859              : 
     860              : CCC_Count
     861          512 : CCC_flat_bitset_first_leading_zero(CCC_Flat_bitset const *const bitset) {
     862          512 :     return first_leading_bit_range(bitset, 0, bitset->count, CCC_FALSE);
     863          512 : }
     864              : 
     865              : CCC_Count
     866         4280 : CCC_flat_bitset_first_leading_zeros(
     867              :     CCC_Flat_bitset const *const bitset, size_t const zeros_count
     868              : ) {
     869         4280 :     return first_leading_bits_range(
     870         4280 :         bitset, 0, bitset->count, zeros_count, CCC_FALSE
     871              :     );
     872         4280 : }
     873              : 
     874              : CCC_Count
     875         4313 : CCC_flat_bitset_first_leading_zeros_range(
     876              :     CCC_Flat_bitset const *const bitset,
     877              :     size_t const range_start_index,
     878              :     size_t const range_bit_count,
     879              :     size_t const zeros_count
     880              : ) {
     881         4313 :     return first_leading_bits_range(
     882         4313 :         bitset, range_start_index, range_bit_count, zeros_count, CCC_FALSE
     883              :     );
     884         4313 : }
     885              : 
     886              : CCC_Result
     887            6 : CCC_flat_bitset_clear(CCC_Flat_bitset *const bitset) {
     888            6 :     if (!bitset) {
     889            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     890              :     }
     891            5 :     if (bitset->blocks) {
     892            5 :         assert(bitset->capacity);
     893            5 :         (void)memset(
     894            5 :             bitset->blocks,
     895              :             CCC_FALSE,
     896            5 :             block_count(bitset->capacity) * SIZEOF_BLOCK
     897              :         );
     898            5 :     }
     899            5 :     bitset->count = 0;
     900            5 :     return CCC_RESULT_OK;
     901            6 : }
     902              : 
     903              : CCC_Result
     904           11 : CCC_flat_bitset_clear_and_free(
     905              :     CCC_Flat_bitset *const bitset, CCC_Allocator const *const allocator
     906              : ) {
     907           11 :     if (!bitset || !allocator) {
     908            2 :         return CCC_RESULT_ARGUMENT_ERROR;
     909              :     }
     910            9 :     if (!allocator->allocate) {
     911            5 :         return CCC_RESULT_NO_ALLOCATION_FUNCTION;
     912              :     }
     913            4 :     if (bitset->blocks) {
     914            9 :         (void)allocator->allocate((CCC_Allocator_arguments){
     915            3 :             .input = bitset->blocks,
     916              :             .bytes = 0,
     917              :             .alignment = alignof(*bitset->blocks),
     918            3 :             .context = allocator->context,
     919              :         });
     920            3 :     }
     921            4 :     bitset->count = 0;
     922            4 :     bitset->capacity = 0;
     923            4 :     bitset->blocks = NULL;
     924            4 :     return CCC_RESULT_OK;
     925           11 : }
     926              : 
     927              : CCC_Result
     928           49 : CCC_flat_bitset_reserve(
     929              :     CCC_Flat_bitset *const bitset,
     930              :     size_t const to_add,
     931              :     CCC_Allocator const *const allocator
     932              : ) {
     933           49 :     if (!bitset || !allocator || !allocator->allocate || !to_add) {
     934            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     935              :     }
     936           46 :     return maybe_resize(bitset, to_add, allocator);
     937           49 : }
     938              : 
     939              : CCC_Result
     940            8 : CCC_flat_bitset_copy(
     941              :     CCC_Flat_bitset *const destination,
     942              :     CCC_Flat_bitset const *const source,
     943              :     CCC_Allocator const *const allocator
     944              : ) {
     945            8 :     if (!destination || !source || !allocator
     946            6 :         || (destination->capacity < source->capacity && !allocator->allocate)) {
     947            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     948              :     }
     949            5 :     if (!source->capacity) {
     950            1 :         destination->count = 0;
     951            1 :         return CCC_RESULT_OK;
     952              :     }
     953            4 :     if (destination->capacity < source->capacity) {
     954            6 :         Bit_block *const new_data
     955           12 :             = allocator->allocate((CCC_Allocator_arguments){
     956            3 :                 .input = destination->blocks,
     957            3 :                 .bytes = block_count(source->capacity) * SIZEOF_BLOCK,
     958              :                 .alignment = alignof((*destination->blocks)),
     959            3 :                 .context = allocator->context,
     960              :             });
     961            3 :         if (!new_data) {
     962            1 :             return CCC_RESULT_ALLOCATOR_ERROR;
     963              :         }
     964            2 :         destination->blocks = new_data;
     965            2 :         destination->capacity = source->capacity;
     966            3 :     }
     967            3 :     if (!source->blocks || !destination->blocks) {
     968            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     969              :     }
     970            2 :     destination->count = source->count;
     971            2 :     (void)memcpy(
     972            2 :         destination->blocks,
     973            2 :         source->blocks,
     974            2 :         block_count(source->capacity) * SIZEOF_BLOCK
     975              :     );
     976            2 :     fix_end(destination);
     977            2 :     return CCC_RESULT_OK;
     978            8 : }
     979              : 
     980              : void *
     981            2 : CCC_flat_bitset_data(CCC_Flat_bitset const *const bitset) {
     982            2 :     if (!bitset) {
     983            1 :         return NULL;
     984              :     }
     985            1 :     return bitset->blocks;
     986            2 : }
     987              : 
     988              : CCC_Tribool
     989            7 : CCC_flat_bitset_is_equal(
     990              :     CCC_Flat_bitset const *const left, CCC_Flat_bitset const *const right
     991              : ) {
     992            7 :     if (!left || !right) {
     993            2 :         return CCC_TRIBOOL_ERROR;
     994              :     }
     995            5 :     if (left->count != right->count) {
     996            1 :         return CCC_FALSE;
     997              :     }
     998            4 :     if (!left->count) {
     999            1 :         return CCC_TRUE;
    1000              :     }
    1001            6 :     return memcmp(
    1002            3 :                left->blocks,
    1003            3 :                right->blocks,
    1004            3 :                block_count(left->count) * SIZEOF_BLOCK
    1005              :            )
    1006            3 :         == 0;
    1007            7 : }
    1008              : 
    1009              : /*=========================     Private Interface   =========================*/
    1010              : 
    1011              : CCC_Result
    1012           46 : CCC_private_flat_bitset_reserve(
    1013              :     struct CCC_Flat_bitset *const bitset,
    1014              :     size_t const to_add,
    1015              :     CCC_Allocator const *const allocator
    1016              : ) {
    1017           46 :     return CCC_flat_bitset_reserve(bitset, to_add, allocator);
    1018              : }
    1019              : 
    1020              : CCC_Tribool
    1021         2508 : CCC_private_flat_bitset_set(
    1022              :     struct CCC_Flat_bitset *const bitset,
    1023              :     size_t const index,
    1024              :     CCC_Tribool const bit
    1025              : ) {
    1026         2508 :     return CCC_flat_bitset_set(bitset, index, bit);
    1027              : }
    1028              : 
    1029              : /*=======================    Static Helpers    ==============================*/
    1030              : 
    1031              : /** Assumes set size is greater than or equal to subset size. */
    1032              : static inline CCC_Tribool
    1033            9 : is_subset_of(
    1034              :     struct CCC_Flat_bitset const *const subset,
    1035              :     struct CCC_Flat_bitset const *const set
    1036              : ) {
    1037            9 :     assert(set->count >= subset->count);
    1038           69 :     for (Block_count i = 0, end = block_count(subset->count); i < end; ++i) {
    1039              :         /* Invariant: the last N unused bits in a set zero so this works. */
    1040           60 :         if (!is_mask_match(set->blocks[i], subset->blocks[i])) {
    1041            4 :             return CCC_FALSE;
    1042              :         }
    1043           56 :     }
    1044            5 :     return CCC_TRUE;
    1045            9 : }
    1046              : 
    1047              : static CCC_Result
    1048         1743 : maybe_resize(
    1049              :     struct CCC_Flat_bitset *const bitset,
    1050              :     size_t const to_add,
    1051              :     CCC_Allocator const *const allocator
    1052              : ) {
    1053         1743 :     size_t bits_needed = 0;
    1054         1743 :     if (ckd_add(&bits_needed, bitset->count, to_add)) {
    1055            0 :         return CCC_RESULT_ALLOCATOR_ERROR;
    1056              :     }
    1057         1743 :     if (bits_needed <= bitset->capacity) {
    1058         1692 :         return CCC_RESULT_OK;
    1059              :     }
    1060           51 :     if (!allocator->allocate) {
    1061            3 :         return CCC_RESULT_NO_ALLOCATION_FUNCTION;
    1062              :     }
    1063           48 :     if (to_add == 1 && ckd_mul(&bits_needed, bits_needed, 2)) {
    1064            0 :         return CCC_RESULT_ALLOCATOR_ERROR;
    1065              :     }
    1066              :     static_assert(
    1067              :         (BLOCK_BITS & (BLOCK_BITS - 1)) == 0,
    1068              :         "rounding trick only works for powers of 2"
    1069              :     );
    1070           48 :     size_t new_capacity = 0;
    1071           48 :     if (CCC_checked_roundup(&new_capacity, bits_needed, BLOCK_BITS)) {
    1072            1 :         return CCC_RESULT_ALLOCATOR_ERROR;
    1073              :     }
    1074           47 :     size_t new_bytes = 0;
    1075           47 :     if (checked_block_count(&new_bytes, new_capacity - bitset->count)
    1076           47 :         || ckd_mul(&new_bytes, new_bytes, (size_t)SIZEOF_BLOCK)) {
    1077            0 :         return CCC_RESULT_ALLOCATOR_ERROR;
    1078              :     }
    1079              :     /* Don't need to check old allocation for overflow because it has already
    1080              :        been successfully allocated. */
    1081           94 :     size_t const old_bytes
    1082           47 :         = bitset->count ? block_count(bitset->count) * SIZEOF_BLOCK : 0;
    1083           47 :     size_t total_allocation_bytes = 0;
    1084           47 :     if (checked_block_count(&total_allocation_bytes, new_capacity)
    1085           47 :         || ckd_mul(
    1086              :             &total_allocation_bytes,
    1087           47 :             total_allocation_bytes,
    1088              :             (size_t)SIZEOF_BLOCK
    1089              :         )) {
    1090            0 :         return CCC_RESULT_ALLOCATOR_ERROR;
    1091              :     }
    1092          188 :     Bit_block *const new_data = allocator->allocate((CCC_Allocator_arguments){
    1093           47 :         .input = bitset->blocks,
    1094           47 :         .bytes = total_allocation_bytes,
    1095              :         .alignment = alignof(*bitset->blocks),
    1096           47 :         .context = allocator->context,
    1097              :     });
    1098           47 :     if (!new_data) {
    1099            1 :         return CCC_RESULT_ALLOCATOR_ERROR;
    1100              :     }
    1101           46 :     (void)memset((char *)new_data + old_bytes, 0, new_bytes);
    1102           46 :     bitset->capacity = new_capacity;
    1103           46 :     bitset->blocks = new_data;
    1104           46 :     return CCC_RESULT_OK;
    1105         1743 : }
    1106              : 
    1107              : /** A trailing bit in a range is the first bit set to the specified boolean
    1108              : value in the provided range. The input i gives the starting bit of the search,
    1109              : meaning a bit within a block that is the inclusive start of the range. The count
    1110              : gives us the end of the search for an overall range of `[i, i + count)`. This
    1111              : means if the search range is greater than a single block we will iterate in
    1112              : ascending order through our blocks and from least to most significant bit within
    1113              : each block. */
    1114              : static CCC_Count
    1115         3073 : first_trailing_bit_range(
    1116              :     struct CCC_Flat_bitset const *const bitset,
    1117              :     size_t const i,
    1118              :     size_t const count,
    1119              :     CCC_Tribool const is_one
    1120              : ) {
    1121         3073 :     size_t exclusive_end = 0;
    1122         3073 :     if (ckd_add(&exclusive_end, i, count) || !bitset || !count
    1123         3073 :         || i >= bitset->count || exclusive_end > bitset->count) {
    1124            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
    1125              :     }
    1126         3072 :     Block_count start_block = block_count_index(i);
    1127         3072 :     Bit_count const start_bit = bit_count_index(i);
    1128         3072 :     Bit_block first_block_mask = leading_ones_mask(BLOCK_BITS - start_bit);
    1129         3072 :     if (start_bit + count < BLOCK_BITS) {
    1130           65 :         first_block_mask &= trailing_ones_mask((Bit_count)(start_bit + count));
    1131           65 :     }
    1132         6144 :     Bit_count trailing_zeros = count_trailing_zeros(
    1133         3072 :         first_block_mask
    1134         3072 :         & (is_one ? bitset->blocks[start_block] : ~bitset->blocks[start_block])
    1135              :     );
    1136         3072 :     if (trailing_zeros != BLOCK_BITS) {
    1137         2112 :         return (CCC_Count){
    1138         1056 :             .count = (start_block * BLOCK_BITS) + trailing_zeros,
    1139              :         };
    1140              :     }
    1141         2016 :     Block_count const end_block = block_count_index(exclusive_end - 1);
    1142         2016 :     if (end_block == start_block) {
    1143           66 :         return (CCC_Count){.error = CCC_RESULT_FAIL};
    1144              :     }
    1145        15364 :     while (++start_block < end_block) {
    1146        14338 :         trailing_zeros = count_trailing_zeros(
    1147        14338 :             is_one ? bitset->blocks[start_block] : ~bitset->blocks[start_block]
    1148              :         );
    1149        14338 :         if (trailing_zeros != BLOCK_BITS) {
    1150         1848 :             return (CCC_Count){
    1151          924 :                 .count = (start_block * BLOCK_BITS) + trailing_zeros,
    1152              :             };
    1153              :         }
    1154              :     }
    1155         2052 :     Bit_block const last_block_mask
    1156         1026 :         = trailing_ones_mask(bit_count_index(exclusive_end - 1) + 1);
    1157         1026 :     trailing_zeros = count_trailing_zeros(
    1158         1026 :         last_block_mask
    1159         1026 :         & (is_one ? bitset->blocks[end_block] : ~bitset->blocks[end_block])
    1160              :     );
    1161         1026 :     if (trailing_zeros != BLOCK_BITS) {
    1162          134 :         return (CCC_Count){
    1163           67 :             .count = (end_block * BLOCK_BITS) + trailing_zeros,
    1164              :         };
    1165              :     }
    1166          959 :     return (CCC_Count){.error = CCC_RESULT_FAIL};
    1167         3073 : }
    1168              : 
    1169              : /** Finds the starting index of a sequence of 1's or 0's of the num_bits size in
    1170              : linear time. The algorithm aims to efficiently skip as many bits as possible
    1171              : while searching for the desired group. This avoids both an O(N^2) runtime and
    1172              : the use of any unnecessary modulo or division operations in a hot loop. */
    1173              : static CCC_Count
    1174        17225 : first_trailing_bits_range( /* NOLINT (*cognitive-complexity) */
    1175              :     struct CCC_Flat_bitset const *const bitset,
    1176              :     size_t const i,
    1177              :     size_t const count,
    1178              :     size_t const num_bits,
    1179              :     CCC_Tribool const ones
    1180              : ) {
    1181        17225 :     size_t exclusive_end = 0;
    1182        17225 :     if (ckd_add(&exclusive_end, i, count) || !bitset || !count || !num_bits
    1183        17218 :         || i >= bitset->count || num_bits > count
    1184        17218 :         || exclusive_end > bitset->count) {
    1185          209 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
    1186              :     }
    1187        17016 :     size_t bit_count = 0;
    1188        17016 :     size_t window_start = i;
    1189        17016 :     Block_count block_index = block_count_index(i);
    1190        17016 :     size_t window_end = (block_index * BLOCK_BITS) + BLOCK_BITS;
    1191        17016 :     Bit_count bit_index = bit_count_index(i);
    1192        34032 :     Bit_block bits
    1193        17016 :         = ones ? bitset->blocks[block_index] : ~bitset->blocks[block_index];
    1194        17016 :     bits &= leading_ones_mask(BLOCK_BITS - bit_index);
    1195       125970 :     for (;;) {
    1196       125970 :         if (window_end > exclusive_end) {
    1197         6317 :             bits &= trailing_ones_mask(bit_count_index(exclusive_end - 1) + 1);
    1198         6317 :         }
    1199       125970 :         if (!bits) {
    1200        97187 :             window_start = (block_index + 1) * BLOCK_BITS;
    1201        97187 :             bit_count = 0;
    1202        97187 :         } else {
    1203        28783 :             size_t bits_remain = num_bits - bit_count;
    1204              :             /* I would rather check for a prefix that could be completing in
    1205              :                this block here than check for a failure and reset to number of
    1206              :                bits on every iteration of the next loop. Think of this like loop
    1207              :                unrolling while also making next block simpler. */
    1208        28783 :             if (bits_remain <= BLOCK_BITS && bits_remain < num_bits) {
    1209        10068 :                 assert(bit_index < BLOCK_BITS && "shifts are valid for block");
    1210        10068 :                 Bit_block const shifted_bits = bits >> bit_index;
    1211        10068 :                 if (is_mask_match(
    1212        10068 :                         shifted_bits, trailing_ones_mask((Bit_count)bits_remain)
    1213              :                     )) {
    1214         6052 :                     return (CCC_Count){.count = window_start};
    1215              :                 }
    1216         4016 :                 bits_remain = num_bits;
    1217         4016 :                 bit_index += count_trailing_zeros(~shifted_bits);
    1218         4016 :                 bit_count = 0;
    1219         4016 :                 window_start = (block_index * BLOCK_BITS) + bit_index;
    1220        10068 :             }
    1221        22731 :             if (bits_remain <= BLOCK_BITS) {
    1222        10269 :                 assert(bit_index < BLOCK_BITS && "shifts are valid for block");
    1223        10269 :                 Bit_block shifted_bits = bits >> bit_index;
    1224        20538 :                 Bit_block const bits_remain_mask
    1225        10269 :                     = trailing_ones_mask((Bit_count)bits_remain);
    1226              :                 /* The loop continues only while our block is numerically
    1227              :                    greater than the mask. Because unsigned integers are
    1228              :                    represented in base 2 we get two automatic early exits here.
    1229              :                        - If the block is missing a high-order bit in the
    1230              :                          required mask, it is numerically smaller than the mask
    1231              :                          and cannot match with further shifting.
    1232              :                        - If all high bits match but some lower required bits are
    1233              :                          zero, the block is numerically smaller than the mask
    1234              :                          and cannot match with further shifting.
    1235              :                    If the block has high order bits not in the mask it is
    1236              :                    greater than the mask and we continue checking, which is
    1237              :                    correct. This strategy optimizes out some useless shifts. */
    1238        54884 :                 while (shifted_bits >= bits_remain_mask) {
    1239        47162 :                     if (is_mask_match(shifted_bits, bits_remain_mask)) {
    1240         5094 :                         return (CCC_Count){
    1241         2547 :                             .count = (block_index * BLOCK_BITS) + bit_index,
    1242              :                         };
    1243              :                     }
    1244        44615 :                     ++bit_index;
    1245        44615 :                     shifted_bits >>= 1;
    1246              :                 }
    1247         7722 :                 bit_count = 0;
    1248        10269 :             }
    1249              :             /* 2 cases covered: the ones remaining are greater than this block
    1250              :                could hold or we did not find a match by the masking we just did.
    1251              :                In either case we need the maximum contiguous ones that run all
    1252              :                the way to the MSB. The best we could have is a full block of
    1253              :                1's. Otherwise we need to find where to start our new search for
    1254              :                contiguous 1's. This could be the next block if there are not 1's
    1255              :                that continue to MSB. */
    1256        20184 :             Bit_count const leading_ones = count_leading_zeros(~bits);
    1257        20184 :             bit_count += leading_ones;
    1258        20184 :             if (leading_ones < BLOCK_BITS) {
    1259              :                 window_start
    1260        15658 :                     = (block_index * BLOCK_BITS) + (BLOCK_BITS - leading_ones);
    1261        15658 :             }
    1262        28783 :         }
    1263       117371 :         if (window_start + num_bits > exclusive_end) {
    1264         8417 :             return (CCC_Count){.error = CCC_RESULT_FAIL};
    1265              :         }
    1266       108954 :         bit_index = 0;
    1267       108954 :         ++block_index;
    1268       108954 :         window_end += BLOCK_BITS;
    1269            0 :         assert(
    1270       108954 :             block_index < block_count_index(bitset->capacity)
    1271       108954 :             && "only load bits within block array capacity"
    1272              :         );
    1273              :         bits
    1274       108954 :             = ones ? bitset->blocks[block_index] : ~bitset->blocks[block_index];
    1275              :     }
    1276        17225 : }
    1277              : 
    1278              : /** A leading bit is the first bit in the range to be set to the indicated value
    1279              : within a block starting the search from the Most Significant Bit of each block.
    1280              : This means that if the range is larger than a single block we iterate in
    1281              : descending order through the set of blocks starting at `i + count
    1282              : - 1` for the range of `[i, i + count)`. The search within a given block
    1283              : proceeds from Most Significant Bit toward Least Significant Bit. */
    1284              : static CCC_Count
    1285         3088 : first_leading_bit_range(
    1286              :     struct CCC_Flat_bitset const *const bitset,
    1287              :     size_t const start_index,
    1288              :     size_t const count,
    1289              :     CCC_Tribool const is_one
    1290              : ) {
    1291         3088 :     size_t window_start = 0;
    1292         3088 :     if (ckd_add(&window_start, start_index, count) || !bitset || !count
    1293         3088 :         || start_index >= bitset->count || window_start > bitset->count) {
    1294         1022 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
    1295              :     }
    1296         2066 :     window_start -= 1;
    1297         2066 :     Bit_count const start_bit = bit_count_index(window_start);
    1298         2066 :     Bit_count const end_bit = bit_count_index(start_index);
    1299         2066 :     Block_count start_block = block_count_index(window_start);
    1300         2066 :     Bit_block first_block_mask = trailing_ones_mask(start_bit + 1);
    1301         2066 :     if (start_index + count < BLOCK_BITS) {
    1302           76 :         first_block_mask &= leading_ones_mask(BLOCK_BITS - end_bit);
    1303           76 :     }
    1304         4132 :     Bit_count leading_zeros = count_leading_zeros(
    1305         2066 :         first_block_mask
    1306         2066 :         & (is_one ? bitset->blocks[start_block] : ~bitset->blocks[start_block])
    1307              :     );
    1308         2066 :     if (leading_zeros != BLOCK_BITS) {
    1309         2132 :         return (CCC_Count){
    1310         1066 :             .count = (start_block * BLOCK_BITS)
    1311         1066 :                    + (Block_count)(BLOCK_BITS - leading_zeros - 1),
    1312              :         };
    1313              :     }
    1314         1000 :     Block_count const end_block = block_count_index(start_index);
    1315         1000 :     if (start_block == end_block) {
    1316            4 :         return (CCC_Count){.error = CCC_RESULT_FAIL};
    1317              :     }
    1318         7774 :     while (--start_block > end_block) {
    1319         7702 :         leading_zeros = count_leading_zeros(
    1320         7702 :             is_one ? bitset->blocks[start_block] : ~bitset->blocks[start_block]
    1321              :         );
    1322         7702 :         if (leading_zeros != BLOCK_BITS) {
    1323         1848 :             return (CCC_Count){
    1324          924 :                 .count = (start_block * BLOCK_BITS)
    1325          924 :                        + (Block_count)(BLOCK_BITS - leading_zeros - 1),
    1326              :             };
    1327              :         }
    1328              :     }
    1329           72 :     Bit_block const last_block_on = leading_ones_mask(BLOCK_BITS - end_bit);
    1330           72 :     leading_zeros = count_leading_zeros(
    1331           72 :         last_block_on
    1332           72 :         & (is_one ? bitset->blocks[end_block] : ~bitset->blocks[end_block])
    1333              :     );
    1334           72 :     if (leading_zeros != BLOCK_BITS) {
    1335          138 :         return (CCC_Count){
    1336           69 :             .count = (end_block * BLOCK_BITS)
    1337           69 :                    + (Block_count)(BLOCK_BITS - leading_zeros - 1),
    1338              :         };
    1339              :     }
    1340            3 :     return (CCC_Count){.error = CCC_RESULT_FAIL};
    1341         3088 : }
    1342              : 
    1343              : /** Iterating backward from MSB to LSB requires more care to avoid unsigned
    1344              : integer wrapping. Therefore, this code is not identical to the trailing version
    1345              : due to a few more branches. This function previously used signed types to avoid
    1346              : this branching but that required making new signed types, copious casting, and
    1347              : verification of input to be within ptrdiff_t limits. For consistency and
    1348              : portability I think committing to unsigned is better for this function. */
    1349              : static CCC_Count
    1350        17189 : first_leading_bits_range( /* NOLINT (*cognitive-complexity) */
    1351              :     struct CCC_Flat_bitset const *const bitset,
    1352              :     size_t const index,
    1353              :     size_t const range_count,
    1354              :     size_t const bits_required,
    1355              :     CCC_Tribool const ones
    1356              : ) {
    1357        17189 :     size_t window_start = 0;
    1358        17189 :     if (ckd_add(&window_start, index, range_count) || !bitset || !range_count
    1359        17189 :         || !bits_required || index >= bitset->count
    1360        17188 :         || bits_required > range_count) {
    1361            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
    1362              :     }
    1363        17188 :     window_start -= 1;
    1364        17188 :     size_t bit_count = 0;
    1365        17188 :     Block_count block_index = block_count_index(window_start);
    1366        17188 :     Block_count window_inclusive_end = ((block_index * BLOCK_BITS));
    1367        17188 :     Bit_count bit_index = bit_count_index(window_start);
    1368        34376 :     Bit_block bits
    1369        17188 :         = ones ? bitset->blocks[block_index] : ~bitset->blocks[block_index];
    1370        17188 :     bits &= trailing_ones_mask(bit_index + 1);
    1371       130737 :     for (;;) {
    1372       130737 :         if (window_inclusive_end < index) {
    1373         5545 :             bits &= leading_ones_mask(BLOCK_BITS - bit_count_index(index));
    1374         5545 :         }
    1375       130737 :         if (!bits) {
    1376        96355 :             window_start = block_index ? (block_index * BLOCK_BITS) - 1 : 0;
    1377        96355 :             bit_count = 0;
    1378        96355 :         } else {
    1379        34382 :             size_t bits_remain = bits_required - bit_count;
    1380              :             /* I would rather check for a prefix that could be completing in
    1381              :                this block here than check for a failure and reset to number of
    1382              :                bits on every iteration of the next loop. Think of this like loop
    1383              :                unrolling while also making next block simpler. */
    1384        34382 :             if (bits_remain <= BLOCK_BITS && bits_remain < bits_required) {
    1385        11987 :                 assert(bit_index < BLOCK_BITS && "shifts are valid for block");
    1386        23974 :                 Bit_block const shifted_block = bits
    1387        11987 :                                              << (BLOCK_BITS - bit_index - 1);
    1388        11987 :                 if (is_mask_match(
    1389        11987 :                         shifted_block, leading_ones_mask((Bit_count)bits_remain)
    1390              :                     )) {
    1391         6038 :                     return (CCC_Count){.count = window_start};
    1392              :                 }
    1393         5949 :                 bits_remain = bits_required;
    1394        11898 :                 Bit_count const leading_ones
    1395         5949 :                     = count_leading_zeros(~shifted_block);
    1396         5949 :                 assert(bit_index >= leading_ones && "index cannot underflow");
    1397         5949 :                 bit_index -= leading_ones;
    1398         5949 :                 window_start = (block_index * BLOCK_BITS) + bit_index;
    1399         5949 :                 bit_count = 0;
    1400        11987 :             }
    1401        28344 :             if (bits_remain <= BLOCK_BITS) {
    1402        13287 :                 assert(bit_index < BLOCK_BITS && "shifts are valid for block");
    1403        13287 :                 Bit_block shifted_block = bits << (BLOCK_BITS - bit_index - 1);
    1404        26574 :                 Bit_block const bits_remain_mask
    1405        13287 :                     = leading_ones_mask((Bit_count)bits_remain);
    1406              :                 /* Can't find a clever way to reduce shifts like trailing. */
    1407        13287 :                 Bit_count const end_index = (Bit_count)(bits_remain - 1);
    1408       103330 :                 while (bit_index >= end_index) {
    1409        92586 :                     if (is_mask_match(shifted_block, bits_remain_mask)) {
    1410         5086 :                         return (CCC_Count){
    1411         2543 :                             .count = (block_index * BLOCK_BITS) + bit_index,
    1412              :                         };
    1413              :                     }
    1414        90043 :                     --bit_index;
    1415        90043 :                     shifted_block <<= 1;
    1416              :                 }
    1417        10744 :                 bit_count = 0;
    1418        13287 :             }
    1419        25801 :             Bit_count const trailing_ones = count_trailing_zeros(~bits);
    1420        25801 :             bit_count += trailing_ones;
    1421        25801 :             if (trailing_ones < BLOCK_BITS) {
    1422        20402 :                 window_start = (block_index * BLOCK_BITS) + trailing_ones;
    1423        20402 :                 if (window_start) {
    1424        19876 :                     --window_start;
    1425        19876 :                 }
    1426        20402 :             }
    1427        34382 :         }
    1428       122156 :         if (window_start < index + bits_required - 1) {
    1429         8607 :             return (CCC_Count){.error = CCC_RESULT_FAIL};
    1430              :         }
    1431       113549 :         bit_index = BLOCK_BITS - 1;
    1432       113549 :         --block_index;
    1433       113549 :         window_inclusive_end = window_inclusive_end >= BLOCK_BITS
    1434       113549 :                                  ? window_inclusive_end - BLOCK_BITS
    1435              :                                  : 0;
    1436            0 :         assert(
    1437       113549 :             block_index < block_count_index(bitset->capacity)
    1438       113549 :             && "current block within range while iterating toward LSB"
    1439              :         );
    1440              :         bits
    1441       113549 :             = ones ? bitset->blocks[block_index] : ~bitset->blocks[block_index];
    1442              :     }
    1443        17189 : }
    1444              : 
    1445              : /** Performs the any or none scan operation over the specified range. The only
    1446              : difference between the operations is the return value. Specify the desired
    1447              : Tribool value to return upon encountering an on bit. For any this is CCC_TRUE.
    1448              : For none this is CCC_FALSE. Saves writing two identical fns. */
    1449              : static CCC_Tribool
    1450         2571 : any_or_none_range(
    1451              :     struct CCC_Flat_bitset const *const bitset,
    1452              :     size_t const i,
    1453              :     size_t const count,
    1454              :     CCC_Tribool const any_or_none
    1455              : ) {
    1456         2571 :     size_t range_end = 0;
    1457         2571 :     if (ckd_add(&range_end, i, count) || !bitset || !count || i >= bitset->count
    1458         2570 :         || range_end > bitset->count || any_or_none < CCC_FALSE
    1459         2570 :         || any_or_none > CCC_TRUE) {
    1460            1 :         return CCC_TRIBOOL_ERROR;
    1461              :     }
    1462         2570 :     Block_count start_block = block_count_index(i);
    1463         2570 :     Bit_count const start_bit = bit_count_index(i);
    1464         2570 :     Bit_block first_block_mask = leading_ones_mask(BLOCK_BITS - start_bit);
    1465         2570 :     if (start_bit + count < BLOCK_BITS) {
    1466           18 :         first_block_mask &= trailing_ones_mask((Bit_count)(start_bit + count));
    1467           18 :     }
    1468         2570 :     if (first_block_mask & bitset->blocks[start_block]) {
    1469          166 :         return any_or_none;
    1470              :     }
    1471         2404 :     Block_count const end_block = block_count_index(range_end - 1);
    1472         2404 :     if (end_block == start_block) {
    1473           18 :         return !any_or_none;
    1474              :     }
    1475              :     /* If this is the any check we might get lucky by checking the last
    1476              :        block before looping over everything. */
    1477         4772 :     Bit_block const last_block_mask
    1478         2386 :         = trailing_ones_mask(bit_count_index(range_end - 1) + 1);
    1479         2386 :     if (last_block_mask & bitset->blocks[end_block]) {
    1480          226 :         return any_or_none;
    1481              :     }
    1482        20864 :     for (++start_block; start_block < end_block; ++start_block) {
    1483        19600 :         if (bitset->blocks[start_block] & BLOCK_ON) {
    1484          896 :             return any_or_none;
    1485              :         }
    1486        18704 :     }
    1487         1264 :     return !any_or_none;
    1488         2571 : }
    1489              : 
    1490              : /** Check for all on is slightly different from the any or none checks so we
    1491              : need a painfully repetitive function. */
    1492              : static CCC_Tribool
    1493         1037 : all_range(
    1494              :     struct CCC_Flat_bitset const *const bitset,
    1495              :     size_t const i,
    1496              :     size_t const count
    1497              : ) {
    1498         1037 :     size_t range_end = 0;
    1499         1037 :     if (ckd_add(&range_end, i, count) || !bitset || !count || i >= bitset->count
    1500         1036 :         || range_end > bitset->count) {
    1501            1 :         return CCC_TRIBOOL_ERROR;
    1502              :     }
    1503         1036 :     Block_count start_block = block_count_index(i);
    1504         1036 :     Bit_count const start_bit = bit_count_index(i);
    1505         1036 :     Bit_block first_block_mask = leading_ones_mask(BLOCK_BITS - start_bit);
    1506         1036 :     if (start_bit + count < BLOCK_BITS) {
    1507            5 :         first_block_mask &= trailing_ones_mask((Bit_count)(start_bit + count));
    1508            5 :     }
    1509         1036 :     if ((first_block_mask & bitset->blocks[start_block]) != first_block_mask) {
    1510          771 :         return CCC_FALSE;
    1511              :     }
    1512          265 :     Block_count const end_block = block_count_index(range_end - 1);
    1513          265 :     if (end_block == start_block) {
    1514            4 :         return CCC_TRUE;
    1515              :     }
    1516         2079 :     while (++start_block < end_block) {
    1517         1819 :         if (bitset->blocks[start_block] != BLOCK_ON) {
    1518            1 :             return CCC_FALSE;
    1519              :         }
    1520              :     }
    1521          520 :     Bit_block const last_block_mask
    1522          260 :         = trailing_ones_mask(bit_count_index(range_end - 1) + 1);
    1523          260 :     return is_mask_match(bitset->blocks[end_block], last_block_mask);
    1524         1037 : }
    1525              : 
    1526              : /** Given the 0 based index from `[0, count of used bits in set)` returns a
    1527              : reference to the block that such a bit belongs to. This block reference will
    1528              : point to some block at index [0, count of blocks used in the set). */
    1529              : static inline Bit_block *
    1530        40900 : block_at(
    1531              :     struct CCC_Flat_bitset const *const bitset, size_t const flat_bitset_index
    1532              : ) {
    1533        40900 :     return &bitset->blocks[block_count_index(flat_bitset_index)];
    1534              : }
    1535              : 
    1536              : /** Sets all bits in bulk to value b and fixes the end block to ensure all bits
    1537              : in the final block that are not in use are zeroed out. */
    1538              : static inline void
    1539           36 : set_all(struct CCC_Flat_bitset *const bitset, CCC_Tribool const b) {
    1540           36 :     int const v = b ? ~0 : 0;
    1541           36 :     (void)memset(bitset->blocks, v, block_count(bitset->count) * SIZEOF_BLOCK);
    1542           36 :     fix_end(bitset);
    1543           36 : }
    1544              : 
    1545              : /** Given the appropriate block in which bit_i resides, sets the bits position
    1546              : to 0 or 1 as specified by the CCC_Tribool argument b.
    1547              : 
    1548              : Assumes block has been retrieved correctly in range [0, count of blocks in set)
    1549              : and that bit_i is in range [0, count of active bits in set). */
    1550              : static inline void
    1551        15412 : set(Bit_block *const block,
    1552              :     size_t const flat_bitset_index,
    1553              :     CCC_Tribool const b) {
    1554        15412 :     if (b) {
    1555         8986 :         *block |= on(flat_bitset_index);
    1556         8986 :     } else {
    1557         6426 :         *block &= ~on(flat_bitset_index);
    1558              :     }
    1559        15412 : }
    1560              : 
    1561              : /** Given the bit set and the set index, set index is allowed to be greater than
    1562              : the size of one block, returns the status of the bit at that index. */
    1563              : static inline CCC_Tribool
    1564        20136 : status(Bit_block const *const bitset, size_t const flat_bitset_index) {
    1565              :     /* Be careful. The & op does not promise to evaluate to 1 or 0. We often
    1566              :        just use it where that conversion takes place implicitly for us. */
    1567        20136 :     return (*bitset & on(flat_bitset_index)) != 0;
    1568              : }
    1569              : 
    1570              : /** Given the true bit index in the bit set, expected to be in the range
    1571              : [0, count of active bits in set), returns a Bit_block mask with only this bit
    1572              : on in block to which it belongs. This mask guarantees to have a bit on within
    1573              : a bit block at index [0, BIT_BLOCK_BITS - 1). */
    1574              : static inline Bit_block
    1575        35552 : on(size_t flat_bitset_index) {
    1576        35552 :     return (Bit_block)1 << bit_count_index(flat_bitset_index);
    1577              : }
    1578              : 
    1579              : /** Clears unused bits in the last block according to count. Sets the last block
    1580              : to have only the used bits set to their given values and all bits after to zero.
    1581              : This is used as a safety mechanism throughout the code after complex operations
    1582              : on bit blocks to ensure any side effects on unused bits are deleted. */
    1583              : static inline void
    1584        19092 : fix_end(struct CCC_Flat_bitset *const bitset) {
    1585        19092 :     bitset->count
    1586        19072 :         ? (*block_at(bitset, bitset->count - 1)
    1587        38144 :            &= trailing_ones_mask(bit_count_index(bitset->count - 1) + 1))
    1588           20 :         : (bitset->blocks[0] = 0);
    1589        19092 : }
    1590              : 
    1591              : /** Returns the 0-based index of the block in the block array allocation to
    1592              : which the given index belongs. Assumes the given index is somewhere between [0,
    1593              : count of bits set). The returned index then represents the block in which this
    1594              : index resides which is in the range [0, block containing last in use bit). */
    1595              : static inline Block_count
    1596       360618 : block_count_index(size_t const flat_bitset_index) {
    1597              :     static_assert(
    1598              :         (typeof(flat_bitset_index))~((typeof(flat_bitset_index))0)
    1599              :             >= (typeof(flat_bitset_index))0,
    1600              :         "shifting to avoid division with power of 2 divisor is only "
    1601              :         "defined for unsigned types"
    1602              :     );
    1603       360618 :     return flat_bitset_index >> BLOCK_BITS_LOG2;
    1604              : }
    1605              : 
    1606              : /** Returns the 0-based index within a block to which the given index belongs.
    1607              : This index will always be between [0, BIT_BLOCK_BITS - 1). */
    1608              : static inline Bit_count
    1609       161186 : bit_count_index(size_t const flat_bitset_index) {
    1610       161186 :     return flat_bitset_index & (BLOCK_BITS - 1);
    1611              : }
    1612              : 
    1613              : /** Returns the number of blocks required to store the given bits. Assumes bits
    1614              : is non-zero. For any bits > 1 the block count is always less than bits. */
    1615              : static inline Block_count
    1616         9365 : block_count(size_t const bit_count) {
    1617              :     static_assert(
    1618              :         (typeof(bit_count))~((typeof(bit_count))0) >= (typeof(bit_count))0,
    1619              :         "shifting to avoid division with power of 2 divisor is only "
    1620              :         "defined for unsigned types"
    1621              :     );
    1622         9365 :     assert(bit_count && "calculating block count for non-empty bitset");
    1623         9365 :     return (bit_count + (BLOCK_BITS - 1)) >> BLOCK_BITS_LOG2;
    1624              : }
    1625              : 
    1626              : /** Returns the number of blocks required to store the given bits. Assumes bits
    1627              : is non-zero. For any bits > 1 the block count is always less than bits.
    1628              : 
    1629              : This function checks for overflow when obtaining the count and returns CCC_TRUE
    1630              : if overflow occured otherwise CCC_FALSE. */
    1631              : static inline CCC_Tribool
    1632           94 : checked_block_count(Block_count *const result, size_t const bit_count) {
    1633           94 :     assert(bit_count && "calculating block count for non-empty bitset");
    1634           94 :     if (ckd_add(result, bit_count, (BLOCK_BITS - 1))) {
    1635            0 :         return CCC_TRUE;
    1636              :     }
    1637           94 :     *result >>= BLOCK_BITS_LOG2;
    1638           94 :     return CCC_FALSE;
    1639           94 : }
    1640              : 
    1641              : /** Returns true if the on bit mask is present in the block. All one bits in the
    1642              : mask must be found at the same positions in the block being queried. */
    1643              : static inline CCC_Tribool
    1644       162123 : is_mask_match(Bit_block const block, Bit_block const on_mask) {
    1645       162123 :     return (block & on_mask) == on_mask;
    1646              : }
    1647              : 
    1648              : /** Returns a mask of the specified count of trailing bits set to 1 (CCC_TRUE)
    1649              : within a bit block. This is the same integer type that is stored in the bit set
    1650              : integer block array. Trailing ones are ones starting from index 0, the Least
    1651              : Significant Bit, counting toward the Most Significant Bit of the block. A count
    1652              : of zero will return 0. A count equivalent to the block bit width will return a
    1653              : mask with all bits set to 1. */
    1654              : static inline Bit_block
    1655        92434 : trailing_ones_mask(Bit_count const ones_count) {
    1656        92434 :     assert(ones_count <= BLOCK_BITS && "shift is well defined for mask");
    1657        92434 :     return ones_count ? BLOCK_ON >> (BLOCK_BITS - ones_count) : 0;
    1658              : }
    1659              : 
    1660              : /** Returns a mask of the specified count of leading bits set to 1 (CCC_TRUE)
    1661              : within a bit block. This is the same integer type that is stored in the bit set
    1662              : integer block array. Leading ones are ones starting from index BLOCK_BITS - 1,
    1663              : the Most Significant Bit, counting toward 0, the Least Significant Bit, of the
    1664              : block. A count of zero will return 0. A count equivalent to the block bit width
    1665              : will return a mask with all bits set to 1. */
    1666              : static inline Bit_block
    1667        78939 : leading_ones_mask(Bit_count const ones_count) {
    1668        78939 :     assert(ones_count <= BLOCK_BITS && "shift is well defined for mask");
    1669        78939 :     return ones_count ? BLOCK_ON << (BLOCK_BITS - ones_count) : 0;
    1670              : }
    1671              : 
    1672              : /** The following asserts assure that whether portable or built in bit
    1673              : operations are used in the coming section we are safe in our assumptions about
    1674              : widths and counts.  Much of the code relies on the assumption that iterating
    1675              : over blocks at at a time is faster than using mathematical operations to
    1676              : conceptually iterate over bits. This assumptions mostly comes from the use of
    1677              : these built-ins to keep the processing time linear for range based queries,
    1678              : while avoiding division and modulo operations. I should test to see the
    1679              : performance implications when these built-ins are gone. However they are pretty
    1680              : ubiquitous these days. */
    1681              : 
    1682              : static_assert(
    1683              :     BLOCK_MSB < BLOCK_ON, "most significant bit is set for correct block width"
    1684              : );
    1685              : static_assert(
    1686              :     SIZEOF_BLOCK == sizeof(unsigned),
    1687              :     "builtins remain in sync with bitset block width"
    1688              : );
    1689              : static_assert(
    1690              :     sizeof(Bit_block) * CHAR_BIT <= U8_BLOCK_MAX,
    1691              :     "bit counts are valid for smaller width types a bit set uses"
    1692              : );
    1693              : 
    1694              : /** Counts the number of trailing zeros in a bit block starting from least
    1695              : significant bit. */
    1696              : static inline Bit_count
    1697        48253 : count_trailing_zeros(Bit_block const b) {
    1698        48253 :     return (Bit_count)CCC_count_trailing_zeros(b);
    1699              : }
    1700              : 
    1701              : /** Counts the leading zeros in a bit block starting from the most significant
    1702              : bit. */
    1703              : static inline Bit_count
    1704        35973 : count_leading_zeros(Bit_block const b) {
    1705        35973 :     return (Bit_count)CCC_count_leading_zeros(b);
    1706              : }
    1707              : 
    1708              : /** Counts the on bits in a bit block. */
    1709              : static inline Bit_count
    1710       227961 : popcount(Bit_block const b) {
    1711       227961 :     return (Bit_count)CCC_popcount(b);
    1712              : }
        

Generated by: LCOV version 2.4-beta