Musa-STL-Cpp/lib/Base/Bit_Array.h

175 lines
4.2 KiB
C

struct Bit_Array { // we need to keep track of our allocator separately.
u64* data;
s32 count;
s32 data_count; // do we even need this??
bool operator[](s64 index) {
#if ARRAY_ENABLE_BOUNDS_CHECKING
if (index < 0 || index >= count) { debug_break(); } // index out of bounds
#endif
return (bool)(data[index >> 6] & (1ull << (index & 63)));
}
}; // 16 B.
// bool contains (Bit_Array* src, Bit_Array* query) {
// Assert(src && query);
// Assert(src->data_count == query->data_count);
// for (s32 i = 0; i < src->data_count; i += 1) {
// if (src->data[i] & query->data[i] != query->data[i]) {
// return false;
// }
// }
// return true;
// }
bool contains_single_ascii (Bit_Array* src, Bit_Array* query) {
Assert(src && query);
Assert(src->data_count == query->data_count);
for (s32 i = 0; i < src->data_count; i += 1) {
// if query u64 is non-zero, we should get a non-zero result:
if (query->data[i] && (src->data[i] & query->data[i]) == 0) {
return false;
}
}
return true;
}
void bit_array_initialize (Bit_Array* ba, s64 count) {
s64 u64_count = (count + 63) >> 6;
ba->data = NewArray<u64>(u64_count);
ba->data_count = u64_count;
ba->count = count;
}
// Returns a bit array of the given size:
Bit_Array new_bit_array (s64 count) {
Bit_Array ba;
bit_array_initialize(&ba, count);
return ba;
}
void bit_array_delete (Bit_Array* ba) {
internal_free(ba->data);
ba->count = 0;
ba->data_count = 0;
}
void set_bit (Bit_Array* ba, s64 i) {
Assert(i < ba->count);
ba->data[i >> 6] |= (1ull << (i & 63));
}
void clear_bit (Bit_Array* ba, s64 i) {
Assert(i < ba->count);
ba->data[i >> 6] &= ~(1ull << (i & 63));
}
void toggle_bit (Bit_Array* ba, s64 i) {
Assert(i < ba->count);
ba->data[i >> 6] ^= ~(1ull << (i & 63));
}
// See "Conditionally set or clear bits without branching" at http://graphics.stanford.edu/~seander/bithacks.html
force_inline s64 set_bits (s64 w, s64 m, bool b) {
return (w & ~m) | ((-(s64)b) & m);
}
void set_bit_to (Bit_Array* ba, s64 i, bool value) {
Assert(i < ba->count);
ba->data[i >> 6] = set_bits(ba->data[i >> 6], 1ull << (i & 63), value);
Assert((*ba)[i] == value);
}
void clear_all_bits (Bit_Array* ba) {
memset(ba->data, 0, ba->data_count * sizeof(u64));
}
void set_all_bits (Bit_Array* ba) {
memset(ba->data, 0xFF, ba->data_count * sizeof(u64));
}
void toggle_all_bits (Bit_Array* ba) {
for (s64 s = 0; s < ba->data_count; s += 1) {
ba->data[s] ^= U64_MAX;
}
}
// Using Bit_Array.jai as a reference:
/*
struct Bit_Array { // 40 B
ArrayView<u64> slots;
s64 count; // bit count;
Allocator allocator;
bool operator[](s64 index) {
#if ARRAY_ENABLE_BOUNDS_CHECKING
if (index < 0 || index >= count) { debug_break(); } // index out of bounds
#endif
return (bool)(slots[index >> 6] & (1ull << (index & 63)));
}
};
void bit_array_initialize (Bit_Array* ba, s64 count) {
if (ba->allocator.proc == nullptr) ba->allocator = context_allocator();
s64 u64_count = (count + 63) >> 6;
ba->slots = ArrayView<u64>(ba->allocator, u64_count);
ba->count = count;
}
// Returns a bit array of the given size:
Bit_Array new_bit_array (s64 count) {
Bit_Array ba;
bit_array_initialize(&ba, count);
return ba;
}
void bit_array_delete (Bit_Array* ba) {
push_allocator(ba->allocator);
array_free(ba->slots);
ba->slots = {};
ba->count = 0;
}
// #TODO: set_bit, clear_bit, toggle_bit, etc.
void set_bit (Bit_Array* ba, s64 i) {
Assert(i < ba->count);
ba->slots[i >> 6] |= (1ull << (i & 63));
}
void clear_bit (Bit_Array* ba, s64 i) {
Assert(i < ba->count);
ba->slots[i >> 6] &= ~(1ull << (i & 63));
}
void toggle_bit (Bit_Array* ba, s64 i) {
Assert(i < ba->count);
ba->slots[i >> 6] ^= ~(1ull << (i & 63));
}
void set_bit_to (Bit_Array* ba, s64 i, bool value) {
Assert(i < ba->count);
ba->slots[i >> 6] = set_bits(ba->slots[i >> 6], 1ull << (i & 63), value);
Assert((*ba)[i] == value);
}
void clear_all_bits (Bit_Array* ba) {
array_zero(ba->slots);
}
void set_all_bits (Bit_Array* ba) {
memset(ba->slots.data, 0xFF, ba->slots.count * sizeof(u64));
}
void toggle_all_bits (Bit_Array* ba) {
for_each(s, ba->slots) {
ba->slots[s] ^= U64_MAX;
}
}
*/