bit_array.odin 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. package container_dynamic_bit_array
  2. import "base:builtin"
  3. import "base:intrinsics"
  4. import "core:mem"
  5. /*
  6. Note that these constants are dependent on the backing being a u64.
  7. */
  8. @(private="file")
  9. INDEX_SHIFT :: 6
  10. @(private="file")
  11. INDEX_MASK :: 63
  12. @(private="file")
  13. NUM_BITS :: 64
  14. Bit_Array :: struct {
  15. bits: [dynamic]u64,
  16. bias: int,
  17. length: int,
  18. free_pointer: bool,
  19. }
  20. Bit_Array_Iterator :: struct {
  21. array: ^Bit_Array,
  22. word_idx: int,
  23. bit_idx: uint,
  24. }
  25. /*
  26. Wraps a `Bit_Array` into an Iterator
  27. Inputs:
  28. - ba: Pointer to the Bit_Array
  29. Returns:
  30. - it: Iterator struct
  31. */
  32. make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) {
  33. return Bit_Array_Iterator { array = ba }
  34. }
  35. /*
  36. Returns the next bit, including its set-state. ok=false once exhausted
  37. Inputs:
  38. - it: The iterator that holds the state.
  39. Returns:
  40. - set: `true` if the bit at `index` is set.
  41. - index: The next bit of the Bit_Array referenced by `it`.
  42. - ok: `true` if the iterator can continue, `false` if the iterator is done
  43. */
  44. iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
  45. index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
  46. if index >= it.array.length + it.array.bias { return false, 0, false }
  47. word := it.array.bits[it.word_idx] if builtin.len(it.array.bits) > it.word_idx else 0
  48. set = (word >> it.bit_idx & 1) == 1
  49. it.bit_idx += 1
  50. if it.bit_idx >= NUM_BITS {
  51. it.bit_idx = 0
  52. it.word_idx += 1
  53. }
  54. return set, index, true
  55. }
  56. /*
  57. Returns the next Set Bit, for example if `0b1010`, then the iterator will return index={1, 3} over two calls.
  58. Inputs:
  59. - it: The iterator that holds the state.
  60. Returns:
  61. - index: The next *set* bit of the Bit_Array referenced by `it`.
  62. - ok: `true` if the iterator can continue, `false` if the iterator is done
  63. */
  64. iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
  65. return iterate_internal_(it, true)
  66. }
  67. /*
  68. Returns the next Unset Bit, for example if `0b1010`, then the iterator will return index={0, 2} over two calls.
  69. Inputs:
  70. - it: The iterator that holds the state.
  71. Returns:
  72. - index: The next *unset* bit of the Bit_Array referenced by `it`.
  73. - ok: `true` if the iterator can continue, `false` if the iterator is done
  74. */
  75. iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
  76. return iterate_internal_(it, false)
  77. }
  78. /*
  79. Iterates through set/unset bits
  80. *Private*
  81. Inputs:
  82. - it: The iterator that holds the state.
  83. - ITERATE_SET_BITS: `true` for returning only set bits, false for returning only unset bits
  84. Returns:
  85. - index: The next *unset* bit of the Bit_Array referenced by `it`.
  86. - ok: `true` if the iterator can continue, `false` if the iterator is done
  87. */
  88. @(private="file")
  89. iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
  90. word := it.array.bits[it.word_idx] if builtin.len(it.array.bits) > it.word_idx else 0
  91. when ! ITERATE_SET_BITS { word = ~word }
  92. // If the word is empty or we have already gone over all the bits in it,
  93. // b.bit_idx is greater than the index of any set bit in the word,
  94. // meaning that word >> b.bit_idx == 0.
  95. for it.word_idx < builtin.len(it.array.bits) && word >> it.bit_idx == 0 {
  96. it.word_idx += 1
  97. it.bit_idx = 0
  98. word = it.array.bits[it.word_idx] if builtin.len(it.array.bits) > it.word_idx else 0
  99. when ! ITERATE_SET_BITS { word = ~word }
  100. }
  101. // If we are iterating the set bits, reaching the end of the array means we have no more bits to check
  102. when ITERATE_SET_BITS {
  103. if it.word_idx >= builtin.len(it.array.bits) {
  104. return 0, false
  105. }
  106. }
  107. // Reaching here means that the word has some set bits
  108. it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx))
  109. index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
  110. it.bit_idx += 1
  111. if it.bit_idx >= NUM_BITS {
  112. it.bit_idx = 0
  113. it.word_idx += 1
  114. }
  115. return index, index < it.array.length + it.array.bias
  116. }
  117. /*
  118. Gets the state of a bit in the bit-array
  119. Inputs:
  120. - ba: Pointer to the Bit_Array
  121. - index: Which bit in the array
  122. Returns:
  123. - res: `true` if the bit at `index` is set.
  124. - ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
  125. */
  126. get :: proc(ba: ^Bit_Array, #any_int index: uint) -> (res: bool, ok: bool) #optional_ok {
  127. idx := int(index) - ba.bias
  128. if ba == nil || int(index) < ba.bias { return false, false }
  129. leg_index := idx >> INDEX_SHIFT
  130. bit_index := idx & INDEX_MASK
  131. /*
  132. If we `get` a bit that doesn't fit in the Bit Array, it's naturally `false`.
  133. This early-out prevents unnecessary resizing.
  134. */
  135. if leg_index + 1 > builtin.len(ba.bits) { return false, true }
  136. val := u64(1 << uint(bit_index))
  137. res = ba.bits[leg_index] & val == val
  138. return res, true
  139. }
  140. /*
  141. Gets the state of a bit in the bit-array
  142. *Bypasses all Checks*
  143. Inputs:
  144. - ba: Pointer to the Bit_Array
  145. - index: Which bit in the array
  146. Returns:
  147. - `true` if bit is set
  148. */
  149. unsafe_get :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint) -> bool #no_bounds_check {
  150. return bool((ba.bits[index >> INDEX_SHIFT] >> uint(index & INDEX_MASK)) & 1)
  151. }
  152. /*
  153. Sets the state of a bit in the bit-array
  154. *Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
  155. Inputs:
  156. - ba: Pointer to the Bit_Array
  157. - index: Which bit in the array
  158. - set_to: `true` sets the bit on, `false` to turn it off
  159. - allocator: (default is context.allocator)
  160. Returns:
  161. - ok: Whether the set was successful, `false` on allocation failure or bad index
  162. */
  163. set :: proc(ba: ^Bit_Array, #any_int index: uint, set_to: bool = true, allocator := context.allocator) -> (ok: bool) {
  164. idx := int(index) - ba.bias
  165. if ba == nil || int(index) < ba.bias { return false }
  166. context.allocator = allocator
  167. leg_index := idx >> INDEX_SHIFT
  168. bit_index := idx & INDEX_MASK
  169. resize_if_needed(ba, leg_index) or_return
  170. ba.length = max(1 + idx, ba.length)
  171. if set_to {
  172. ba.bits[leg_index] |= 1 << uint(bit_index)
  173. } else {
  174. ba.bits[leg_index] &~= 1 << uint(bit_index)
  175. }
  176. return true
  177. }
  178. /*
  179. Sets the state of a bit in the bit-array
  180. *Bypasses all checks*
  181. Inputs:
  182. - ba: Pointer to the Bit_Array
  183. - index: Which bit in the array
  184. */
  185. unsafe_set :: proc(ba: ^Bit_Array, bit: int) #no_bounds_check {
  186. ba.bits[bit >> INDEX_SHIFT] |= 1 << uint(bit & INDEX_MASK)
  187. }
  188. /*
  189. Unsets the state of a bit in the bit-array. (Convienence wrapper for `set`)
  190. *Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
  191. Inputs:
  192. - ba: Pointer to the Bit_Array
  193. - index: Which bit in the array
  194. - allocator: (default is context.allocator)
  195. Returns:
  196. - ok: Whether the unset was successful, `false` on allocation failure or bad index
  197. */
  198. unset :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
  199. return set(ba, index, false, allocator)
  200. }
  201. /*
  202. Unsets the state of a bit in the bit-array
  203. *Bypasses all Checks*
  204. Inputs:
  205. - ba: Pointer to the Bit_Array
  206. - index: Which bit in the array
  207. */
  208. unsafe_unset :: proc(b: ^Bit_Array, bit: int) #no_bounds_check {
  209. b.bits[bit >> INDEX_SHIFT] &~= 1 << uint(bit & INDEX_MASK)
  210. }
  211. /*
  212. A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
  213. The range of bits created by this procedure is `min_index..<max_index`, and the
  214. array will be able to expand beyond `max_index` if needed.
  215. *Allocates (`new(Bit_Array) & make(ba.bits)`)*
  216. Inputs:
  217. - max_index: maximum starting index
  218. - min_index: minimum starting index (used as a bias)
  219. - allocator: (default is context.allocator)
  220. Returns:
  221. - ba: Allocates a bit_Array, backing data is set to `max-min / 64` indices, rounded up (eg 65 - 0 allocates for [2]u64).
  222. */
  223. create :: proc(max_index: int, min_index: int = 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
  224. size_in_bits := max_index - min_index
  225. if size_in_bits < 0 { return {}, false }
  226. res = new(Bit_Array, allocator)
  227. ok = init(res, max_index, min_index, allocator)
  228. res.free_pointer = true
  229. if !ok { free(res, allocator) }
  230. return
  231. }
  232. /*
  233. A helper function to initialize a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
  234. The range of bits created by this procedure is `min_index..<max_index`, and the
  235. array will be able to expand beyond `max_index` if needed.
  236. *Allocates (`make(ba.bits)`)*
  237. Inputs:
  238. - max_index: maximum starting index
  239. - min_index: minimum starting index (used as a bias)
  240. - allocator: (default is context.allocator)
  241. */
  242. init :: proc(res: ^Bit_Array, max_index: int, min_index: int = 0, allocator := context.allocator) -> (ok: bool) {
  243. size_in_bits := max_index - min_index
  244. if size_in_bits < 0 { return false }
  245. legs := size_in_bits >> INDEX_SHIFT
  246. if size_in_bits & INDEX_MASK > 0 { legs += 1 }
  247. bits, err := make([dynamic]u64, legs, allocator)
  248. ok = err == nil
  249. res.bits = bits
  250. res.bias = min_index
  251. res.length = max_index - min_index
  252. res.free_pointer = false
  253. return
  254. }
  255. /*
  256. Sets all values in the Bit_Array to zero.
  257. Inputs:
  258. - ba: The target Bit_Array
  259. */
  260. clear :: proc(ba: ^Bit_Array) {
  261. if ba == nil { return }
  262. mem.zero_slice(ba.bits[:])
  263. }
  264. /*
  265. Gets the length of set and unset valid bits in the Bit_Array.
  266. Inputs:
  267. - ba: The target Bit_Array
  268. Returns:
  269. - length: The length of valid bits.
  270. */
  271. len :: proc(ba: ^Bit_Array) -> (length: int) {
  272. if ba == nil { return }
  273. return ba.length
  274. }
  275. /*
  276. Shrinks the Bit_Array's backing storage to the smallest possible size.
  277. Inputs:
  278. - ba: The target Bit_Array
  279. */
  280. shrink :: proc(ba: ^Bit_Array) #no_bounds_check {
  281. if ba == nil { return }
  282. legs_needed := builtin.len(ba.bits)
  283. for i := legs_needed - 1; i >= 0; i -= 1 {
  284. if ba.bits[i] == 0 {
  285. legs_needed -= 1
  286. } else {
  287. break
  288. }
  289. }
  290. if legs_needed == builtin.len(ba.bits) {
  291. return
  292. }
  293. ba.length = 0
  294. if legs_needed > 0 {
  295. if legs_needed > 1 {
  296. ba.length = (legs_needed - 1) * NUM_BITS
  297. }
  298. ba.length += NUM_BITS - int(intrinsics.count_leading_zeros(ba.bits[legs_needed - 1]))
  299. }
  300. resize(&ba.bits, legs_needed)
  301. builtin.shrink(&ba.bits)
  302. }
  303. /*
  304. Deallocates the Bit_Array and its backing storage
  305. Inputs:
  306. - ba: The target Bit_Array
  307. */
  308. destroy :: proc(ba: ^Bit_Array) {
  309. if ba == nil { return }
  310. delete(ba.bits)
  311. if ba.free_pointer { // Only free if this Bit_Array was created using `create`, not when on the stack.
  312. free(ba)
  313. }
  314. }
  315. /*
  316. Resizes the Bit Array. For internal use. Provisions needed capacity+1
  317. If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`.
  318. */
  319. @(private="file")
  320. resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocator) -> (ok: bool) {
  321. if ba == nil { return false }
  322. context.allocator = allocator
  323. if legs + 1 > builtin.len(ba.bits) {
  324. resize(&ba.bits, legs + 1)
  325. }
  326. return builtin.len(ba.bits) > legs
  327. }