GBAlatro
A Demake of Balatro for the GBA
Loading...
Searching...
No Matches
bitset.c
1#include "bitset.h"
2
3#include "util.h"
4
5void bitset_set_idx(Bitset* bitset, int idx, bool on)
6{
7 uint32_t i = idx / BITSET_BITS_PER_WORD;
8 uint32_t b = idx % BITSET_BITS_PER_WORD;
9
10 // Below are the "fast" forms of the above operations, respectively.
11 // These are more efficient, but removed for readability
12 // See: https://github.com/cellos51/balatro-gba/pull/132#discussion_r2365966071
13 // Divide by 32 to get the word index
14 // uint32_t i = idx >> 5;
15 // Get last 5-bits, same as a modulo (% 32) operation on positive numbers
16 // uint32_t b = idx & 0x1F;
17 if (on)
18 {
19 bitset->w[i] |= (uint32_t)1 << b;
20 }
21 else
22 {
23 bitset->w[i] &= ~((uint32_t)1 << b);
24 }
25}
26
28{
29 for (uint32_t i = 0; i < bitset->nwords; i++)
30 {
31 uint32_t inv = ~bitset->w[i];
32
33 // guard so we don't call `ctz` with 0, since __builtin_ctz(0) is undefined
34 // https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html#index-_005f_005fbuiltin_005fctz
35 //
36 // By using the bitwise inverse of the word, you can skip words that are full
37 // quickly (where the value is 0 or 'false' since all bits are '1', or 'in use'). Any value
38 // greater than 0 indicates there is a free slot. Then, when counting the trailing 0's, you
39 // can test very quickly where the first free slot is. This operation prevents looping
40 // through every bit of filled flags, and will instead operate only on the first word with
41 // free slots.
42 if (inv)
43 {
44 int bit = __builtin_ctz(inv);
45 bitset->w[i] |= ((uint32_t)1 << bit);
46 int idx = i * BITSET_BITS_PER_WORD + bit;
47 return (idx < bitset->cap) ? idx : UNDEFINED;
48 }
49 }
50
51 return UNDEFINED;
52}
53
54void bitset_clear(Bitset* bitset)
55{
56 for (int i = 0; i < bitset->nwords; i++)
57 {
58 bitset->w[i] = 0;
59 }
60}
61
63{
64 for (int i = 0; i < bitset->nwords; i++)
65 {
66 if (bitset->w[i])
67 return false;
68 }
69 return true;
70}
71
72bool bitset_get_idx(Bitset* bitset, int idx)
73{
74 uint32_t i = idx / BITSET_BITS_PER_WORD;
75 uint32_t b = idx % BITSET_BITS_PER_WORD;
76
77 return bitset->w[i] & (uint32_t)1 << b;
78}
79
81{
82 int sum = 0;
83
84 for (int i = 0; i < bitset->nwords; i++)
85 {
86 sum += __builtin_popcount(bitset->w[i]);
87 }
88
89 return sum;
90}
91
92int bitset_find_idx_of_nth_set(const Bitset* bitset, int n)
93{
94 int tracker = 0;
95 int prev_tracker = 0;
96
97 for (int i = 0; i < bitset->nwords; i++)
98 {
99 tracker += __builtin_popcount(bitset->w[i]);
100
101 if (tracker > n)
102 {
103 // The index is here somewhere
104 // this one is to count the 1's not the offset, underflow to -1 is good for finding the
105 // 0 index
106 int base = prev_tracker - 1;
107 // this one is for the actual offset we want to map the id to
108 int offset = bitset->nbits * i;
109 for (int j = 0; j < bitset->nbits; j++)
110 {
111 if (base == n)
112 {
113 return offset - 1;
114 }
115 base += (bitset->w[i] >> j) & 0x01;
116 offset++;
117 }
118
119 break;
120 }
121
122 prev_tracker = tracker;
123 }
124
125 return UNDEFINED;
126}
127
129{
130 BitsetItr itr = {
131 .bitset = bitset,
132 .word = 0,
133 .bit = 0,
134 .itr = 0,
135 };
136
137 return itr;
138}
139
141{
142 // So, worst case scenario for this is one bit at the end of the last
143 // word in the bitset. You would look (32 * 7) + 31 times!
144 // This can be sped up with by checking if the word is empty first.
145 // Then the worst enemy of this method would be something like a set bit at the end
146 // of every word. In that case you would need to loop 31 times maximum.
147 // So one last thing you could do is something like `bitset_allocate_idx` does with the
148 // __builtin_ctz function as well.
149 //
150 // The point being, this can be very slow, but it's simple and can be much faster.
151 for (; itr->word < itr->bitset->nwords; itr->word++)
152 {
153 for (; itr->bit < itr->bitset->nbits; itr->bit++)
154 {
155 itr->itr++;
156 if (itr->bitset->w[itr->word] & (1 << itr->bit))
157 {
158 // if itr->bit == nbits on the next run, the for loop will handle it
159 itr->bit++;
160 // above we always make it one more than it is
161 // it's so we can return without mutating the actual iterator
162 // once it gets here. Just subtract one
163 return itr->itr - 1;
164 }
165 }
166 itr->bit = 0;
167 }
168 itr->word = 0;
169
170 return UNDEFINED;
171}
A bitset for operating on flags.
bool bitset_get_idx(Bitset *bitset, int idx)
Get the value of a flag.
Definition bitset.c:72
bool bitset_is_empty(Bitset *bitset)
Check if a bitset is empty (all 0's)
Definition bitset.c:62
void bitset_clear(Bitset *bitset)
Clear the bitset, all to 0.
Definition bitset.c:54
int bitset_num_set_bits(Bitset *bitset)
Count how many bits are set to 1 in a bitset.
Definition bitset.c:80
int bitset_find_idx_of_nth_set(const Bitset *bitset, int n)
Find the index of the nth set bit.
Definition bitset.c:92
#define BITSET_BITS_PER_WORD
Number of bits in a word for a bitset.
Definition bitset.h:18
int bitset_set_next_free_idx(Bitset *bitset)
Set the next free index in the bitset and return the index value.
Definition bitset.c:27
BitsetItr bitset_itr_create(const Bitset *bitset)
Declare a BitsetItr.
Definition bitset.c:128
int bitset_itr_next(BitsetItr *itr)
Get the index of the next set bit in the bitset from a BitsetItr.
Definition bitset.c:140
void bitset_set_idx(Bitset *bitset, int idx, bool on)
Set a flag in a bitset to a value.
Definition bitset.c:5
An iterator into a Bitset.
Definition bitset.h:73
int bit
Current bit the iterator is on.
Definition bitset.h:87
int word
Current word the iterator is on.
Definition bitset.h:82
int itr
Number of bits that have been iterated through in total.
Definition bitset.h:92
const Bitset * bitset
Bitset this is iterating through
Definition bitset.h:77
A bitset spread across multiple uint32_t words.
Definition bitset.h:40
uint32_t nbits
Number of bits in a word, will be 32.
Definition bitset.h:49
uint32_t nwords
Number of words int the w array.
Definition bitset.h:54
uint32_t * w
Word array of uint32_t to hold the bitset data.
Definition bitset.h:44
Utilities relating around number string representation and protected arithmatic helper functions.