Rusty Russell
6 years ago
9 changed files with 775 additions and 0 deletions
@ -0,0 +1 @@ |
|||
../../licenses/LGPL-2.1 |
@ -0,0 +1,32 @@ |
|||
#include "config.h" |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
/** |
|||
* bitmap - bitmap handling |
|||
* |
|||
* This code handles manipulation of bitmaps, arbitrary length arrays |
|||
* of bits. |
|||
* |
|||
* License: LGPL (v2.1 or any later version) |
|||
* Author: David Gibson <david@gibson.dropbear.id.au> |
|||
*/ |
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
/* Expect exactly one argument */ |
|||
if (argc != 2) |
|||
return 1; |
|||
|
|||
if (strcmp(argv[1], "depends") == 0) { |
|||
printf("ccan/endian\n"); |
|||
return 0; |
|||
} |
|||
|
|||
if (strcmp(argv[1], "testdepends") == 0) { |
|||
printf("ccan/array_size\n"); |
|||
printf("ccan/foreach\n"); |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
@ -0,0 +1,125 @@ |
|||
/* Licensed under LGPLv2.1+ - see LICENSE file for details */ |
|||
|
|||
#include "config.h" |
|||
|
|||
#include <ccan/bitmap/bitmap.h> |
|||
|
|||
#include <assert.h> |
|||
|
|||
#define BIT_ALIGN_DOWN(n) ((n) & ~(BITMAP_WORD_BITS - 1)) |
|||
#define BIT_ALIGN_UP(n) BIT_ALIGN_DOWN((n) + BITMAP_WORD_BITS - 1) |
|||
|
|||
void bitmap_zero_range(bitmap *bitmap, unsigned long n, unsigned long m) |
|||
{ |
|||
unsigned long an = BIT_ALIGN_UP(n); |
|||
unsigned long am = BIT_ALIGN_DOWN(m); |
|||
bitmap_word headmask = -1ULL >> (n % BITMAP_WORD_BITS); |
|||
bitmap_word tailmask = ~(-1ULL >> (m % BITMAP_WORD_BITS)); |
|||
|
|||
assert(m >= n); |
|||
|
|||
if (am < an) { |
|||
BITMAP_WORD(bitmap, n) &= ~bitmap_bswap(headmask & tailmask); |
|||
return; |
|||
} |
|||
|
|||
if (an > n) |
|||
BITMAP_WORD(bitmap, n) &= ~bitmap_bswap(headmask); |
|||
|
|||
if (am > an) |
|||
memset(&BITMAP_WORD(bitmap, an), 0, |
|||
(am - an) / BITMAP_WORD_BITS * sizeof(bitmap_word)); |
|||
|
|||
if (m > am) |
|||
BITMAP_WORD(bitmap, m) &= ~bitmap_bswap(tailmask); |
|||
} |
|||
|
|||
void bitmap_fill_range(bitmap *bitmap, unsigned long n, unsigned long m) |
|||
{ |
|||
unsigned long an = BIT_ALIGN_UP(n); |
|||
unsigned long am = BIT_ALIGN_DOWN(m); |
|||
bitmap_word headmask = -1ULL >> (n % BITMAP_WORD_BITS); |
|||
bitmap_word tailmask = ~(-1ULL >> (m % BITMAP_WORD_BITS)); |
|||
|
|||
assert(m >= n); |
|||
|
|||
if (am < an) { |
|||
BITMAP_WORD(bitmap, n) |= bitmap_bswap(headmask & tailmask); |
|||
return; |
|||
} |
|||
|
|||
if (an > n) |
|||
BITMAP_WORD(bitmap, n) |= bitmap_bswap(headmask); |
|||
|
|||
if (am > an) |
|||
memset(&BITMAP_WORD(bitmap, an), 0xff, |
|||
(am - an) / BITMAP_WORD_BITS * sizeof(bitmap_word)); |
|||
|
|||
if (m > am) |
|||
BITMAP_WORD(bitmap, m) |= bitmap_bswap(tailmask); |
|||
} |
|||
|
|||
static int bitmap_clz(bitmap_word w) |
|||
{ |
|||
#if HAVE_BUILTIN_CLZL |
|||
return __builtin_clzl(w); |
|||
#else |
|||
int lz = 0; |
|||
bitmap_word mask = 1UL << (BITMAP_WORD_BITS - 1); |
|||
|
|||
while (!(w & mask)) { |
|||
lz++; |
|||
mask >>= 1; |
|||
} |
|||
|
|||
return lz; |
|||
#endif |
|||
} |
|||
|
|||
unsigned long bitmap_ffs(const bitmap *bitmap, |
|||
unsigned long n, unsigned long m) |
|||
{ |
|||
unsigned long an = BIT_ALIGN_UP(n); |
|||
unsigned long am = BIT_ALIGN_DOWN(m); |
|||
bitmap_word headmask = -1ULL >> (n % BITMAP_WORD_BITS); |
|||
bitmap_word tailmask = ~(-1ULL >> (m % BITMAP_WORD_BITS)); |
|||
|
|||
assert(m >= n); |
|||
|
|||
if (am < an) { |
|||
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, n)); |
|||
|
|||
w &= (headmask & tailmask); |
|||
|
|||
return w ? am + bitmap_clz(w) : m; |
|||
} |
|||
|
|||
if (an > n) { |
|||
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, n)); |
|||
|
|||
w &= headmask; |
|||
|
|||
if (w) |
|||
return BIT_ALIGN_DOWN(n) + bitmap_clz(w); |
|||
} |
|||
|
|||
while (an < am) { |
|||
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, an)); |
|||
|
|||
if (w) |
|||
return an + bitmap_clz(w); |
|||
|
|||
an += BITMAP_WORD_BITS; |
|||
} |
|||
|
|||
if (m > am) { |
|||
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, m)); |
|||
|
|||
w &= tailmask; |
|||
|
|||
if (w) |
|||
return am + bitmap_clz(w); |
|||
} |
|||
|
|||
return m; |
|||
} |
@ -0,0 +1,243 @@ |
|||
/* Licensed under LGPLv2+ - see LICENSE file for details */ |
|||
#ifndef CCAN_BITMAP_H_ |
|||
#define CCAN_BITMAP_H_ |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <limits.h> |
|||
|
|||
#include <ccan/endian/endian.h> |
|||
|
|||
typedef unsigned long bitmap_word; |
|||
|
|||
#define BITMAP_WORD_BITS (sizeof(bitmap_word) * CHAR_BIT) |
|||
#define BITMAP_NWORDS(_n) \ |
|||
(((_n) + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS) |
|||
|
|||
/*
|
|||
* We wrap each word in a structure for type checking. |
|||
*/ |
|||
typedef struct { |
|||
bitmap_word w; |
|||
} bitmap; |
|||
|
|||
#define BITMAP_DECLARE(_name, _nbits) \ |
|||
bitmap (_name)[BITMAP_NWORDS(_nbits)] |
|||
|
|||
static inline size_t bitmap_sizeof(unsigned long nbits) |
|||
{ |
|||
return BITMAP_NWORDS(nbits) * sizeof(bitmap_word); |
|||
} |
|||
|
|||
static inline bitmap_word bitmap_bswap(bitmap_word w) |
|||
{ |
|||
if (BITMAP_WORD_BITS == 32) |
|||
return (ENDIAN_CAST bitmap_word)cpu_to_be32(w); |
|||
else if (BITMAP_WORD_BITS == 64) |
|||
return (ENDIAN_CAST bitmap_word)cpu_to_be64(w); |
|||
} |
|||
|
|||
#define BITMAP_WORD(_bm, _n) ((_bm)[(_n) / BITMAP_WORD_BITS].w) |
|||
#define BITMAP_WORDBIT(_n) \ |
|||
(bitmap_bswap(1UL << (BITMAP_WORD_BITS - ((_n) % BITMAP_WORD_BITS) - 1))) |
|||
|
|||
#define BITMAP_HEADWORDS(_nbits) \ |
|||
((_nbits) / BITMAP_WORD_BITS) |
|||
#define BITMAP_HEADBYTES(_nbits) \ |
|||
(BITMAP_HEADWORDS(_nbits) * sizeof(bitmap_word)) |
|||
|
|||
#define BITMAP_TAILWORD(_bm, _nbits) \ |
|||
((_bm)[BITMAP_HEADWORDS(_nbits)].w) |
|||
#define BITMAP_HASTAIL(_nbits) (((_nbits) % BITMAP_WORD_BITS) != 0) |
|||
#define BITMAP_TAILBITS(_nbits) \ |
|||
(bitmap_bswap(~(-1UL >> ((_nbits) % BITMAP_WORD_BITS)))) |
|||
#define BITMAP_TAIL(_bm, _nbits) \ |
|||
(BITMAP_TAILWORD(_bm, _nbits) & BITMAP_TAILBITS(_nbits)) |
|||
|
|||
static inline void bitmap_set_bit(bitmap *bitmap, unsigned long n) |
|||
{ |
|||
BITMAP_WORD(bitmap, n) |= BITMAP_WORDBIT(n); |
|||
} |
|||
|
|||
static inline void bitmap_clear_bit(bitmap *bitmap, unsigned long n) |
|||
{ |
|||
BITMAP_WORD(bitmap, n) &= ~BITMAP_WORDBIT(n); |
|||
} |
|||
|
|||
static inline void bitmap_change_bit(bitmap *bitmap, unsigned long n) |
|||
{ |
|||
BITMAP_WORD(bitmap, n) ^= BITMAP_WORDBIT(n); |
|||
} |
|||
|
|||
static inline bool bitmap_test_bit(const bitmap *bitmap, unsigned long n) |
|||
{ |
|||
return !!(BITMAP_WORD(bitmap, n) & BITMAP_WORDBIT(n)); |
|||
} |
|||
|
|||
void bitmap_zero_range(bitmap *bitmap, unsigned long n, unsigned long m); |
|||
void bitmap_fill_range(bitmap *bitmap, unsigned long n, unsigned long m); |
|||
|
|||
static inline void bitmap_zero(bitmap *bitmap, unsigned long nbits) |
|||
{ |
|||
memset(bitmap, 0, bitmap_sizeof(nbits)); |
|||
} |
|||
|
|||
static inline void bitmap_fill(bitmap *bitmap, unsigned long nbits) |
|||
{ |
|||
memset(bitmap, 0xff, bitmap_sizeof(nbits)); |
|||
} |
|||
|
|||
static inline void bitmap_copy(bitmap *dst, const bitmap *src, |
|||
unsigned long nbits) |
|||
{ |
|||
memcpy(dst, src, bitmap_sizeof(nbits)); |
|||
} |
|||
|
|||
#define BITMAP_DEF_BINOP(_name, _op) \ |
|||
static inline void bitmap_##_name(bitmap *dst, bitmap *src1, bitmap *src2, \ |
|||
unsigned long nbits) \ |
|||
{ \ |
|||
unsigned long i = 0; \ |
|||
for (i = 0; i < BITMAP_NWORDS(nbits); i++) { \ |
|||
dst[i].w = src1[i].w _op src2[i].w; \ |
|||
} \ |
|||
} |
|||
|
|||
BITMAP_DEF_BINOP(and, &) |
|||
BITMAP_DEF_BINOP(or, |) |
|||
BITMAP_DEF_BINOP(xor, ^) |
|||
BITMAP_DEF_BINOP(andnot, & ~) |
|||
|
|||
#undef BITMAP_DEF_BINOP |
|||
|
|||
static inline void bitmap_complement(bitmap *dst, const bitmap *src, |
|||
unsigned long nbits) |
|||
{ |
|||
unsigned long i; |
|||
|
|||
for (i = 0; i < BITMAP_NWORDS(nbits); i++) |
|||
dst[i].w = ~src[i].w; |
|||
} |
|||
|
|||
static inline bool bitmap_equal(const bitmap *src1, const bitmap *src2, |
|||
unsigned long nbits) |
|||
{ |
|||
return (memcmp(src1, src2, BITMAP_HEADBYTES(nbits)) == 0) |
|||
&& (!BITMAP_HASTAIL(nbits) |
|||
|| (BITMAP_TAIL(src1, nbits) == BITMAP_TAIL(src2, nbits))); |
|||
} |
|||
|
|||
static inline bool bitmap_intersects(const bitmap *src1, const bitmap *src2, |
|||
unsigned long nbits) |
|||
{ |
|||
unsigned long i; |
|||
|
|||
for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) { |
|||
if (src1[i].w & src2[i].w) |
|||
return true; |
|||
} |
|||
if (BITMAP_HASTAIL(nbits) && |
|||
(BITMAP_TAIL(src1, nbits) & BITMAP_TAIL(src2, nbits))) |
|||
return true; |
|||
return false; |
|||
} |
|||
|
|||
static inline bool bitmap_subset(const bitmap *src1, const bitmap *src2, |
|||
unsigned long nbits) |
|||
{ |
|||
unsigned long i; |
|||
|
|||
for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) { |
|||
if (src1[i].w & ~src2[i].w) |
|||
return false; |
|||
} |
|||
if (BITMAP_HASTAIL(nbits) && |
|||
(BITMAP_TAIL(src1, nbits) & ~BITMAP_TAIL(src2, nbits))) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
static inline bool bitmap_full(const bitmap *bitmap, unsigned long nbits) |
|||
{ |
|||
unsigned long i; |
|||
|
|||
for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) { |
|||
if (bitmap[i].w != -1UL) |
|||
return false; |
|||
} |
|||
if (BITMAP_HASTAIL(nbits) && |
|||
(BITMAP_TAIL(bitmap, nbits) != BITMAP_TAILBITS(nbits))) |
|||
return false; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
static inline bool bitmap_empty(const bitmap *bitmap, unsigned long nbits) |
|||
{ |
|||
unsigned long i; |
|||
|
|||
for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) { |
|||
if (bitmap[i].w != 0) |
|||
return false; |
|||
} |
|||
if (BITMAP_HASTAIL(nbits) && (BITMAP_TAIL(bitmap, nbits) != 0)) |
|||
return false; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
unsigned long bitmap_ffs(const bitmap *bitmap, |
|||
unsigned long n, unsigned long m); |
|||
|
|||
/*
|
|||
* Allocation functions |
|||
*/ |
|||
static inline bitmap *bitmap_alloc(unsigned long nbits) |
|||
{ |
|||
return malloc(bitmap_sizeof(nbits)); |
|||
} |
|||
|
|||
static inline bitmap *bitmap_alloc0(unsigned long nbits) |
|||
{ |
|||
bitmap *bitmap; |
|||
|
|||
bitmap = bitmap_alloc(nbits); |
|||
if (bitmap) |
|||
bitmap_zero(bitmap, nbits); |
|||
return bitmap; |
|||
} |
|||
|
|||
static inline bitmap *bitmap_alloc1(unsigned long nbits) |
|||
{ |
|||
bitmap *bitmap; |
|||
|
|||
bitmap = bitmap_alloc(nbits); |
|||
if (bitmap) |
|||
bitmap_fill(bitmap, nbits); |
|||
return bitmap; |
|||
} |
|||
|
|||
static inline bitmap *bitmap_realloc0(bitmap *bitmap, |
|||
unsigned long obits, unsigned long nbits) |
|||
{ |
|||
bitmap = realloc(bitmap, bitmap_sizeof(nbits)); |
|||
|
|||
if ((nbits > obits) && bitmap) |
|||
bitmap_zero_range(bitmap, obits, nbits); |
|||
|
|||
return bitmap; |
|||
} |
|||
|
|||
static inline bitmap *bitmap_realloc1(bitmap *bitmap, |
|||
unsigned long obits, unsigned long nbits) |
|||
{ |
|||
bitmap = realloc(bitmap, bitmap_sizeof(nbits)); |
|||
|
|||
if ((nbits > obits) && bitmap) |
|||
bitmap_fill_range(bitmap, obits, nbits); |
|||
|
|||
return bitmap; |
|||
} |
|||
|
|||
#endif /* CCAN_BITMAP_H_ */ |
@ -0,0 +1,101 @@ |
|||
#include <ccan/bitmap/bitmap.h> |
|||
#include <ccan/tap/tap.h> |
|||
#include <ccan/array_size/array_size.h> |
|||
#include <ccan/foreach/foreach.h> |
|||
|
|||
#include <ccan/bitmap/bitmap.c> |
|||
|
|||
int bitmap_sizes[] = { |
|||
1, 2, 3, 4, 5, 6, 7, 8, |
|||
16, 17, 24, 32, 33, |
|||
64, 65, 127, 128, 129, |
|||
1023, 1024, 1025, |
|||
}; |
|||
#define NSIZES ARRAY_SIZE(bitmap_sizes) |
|||
#define NTESTS_BASE 4 |
|||
#define NTESTS_REALLOC 10 |
|||
|
|||
static void test_basic_alloc(int nbits) |
|||
{ |
|||
bitmap *bitmap; |
|||
|
|||
bitmap = bitmap_alloc0(nbits); |
|||
ok1(bitmap != NULL); |
|||
ok1(bitmap_empty(bitmap, nbits)); |
|||
|
|||
free(bitmap); |
|||
|
|||
bitmap = bitmap_alloc1(nbits); |
|||
ok1(bitmap != NULL); |
|||
ok1(bitmap_full(bitmap, nbits)); |
|||
|
|||
free(bitmap); |
|||
} |
|||
|
|||
static void test_realloc(int obits, int nbits) |
|||
{ |
|||
bitmap *bitmap; |
|||
int i; |
|||
bool wrong; |
|||
|
|||
bitmap = bitmap_alloc0(obits); |
|||
ok1(bitmap != NULL); |
|||
ok1(bitmap_empty(bitmap, obits)); |
|||
|
|||
bitmap = bitmap_realloc1(bitmap, obits, nbits); |
|||
ok1(bitmap != NULL); |
|||
if (obits < nbits) |
|||
ok1(bitmap_empty(bitmap, obits)); |
|||
else |
|||
ok1(bitmap_empty(bitmap, nbits)); |
|||
|
|||
wrong = false; |
|||
for (i = obits; i < nbits; i++) |
|||
wrong = wrong || !bitmap_test_bit(bitmap, i); |
|||
ok1(!wrong); |
|||
|
|||
free(bitmap); |
|||
|
|||
bitmap = bitmap_alloc1(obits); |
|||
ok1(bitmap != NULL); |
|||
ok1(bitmap_full(bitmap, obits)); |
|||
|
|||
bitmap = bitmap_realloc0(bitmap, obits, nbits); |
|||
ok1(bitmap != NULL); |
|||
if (obits < nbits) |
|||
ok1(bitmap_full(bitmap, obits)); |
|||
else |
|||
ok1(bitmap_full(bitmap, nbits)); |
|||
|
|||
wrong = false; |
|||
for (i = obits; i < nbits; i++) |
|||
wrong = wrong || bitmap_test_bit(bitmap, i); |
|||
ok1(!wrong); |
|||
|
|||
free(bitmap); |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
int i, j; |
|||
|
|||
/* This is how many tests you plan to run */ |
|||
plan_tests(NSIZES * NTESTS_BASE + NSIZES * NSIZES * NTESTS_REALLOC); |
|||
|
|||
for (i = 0; i < NSIZES; i++) { |
|||
diag("Testing %d-bit bitmap", bitmap_sizes[i]); |
|||
test_basic_alloc(bitmap_sizes[i]); |
|||
} |
|||
|
|||
for (i = 0; i < NSIZES; i++) { |
|||
for (j = 0; j < NSIZES; j++) { |
|||
diag("Testing %d-bit => %d-bit bitmap", |
|||
bitmap_sizes[i], bitmap_sizes[j]); |
|||
|
|||
test_realloc(bitmap_sizes[i], bitmap_sizes[j]); |
|||
} |
|||
} |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,74 @@ |
|||
#include <ccan/bitmap/bitmap.h> |
|||
#include <ccan/tap/tap.h> |
|||
#include <ccan/array_size/array_size.h> |
|||
#include <ccan/foreach/foreach.h> |
|||
|
|||
#include <ccan/bitmap/bitmap.c> |
|||
|
|||
int bitmap_sizes[] = { |
|||
1, 2, 3, 4, 5, 6, 7, 8, |
|||
16, 17, 24, 32, 33, |
|||
64, 65, 127, 128, 129, |
|||
1023, 1024, 1025, |
|||
}; |
|||
#define NSIZES ARRAY_SIZE(bitmap_sizes) |
|||
|
|||
#define ok_eq(a, b) \ |
|||
ok((a) == (b), "%s [%u] == %s [%u]", \ |
|||
#a, (unsigned)(a), #b, (unsigned)(b)) |
|||
|
|||
static void test_size(int nbits) |
|||
{ |
|||
BITMAP_DECLARE(bitmap, nbits); |
|||
int i; |
|||
|
|||
bitmap_zero(bitmap, nbits); |
|||
ok_eq(bitmap_ffs(bitmap, 0, nbits), nbits); |
|||
|
|||
for (i = 0; i < nbits; i++) { |
|||
bitmap_zero(bitmap, nbits); |
|||
bitmap_set_bit(bitmap, i); |
|||
|
|||
ok_eq(bitmap_ffs(bitmap, 0, nbits), i); |
|||
ok_eq(bitmap_ffs(bitmap, i, nbits), i); |
|||
ok_eq(bitmap_ffs(bitmap, i + 1, nbits), nbits); |
|||
|
|||
bitmap_zero(bitmap, nbits); |
|||
bitmap_fill_range(bitmap, i, nbits); |
|||
|
|||
ok_eq(bitmap_ffs(bitmap, 0, nbits), i); |
|||
ok_eq(bitmap_ffs(bitmap, i, nbits), i); |
|||
ok_eq(bitmap_ffs(bitmap, i + 1, nbits), (i + 1)); |
|||
ok_eq(bitmap_ffs(bitmap, nbits - 1, nbits), (nbits - 1)); |
|||
|
|||
if (i > 0) { |
|||
ok_eq(bitmap_ffs(bitmap, 0, i), i); |
|||
ok_eq(bitmap_ffs(bitmap, 0, i - 1), (i - 1)); |
|||
} |
|||
|
|||
if (i > 0) { |
|||
bitmap_zero(bitmap, nbits); |
|||
bitmap_fill_range(bitmap, 0, i); |
|||
|
|||
ok_eq(bitmap_ffs(bitmap, 0, nbits), 0); |
|||
ok_eq(bitmap_ffs(bitmap, i - 1, nbits), (i - 1)); |
|||
ok_eq(bitmap_ffs(bitmap, i, nbits), nbits); |
|||
} |
|||
} |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
int i; |
|||
|
|||
/* Too complicated to work out the exact number */ |
|||
plan_no_plan(); |
|||
|
|||
for (i = 0; i < NSIZES; i++) { |
|||
diag("Testing %d-bit bitmap", bitmap_sizes[i]); |
|||
test_size(bitmap_sizes[i]); |
|||
} |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,77 @@ |
|||
#include <ccan/bitmap/bitmap.h> |
|||
#include <ccan/tap/tap.h> |
|||
#include <ccan/array_size/array_size.h> |
|||
#include <ccan/foreach/foreach.h> |
|||
|
|||
#include <ccan/bitmap/bitmap.c> |
|||
|
|||
int bitmap_sizes[] = { |
|||
1, 2, 3, 4, 5, 6, 7, 8, |
|||
16, 24, 32, 64, 256, |
|||
/*
|
|||
* Don't put too big sizes in here, or it will take forever to |
|||
* run under valgrind (the test is O(n^3)). |
|||
*/ |
|||
}; |
|||
#define NSIZES ARRAY_SIZE(bitmap_sizes) |
|||
#define NTESTS 2 |
|||
|
|||
static void test_size(int nbits) |
|||
{ |
|||
BITMAP_DECLARE(bitmap, nbits); |
|||
uint32_t marker = 0xdeadbeef; |
|||
int i, j, k; |
|||
bool wrong; |
|||
|
|||
for (i = 0; i < nbits; i++) { |
|||
for (j = i; j <= nbits; j++) { |
|||
bitmap_zero(bitmap, nbits); |
|||
bitmap_fill_range(bitmap, i, j); |
|||
|
|||
wrong = false; |
|||
for (k = 0; k < nbits; k++) { |
|||
bool inrange = (k >= i) && (k < j); |
|||
wrong = wrong || (bitmap_test_bit(bitmap, k) != inrange); |
|||
} |
|||
ok1(!wrong); |
|||
} |
|||
} |
|||
|
|||
for (i = 0; i < nbits; i++) { |
|||
for (j = i; j <= nbits; j++) { |
|||
bitmap_fill(bitmap, nbits); |
|||
bitmap_zero_range(bitmap, i, j); |
|||
|
|||
wrong = false; |
|||
for (k = 0; k < nbits; k++) { |
|||
bool inrange = (k >= i) && (k < j); |
|||
wrong = wrong || (bitmap_test_bit(bitmap, k) == inrange); |
|||
} |
|||
ok1(!wrong); |
|||
} |
|||
} |
|||
|
|||
ok1(marker == 0xdeadbeef); |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
int totaltests = 0; |
|||
int i; |
|||
|
|||
for (i = 0; i < NSIZES; i++) { |
|||
int size = bitmap_sizes[i]; |
|||
|
|||
/* Summing the arithmetic series gives: */ |
|||
totaltests += size*(size + 3) + 1; |
|||
} |
|||
plan_tests(totaltests); |
|||
|
|||
for (i = 0; i < NSIZES; i++) { |
|||
diag("Testing %d-bit bitmap", bitmap_sizes[i]); |
|||
test_size(bitmap_sizes[i]); |
|||
} |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,118 @@ |
|||
#include <ccan/bitmap/bitmap.h> |
|||
#include <ccan/tap/tap.h> |
|||
#include <ccan/array_size/array_size.h> |
|||
#include <ccan/foreach/foreach.h> |
|||
|
|||
#include <ccan/bitmap/bitmap.c> |
|||
|
|||
int bitmap_sizes[] = { |
|||
1, 2, 3, 4, 5, 6, 7, 8, |
|||
16, 17, 24, 32, 33, |
|||
64, 65, 127, 128, 129, |
|||
1023, 1024, 1025, |
|||
}; |
|||
#define NSIZES ARRAY_SIZE(bitmap_sizes) |
|||
#define NTESTS 9 |
|||
|
|||
static void test_sizes(int nbits, bool dynalloc) |
|||
{ |
|||
BITMAP_DECLARE(sbitmap, nbits); |
|||
uint32_t marker; |
|||
bitmap *bitmap; |
|||
int i, j; |
|||
bool wrong; |
|||
|
|||
if (dynalloc) { |
|||
bitmap = bitmap_alloc(nbits); |
|||
ok1(bitmap != NULL); |
|||
} else { |
|||
bitmap = sbitmap; |
|||
marker = 0xdeadbeef; |
|||
} |
|||
|
|||
bitmap_zero(bitmap, nbits); |
|||
wrong = false; |
|||
for (i = 0; i < nbits; i++) { |
|||
wrong = wrong || bitmap_test_bit(bitmap, i); |
|||
} |
|||
ok1(!wrong); |
|||
|
|||
bitmap_fill(bitmap, nbits); |
|||
wrong = false; |
|||
for (i = 0; i < nbits; i++) { |
|||
wrong = wrong || !bitmap_test_bit(bitmap, i); |
|||
} |
|||
ok1(!wrong); |
|||
|
|||
wrong = false; |
|||
for (i = 0; i < nbits; i++) { |
|||
bitmap_zero(bitmap, nbits); |
|||
bitmap_set_bit(bitmap, i); |
|||
for (j = 0; j < nbits; j++) { |
|||
bool val = (i == j); |
|||
|
|||
wrong = wrong || (bitmap_test_bit(bitmap, j) != val); |
|||
} |
|||
} |
|||
ok1(!wrong); |
|||
|
|||
wrong = false; |
|||
for (i = 0; i < nbits; i++) { |
|||
bitmap_fill(bitmap, nbits); |
|||
bitmap_clear_bit(bitmap, i); |
|||
for (j = 0; j < nbits; j++) { |
|||
bool val = !(i == j); |
|||
|
|||
wrong = wrong || (bitmap_test_bit(bitmap, j) != val); |
|||
} |
|||
} |
|||
ok1(!wrong); |
|||
|
|||
bitmap_zero(bitmap, nbits); |
|||
ok1(bitmap_empty(bitmap, nbits)); |
|||
|
|||
wrong = false; |
|||
for (i = 0; i < nbits; i++) { |
|||
bitmap_zero(bitmap, nbits); |
|||
bitmap_set_bit(bitmap, i); |
|||
wrong = wrong || bitmap_empty(bitmap, nbits); |
|||
} |
|||
ok1(!wrong); |
|||
|
|||
bitmap_fill(bitmap, nbits); |
|||
ok1(bitmap_full(bitmap, nbits)); |
|||
|
|||
wrong = false; |
|||
for (i = 0; i < nbits; i++) { |
|||
bitmap_fill(bitmap, nbits); |
|||
bitmap_clear_bit(bitmap, i); |
|||
wrong = wrong || bitmap_full(bitmap, nbits); |
|||
} |
|||
ok1(!wrong); |
|||
|
|||
if (dynalloc) { |
|||
free(bitmap); |
|||
} else { |
|||
ok1(marker == 0xdeadbeef); |
|||
} |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
int i; |
|||
bool dynalloc; |
|||
|
|||
/* This is how many tests you plan to run */ |
|||
plan_tests(NSIZES * NTESTS * 2); |
|||
|
|||
for (i = 0; i < NSIZES; i++) { |
|||
foreach_int(dynalloc, false, true) { |
|||
diag("Testing %d-bit bitmap (%s allocation)", |
|||
bitmap_sizes[i], dynalloc ? "dynamic" : "static"); |
|||
test_sizes(bitmap_sizes[i], dynalloc); |
|||
} |
|||
} |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
Loading…
Reference in new issue