Commit 03ae07ab authored by Andreas Schmidt's avatar Andreas Schmidt
Browse files

Improve bitmap efficiency and tests

parent f10b2e3e
Loading
Loading
Loading
Loading
Loading
+55 −16
Original line number Diff line number Diff line
@@ -28,32 +28,71 @@ Bitmap *Bitmap_create(bool initialValue, uint32_t elementCount)

void Bitmap_set_range_0(Bitmap *bitmap, uint32_t start, uint32_t length)
{
    uint32_t i = 0;
    // TODO: highly inefficient - optimize
	for(i = 0; i < length; i++) {
		Bitmap_set_0(bitmap, start + i);
    uint32_t start_byte = start / 32;
    uint32_t start_bit = start % 32;
    uint32_t end_byte = (start + length) / 32;
    uint32_t end_bit = (start + length) % 32;
    uint32_t full_mask = ~0u;

    if (start_byte == end_byte) {
        uint32_t mask = (full_mask << end_bit) ^ (full_mask << start_bit);
        bitmap->data[start_byte] ^= (bitmap->data[start_byte] & mask);
    } else {
        uint32_t start_mask = full_mask << start_bit;
        bitmap->data[start_byte] ^= (bitmap->data[start_byte] & start_mask);
        for (uint32_t current_byte = start_byte + 1; current_byte < end_byte; ++current_byte) {
            bitmap->data[current_byte] = 0;
        }
        uint32_t end_mask = ~(full_mask << end_bit);
        bitmap->data[end_byte] ^= (bitmap->data[end_byte] & end_mask);
    }
}

void Bitmap_set_range_1(Bitmap *bitmap, uint32_t start, uint32_t length)
{
    uint32_t i = 0;
    // TODO: highly inefficient - optimize
	for(i = 0; i < length; i++) {
		Bitmap_set_1(bitmap, start + i);
    uint32_t start_byte = start / 32;
    uint32_t start_bit = start % 32;
    uint32_t end_byte = (start + length) / 32;
    uint32_t end_bit = (start + length) % 32;
    uint32_t full_mask = ~0u;

    if (start_byte == end_byte) {
        uint32_t mask = (full_mask << end_bit) ^ (full_mask << start_bit);
        bitmap->data[start_byte] |= mask;
    } else {
        uint32_t start_mask = full_mask << start_bit;
        bitmap->data[start_byte] |= start_mask;
        for (uint32_t current_byte = start_byte + 1; current_byte < end_byte; ++current_byte) {
            bitmap->data[current_byte] = full_mask;
        }
        uint32_t end_mask = ~(full_mask << end_bit);
        bitmap->data[end_byte] |= end_mask;
    }
}

uint32_t Bitmap_sum_ones(Bitmap *bitmap, uint32_t start, uint32_t length)
{
    uint32_t sum = 0;
    uint32_t i = 0;
    // TODO: highly inefficient - optimize
    for(i = 0; i < length; i++) {
        sum += (Bitmap_get(bitmap, start + i) == true);
    uint32_t start_byte = start / 32;
    uint32_t start_bit = start % 32;
    uint32_t end_byte = (start + length) / 32;
    uint32_t end_bit = (start + length) % 32;
    uint32_t full_mask = ~0u;

    if (start_byte == end_byte) {
        uint32_t mask = (full_mask << end_bit) ^ (full_mask << start_bit);
        return __builtin_popcount(bitmap->data[start_byte] & mask);
    } else {
        uint32_t start_mask = full_mask << start_bit;
        uint32_t sum = __builtin_popcount(bitmap->data[start_byte] & start_mask);
        for (uint32_t current_byte = start_byte + 1; current_byte < end_byte; ++current_byte) {
            sum += __builtin_popcount(bitmap->data[current_byte]);
        }
        uint32_t end_mask = ~(full_mask << end_bit);
        sum += __builtin_popcount(bitmap->data[end_byte] & end_mask);

        return sum;
    }
}

uint32_t Bitmap_sum_zeros(Bitmap *bitmap, uint32_t start, uint32_t length)
{
+18 −8
Original line number Diff line number Diff line
@@ -54,12 +54,22 @@ TEST_F(BitmapTest, GetRange)

TEST_F(BitmapTest, SetRange)
{
    ASSERT_EQ(5, Bitmap_sum_ones(bitmap, 1, 5));
    ASSERT_EQ(0, Bitmap_sum_zeros(bitmap, 1, 5));
    Bitmap_set_range(bitmap, 2, 2, false);
    ASSERT_FALSE(Bitmap_get(bitmap, 2));
    ASSERT_FALSE(Bitmap_get(bitmap, 3));
    ASSERT_TRUE(Bitmap_get(bitmap, 4));
    ASSERT_EQ(3, Bitmap_sum_ones(bitmap, 1, 5));
    ASSERT_EQ(2, Bitmap_sum_zeros(bitmap, 1, 5));
    ASSERT_EQ(500, Bitmap_sum_ones(bitmap, 17, 500));
    ASSERT_EQ(0, Bitmap_sum_zeros(bitmap, 17, 500));

    Bitmap_set_range(bitmap, 2, 300, false);
    ASSERT_TRUE(Bitmap_get(bitmap, 1));
    for (int i = 2; i < 302; ++i) {
        ASSERT_FALSE(Bitmap_get(bitmap, i));
    }
    ASSERT_TRUE(Bitmap_get(bitmap, 302));

    Bitmap_set_range(bitmap, 150, 100, true);
    ASSERT_FALSE(Bitmap_get(bitmap, 149));
    for (int i = 150; i < 250; ++i) {
        ASSERT_TRUE(Bitmap_get(bitmap, i));
    }
    ASSERT_FALSE(Bitmap_get(bitmap, 250));
    ASSERT_EQ(300, Bitmap_sum_ones(bitmap, 1, 500));
    ASSERT_EQ(200, Bitmap_sum_zeros(bitmap, 1, 500));
}