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