bit_array.odin 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. package dynamic_bit_array
  2. import "core:intrinsics"
  3. import "core:mem"
  4. /*
  5. Note that these constants are dependent on the backing being a u64.
  6. */
  7. @(private="file")
  8. INDEX_SHIFT :: 6
  9. @(private="file")
  10. INDEX_MASK :: 63
  11. @(private="file")
  12. NUM_BITS :: 64
  13. Bit_Array :: struct {
  14. bits: [dynamic]u64,
  15. bias: int,
  16. max_index: int,
  17. free_pointer: bool,
  18. }
  19. Bit_Array_Iterator :: struct {
  20. array: ^Bit_Array,
  21. word_idx: int,
  22. bit_idx: uint,
  23. }
  24. /*
  25. In:
  26. - ba: ^Bit_Array - the array to iterate over
  27. Out:
  28. - it: ^Bit_Array_Iterator - the iterator that holds iteration state
  29. */
  30. make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) {
  31. return Bit_Array_Iterator { array = ba }
  32. }
  33. /*
  34. In:
  35. - it: ^Bit_Array_Iterator - the iterator struct that holds the state.
  36. Out:
  37. - set: bool - the state of the bit at `index`
  38. - index: int - the next bit of the Bit_Array referenced by `it`.
  39. - ok: bool - `true` if the iterator returned a valid index,
  40. `false` if there were no more bits
  41. */
  42. iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
  43. index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
  44. if index > it.array.max_index { return false, 0, false }
  45. word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
  46. set = (word >> it.bit_idx & 1) == 1
  47. it.bit_idx += 1
  48. if it.bit_idx >= NUM_BITS {
  49. it.bit_idx = 0
  50. it.word_idx += 1
  51. }
  52. return set, index, true
  53. }
  54. /*
  55. In:
  56. - it: ^Bit_Array_Iterator - the iterator struct that holds the state.
  57. Out:
  58. - index: int - the next set bit of the Bit_Array referenced by `it`.
  59. - ok: bool - `true` if the iterator returned a valid index,
  60. `false` if there were no more bits set
  61. */
  62. iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
  63. return iterate_internal_(it, true)
  64. }
  65. /*
  66. In:
  67. - it: ^Bit_Array_Iterator - the iterator struct that holds the state.
  68. Out:
  69. - index: int - the next unset bit of the Bit_Array referenced by `it`.
  70. - ok: bool - `true` if the iterator returned a valid index,
  71. `false` if there were no more unset bits
  72. */
  73. iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
  74. return iterate_internal_(it, false)
  75. }
  76. @(private="file")
  77. iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
  78. word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
  79. when ! ITERATE_SET_BITS { word = ~word }
  80. // if the word is empty or we have already gone over all the bits in it,
  81. // b.bit_idx is greater than the index of any set bit in the word,
  82. // meaning that word >> b.bit_idx == 0.
  83. for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
  84. it.word_idx += 1
  85. it.bit_idx = 0
  86. word = it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
  87. when ! ITERATE_SET_BITS { word = ~word }
  88. }
  89. // if we are iterating the set bits, reaching the end of the array means we have no more bits to check
  90. when ITERATE_SET_BITS {
  91. if it.word_idx >= len(it.array.bits) {
  92. return 0, false
  93. }
  94. }
  95. // reaching here means that the word has some set bits
  96. it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx))
  97. index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
  98. it.bit_idx += 1
  99. if it.bit_idx >= NUM_BITS {
  100. it.bit_idx = 0
  101. it.word_idx += 1
  102. }
  103. return index, index <= it.array.max_index
  104. }
  105. /*
  106. In:
  107. - ba: ^Bit_Array - a pointer to the Bit Array
  108. - index: The bit index. Can be an enum member.
  109. Out:
  110. - res: The bit you're interested in.
  111. - ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
  112. The `ok` return value may be ignored.
  113. */
  114. get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (res: bool, ok: bool) {
  115. idx := int(index) - ba.bias
  116. if ba == nil || int(index) < ba.bias { return false, false }
  117. context.allocator = allocator
  118. leg_index := idx >> INDEX_SHIFT
  119. bit_index := idx & INDEX_MASK
  120. /*
  121. If we `get` a bit that doesn't fit in the Bit Array, it's naturally `false`.
  122. This early-out prevents unnecessary resizing.
  123. */
  124. if leg_index + 1 > len(ba.bits) { return false, true }
  125. val := u64(1 << uint(bit_index))
  126. res = ba.bits[leg_index] & val == val
  127. return res, true
  128. }
  129. /*
  130. In:
  131. - ba: ^Bit_Array - a pointer to the Bit Array
  132. - index: The bit index. Can be an enum member.
  133. Out:
  134. - ok: Whether or not we managed to set requested bit.
  135. `set` automatically resizes the Bit Array to accommodate the requested index if needed.
  136. */
  137. set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
  138. idx := int(index) - ba.bias
  139. if ba == nil || int(index) < ba.bias { return false }
  140. context.allocator = allocator
  141. leg_index := idx >> INDEX_SHIFT
  142. bit_index := idx & INDEX_MASK
  143. resize_if_needed(ba, leg_index) or_return
  144. ba.max_index = max(idx, ba.max_index)
  145. ba.bits[leg_index] |= 1 << uint(bit_index)
  146. return true
  147. }
  148. /*
  149. A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
  150. */
  151. create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
  152. context.allocator = allocator
  153. size_in_bits := max_index - min_index
  154. if size_in_bits < 1 { return {}, false }
  155. legs := size_in_bits >> INDEX_SHIFT
  156. res = new(Bit_Array)
  157. res.bias = min_index
  158. res.max_index = max_index
  159. res.free_pointer = true
  160. return res, resize_if_needed(res, legs)
  161. }
  162. /*
  163. Sets all bits to `false`.
  164. */
  165. clear :: proc(ba: ^Bit_Array) {
  166. if ba == nil { return }
  167. mem.zero_slice(ba.bits[:])
  168. }
  169. /*
  170. Releases the memory used by the Bit Array.
  171. */
  172. destroy :: proc(ba: ^Bit_Array) {
  173. if ba == nil { return }
  174. delete(ba.bits)
  175. if ba.free_pointer { // Only free if this Bit_Array was created using `create`, not when on the stack.
  176. free(ba)
  177. }
  178. }
  179. /*
  180. Resizes the Bit Array. For internal use.
  181. If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`.
  182. */
  183. @(private="file")
  184. resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocator) -> (ok: bool) {
  185. if ba == nil { return false }
  186. context.allocator = allocator
  187. if legs + 1 > len(ba.bits) {
  188. resize(&ba.bits, legs + 1)
  189. }
  190. return len(ba.bits) > legs
  191. }