]> xenbits.xensource.com Git - libvirt.git/commitdiff
util: bitmap: Introduce self-expanding bitmap APIs
authorPeter Krempa <pkrempa@redhat.com>
Fri, 18 Mar 2016 14:41:59 +0000 (15:41 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Tue, 29 Mar 2016 19:25:41 +0000 (21:25 +0200)
In some cases it's impractical to use the regular APIs as the bitmap
size needs to be pre-declared. These new APIs allow to use bitmaps that
self expand.

The new code adds a property to the bitmap to track the allocation of
memory so that VIR_RESIZE_N can be used.

src/libvirt_private.syms
src/util/virbitmap.c
src/util/virbitmap.h
tests/virbitmaptest.c

index 7c44047281722003a4abe15e7a3a8bfd3e9433ff..3e110081bf4d3c6f8a39e46f5bfce2aa94de1ec6 100644 (file)
@@ -1134,6 +1134,7 @@ virAuthConfigNewData;
 # util/virbitmap.h
 virBitmapClearAll;
 virBitmapClearBit;
+virBitmapClearBitExpand;
 virBitmapCopy;
 virBitmapCountBits;
 virBitmapDataToString;
@@ -1148,6 +1149,7 @@ virBitmapLastSetBit;
 virBitmapNew;
 virBitmapNewCopy;
 virBitmapNewData;
+virBitmapNewEmpty;
 virBitmapNewQuiet;
 virBitmapNextClearBit;
 virBitmapNextSetBit;
@@ -1155,6 +1157,7 @@ virBitmapOverlaps;
 virBitmapParse;
 virBitmapSetAll;
 virBitmapSetBit;
+virBitmapSetBitExpand;
 virBitmapSize;
 virBitmapString;
 virBitmapSubtract;
index f116607998c809c6b425b209139dbf43d33b14d9..9283aef1735b1eaa39455a8e64e3e5bfae94db7d 100644 (file)
@@ -43,6 +43,7 @@
 struct _virBitmap {
     size_t max_bit;
     size_t map_len;
+    size_t map_alloc;
     unsigned long *map;
 };
 
@@ -83,6 +84,7 @@ virBitmapNewQuiet(size_t size)
 
     bitmap->max_bit = size;
     bitmap->map_len = sz;
+    bitmap->map_alloc = sz;
     return bitmap;
 }
 
@@ -108,6 +110,25 @@ virBitmapNew(size_t size)
 }
 
 
+/**
+ * virBitmapNewEmpty:
+ *
+ * Allocate an empty bitmap. It can be used with self-expanding APIs.
+ *
+ * Returns a pointer to the allocated bitmap or NULL if memory cannot be
+ * allocated. Reports libvirt errors.
+ */
+virBitmapPtr
+virBitmapNewEmpty(void)
+{
+    virBitmapPtr ret;
+
+    ignore_value(VIR_ALLOC(ret));
+
+    return ret;
+}
+
+
 /**
  * virBitmapFree:
  * @bitmap: previously allocated bitmap
@@ -154,6 +175,54 @@ int virBitmapSetBit(virBitmapPtr bitmap, size_t b)
     return 0;
 }
 
+/**
+ * virBitmapExpand:
+ * @map: Pointer to bitmap
+ * @b: bit position to include in bitmap
+ *
+ * Resizes the bitmap so that bit @b will fit into it. This shall be called only
+ * if @b would not fit into the map.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+static int virBitmapExpand(virBitmapPtr map, size_t b)
+{
+    size_t new_len = VIR_DIV_UP(b, VIR_BITMAP_BITS_PER_UNIT);
+
+    /* resize the memory if necessary */
+    if (map->map_len < new_len) {
+        if (VIR_RESIZE_N(map->map, map->map_alloc, map->map_len,
+                         new_len - map->map_len) < 0)
+            return -1;
+    }
+
+    map->max_bit = b + 1;
+    map->map_len = new_len;
+
+    return 0;
+}
+
+
+/**
+ * virBitmapSetBitExpand:
+ * @bitmap: Pointer to bitmap
+ * @b: bit position to set
+ *
+ * Set bit position @b in @bitmap. Expands the bitmap as necessary so that @b is
+ * included in the map.
+ *
+ * Returns 0 on if bit is successfully set, -1 on error.
+ */
+int virBitmapSetBitExpand(virBitmapPtr bitmap, size_t b)
+{
+    if (bitmap->max_bit <= b && virBitmapExpand(bitmap, b) < 0)
+        return -1;
+
+    bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] |= VIR_BITMAP_BIT(b);
+    return 0;
+}
+
+
 /**
  * virBitmapClearBit:
  * @bitmap: Pointer to bitmap
@@ -172,6 +241,30 @@ int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
     return 0;
 }
 
+
+/**
+ * virBitmapClearBitExpand:
+ * @bitmap: Pointer to bitmap
+ * @b: bit position to set
+ *
+ * Clear bit position @b in @bitmap. Expands the bitmap as necessary so that
+ * @b is included in the map.
+ *
+ * Returns 0 on if bit is successfully cleared, -1 on error.
+ */
+int virBitmapClearBitExpand(virBitmapPtr bitmap, size_t b)
+{
+    if (bitmap->max_bit <= b) {
+        if (virBitmapExpand(bitmap, b) < 0)
+            return -1;
+    } else {
+        bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] &= ~VIR_BITMAP_BIT(b);
+    }
+
+    return 0;
+}
+
+
 /* Helper function. caller must ensure b < bitmap->max_bit */
 static bool virBitmapIsSet(virBitmapPtr bitmap, size_t b)
 {
index 846aca3682537c09f6aa7e95d209e5e441b6a3ab..79f53dd37832f0bcf50a8c0a28df06c95611a102 100644 (file)
@@ -37,6 +37,7 @@ typedef virBitmap *virBitmapPtr;
  */
 virBitmapPtr virBitmapNewQuiet(size_t size) ATTRIBUTE_RETURN_CHECK;
 virBitmapPtr virBitmapNew(size_t size) ATTRIBUTE_RETURN_CHECK;
+virBitmapPtr virBitmapNewEmpty(void) ATTRIBUTE_RETURN_CHECK;
 
 /*
  * Free previously allocated bitmap
@@ -55,12 +56,19 @@ int virBitmapCopy(virBitmapPtr dst, virBitmapPtr src);
 int virBitmapSetBit(virBitmapPtr bitmap, size_t b)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 
+int virBitmapSetBitExpand(virBitmapPtr bitmap, size_t b)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
+
 /*
  * Clear bit position @b in @bitmap
  */
 int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 
+int virBitmapClearBitExpand(virBitmapPtr bitmap, size_t b)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
 /*
  * Get bit @b in @bitmap. Returns false if b is out of range.
  */
index 967a5c8291041ec530704bf34d7c60387dcca043..a030a92e03e73dc2c9443a111f4348faec0a2485 100644 (file)
@@ -590,6 +590,57 @@ test11(const void *opaque)
     return ret;
 }
 
+#define TEST_MAP(sz, expect)                                                   \
+    do {                                                                       \
+        char *actual;                                                          \
+        if (virBitmapSize(map) != sz) {                                        \
+            fprintf(stderr, "\n expected bitmap size: '%d' actual size: "      \
+                    "'%zu'\n", sz, virBitmapSize(map));                        \
+            goto cleanup;                                                      \
+        }                                                                      \
+                                                                               \
+        actual = virBitmapFormat(map);                                         \
+                                                                               \
+        if (STRNEQ_NULLABLE(expect, actual)) {                                 \
+            fprintf(stderr, "\n expected bitmap contents '%s' actual contents "\
+                    "'%s'\n", NULLSTR(expect), NULLSTR(actual));               \
+            VIR_FREE(actual);                                                  \
+            goto cleanup;                                                      \
+        }                                                                      \
+        VIR_FREE(actual);                                                      \
+    } while (0)
+
+/* test self-expanding bitmap APIs */
+static int
+test12(const void *opaque ATTRIBUTE_UNUSED)
+{
+    virBitmapPtr map = NULL;
+    int ret = -1;
+
+    if (!(map = virBitmapNewEmpty()))
+        return -1;
+
+    TEST_MAP(0, "");
+
+    if (virBitmapSetBitExpand(map, 100) < 0)
+        goto cleanup;
+
+    TEST_MAP(101, "100");
+
+    if (virBitmapClearBitExpand(map, 150) < 0)
+        goto cleanup;
+
+    TEST_MAP(151, "100");
+
+    ret = 0;
+
+ cleanup:
+    virBitmapFree(map);
+    return ret;
+}
+#undef TEST_MAP
+
+
 #define TESTBINARYOP(A, B, RES, FUNC)                                         \
     testBinaryOpData.a = A;                                                   \
     testBinaryOpData.b = B;                                                   \
@@ -633,6 +684,9 @@ mymain(void)
     TESTBINARYOP("0-3", "0,^0", "0-3", test11);
     TESTBINARYOP("0,2", "1,3", "0,2", test11);
 
+    if (virtTestRun("test12", test12, NULL) < 0)
+        ret = -1;
+
     return ret;
 }