diff options
author | Damien Miller <djm@mindrot.org> | 2015-01-15 02:28:00 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2015-01-15 02:28:00 +1100 |
commit | 4f38c61c68ae7e3f9ee4b3c38bc86cd39f65ece9 (patch) | |
tree | c6eb9b262ac8c101657ce81a9fbda8318f72c32e /bitmap.c | |
parent | a165bab605f7be55940bb8fae977398e8c96a46d (diff) |
add files missed in last commit
Diffstat (limited to 'bitmap.c')
-rw-r--r-- | bitmap.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/bitmap.c b/bitmap.c new file mode 100644 index 000000000..cd9df8c77 --- /dev/null +++ b/bitmap.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015 Damien Miller <djm@mindrot.org> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <sys/types.h> | ||
18 | #include <string.h> | ||
19 | #include <stdlib.h> | ||
20 | |||
21 | #include "bitmap.h" | ||
22 | |||
23 | #define BITMAP_WTYPE u_int | ||
24 | #define BITMAP_MAX (1<<24) | ||
25 | #define BITMAP_BYTES (sizeof(BITMAP_WTYPE)) | ||
26 | #define BITMAP_BITS (sizeof(BITMAP_WTYPE) * 8) | ||
27 | #define BITMAP_WMASK ((BITMAP_WTYPE)BITMAP_BITS - 1) | ||
28 | struct bitmap { | ||
29 | BITMAP_WTYPE *d; | ||
30 | size_t len; /* number of words allocated */ | ||
31 | size_t top; /* index of top word allocated */ | ||
32 | }; | ||
33 | |||
34 | struct bitmap * | ||
35 | bitmap_new(void) | ||
36 | { | ||
37 | struct bitmap *ret; | ||
38 | |||
39 | if ((ret = calloc(1, sizeof(*ret))) == NULL) | ||
40 | return NULL; | ||
41 | if ((ret->d = calloc(1, BITMAP_BYTES)) == NULL) { | ||
42 | free(ret); | ||
43 | return NULL; | ||
44 | } | ||
45 | ret->len = 1; | ||
46 | ret->top = 0; | ||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | void | ||
51 | bitmap_free(struct bitmap *b) | ||
52 | { | ||
53 | if (b != NULL && b->d != NULL) { | ||
54 | memset(b->d, 0, b->len); | ||
55 | free(b->d); | ||
56 | } | ||
57 | free(b); | ||
58 | } | ||
59 | |||
60 | void | ||
61 | bitmap_zero(struct bitmap *b) | ||
62 | { | ||
63 | memset(b->d, 0, b->len * BITMAP_BYTES); | ||
64 | b->top = 0; | ||
65 | } | ||
66 | |||
67 | int | ||
68 | bitmap_test_bit(struct bitmap *b, u_int n) | ||
69 | { | ||
70 | if (b->top >= b->len) | ||
71 | return 0; /* invalid */ | ||
72 | if (b->len == 0 || (n / BITMAP_BITS) > b->top) | ||
73 | return 0; | ||
74 | return (b->d[n / BITMAP_BITS] >> (n & BITMAP_WMASK)) & 1; | ||
75 | } | ||
76 | |||
77 | static int | ||
78 | reserve(struct bitmap *b, u_int n) | ||
79 | { | ||
80 | BITMAP_WTYPE *tmp; | ||
81 | size_t nlen; | ||
82 | |||
83 | if (b->top >= b->len || n > BITMAP_MAX) | ||
84 | return -1; /* invalid */ | ||
85 | nlen = (n / BITMAP_BITS) + 1; | ||
86 | if (b->len < nlen) { | ||
87 | if ((tmp = reallocarray(b->d, nlen, BITMAP_BYTES)) == NULL) | ||
88 | return -1; | ||
89 | b->d = tmp; | ||
90 | memset(b->d + b->len, 0, (nlen - b->len) * BITMAP_BYTES); | ||
91 | b->len = nlen; | ||
92 | } | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | int | ||
97 | bitmap_set_bit(struct bitmap *b, u_int n) | ||
98 | { | ||
99 | int r; | ||
100 | size_t offset; | ||
101 | |||
102 | if ((r = reserve(b, n)) != 0) | ||
103 | return r; | ||
104 | offset = n / BITMAP_BITS; | ||
105 | if (offset > b->top) | ||
106 | b->top = offset; | ||
107 | b->d[offset] |= (BITMAP_WTYPE)1 << (n & BITMAP_WMASK); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | /* Resets b->top to point to the most significant bit set in b->d */ | ||
112 | static void | ||
113 | retop(struct bitmap *b) | ||
114 | { | ||
115 | if (b->top >= b->len) | ||
116 | return; | ||
117 | while (b->top > 0 && b->d[b->top] == 0) | ||
118 | b->top--; | ||
119 | } | ||
120 | |||
121 | void | ||
122 | bitmap_clear_bit(struct bitmap *b, u_int n) | ||
123 | { | ||
124 | size_t offset; | ||
125 | |||
126 | if (b->top >= b->len || n > BITMAP_MAX) | ||
127 | return; /* invalid */ | ||
128 | offset = n / BITMAP_BITS; | ||
129 | if (offset > b->top) | ||
130 | return; | ||
131 | b->d[offset] &= ~((BITMAP_WTYPE)1 << (n & BITMAP_WMASK)); | ||
132 | /* The top may have changed as a result of the clear */ | ||
133 | retop(b); | ||
134 | } | ||
135 | |||
136 | size_t | ||
137 | bitmap_nbits(struct bitmap *b) | ||
138 | { | ||
139 | size_t bits; | ||
140 | BITMAP_WTYPE w; | ||
141 | |||
142 | retop(b); | ||
143 | if (b->top >= b->len) | ||
144 | return 0; /* invalid */ | ||
145 | if (b->len == 0 || (b->top == 0 && b->d[0] == 0)) | ||
146 | return 0; | ||
147 | /* Find MSB set */ | ||
148 | w = b->d[b->top]; | ||
149 | bits = (b->top + 1) * BITMAP_BITS; | ||
150 | while (!(w & ((BITMAP_WTYPE)1 << (BITMAP_BITS - 1)))) { | ||
151 | w <<= 1; | ||
152 | bits--; | ||
153 | } | ||
154 | return bits; | ||
155 | |||
156 | } | ||
157 | |||
158 | size_t | ||
159 | bitmap_nbytes(struct bitmap *b) | ||
160 | { | ||
161 | return (bitmap_nbits(b) + 7) / 8; | ||
162 | } | ||
163 | |||
164 | int | ||
165 | bitmap_to_string(struct bitmap *b, void *p, size_t l) | ||
166 | { | ||
167 | u_char *s = (u_char *)p; | ||
168 | size_t i, j, k, need = bitmap_nbytes(b); | ||
169 | |||
170 | if (l < need || b->top >= b->len) | ||
171 | return -1; | ||
172 | if (l > need) | ||
173 | l = need; | ||
174 | /* Put the bytes from LSB backwards */ | ||
175 | for (i = k = 0; i < b->top + 1; i++) { | ||
176 | for (j = 0; j < BITMAP_BYTES; j++) { | ||
177 | if (k >= l) | ||
178 | break; | ||
179 | s[need - 1 - k++] = (b->d[i] >> (j * 8)) & 0xff; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | int | ||
187 | bitmap_from_string(struct bitmap *b, const void *p, size_t l) | ||
188 | { | ||
189 | int r; | ||
190 | size_t i, offset, shift; | ||
191 | u_char *s = (u_char *)p; | ||
192 | |||
193 | if (l > BITMAP_MAX / 8) | ||
194 | return -1; | ||
195 | if ((r = reserve(b, l * 8)) != 0) | ||
196 | return r; | ||
197 | bitmap_zero(b); | ||
198 | if (l == 0) | ||
199 | return 0; | ||
200 | b->top = offset = ((l + (BITMAP_BYTES - 1)) / BITMAP_BYTES) - 1; | ||
201 | shift = ((l + (BITMAP_BYTES - 1)) % BITMAP_BYTES) * 8; | ||
202 | for (i = 0; i < l; i++) { | ||
203 | b->d[offset] |= (BITMAP_WTYPE)s[i] << shift; | ||
204 | if (shift == 0) { | ||
205 | offset--; | ||
206 | shift = BITMAP_BITS - 8; | ||
207 | } else | ||
208 | shift -= 8; | ||
209 | } | ||
210 | retop(b); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | #ifdef BITMAP_TEST | ||
215 | |||
216 | /* main() test against OpenSSL BN */ | ||
217 | #include <err.h> | ||
218 | #include <openssl/bn.h> | ||
219 | #include <stdio.h> | ||
220 | #include <stdarg.h> | ||
221 | |||
222 | #define LIM 131 | ||
223 | #define FAIL(...) fail(__FILE__, __LINE__, __VA_ARGS__) | ||
224 | |||
225 | void | ||
226 | bitmap_dump(struct bitmap *b, FILE *f) | ||
227 | { | ||
228 | size_t i; | ||
229 | |||
230 | fprintf(f, "bitmap %p len=%zu top=%zu d =", b, b->len, b->top); | ||
231 | for (i = 0; i < b->len; i++) { | ||
232 | fprintf(f, " %0*llx", (int)BITMAP_BITS / 4, | ||
233 | (unsigned long long)b->d[i]); | ||
234 | } | ||
235 | fputc('\n', f); | ||
236 | } | ||
237 | |||
238 | static void | ||
239 | fail(char *file, int line, char *fmt, ...) | ||
240 | { | ||
241 | va_list ap; | ||
242 | |||
243 | fprintf(stderr, "%s:%d ", file, line); | ||
244 | va_start(ap, fmt); | ||
245 | vfprintf(stderr, fmt, ap); | ||
246 | va_end(ap); | ||
247 | fputc('\n', stdout); | ||
248 | /* abort(); */ | ||
249 | exit(1); | ||
250 | } | ||
251 | |||
252 | static void | ||
253 | dump(const char *s, const u_char *buf, size_t l) | ||
254 | { | ||
255 | size_t i; | ||
256 | |||
257 | fprintf(stderr, "%s len %zu = ", s, l); | ||
258 | for (i = 0; i < l; i++) | ||
259 | fprintf(stderr, "%02x ", buf[i]); | ||
260 | fputc('\n', stderr); | ||
261 | } | ||
262 | |||
263 | int main(void) { | ||
264 | struct bitmap *b = bitmap_new(); | ||
265 | BIGNUM *bn = BN_new(); | ||
266 | size_t len; | ||
267 | int i, j, k, n; | ||
268 | u_char bbuf[1024], bnbuf[1024]; | ||
269 | int r; | ||
270 | |||
271 | for (i = -1; i < LIM; i++) { | ||
272 | fputc('i', stdout); | ||
273 | fflush(stdout); | ||
274 | for (j = -1; j < LIM; j++) { | ||
275 | for (k = -1; k < LIM; k++) { | ||
276 | bitmap_zero(b); | ||
277 | BN_clear(bn); | ||
278 | /* Test setting bits */ | ||
279 | if (i > 0 && bitmap_set_bit(b, i) != 0) | ||
280 | FAIL("bitmap_set_bit %d fail", i); | ||
281 | if (j > 0 && bitmap_set_bit(b, j) != 0) | ||
282 | FAIL("bitmap_set_bit %d fail", j); | ||
283 | if (k > 0 && bitmap_set_bit(b, k) != 0) | ||
284 | FAIL("bitmap_set_bit %d fail", k); | ||
285 | if ((i > 0 && BN_set_bit(bn, i) != 1) || | ||
286 | (j > 0 && BN_set_bit(bn, j) != 1) || | ||
287 | (k > 0 && BN_set_bit(bn, k) != 1)) | ||
288 | FAIL("BN_set_bit fail"); | ||
289 | for (n = 0; n < LIM; n++) { | ||
290 | if (BN_is_bit_set(bn, n) != | ||
291 | bitmap_test_bit(b, n)) { | ||
292 | FAIL("miss %d/%d/%d %d " | ||
293 | "%d %d", i, j, k, n, | ||
294 | BN_is_bit_set(bn, n), | ||
295 | bitmap_test_bit(b, n)); | ||
296 | } | ||
297 | } | ||
298 | /* Test length calculations */ | ||
299 | if (BN_num_bytes(bn) != (int)bitmap_nbytes(b)) { | ||
300 | FAIL("bytes %d/%d/%d %d != %zu", | ||
301 | i, j, k, BN_num_bytes(bn), | ||
302 | bitmap_nbytes(b)); | ||
303 | } | ||
304 | if (BN_num_bits(bn) != (int)bitmap_nbits(b)) { | ||
305 | FAIL("bits %d/%d/%d %d != %zu", | ||
306 | i, j, k, BN_num_bits(bn), | ||
307 | bitmap_nbits(b)); | ||
308 | } | ||
309 | /* Test serialisation */ | ||
310 | len = bitmap_nbytes(b); | ||
311 | memset(bbuf, 0xfc, sizeof(bbuf)); | ||
312 | if (bitmap_to_string(b, bbuf, | ||
313 | sizeof(bbuf)) != 0) | ||
314 | FAIL("bitmap_to_string %d/%d/%d", | ||
315 | i, j, k); | ||
316 | for (n = len; n < (int)sizeof(bbuf); n++) { | ||
317 | if (bbuf[n] != 0xfc) | ||
318 | FAIL("bad string " | ||
319 | "%d/%d/%d %d 0x%02x", | ||
320 | i, j, k, n, bbuf[n]); | ||
321 | } | ||
322 | if ((r = BN_bn2bin(bn, bnbuf)) < 0) | ||
323 | FAIL("BN_bn2bin %d/%d/%d", | ||
324 | i, j, k); | ||
325 | if ((size_t)r != len) | ||
326 | FAIL("len bad %d/%d/%d", i, j, k); | ||
327 | if (memcmp(bbuf, bnbuf, len) != 0) { | ||
328 | dump("bbuf", bbuf, sizeof(bbuf)); | ||
329 | dump("bnbuf", bnbuf, sizeof(bnbuf)); | ||
330 | FAIL("buf bad %d/%d/%d", i, j, k); | ||
331 | } | ||
332 | /* Test deserialisation */ | ||
333 | bitmap_zero(b); | ||
334 | if (bitmap_from_string(b, bnbuf, len) != 0) | ||
335 | FAIL("bitmap_to_string %d/%d/%d", | ||
336 | i, j, k); | ||
337 | for (n = 0; n < LIM; n++) { | ||
338 | if (BN_is_bit_set(bn, n) != | ||
339 | bitmap_test_bit(b, n)) { | ||
340 | FAIL("miss %d/%d/%d %d " | ||
341 | "%d %d", i, j, k, n, | ||
342 | BN_is_bit_set(bn, n), | ||
343 | bitmap_test_bit(b, n)); | ||
344 | } | ||
345 | } | ||
346 | /* Test clearing bits */ | ||
347 | for (n = 0; n < LIM; n++) { | ||
348 | if (bitmap_set_bit(b, n) != 0) { | ||
349 | bitmap_dump(b, stderr); | ||
350 | FAIL("bitmap_set_bit %d " | ||
351 | "fail", n); | ||
352 | } | ||
353 | if (BN_set_bit(bn, n) != 1) | ||
354 | FAIL("BN_set_bit fail"); | ||
355 | } | ||
356 | if (i > 0) { | ||
357 | bitmap_clear_bit(b, i); | ||
358 | BN_clear_bit(bn, i); | ||
359 | } | ||
360 | if (j > 0) { | ||
361 | bitmap_clear_bit(b, j); | ||
362 | BN_clear_bit(bn, j); | ||
363 | } | ||
364 | if (k > 0) { | ||
365 | bitmap_clear_bit(b, k); | ||
366 | BN_clear_bit(bn, k); | ||
367 | } | ||
368 | for (n = 0; n < LIM; n++) { | ||
369 | if (BN_is_bit_set(bn, n) != | ||
370 | bitmap_test_bit(b, n)) { | ||
371 | bitmap_dump(b, stderr); | ||
372 | FAIL("cmiss %d/%d/%d %d " | ||
373 | "%d %d", i, j, k, n, | ||
374 | BN_is_bit_set(bn, n), | ||
375 | bitmap_test_bit(b, n)); | ||
376 | } | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | fputc('\n', stdout); | ||
382 | bitmap_free(b); | ||
383 | BN_free(bn); | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | #endif | ||