]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/bitmap.c
Merge pull request #815 from poettering/coding-style-for
[thirdparty/systemd.git] / src / basic / bitmap.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2015 Tom Gundersen
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "util.h"
23
24 #include "bitmap.h"
25
26 struct Bitmap {
27 uint64_t *bitmaps;
28 size_t n_bitmaps;
29 size_t bitmaps_allocated;
30 };
31
32 /* Bitmaps are only meant to store relatively small numbers
33 * (corresponding to, say, an enum), so it is ok to limit
34 * the max entry. 64k should be plenty. */
35 #define BITMAPS_MAX_ENTRY 0xffff
36
37 /* This indicates that we reached the end of the bitmap */
38 #define BITMAP_END ((unsigned) -1)
39
40 #define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(uint64_t) * 8))
41 #define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(uint64_t) * 8))
42 #define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(uint64_t) * 8 + (rem))
43
44 Bitmap *bitmap_new(void) {
45 return new0(Bitmap, 1);
46 }
47
48 void bitmap_free(Bitmap *b) {
49 if (!b)
50 return;
51
52 free(b->bitmaps);
53 free(b);
54 }
55
56 int bitmap_ensure_allocated(Bitmap **b) {
57 Bitmap *a;
58
59 assert(b);
60
61 if (*b)
62 return 0;
63
64 a = bitmap_new();
65 if (!a)
66 return -ENOMEM;
67
68 *b = a;
69
70 return 0;
71 }
72
73 int bitmap_set(Bitmap *b, unsigned n) {
74 uint64_t bitmask;
75 unsigned offset;
76
77 assert(b);
78
79 /* we refuse to allocate huge bitmaps */
80 if (n > BITMAPS_MAX_ENTRY)
81 return -ERANGE;
82
83 offset = BITMAP_NUM_TO_OFFSET(n);
84
85 if (offset >= b->n_bitmaps) {
86 if (!GREEDY_REALLOC0(b->bitmaps, b->bitmaps_allocated, offset + 1))
87 return -ENOMEM;
88
89 b->n_bitmaps = offset + 1;
90 }
91
92 bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n);
93
94 b->bitmaps[offset] |= bitmask;
95
96 return 0;
97 }
98
99 void bitmap_unset(Bitmap *b, unsigned n) {
100 uint64_t bitmask;
101 unsigned offset;
102
103 if (!b)
104 return;
105
106 offset = BITMAP_NUM_TO_OFFSET(n);
107
108 if (offset >= b->n_bitmaps)
109 return;
110
111 bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n);
112
113 b->bitmaps[offset] &= ~bitmask;
114 }
115
116 bool bitmap_isset(Bitmap *b, unsigned n) {
117 uint64_t bitmask;
118 unsigned offset;
119
120 if (!b)
121 return false;
122
123 offset = BITMAP_NUM_TO_OFFSET(n);
124
125 if (offset >= b->n_bitmaps)
126 return false;
127
128 bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n);
129
130 return !!(b->bitmaps[offset] & bitmask);
131 }
132
133 bool bitmap_isclear(Bitmap *b) {
134 unsigned i;
135
136 assert(b);
137
138 for (i = 0; i < b->n_bitmaps; i++)
139 if (b->bitmaps[i] != 0)
140 return false;
141
142 return true;
143 }
144
145 void bitmap_clear(Bitmap *b) {
146 assert(b);
147
148 free(b->bitmaps);
149 b->bitmaps = NULL;
150 b->n_bitmaps = 0;
151 b->bitmaps_allocated = 0;
152 }
153
154 bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) {
155 uint64_t bitmask;
156 unsigned offset, rem;
157
158 assert(i);
159 assert(n);
160
161 if (!b || i->idx == BITMAP_END)
162 return false;
163
164 offset = BITMAP_NUM_TO_OFFSET(i->idx);
165 rem = BITMAP_NUM_TO_REM(i->idx);
166 bitmask = UINT64_C(1) << rem;
167
168 for (; offset < b->n_bitmaps; offset ++) {
169 if (b->bitmaps[offset]) {
170 for (; bitmask; bitmask <<= 1, rem ++) {
171 if (b->bitmaps[offset] & bitmask) {
172 *n = BITMAP_OFFSET_TO_NUM(offset, rem);
173 i->idx = *n + 1;
174
175 return true;
176 }
177 }
178 }
179
180 rem = 0;
181 bitmask = 1;
182 }
183
184 i->idx = BITMAP_END;
185
186 return false;
187 }
188
189 bool bitmap_equal(Bitmap *a, Bitmap *b) {
190 size_t common_n_bitmaps;
191 Bitmap *c;
192 unsigned i;
193
194 if (!a ^ !b)
195 return false;
196
197 if (!a)
198 return true;
199
200 common_n_bitmaps = MIN(a->n_bitmaps, b->n_bitmaps);
201 if (memcmp(a->bitmaps, b->bitmaps, sizeof(uint64_t) * common_n_bitmaps) != 0)
202 return false;
203
204 c = a->n_bitmaps > b->n_bitmaps ? a : b;
205 for (i = common_n_bitmaps; i < c->n_bitmaps; i++)
206 if (c->bitmaps[i] != 0)
207 return false;
208
209 return true;
210 }