]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bitmap.c
io.systemd.Unit.List fix context/runtime split (#38172)
[thirdparty/systemd.git] / src / shared / bitmap.c
CommitLineData
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 21Bitmap* bitmap_new(void) {
5ffa42cb
TG
22 return new0(Bitmap, 1);
23}
24
75db809a 25Bitmap* 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 40Bitmap* 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
48int 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
65int 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
91void 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 108bool 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 125bool 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
137void 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 145bool 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 180bool 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}