virBitmapNextLastSetBit: Search for the last set bit before certain position. virBitmapNextLastSetBit: Search for the last clear bit before certain position. --- src/libvirt_private.syms | 2 + src/util/virbitmap.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virbitmap.h | 6 +++ tests/virbitmaptest.c | 51 ++++++++++++++++++++++++- 4 files changed, 154 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 5cad990..a17465a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1045,6 +1045,8 @@ virBitmapNew; virBitmapNewCopy; virBitmapNewData; virBitmapNextClearBit; +virBitmapNextLastClearBit; +virBitmapNextLastSetBit; virBitmapNextSetBit; virBitmapParse; virBitmapSetAll; diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index 21509ac..bb677db 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -50,6 +50,21 @@ struct _virBitmap { #define VIR_BITMAP_BIT_OFFSET(b) ((b) % VIR_BITMAP_BITS_PER_UNIT) #define VIR_BITMAP_BIT(b) (1UL << VIR_BITMAP_BIT_OFFSET(b)) +/* helper function to get last set bit in long integer */ +static int +flsl(long mask) +{ + int bit = VIR_BITMAP_BITS_PER_UNIT; + + if (mask == 0) + return 0; + + for (; !(mask & 1UL << (VIR_BITMAP_BITS_PER_UNIT - 1)); bit--) { + mask = (unsigned long)mask << 1; + } + + return bit; +} /** * virBitmapNew: @@ -632,6 +647,46 @@ virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) } /** + * virBitmapNextLastSetBit + * @bitmap: the bitmap + * @pos: the position before which to search for a set bit + * + * Search for the last set bit before position @pos in bitmap @bitmap. + * @pos can be -1 to search for the last set bit. Position starts + * at bitmap->max_bit. + */ + +ssize_t +virBitmapNextLastSetBit(virBitmapPtr bitmap, ssize_t pos) +{ + ssize_t nl; + size_t nb; + unsigned long bits; + + if (pos < 0) + pos = bitmap->max_bit; + + pos--; + + if (pos < 0 || 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 >> (VIR_BITMAP_BITS_PER_UNIT - nb - 1); + + while (bits == 0 && --nl >= 0) { + bits = bitmap->map[nl]; + } + + if (bits == 0) + return -1; + + return flsl(bits) - 1 + nl * VIR_BITMAP_BITS_PER_UNIT; +} + +/** * virBitmapNextClearBit: * @bitmap: the bitmap * @pos: the position after which to search for a clear bit @@ -679,6 +734,47 @@ virBitmapNextClearBit(virBitmapPtr bitmap, ssize_t pos) return ffsl(bits) - 1 + nl * VIR_BITMAP_BITS_PER_UNIT; } +/** + * virBitmapNextLastClearBit: + * @bitmap: the bitmap + * @pos: the position before which to search for a clear bit + * + * Search for the last clear bit before position @pos in bitmap @bitmap. + * @pos can be -1 to search for the last clear bit. Position starts + * at bitmap->max_bit. + * + * Returns the position of the found bit, or -1 if no bit found. + */ +ssize_t +virBitmapNextLastClearBit(virBitmapPtr bitmap, ssize_t pos) +{ + ssize_t nl; + size_t nb; + unsigned long bits; + + if (pos < 0) + pos = bitmap->max_bit; + + pos--; + + if (pos < 0 || 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 >> (VIR_BITMAP_BITS_PER_UNIT - nb - 1); + + while (bits == 0 && --nl >= 0) { + bits = ~bitmap->map[nl]; + } + + if (bits == 0) + return -1; + + return flsl(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 044c7a6..d650e1f 100644 --- a/src/util/virbitmap.h +++ b/src/util/virbitmap.h @@ -103,9 +103,15 @@ bool virBitmapIsAllSet(virBitmapPtr bitmap) ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) ATTRIBUTE_NONNULL(1); +ssize_t virBitmapNextLastSetBit(virBitmapPtr bitmap, ssize_t pos) + ATTRIBUTE_NONNULL(1); + ssize_t virBitmapNextClearBit(virBitmapPtr bitmap, ssize_t pos) ATTRIBUTE_NONNULL(1); +ssize_t virBitmapNextLastClearBit(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 95d010a..f0a3086 100644 --- a/tests/virbitmaptest.c +++ b/tests/virbitmaptest.c @@ -161,7 +161,9 @@ error: return ret; } -/* test for virBitmapNextSetBit, virBitmapNextClearBit */ +/* test for virBitmapNextSetBit, virBitmapNextClearBit + * virBitmapNextLastSetBit, virBitmapNextLastClearBit + */ static int test4(const void *data ATTRIBUTE_UNUSED) { const char *bitsString = "0, 2-4, 6-10, 12, 14-18, 20, 22, 25"; @@ -193,9 +195,21 @@ static int test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextClearBit(bitmap, i - 1) != i) goto error; } + if (virBitmapNextClearBit(bitmap, i) != -1) goto error; + if (virBitmapNextLastSetBit(bitmap, -1) != -1) + goto error; + + for (i = size; i > 0; i--) { + if (virBitmapNextLastClearBit(bitmap, i) != i - 1) + goto error; + } + + if (virBitmapNextLastClearBit(bitmap, i) != -1) + goto error; + virBitmapFree(bitmap); bitmap = NULL; @@ -218,6 +232,18 @@ static int test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextSetBit(bitmap, i) != -1) goto error; + j = 1; + i = -1; + + while (j <= ARRAY_CARDINALITY(bitsPos)) { + i = virBitmapNextLastSetBit(bitmap, i); + if (i != bitsPos[ARRAY_CARDINALITY(bitsPos) - j++]) + goto error; + } + + if (virBitmapNextLastSetBit(bitmap, i) != -1) + goto error; + j = 0; i = -1; @@ -230,6 +256,18 @@ static int test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextClearBit(bitmap, i) != -1) goto error; + j = 1; + i = -1; + + while (j <= ARRAY_CARDINALITY(bitsPosInv)) { + i = virBitmapNextLastClearBit(bitmap, i); + if (i != bitsPosInv[ARRAY_CARDINALITY(bitsPosInv) - j++]) + goto error; + } + + if (virBitmapNextLastClearBit(bitmap, i) != -1) + goto error; + /* 3. full set */ virBitmapSetAll(bitmap); @@ -244,6 +282,17 @@ static int test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextClearBit(bitmap, -1) != -1) goto error; + for (i = size; i > 0; i--) { + if (virBitmapNextLastSetBit(bitmap, i) != i - 1) + goto error; + } + + if (virBitmapNextLastSetBit(bitmap, i) != -1) + goto error; + + if (virBitmapNextLastClearBit(bitmap, -1) != -1) + goto error; + virBitmapFree(bitmap); return 0; -- 1.7.11.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list