From fac68630b890f8e8563748d5e88918b6b219c1bc Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 5 Nov 2018 11:52:03 +1030 Subject: [PATCH] ccan: add ccan/bitmap. Signed-off-by: Rusty Russell --- Makefile | 4 + ccan/ccan/bitmap/LICENSE | 1 + ccan/ccan/bitmap/_info | 32 ++++ ccan/ccan/bitmap/bitmap.c | 125 +++++++++++++++ ccan/ccan/bitmap/bitmap.h | 243 +++++++++++++++++++++++++++++ ccan/ccan/bitmap/test/run-alloc.c | 101 ++++++++++++ ccan/ccan/bitmap/test/run-ffs.c | 74 +++++++++ ccan/ccan/bitmap/test/run-ranges.c | 77 +++++++++ ccan/ccan/bitmap/test/run.c | 118 ++++++++++++++ 9 files changed, 775 insertions(+) create mode 120000 ccan/ccan/bitmap/LICENSE create mode 100644 ccan/ccan/bitmap/_info create mode 100644 ccan/ccan/bitmap/bitmap.c create mode 100644 ccan/ccan/bitmap/bitmap.h create mode 100644 ccan/ccan/bitmap/test/run-alloc.c create mode 100644 ccan/ccan/bitmap/test/run-ffs.c create mode 100644 ccan/ccan/bitmap/test/run-ranges.c create mode 100644 ccan/ccan/bitmap/test/run.c diff --git a/Makefile b/Makefile index 80669e4c4..b55a87128 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,7 @@ FEATURES := CCAN_OBJS := \ ccan-asort.o \ ccan-autodata.o \ + ccan-bitmap.o \ ccan-bitops.o \ ccan-breakpoint.o \ ccan-crc.o \ @@ -97,6 +98,7 @@ CCAN_HEADERS := \ $(CCANDIR)/ccan/array_size/array_size.h \ $(CCANDIR)/ccan/asort/asort.h \ $(CCANDIR)/ccan/autodata/autodata.h \ + $(CCANDIR)/ccan/bitmap/bitmap.h \ $(CCANDIR)/ccan/bitops/bitops.h \ $(CCANDIR)/ccan/breakpoint/breakpoint.h \ $(CCANDIR)/ccan/build_assert/build_assert.h \ @@ -604,5 +606,7 @@ ccan-str-base32.o: $(CCANDIR)/ccan/str/base32/base32.c $(CC) $(CFLAGS) -c -o $@ $< ccan-utf8.o: $(CCANDIR)/ccan/utf8/utf8.c $(CC) $(CFLAGS) -c -o $@ $< +ccan-bitmap.o: $(CCANDIR)/ccan/bitmap/bitmap.c + $(CC) $(CFLAGS) -c -o $@ $< ccan-membuf.o: $(CCANDIR)/ccan/membuf/membuf.c $(CC) $(CFLAGS) -c -o $@ $< diff --git a/ccan/ccan/bitmap/LICENSE b/ccan/ccan/bitmap/LICENSE new file mode 120000 index 000000000..dc314ecac --- /dev/null +++ b/ccan/ccan/bitmap/LICENSE @@ -0,0 +1 @@ +../../licenses/LGPL-2.1 \ No newline at end of file diff --git a/ccan/ccan/bitmap/_info b/ccan/ccan/bitmap/_info new file mode 100644 index 000000000..b8d297d16 --- /dev/null +++ b/ccan/ccan/bitmap/_info @@ -0,0 +1,32 @@ +#include "config.h" +#include +#include + +/** + * 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 + */ +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; +} diff --git a/ccan/ccan/bitmap/bitmap.c b/ccan/ccan/bitmap/bitmap.c new file mode 100644 index 000000000..d812af6a2 --- /dev/null +++ b/ccan/ccan/bitmap/bitmap.c @@ -0,0 +1,125 @@ +/* Licensed under LGPLv2.1+ - see LICENSE file for details */ + +#include "config.h" + +#include + +#include + +#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; +} diff --git a/ccan/ccan/bitmap/bitmap.h b/ccan/ccan/bitmap/bitmap.h new file mode 100644 index 000000000..9e6c2bbc5 --- /dev/null +++ b/ccan/ccan/bitmap/bitmap.h @@ -0,0 +1,243 @@ +/* Licensed under LGPLv2+ - see LICENSE file for details */ +#ifndef CCAN_BITMAP_H_ +#define CCAN_BITMAP_H_ + +#include +#include +#include +#include + +#include + +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_ */ diff --git a/ccan/ccan/bitmap/test/run-alloc.c b/ccan/ccan/bitmap/test/run-alloc.c new file mode 100644 index 000000000..fcdaf4daa --- /dev/null +++ b/ccan/ccan/bitmap/test/run-alloc.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +#include + +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(); +} diff --git a/ccan/ccan/bitmap/test/run-ffs.c b/ccan/ccan/bitmap/test/run-ffs.c new file mode 100644 index 000000000..0f6cc4cf8 --- /dev/null +++ b/ccan/ccan/bitmap/test/run-ffs.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +#include + +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(); +} diff --git a/ccan/ccan/bitmap/test/run-ranges.c b/ccan/ccan/bitmap/test/run-ranges.c new file mode 100644 index 000000000..5ba383caf --- /dev/null +++ b/ccan/ccan/bitmap/test/run-ranges.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +#include + +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(); +} diff --git a/ccan/ccan/bitmap/test/run.c b/ccan/ccan/bitmap/test/run.c new file mode 100644 index 000000000..efd245d77 --- /dev/null +++ b/ccan/ccan/bitmap/test/run.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include + +#include + +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(); +}