diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0d3481778f..57e3eb4188 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -18,6 +18,7 @@ virBitmapIsAllSet; virBitmapNew; virBitmapNewCopy; virBitmapNewData; +virBitmapNextClearBit; virBitmapNextSetBit; virBitmapParse; virBitmapSetAll; diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index 2cfe03a9d5..21509ac396 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -1,7 +1,7 @@ /* * virbitmap.h: Simple bitmap operations * - * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright (C) 2010-2013 Red Hat, Inc. * Copyright (C) 2010 Novell, Inc. * * This library is free software; you can redistribute it and/or @@ -595,13 +595,14 @@ bool virBitmapIsAllSet(virBitmapPtr bitmap) * @bitmap: the bitmap * @pos: the position after which to search for a set bit * - * search the first set bit after position @pos in bitmap @bitmap. + * Search for the first set bit after position @pos in bitmap @bitmap. * @pos can be -1 to search for the first set bit. Position starts * at 0. * - * returns the position of the found bit, or -1 if no bit found. + * Returns the position of the found bit, or -1 if no bit found. */ -ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) +ssize_t +virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) { size_t nl; size_t nb; @@ -630,6 +631,54 @@ ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) return ffsl(bits) - 1 + nl * VIR_BITMAP_BITS_PER_UNIT; } +/** + * virBitmapNextClearBit: + * @bitmap: the bitmap + * @pos: the position after which to search for a clear bit + * + * Search for the first clear bit after position @pos in bitmap @bitmap. + * @pos can be -1 to search for the first set bit. Position starts + * at 0. + * + * Returns the position of the found bit, or -1 if no bit found. + */ +ssize_t +virBitmapNextClearBit(virBitmapPtr bitmap, ssize_t pos) +{ + size_t nl; + size_t nb; + unsigned long bits; + + if (pos < 0) + pos = -1; + + pos++; + + if (pos >= bitmap->max_bit) + return -1; + + nl = pos / VIR_BITMAP_BITS_PER_UNIT; + nb = pos % VIR_BITMAP_BITS_PER_UNIT; + + bits = ~bitmap->map[nl] & ~((1UL << nb) - 1); + + while (bits == 0 && ++nl < bitmap->map_len) { + bits = ~bitmap->map[nl]; + } + + if (nl == bitmap->map_len - 1) { + /* Ensure tail bits are ignored. */ + int tail = bitmap->max_bit % VIR_BITMAP_BITS_PER_UNIT; + + if (tail) + bits &= -1UL >> (VIR_BITMAP_BITS_PER_UNIT - tail); + } + if (bits == 0) + return -1; + + return ffsl(bits) - 1 + nl * VIR_BITMAP_BITS_PER_UNIT; +} + /* Return the number of bits currently set in the map. */ size_t virBitmapCountBits(virBitmapPtr bitmap) diff --git a/src/util/virbitmap.h b/src/util/virbitmap.h index 0f68b791ad..044c7a65fc 100644 --- a/src/util/virbitmap.h +++ b/src/util/virbitmap.h @@ -1,7 +1,7 @@ /* * virbitmap.h: Simple bitmap operations * - * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012-2013 Red Hat, Inc. * Copyright (C) 2010 Novell, Inc. * * This library is free software; you can redistribute it and/or @@ -103,6 +103,9 @@ bool virBitmapIsAllSet(virBitmapPtr bitmap) ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) ATTRIBUTE_NONNULL(1); +ssize_t virBitmapNextClearBit(virBitmapPtr bitmap, ssize_t pos) + ATTRIBUTE_NONNULL(1); + size_t virBitmapCountBits(virBitmapPtr bitmap) ATTRIBUTE_NONNULL(1); diff --git a/tests/virbitmaptest.c b/tests/virbitmaptest.c index 66ffd1b49d..95d010a113 100644 --- a/tests/virbitmaptest.c +++ b/tests/virbitmaptest.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2013 Red Hat, Inc. * Copyright (C) 2012 Fujitsu. * * This library is free software; you can redistribute it and/or @@ -160,7 +161,7 @@ error: return ret; } -/* test for virBitmapNextSetBit */ +/* test for virBitmapNextSetBit, virBitmapNextClearBit */ static int test4(const void *data ATTRIBUTE_UNUSED) { const char *bitsString = "0, 2-4, 6-10, 12, 14-18, 20, 22, 25"; @@ -169,17 +170,30 @@ static int test4(const void *data ATTRIBUTE_UNUSED) 0, 2, 3, 4, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 25 }; - int npos = 18; + int bitsPosInv[] = { + 1, 5, 11, 13, 19, 21, 23, 24, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 + }; virBitmapPtr bitmap = NULL; int i, j; + if (ARRAY_CARDINALITY(bitsPos) + ARRAY_CARDINALITY(bitsPosInv) != size) + goto error; + /* 1. zero set */ bitmap = virBitmapNew(size); if (!bitmap) goto error; - if (virBitmapNextSetBit(bitmap, -1) >= 0) + if (virBitmapNextSetBit(bitmap, -1) != -1) + goto error; + + for (i = 0; i < size; i++) { + if (virBitmapNextClearBit(bitmap, i - 1) != i) + goto error; + } + if (virBitmapNextClearBit(bitmap, i) != -1) goto error; virBitmapFree(bitmap); @@ -195,27 +209,39 @@ static int test4(const void *data ATTRIBUTE_UNUSED) j = 0; i = -1; - while (j < npos) { + while (j < ARRAY_CARDINALITY(bitsPos)) { i = virBitmapNextSetBit(bitmap, i); if (i != bitsPos[j++]) goto error; } - if (virBitmapNextSetBit(bitmap, i) > 0) + if (virBitmapNextSetBit(bitmap, i) != -1) + goto error; + + j = 0; + i = -1; + + while (j < ARRAY_CARDINALITY(bitsPosInv)) { + i = virBitmapNextClearBit(bitmap, i); + if (i != bitsPosInv[j++]) + goto error; + } + + if (virBitmapNextClearBit(bitmap, i) != -1) goto error; /* 3. full set */ - i = -1; virBitmapSetAll(bitmap); - for (j = 0; j < size; j++) { - i = virBitmapNextSetBit(bitmap, i); - if (i != j) + for (i = 0; i < size; i++) { + if (virBitmapNextSetBit(bitmap, i - 1) != i) goto error; } + if (virBitmapNextSetBit(bitmap, i) != -1) + goto error; - if (virBitmapNextSetBit(bitmap, i) > 0) + if (virBitmapNextClearBit(bitmap, -1) != -1) goto error; virBitmapFree(bitmap);