]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/bitmap.c
Merge pull request #682 from ssahani/bridge
[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 b->n_bitmaps = 0;
149 }
150
151 bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) {
152 uint64_t bitmask;
153 unsigned offset, rem;
154
155 assert(i);
156 assert(n);
157
158 if (!b || i->idx == BITMAP_END)
159 return false;
160
161 offset = BITMAP_NUM_TO_OFFSET(i->idx);
162 rem = BITMAP_NUM_TO_REM(i->idx);
163 bitmask = UINT64_C(1) << rem;
164
165 for (; offset < b->n_bitmaps; offset ++) {
166 if (b->bitmaps[offset]) {
167 for (; bitmask; bitmask <<= 1, rem ++) {
168 if (b->bitmaps[offset] & bitmask) {
169 *n = BITMAP_OFFSET_TO_NUM(offset, rem);
170 i->idx = *n + 1;
171
172 return true;
173 }
174 }
175 }
176
177 rem = 0;
178 bitmask = 1;
179 }
180
181 i->idx = BITMAP_END;
182
183 return false;
184 }
185
186 bool bitmap_equal(Bitmap *a, Bitmap *b) {
187
188 if (!a ^ !b)
189 return false;
190
191 if (!a)
192 return true;
193
194 if (a->n_bitmaps != b->n_bitmaps)
195 return false;
196
197 return memcmp(a->bitmaps, b->bitmaps, sizeof(uint64_t) * a->n_bitmaps) == 0;
198 }