In many places we store bitmap info in a chunk of data
(pointed to by a char *), and have redundant codes to
set/unset bits. This patch extends virBitmap, and convert
those codes to use virBitmap in subsequent patches.
---
.gitignore | 1 +
src/libvirt_private.syms | 11 ++
src/util/bitmap.c | 451 +++++++++++++++++++++++++++++++++++++++++++++-
src/util/bitmap.h | 34 ++++
tests/Makefile.am | 7 +-
tests/virbitmaptest.c | 233 ++++++++++++++++++++++++
6 files changed, 731 insertions(+), 6 deletions(-)
create mode 100644 tests/virbitmaptest.c
diff --git a/.gitignore b/.gitignore
index 5041ddf..4851a83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -156,6 +156,7 @@
/tests/utiltest
/tests/viratomictest
/tests/virauthconfigtest
+/tests/virbitmaptest
/tests/virbuftest
/tests/virdrivermoduletest
/tests/virhashtest
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 65067d6..028b65c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -7,11 +7,22 @@
# bitmap.h
virBitmapAlloc;
+virBitmapAllocFromData;
+virBitmapClearAll;
virBitmapClearBit;
+virBitmapCopy;
+virBitmapEqual;
+virBitmapFormat;
virBitmapFree;
virBitmapGetBit;
+virBitmapIsAllSet;
+virBitmapNextSetBit;
+virBitmapParse;
+virBitmapSetAll;
virBitmapSetBit;
+virBitmapSize;
virBitmapString;
+virBitmapToData;
# buf.h
diff --git a/src/util/bitmap.c b/src/util/bitmap.c
index 53a8a38..2ca417a 100644
--- a/src/util/bitmap.c
+++ b/src/util/bitmap.c
@@ -33,11 +33,14 @@
#include "bitmap.h"
#include "memory.h"
#include "buf.h"
+#include "util.h"
+#include "c-ctype.h"
struct _virBitmap {
- size_t size;
- unsigned long *map;
+ size_t size; /* size in bits */
+ size_t size2; /* size in LONGs */
+ unsigned long *map; /* bits are stored in little-endian format */
};
@@ -76,6 +79,7 @@ virBitmapPtr virBitmapAlloc(size_t size)
}
bitmap->size = size;
+ bitmap->size2 = sz;
return bitmap;
}
@@ -129,6 +133,12 @@ int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
return 0;
}
+/* Helper function. caller must ensure b < bitmap->size */
+static bool virBitmapIsSet(virBitmapPtr bitmap, size_t b)
+{
+ return !!(bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] & VIR_BITMAP_BIT(b));
+}
+
/**
* virBitmapGetBit:
* @bitmap: Pointer to bitmap
@@ -145,7 +155,7 @@ int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result)
if (bitmap->size <= b)
return -1;
- *result = !!(bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] & VIR_BITMAP_BIT(b));
+ *result = virBitmapIsSet(bitmap, b);
return 0;
}
@@ -164,8 +174,7 @@ char *virBitmapString(virBitmapPtr bitmap)
virBufferAddLit(&buf, "0x");
- sz = (bitmap->size + VIR_BITMAP_BITS_PER_UNIT - 1) /
- VIR_BITMAP_BITS_PER_UNIT;
+ sz = bitmap->size2;
while (sz--) {
virBufferAsprintf(&buf, "%0*lx",
@@ -180,3 +189,435 @@ char *virBitmapString(virBitmapPtr bitmap)
return virBufferContentAndReset(&buf);
}
+
+/**
+ * virBitmapFormat:
+ * @bitmap: the bitmap
+ *
+ * This function is the counterpart of virBitmapParse. This function creates
+ * a human-readable string representing the bits in bitmap.
+ *
+ * See virBitmapParse for the format of @str.
+ *
+ * Returns the string on success or NULL otherwise. Caller should call
+ * VIR_FREE to free the string.
+ */
+char *virBitmapFormat(virBitmapPtr bitmap)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int first = -1;
+ int start, cur;
+ int ret;
+ bool isset;
+
+ if (!bitmap)
+ return NULL;
+
+ cur = 0;
+ start = -1;
+ while (cur < bitmap->size) {
+ ret = virBitmapGetBit(bitmap, cur, &isset);
+ if (ret != 0)
+ goto error;
+ else if (isset) {
+ if (start == -1)
+ start = cur;
+ } else if (start != -1) {
+ if (!first)
+ virBufferAddLit(&buf, ",");
+ else
+ first = 0;
+ if (cur == start + 1)
+ virBufferAsprintf(&buf, "%d", start);
+ else
+ virBufferAsprintf(&buf, "%d-%d", start, cur - 1);
+ start = -1;
+ }
+ cur++;
+ }
+
+ if (start != -1) {
+ if (!first)
+ virBufferAddLit(&buf, ",");
+ if (cur == start + 1)
+ virBufferAsprintf(&buf, "%d", start);
+ else
+ virBufferAsprintf(&buf, "%d-%d", start, cur - 1);
+ }
+
+ if (virBufferError(&buf)) {
+error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+}
+
+/**
+ * virBitmapParse:
+ * @str: points to a string representing a human-readable bitmap
+ * @bitmap: a bitmap created from @str
+ * @bitmapSize: the upper limit of num of bits in created bitmap
+ *
+ * This function is the counterpart of virBitmapFormat. This function creates
+ * a bitmap, in which bits are set according to the content of @str.
+ *
+ * @str is a comma separated string of fields N, which means a number of bit
+ * to set, and ^N, which means to unset the bit, and N-M for ranges of bits
+ * to set.
+ *
+ * Returns the number of bits set in @bitmap, or -1 in case of error.
+ */
+
+int virBitmapParse(const char *str,
+ char sep,
+ virBitmapPtr *bitmap,
+ size_t bitmapSize)
+{
+ int ret = 0;
+ bool neg = false;
+ const char *cur;
+ char *tmp;
+ int i, start, last;
+
+ if (!str)
+ return -1;
+
+ cur = str;
+ virSkipSpaces(&cur);
+
+ if (*cur == 0)
+ return -1;
+
+ *bitmap = virBitmapAlloc(bitmapSize);
+ if (!*bitmap)
+ return -1;
+
+ while (*cur != 0 && *cur != sep) {
+ /*
+ * 3 constructs are allowed:
+ * - N : a single CPU number
+ * - N-M : a range of CPU numbers with N < M
+ * - ^N : remove a single CPU number from the current set
+ */
+ if (*cur == '^') {
+ cur++;
+ neg = true;
+ }
+
+ if (!c_isdigit(*cur))
+ goto parse_error;
+
+ if (virStrToLong_i(cur, &tmp, 10, &start) < 0)
+ goto parse_error;
+ if (start < 0)
+ goto parse_error;
+
+ cur = tmp;
+
+ virSkipSpaces(&cur);
+
+ if (*cur == ',' || *cur == 0 || *cur == sep) {
+ if (neg) {
+ if (virBitmapIsSet(*bitmap, start)) {
+ ignore_value(virBitmapClearBit(*bitmap, start));
+ ret--;
+ }
+ } else {
+ if (!virBitmapIsSet(*bitmap, start)) {
+ ignore_value(virBitmapSetBit(*bitmap, start));
+ ret++;
+ }
+ }
+ } else if (*cur == '-') {
+ if (neg)
+ goto parse_error;
+
+ cur++;
+ virSkipSpaces(&cur);
+
+ if (virStrToLong_i(cur, &tmp, 10, &last) < 0)
+ goto parse_error;
+ if (last < start)
+ goto parse_error;
+
+ cur = tmp;
+
+ for (i = start; i <= last; i++) {
+ if (!virBitmapIsSet(*bitmap, i)) {
+ ignore_value(virBitmapSetBit(*bitmap, i));
+ ret++;
+ }
+ }
+
+ virSkipSpaces(&cur);
+ }
+
+ if (*cur == ',') {
+ cur++;
+ virSkipSpaces(&cur);
+ neg = false;
+ } else if(*cur == 0 || *cur == sep) {
+ break;
+ } else {
+ goto parse_error;
+ }
+ }
+
+ return ret;
+
+parse_error:
+ virBitmapFree(*bitmap);
+ *bitmap = NULL;
+ return -1;
+}
+
+/**
+ * virBitmapCopy:
+ * @src: the source bitmap.
+ *
+ * Makes a copy of bitmap @src.
+ *
+ * returns the copied bitmap on success, or NULL otherwise. Caller
+ * should call virBitmapFree to free the returned bitmap.
+ */
+virBitmapPtr virBitmapCopy(virBitmapPtr src)
+{
+ virBitmapPtr dst;
+
+ if (VIR_ALLOC(dst) < 0)
+ return NULL;
+
+ if (VIR_ALLOC_N(dst->map, src->size2) < 0) {
+ VIR_FREE(dst);
+ return NULL;
+ }
+
+ memcpy(dst->map, src->map, src->size2);
+ dst->size = src->size;
+ dst->size = src->size2;
+
+ return dst;
+}
+
+#ifdef __BIG_ENDIAN__
+static unsigned long
+virSwapEndian(unsigned long l)
+{
+ if (sizeof(long) == 8)
+ return ((l & 0x00000000000000ffULL) << 56)
+ | ((l & 0x000000000000ff00ULL) << 40)
+ | ((l & 0x0000000000ff0000ULL) << 24)
+ | ((l & 0x00000000ff000000ULL) << 8)
+ | ((l & 0x000000ff00000000ULL) >> 8)
+ | ((l & 0x0000ff0000000000ULL) >> 24)
+ | ((l & 0x00ff000000000000ULL) >> 40)
+ | ((l & 0xff00000000000000ULL) >> 56);
+ else
+ return ((l & 0x000000ffUL) << 24)
+ | ((l & 0x0000ff00UL) << 8)
+ | ((l & 0x00ff0000UL) >> 8)
+ | ((l & 0xff000000UL) >> 24);
+}
+#endif
+
+/**
+ * virBitmapAllocFromData:
+ * @data: the data
+ * @len: length of @data in bytes
+ *
+ * Allocate a bitmap from a chunk of data containing bits
+ * information
+ *
+ * Returns a pointer to the allocated bitmap or NULL if
+ * memory cannot be allocated.
+ */
+virBitmapPtr virBitmapAllocFromData(void *data, int len)
+{
+ virBitmapPtr bitmap;
+#ifdef __BIG_ENDIAN__
+ int i;
+#endif
+
+ bitmap = virBitmapAlloc(len * CHAR_BIT);
+ if (!bitmap)
+ return NULL;
+
+ memcpy(bitmap->map, data, len);
+#ifdef __BIG_ENDIAN__
+ for (i = 0; i < bitmap->size2; i++)
+ bitmap->map[i] = virSwapEndian(bitmap->map[i]);
+#endif
+
+ return bitmap;
+}
+
+/**
+ * virBitmapToData:
+ * @data: the data
+ * @len: len of @data in byte
+ *
+ * Convert a bitmap to a chunk of data containing bits information.
+ * Data consists of sequential bytes, with lower bytes containing
+ * lower bits.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int virBitmapToData(virBitmapPtr bitmap, char **data, int *dataLen)
+{
+ int len;
+#ifdef __BIG_ENDIAN__
+ unsigned long *l;
+#endif
+
+ len = bitmap->size2 * (VIR_BITMAP_BITS_PER_UNIT / CHAR_BIT);
+
+ if (VIR_ALLOC_N(*data, len) < 0)
+ return -1;
+
+ memcpy(*data, bitmap->map, len);
+ *dataLen = len;
+
+#ifdef __BIG_ENDIAN__
+ l = (unsigned long *)*data;
+ for (i = 0; i < bitmap->size2; i++, l++)
+ *l = virSwapEndian(*l);
+#endif
+
+ return 0;
+}
+
+/**
+ * virBitmapEqual:
+ * @b1: bitmap 1
+ * @b2: bitmap 2
+ *
+ * Compares two bitmaps, whose lengths can be different from each other.
+ *
+ * Returns true if two bitmaps have exactly the same set of bits set,
+ * otherwise false.
+ */
+bool virBitmapEqual(virBitmapPtr b1, virBitmapPtr b2)
+{
+ virBitmapPtr tmp;
+ int i;
+
+ if (b1->size > b2->size) {
+ tmp = b1;
+ b1 = b2;
+ b2 = tmp;
+ }
+
+ /* Now b1 is the smaller one, if not equal */
+
+ for (i = 0; i < b1->size2; i++) {
+ if (b1->map[i] != b2->map[i])
+ return false;
+ }
+
+ for (; i < b2->size2; i++) {
+ if (b2->map[i])
+ return false;
+ }
+
+ return true;
+}
+
+size_t virBitmapSize(virBitmapPtr bitmap)
+{
+ return bitmap->size;
+}
+
+/**
+ * virBitmapSetAll:
+ * @bitmap: the bitmap
+ *
+ * set all bits in @bitmap.
+ */
+void virBitmapSetAll(virBitmapPtr bitmap)
+{
+ memset(bitmap->map, 0xff,
+ bitmap->size2 * (VIR_BITMAP_BITS_PER_UNIT / CHAR_BIT));
+}
+
+/**
+ * virBitmapClearAll:
+ * @bitmap: the bitmap
+ *
+ * clear all bits in @bitmap.
+ */
+void virBitmapClearAll(virBitmapPtr bitmap)
+{
+ memset(bitmap->map, 0,
+ bitmap->size2 * (VIR_BITMAP_BITS_PER_UNIT / CHAR_BIT));
+}
+
+/**
+ * virBitmapIsAllSet:
+ * @bitmap: the bitmap to check
+ *
+ * check if all bits in @bitmap are set.
+ */
+bool virBitmapIsAllSet(virBitmapPtr bitmap)
+{
+ int i;
+ int unusedBits;
+ size_t sz;
+
+ unusedBits = bitmap->size2 * VIR_BITMAP_BITS_PER_UNIT - bitmap->size;
+
+ sz = bitmap->size2;
+ if (unusedBits > 0)
+ sz--;
+
+ for (i = 0; i < sz; i++)
+ if (bitmap->map[i] != -1)
+ return false;
+
+ if (unusedBits > 0) {
+ if ((bitmap->map[sz] & ((1U << (VIR_BITMAP_BITS_PER_UNIT -
unusedBits)) - 1))
+ != ((1U << (VIR_BITMAP_BITS_PER_UNIT - unusedBits)) - 1))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * virBitmapNextSetBit:
+ * @bitmap: the bitmap
+ * @i: the position after which to search for a set bit
+ *
+ * search the first set bit after position $i in bitmap @bitmap.
+ *
+ * returns the position of the found bit, or -1 if no bit found.
+ */
+int virBitmapNextSetBit(virBitmapPtr bitmap, int pos)
+{
+ int nl;
+ int nb;
+ unsigned long bits;
+
+ if (pos < 0)
+ pos = -1;
+
+ pos++;
+
+ if (pos >= bitmap->size)
+ 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->size2) {
+ bits = bitmap->map[nl];
+ }
+
+ if (bits == 0)
+ return -1;
+
+ return __builtin_ctzl(bits) + nl * VIR_BITMAP_BITS_PER_UNIT;
+}
diff --git a/src/util/bitmap.h b/src/util/bitmap.h
index c3e6222..a39fbe8 100644
--- a/src/util/bitmap.h
+++ b/src/util/bitmap.h
@@ -62,4 +62,38 @@ int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result)
char *virBitmapString(virBitmapPtr bitmap)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+char *virBitmapFormat(virBitmapPtr bitmap)
+ ATTRIBUTE_NONNULL(1);
+
+int virBitmapParse(const char *str,
+ char sep,
+ virBitmapPtr *bitmap,
+ size_t bitmapSize)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
+
+virBitmapPtr virBitmapCopy(virBitmapPtr src) ATTRIBUTE_NONNULL(1);
+
+virBitmapPtr virBitmapAllocFromData(void *data, int len) ATTRIBUTE_NONNULL(1);
+
+int virBitmapToData(virBitmapPtr bitmap, char **data, int *dataLen)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+bool virBitmapEqual(virBitmapPtr b1, virBitmapPtr b2)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+size_t virBitmapSize(virBitmapPtr bitmap)
+ ATTRIBUTE_NONNULL(1);
+
+void virBitmapSetAll(virBitmapPtr bitmap)
+ ATTRIBUTE_NONNULL(1);
+
+void virBitmapClearAll(virBitmapPtr bitmap)
+ ATTRIBUTE_NONNULL(1);
+
+bool virBitmapIsAllSet(virBitmapPtr bitmap)
+ ATTRIBUTE_NONNULL(1);
+
+int virBitmapNextSetBit(virBitmapPtr bitmap, int pos)
+ ATTRIBUTE_NONNULL(1);
+
#endif
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8cf8015..ed52cc8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -92,7 +92,8 @@ test_programs = virshtest sockettest \
viratomictest \
utiltest virnettlscontexttest shunloadtest \
virtimetest viruritest virkeyfiletest \
- virauthconfigtest
+ virauthconfigtest \
+ virbitmaptest
if WITH_SECDRIVER_SELINUX
test_programs += securityselinuxtest
@@ -562,6 +563,10 @@ viratomictest_SOURCES = \
viratomictest.c testutils.h testutils.c
viratomictest_LDADD = $(LDADDS)
+virbitmaptest_SOURCES = \
+ virbitmaptest.c testutils.h testutils.c
+virbitmaptest_LDADD = $(LDADDS)
+
jsontest_SOURCES = \
jsontest.c testutils.h testutils.c
jsontest_LDADD = $(LDADDS)
diff --git a/tests/virbitmaptest.c b/tests/virbitmaptest.c
new file mode 100644
index 0000000..f5c79c8
--- /dev/null
+++ b/tests/virbitmaptest.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2012 Fujitsu.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <time.h>
+#include <sched.h>
+
+#include "testutils.h"
+
+#include "bitmap.h"
+
+static int test1(const void *data ATTRIBUTE_UNUSED)
+{
+ virBitmapPtr bitmap;
+ int size;
+ int bit;
+ bool result;
+
+ size = 1024;
+ bit = 100;
+ bitmap = virBitmapAlloc(size);
+ if (virBitmapSetBit(bitmap, bit) < 0)
+ return -1;
+
+ if (virBitmapGetBit(bitmap, bit, &result) < 0)
+ return -1;
+
+ if (!result)
+ return -1;
+
+ if (virBitmapGetBit(bitmap, bit + 1, &result) < 0)
+ return -1;
+
+ if (result)
+ return -1;
+
+ return 0;
+}
+
+int testBit(virBitmapPtr bitmap,
+ unsigned int start,
+ unsigned int end,
+ bool expected)
+{
+ int i;
+ bool result;
+
+ for (i = start; i <= end; i++) {
+ if (virBitmapGetBit(bitmap, i, &result) < 0)
+ return -1;
+ if (result == expected)
+ return 0;
+ }
+
+ return -1;
+}
+
+static int test2(const void *data ATTRIBUTE_UNUSED)
+{
+ const char *bitsString1 = "1-32,50,88-99,1021-1023";
+ char *bitsString2 = NULL;
+ virBitmapPtr bitmap = NULL;
+ int ret = -1;
+ int size = 1025;
+
+ if (virBitmapParse(bitsString1, 0, &bitmap, size) < 0)
+ goto error;
+
+ if (testBit(bitmap, 1, 32, true) < 0)
+ goto error;
+ if (testBit(bitmap, 50, 50, true) < 0)
+ goto error;
+ if (testBit(bitmap, 88, 99, true) < 0)
+ goto error;
+ if (testBit(bitmap, 1021, 1023, true) < 0)
+ goto error;
+
+ if (testBit(bitmap, 0, 0, false) < 0)
+ goto error;
+ if (testBit(bitmap, 33, 49, false) < 0)
+ goto error;
+ if (testBit(bitmap, 51, 87, false) < 0)
+ goto error;
+ if (testBit(bitmap, 100, 1020, false) < 0)
+ goto error;
+
+ bitsString2 = virBitmapFormat(bitmap);
+ if (strcmp(bitsString1, bitsString2))
+ goto error;
+
+ virBitmapSetAll(bitmap);
+ if (testBit(bitmap, 0, size - 1, true) < 0)
+ goto error;
+
+ if (!virBitmapIsAllSet(bitmap))
+ goto error;
+
+ virBitmapClearAll(bitmap);
+ if (testBit(bitmap, 0, size - 1, false) < 0)
+ goto error;
+
+ ret = 0;
+
+error:
+ virBitmapFree(bitmap);
+ VIR_FREE(bitsString2);
+ return ret;
+}
+
+static int test3(const void *data ATTRIBUTE_UNUSED)
+{
+ virBitmapPtr bitmap = NULL;
+ int ret = -1;
+ int size = 5;
+ int i;
+
+ if ((bitmap = virBitmapAlloc(size)) == NULL)
+ goto error;
+
+ for (i = 0; i < size; i++)
+ ignore_value(virBitmapSetBit(bitmap, i));
+
+ if (!virBitmapIsAllSet(bitmap))
+ goto error;
+
+ ret = 0;
+
+error:
+ virBitmapFree(bitmap);
+ return ret;
+}
+
+static int test4(const void *data ATTRIBUTE_UNUSED)
+{
+ const char *bitsString = "0, 2-4, 6-10, 12, 14-18, 20, 22, 25";
+ int size = 40;
+ int bitsPos[] = {
+ 0, 2, 3, 4, 6, 7, 8, 9, 10, 12,
+ 14, 15, 16, 17, 18, 20, 22, 25
+ };
+ int npos = 18;
+ virBitmapPtr bitmap = NULL;
+ int i, j;
+
+ /* 1. zero set */
+
+ bitmap = virBitmapAlloc(size);
+ if (!bitmap)
+ goto error;
+
+ if (virBitmapNextSetBit(bitmap, -1) >= 0)
+ goto error;
+
+ virBitmapFree(bitmap);
+ bitmap = NULL;
+
+ /* 2. partial set */
+
+ if (virBitmapParse(bitsString, 0, &bitmap, size) < 0)
+ goto error;
+ if (!bitmap)
+ goto error;
+
+ j = 0;
+ i = -1;
+
+ while (j < npos) {
+ i = virBitmapNextSetBit(bitmap, i);
+ if (i != bitsPos[j++])
+ goto error;
+ }
+
+ if (virBitmapNextSetBit(bitmap, i) > 0)
+ goto error;
+
+ /* 3. full set */
+
+ i = -1;
+ virBitmapSetAll(bitmap);
+
+ for (j = 0; j < size; j++) {
+ i = virBitmapNextSetBit(bitmap, i);
+ if (i != j)
+ goto error;
+ }
+
+ if (virBitmapNextSetBit(bitmap, i) > 0)
+ goto error;
+
+ virBitmapFree(bitmap);
+ return 0;
+
+error:
+ virBitmapFree(bitmap);
+ return -1;
+}
+
+static int
+mymain(void)
+{
+ int ret = 0;
+
+ if (virtTestRun("test1", 1, test1, NULL) < 0)
+ ret = -1;
+ if (virtTestRun("test2", 1, test2, NULL) < 0)
+ ret = -1;
+ if (virtTestRun("test3", 1, test3, NULL) < 0)
+ ret = -1;
+ if (virtTestRun("test4", 1, test4, NULL) < 0)
+ ret = -1;
+
+
+ return ret;
+}
+
+VIRT_TEST_MAIN(mymain)
--
1.7.10.2