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_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 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(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; } } */