]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
5ffa42cb | 2 | |
11c3a366 TA |
3 | #include <string.h> |
4 | ||
b5efdb8a | 5 | #include "alloc-util.h" |
5ffa42cb | 6 | #include "bitmap.h" |
0a970718 | 7 | #include "memory-util.h" |
5ffa42cb | 8 | |
5ffa42cb TG |
9 | /* Bitmaps are only meant to store relatively small numbers |
10 | * (corresponding to, say, an enum), so it is ok to limit | |
11 | * the max entry. 64k should be plenty. */ | |
12 | #define BITMAPS_MAX_ENTRY 0xffff | |
13 | ||
14 | /* This indicates that we reached the end of the bitmap */ | |
f5fbe71d | 15 | #define BITMAP_END (UINT_MAX) |
5ffa42cb | 16 | |
848d08b7 DM |
17 | #define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(uint64_t) * 8)) |
18 | #define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(uint64_t) * 8)) | |
19 | #define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(uint64_t) * 8 + (rem)) | |
5ffa42cb | 20 | |
75db809a | 21 | Bitmap* bitmap_new(void) { |
5ffa42cb TG |
22 | return new0(Bitmap, 1); |
23 | } | |
24 | ||
75db809a | 25 | Bitmap* bitmap_copy(Bitmap *b) { |
17c8de63 LP |
26 | Bitmap *ret; |
27 | ||
28 | ret = bitmap_new(); | |
29 | if (!ret) | |
30 | return NULL; | |
31 | ||
32 | ret->bitmaps = newdup(uint64_t, b->bitmaps, b->n_bitmaps); | |
6b430fdb ZJS |
33 | if (!ret->bitmaps) |
34 | return mfree(ret); | |
17c8de63 | 35 | |
319a4f4b | 36 | ret->n_bitmaps = b->n_bitmaps; |
17c8de63 LP |
37 | return ret; |
38 | } | |
39 | ||
75db809a | 40 | Bitmap* bitmap_free(Bitmap *b) { |
5ffa42cb | 41 | if (!b) |
75db809a | 42 | return NULL; |
5ffa42cb TG |
43 | |
44 | free(b->bitmaps); | |
75db809a | 45 | return mfree(b); |
5ffa42cb TG |
46 | } |
47 | ||
48 | int bitmap_ensure_allocated(Bitmap **b) { | |
49 | Bitmap *a; | |
50 | ||
370a2172 LP |
51 | assert(b); |
52 | ||
5ffa42cb TG |
53 | if (*b) |
54 | return 0; | |
55 | ||
56 | a = bitmap_new(); | |
57 | if (!a) | |
58 | return -ENOMEM; | |
59 | ||
60 | *b = a; | |
61 | ||
62 | return 0; | |
63 | } | |
64 | ||
65 | int bitmap_set(Bitmap *b, unsigned n) { | |
848d08b7 | 66 | uint64_t bitmask; |
5ffa42cb TG |
67 | unsigned offset; |
68 | ||
69 | assert(b); | |
70 | ||
71 | /* we refuse to allocate huge bitmaps */ | |
72 | if (n > BITMAPS_MAX_ENTRY) | |
73 | return -ERANGE; | |
74 | ||
75 | offset = BITMAP_NUM_TO_OFFSET(n); | |
76 | ||
77 | if (offset >= b->n_bitmaps) { | |
319a4f4b | 78 | if (!GREEDY_REALLOC0(b->bitmaps, offset + 1)) |
5ffa42cb TG |
79 | return -ENOMEM; |
80 | ||
81 | b->n_bitmaps = offset + 1; | |
82 | } | |
83 | ||
370a2172 | 84 | bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n); |
5ffa42cb TG |
85 | |
86 | b->bitmaps[offset] |= bitmask; | |
87 | ||
88 | return 0; | |
89 | } | |
90 | ||
91 | void bitmap_unset(Bitmap *b, unsigned n) { | |
848d08b7 | 92 | uint64_t bitmask; |
5ffa42cb TG |
93 | unsigned offset; |
94 | ||
370a2172 LP |
95 | if (!b) |
96 | return; | |
5ffa42cb TG |
97 | |
98 | offset = BITMAP_NUM_TO_OFFSET(n); | |
99 | ||
100 | if (offset >= b->n_bitmaps) | |
101 | return; | |
102 | ||
370a2172 | 103 | bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n); |
5ffa42cb TG |
104 | |
105 | b->bitmaps[offset] &= ~bitmask; | |
106 | } | |
107 | ||
8594c8a5 | 108 | bool bitmap_isset(const Bitmap *b, unsigned n) { |
848d08b7 | 109 | uint64_t bitmask; |
5ffa42cb TG |
110 | unsigned offset; |
111 | ||
370a2172 | 112 | if (!b) |
5ffa42cb TG |
113 | return false; |
114 | ||
115 | offset = BITMAP_NUM_TO_OFFSET(n); | |
116 | ||
117 | if (offset >= b->n_bitmaps) | |
118 | return false; | |
119 | ||
370a2172 | 120 | bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n); |
5ffa42cb TG |
121 | |
122 | return !!(b->bitmaps[offset] & bitmask); | |
123 | } | |
124 | ||
8594c8a5 | 125 | bool bitmap_isclear(const Bitmap *b) { |
5ffa42cb | 126 | |
0b808637 LP |
127 | if (!b) |
128 | return true; | |
5ffa42cb | 129 | |
fae687ec MY |
130 | FOREACH_ARRAY(i, b->bitmaps, b->n_bitmaps) |
131 | if (*i != 0) | |
5ffa42cb TG |
132 | return false; |
133 | ||
134 | return true; | |
135 | } | |
136 | ||
137 | void bitmap_clear(Bitmap *b) { | |
0b808637 LP |
138 | if (!b) |
139 | return; | |
5ffa42cb | 140 | |
a1e58e8e | 141 | b->bitmaps = mfree(b->bitmaps); |
05fb03be | 142 | b->n_bitmaps = 0; |
5ffa42cb TG |
143 | } |
144 | ||
8594c8a5 | 145 | bool bitmap_iterate(const Bitmap *b, Iterator *i, unsigned *n) { |
848d08b7 | 146 | uint64_t bitmask; |
5ffa42cb TG |
147 | unsigned offset, rem; |
148 | ||
370a2172 LP |
149 | assert(i); |
150 | assert(n); | |
151 | ||
22cedfe1 | 152 | if (!b || i->idx == BITMAP_END) |
5ffa42cb TG |
153 | return false; |
154 | ||
cb57dd41 TG |
155 | offset = BITMAP_NUM_TO_OFFSET(i->idx); |
156 | rem = BITMAP_NUM_TO_REM(i->idx); | |
370a2172 | 157 | bitmask = UINT64_C(1) << rem; |
5ffa42cb | 158 | |
b3a9d980 | 159 | for (; offset < b->n_bitmaps; offset++) { |
5ffa42cb | 160 | if (b->bitmaps[offset]) { |
b3a9d980 | 161 | for (; bitmask; bitmask <<= 1, rem++) { |
5ffa42cb TG |
162 | if (b->bitmaps[offset] & bitmask) { |
163 | *n = BITMAP_OFFSET_TO_NUM(offset, rem); | |
cb57dd41 | 164 | i->idx = *n + 1; |
5ffa42cb TG |
165 | |
166 | return true; | |
167 | } | |
168 | } | |
169 | } | |
170 | ||
171 | rem = 0; | |
172 | bitmask = 1; | |
173 | } | |
174 | ||
cb57dd41 | 175 | i->idx = BITMAP_END; |
5ffa42cb TG |
176 | |
177 | return false; | |
178 | } | |
179 | ||
8594c8a5 | 180 | bool bitmap_equal(const Bitmap *a, const Bitmap *b) { |
d5fa8199 | 181 | size_t common_n_bitmaps; |
8594c8a5 | 182 | const Bitmap *c; |
5ffa42cb | 183 | |
7d7fa31c LP |
184 | if (a == b) |
185 | return true; | |
186 | ||
187 | if (!a != !b) | |
5ffa42cb TG |
188 | return false; |
189 | ||
190 | if (!a) | |
191 | return true; | |
192 | ||
d5fa8199 | 193 | common_n_bitmaps = MIN(a->n_bitmaps, b->n_bitmaps); |
65f95765 | 194 | if (memcmp_safe(a->bitmaps, b->bitmaps, sizeof(uint64_t) * common_n_bitmaps) != 0) |
5ffa42cb TG |
195 | return false; |
196 | ||
d5fa8199 | 197 | c = a->n_bitmaps > b->n_bitmaps ? a : b; |
fae687ec | 198 | for (unsigned i = common_n_bitmaps; i < c->n_bitmaps; i++) |
d5fa8199 MM |
199 | if (c->bitmaps[i] != 0) |
200 | return false; | |
201 | ||
202 | return true; | |
5ffa42cb | 203 | } |