stclib / STC

A modern, user friendly, generic, type-safe and fast C99 container library: String, Vector, Sorted and Unordered Map and Set, Deque, Forward List, Smart Pointers, Bitset and Random numbers.
MIT License
1.35k stars 73 forks source link

cbits_resize resets the contents of existing element when shrinking #93

Closed thehoustonian closed 2 months ago

thehoustonian commented 4 months ago

I have noticed what appears to be undesired behavior in the cbits_resize() function. When resizing a cbits object from a size aligned with a buffer entry (such as 64) down to one not aligned to a buffer entry (such as 50), the masking logic will overwrite all bits in the entry to the new default value. This does not occur when cbits size is, for instance, 63 instead of 64. I have created a small test program that illustrates the problem, and I am planning to open a merge request with a proposed fix soon.

In the following program, resizing a cbits object from 64 bits to 53 results in all bits being set to 1, whereas resizing from 63 to 53 appears to behave correctly. The same behavior is also observed when resizing from 128 to 100, except that only bits 65 through 100 are set to the default value of 1 instead of the entire buffer.

#include "STC/include/stc/cbits.h"
#include <stdio.h>

void set_bits(cbits *const bits)
{
    printf("Setting bits\n");
    cbits_set_all(bits, false);
    intptr_t i = 0;

    while (i < cbits_size(bits)) {
        cbits_set(bits, i);
        i += 2;
    }
}

void print_bits(cbits *const bits)
{
    size_t bitsize = (size_t)cbits_size(bits);
    char *bitstring = (char *)malloc(bitsize + 1);

    memset(bitstring, 0, bitsize);

    cbits_to_str(bits, bitstring, 0, bitsize);
    printf("Bitmask: %s\n\n", bitstring);
    free(bitstring);
}

int main()
{
    cbits test_bits = {0};

    printf("Resize to 63\n");
    cbits_resize(&test_bits, 63, true);

    set_bits(&test_bits);
    print_bits(&test_bits);

    printf("Resize to 53\n");
    cbits_resize(&test_bits, 53, true);
    print_bits(&test_bits);

    printf("Resize to 64\n");
    cbits_resize(&test_bits, 64, true);
    print_bits(&test_bits);
    set_bits(&test_bits);
    print_bits(&test_bits);

    printf("Resize to 53\n");
    cbits_resize(&test_bits, 53, true);
    print_bits(&test_bits);

    printf("Resize to 128\n");
    cbits_resize(&test_bits, 128, true);
    set_bits(&test_bits);
    print_bits(&test_bits);

    printf("Resize to 100\n");
    cbits_resize(&test_bits, 100, true);
    print_bits(&test_bits);

    cbits_drop(&test_bits);

    return 0;
}

Program output:

Resize to 63
Setting bits
Bitmask: 101010101010101010101010101010101010101010101010101010101010101

Resize to 53
Bitmask: 10101010101010101010101010101010101010101010101010101

Resize to 64
Bitmask: 1010101010101010101010101010101010101010101010101010111111111111

Setting bits
Bitmask: 1010101010101010101010101010101010101010101010101010101010101010

Resize to 53
Bitmask: 11111111111111111111111111111111111111111111111111111

Resize to 128
Setting bits
Bitmask: 10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010

Resize to 100
Bitmask: 1010101010101010101010101010101010101010101010101010101010101010111111111111111111111111111111111111
tylov commented 2 months ago

Thanks for reporting, and sorry for late response.