Files
operating-system/src/lib/bitmap.c
2024-08-15 18:08:01 +02:00

146 lines
4.3 KiB
C

#include "bitmap.h"
#include <limits.h>
static constexpr struct bitmap B = {0};
static constexpr size_t bits_per_index = sizeof (B.data[0]) * CHAR_BIT;
#define mask(n) ((1<<(n))-1)
_Static_assert(mask(0) == 0b0000);
_Static_assert(mask(1) == 0b0001);
_Static_assert(mask(2) == 0b0011);
_Static_assert(mask(3) == 0b0111);
static inline int trailing_zeroes(int n)
{
return __builtin_ctz(n);
}
int bitmap_set_range(struct bitmap* bitmap, size_t begin, size_t end)
{
if (end < begin) {
return bitmap_set_range(bitmap, end, begin);
}
if (unlikely(begin > bitmap->bit_count)) {
return -1;
}
if (unlikely(end > bitmap->bit_count)) {
return -2;
}
/* begin and end are within the same index: */
if ((begin / bits_per_index) == (end / bits_per_index)) {
#define expr(begin, end) (~mask((begin) % bits_per_index) & mask((end) % bits_per_index))
_Static_assert(expr(1,6) == 0b0000111110, "bitmap range logic invalid!");
bitmap->data[begin / bits_per_index] |= expr(begin, end);
#undef expr
} else {
bitmap->data[begin / bits_per_index] |= ~mask(begin % bits_per_index);
for (size_t i = 1 + begin/bits_per_index;
i < end/bits_per_index;
i++)
{
bitmap->data[i] |= ~0;
}
bitmap->data[end / bits_per_index] |= mask(end % bits_per_index);
}
return 0;
}
int bitmap_clear_range(struct bitmap* bitmap, size_t begin, size_t end)
{
if (end < begin) {
return bitmap_set_range(bitmap, end, begin);
}
if (unlikely(begin > bitmap->bit_count)) {
return -1;
}
if (unlikely(end > bitmap->bit_count)) {
return -2;
}
/* begin and end are within the same index: */
if ((begin / bits_per_index) == (end / bits_per_index)) {
#define expr(begin, end) (~mask((begin) % bits_per_index) & mask((end) % bits_per_index))
_Static_assert(expr(1,6) == 0b0000111110, "bitmap range logic invalid!");
bitmap->data[begin / bits_per_index] &= ~expr(begin, end);
#undef expr
} else {
bitmap->data[begin / bits_per_index] &= mask(begin % bits_per_index);
for (size_t i = 1 + begin/bits_per_index;
i < end/bits_per_index;
i++)
{
bitmap->data[i] = 0;
}
bitmap->data[end / bits_per_index] &= ~mask(end % bits_per_index);
}
return 0;
}
/* This 4 am code is almost certainly wrong. No tests have been written yet.
*
* Returns 0 if range is empty.
* If range is not emtpy, it returns the offset of the first non-zero bit
* from `begin`
*
* TODO: write tests */
int bitmap_range_empty(struct bitmap* bitmap, size_t begin, size_t end)
{
if (end < begin) {
return bitmap_set_range(bitmap, end, begin);
}
if (unlikely(begin > bitmap->bit_count)) {
return -1;
}
if (unlikely(end > bitmap->bit_count)) {
return -2;
}
/* begin and end are within the same index: */
if ((begin / bits_per_index) == (end / bits_per_index)) {
#define expr(begin, end) (~mask((begin) % bits_per_index) & mask((end) % bits_per_index))
_Static_assert(expr(1,6) == 0b0000111110, "bitmap range logic invalid!");
const typeof(bitmap->data[0]) n = bitmap->data[begin / bits_per_index];
if (n & expr(begin, end)) {
return trailing_zeroes(n) - (begin % bits_per_index) ;
};
#undef expr
} else {
{
const typeof(bitmap->data[0]) n = bitmap->data[begin / bits_per_index];
if (n & ~mask(begin % bits_per_index)) {
return trailing_zeroes(n) - (begin % bits_per_index);
}
}
for (size_t i = 1 + begin/bits_per_index;
i < end/bits_per_index;
i++)
{
const typeof(bitmap->data[0]) n = bitmap->data[i];
if (n != 0) {
return i*bits_per_index + trailing_zeroes(n);
}
}
{
const typeof(bitmap->data[0]) n = bitmap->data[end / bits_per_index];
if (n & mask(end % bits_per_index)) {
return (end % bits_per_index) - trailing_zeroes(n);
}
bitmap->data[end / bits_per_index] &= ~mask(end % bits_per_index);
}
}
return 0;
}