mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 17:35:17 +00:00
util: bitmap: Introduce self-expanding bitmap APIs
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.
This commit is contained in:
parent
4ed5937d71
commit
917426c8d7
@ -1134,6 +1134,7 @@ virAuthConfigNewData;
|
|||||||
# util/virbitmap.h
|
# util/virbitmap.h
|
||||||
virBitmapClearAll;
|
virBitmapClearAll;
|
||||||
virBitmapClearBit;
|
virBitmapClearBit;
|
||||||
|
virBitmapClearBitExpand;
|
||||||
virBitmapCopy;
|
virBitmapCopy;
|
||||||
virBitmapCountBits;
|
virBitmapCountBits;
|
||||||
virBitmapDataToString;
|
virBitmapDataToString;
|
||||||
@ -1148,6 +1149,7 @@ virBitmapLastSetBit;
|
|||||||
virBitmapNew;
|
virBitmapNew;
|
||||||
virBitmapNewCopy;
|
virBitmapNewCopy;
|
||||||
virBitmapNewData;
|
virBitmapNewData;
|
||||||
|
virBitmapNewEmpty;
|
||||||
virBitmapNewQuiet;
|
virBitmapNewQuiet;
|
||||||
virBitmapNextClearBit;
|
virBitmapNextClearBit;
|
||||||
virBitmapNextSetBit;
|
virBitmapNextSetBit;
|
||||||
@ -1155,6 +1157,7 @@ virBitmapOverlaps;
|
|||||||
virBitmapParse;
|
virBitmapParse;
|
||||||
virBitmapSetAll;
|
virBitmapSetAll;
|
||||||
virBitmapSetBit;
|
virBitmapSetBit;
|
||||||
|
virBitmapSetBitExpand;
|
||||||
virBitmapSize;
|
virBitmapSize;
|
||||||
virBitmapString;
|
virBitmapString;
|
||||||
virBitmapSubtract;
|
virBitmapSubtract;
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
struct _virBitmap {
|
struct _virBitmap {
|
||||||
size_t max_bit;
|
size_t max_bit;
|
||||||
size_t map_len;
|
size_t map_len;
|
||||||
|
size_t map_alloc;
|
||||||
unsigned long *map;
|
unsigned long *map;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,6 +84,7 @@ virBitmapNewQuiet(size_t size)
|
|||||||
|
|
||||||
bitmap->max_bit = size;
|
bitmap->max_bit = size;
|
||||||
bitmap->map_len = sz;
|
bitmap->map_len = sz;
|
||||||
|
bitmap->map_alloc = sz;
|
||||||
return bitmap;
|
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:
|
* virBitmapFree:
|
||||||
* @bitmap: previously allocated bitmap
|
* @bitmap: previously allocated bitmap
|
||||||
@ -154,6 +175,54 @@ int virBitmapSetBit(virBitmapPtr bitmap, size_t b)
|
|||||||
return 0;
|
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:
|
* virBitmapClearBit:
|
||||||
* @bitmap: Pointer to bitmap
|
* @bitmap: Pointer to bitmap
|
||||||
@ -172,6 +241,30 @@ int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
|
|||||||
return 0;
|
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 */
|
/* Helper function. caller must ensure b < bitmap->max_bit */
|
||||||
static bool virBitmapIsSet(virBitmapPtr bitmap, size_t b)
|
static bool virBitmapIsSet(virBitmapPtr bitmap, size_t b)
|
||||||
{
|
{
|
||||||
|
@ -37,6 +37,7 @@ typedef virBitmap *virBitmapPtr;
|
|||||||
*/
|
*/
|
||||||
virBitmapPtr virBitmapNewQuiet(size_t size) ATTRIBUTE_RETURN_CHECK;
|
virBitmapPtr virBitmapNewQuiet(size_t size) ATTRIBUTE_RETURN_CHECK;
|
||||||
virBitmapPtr virBitmapNew(size_t size) ATTRIBUTE_RETURN_CHECK;
|
virBitmapPtr virBitmapNew(size_t size) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
virBitmapPtr virBitmapNewEmpty(void) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free previously allocated bitmap
|
* Free previously allocated bitmap
|
||||||
@ -55,12 +56,19 @@ int virBitmapCopy(virBitmapPtr dst, virBitmapPtr src);
|
|||||||
int virBitmapSetBit(virBitmapPtr bitmap, size_t b)
|
int virBitmapSetBit(virBitmapPtr bitmap, size_t b)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
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
|
* Clear bit position @b in @bitmap
|
||||||
*/
|
*/
|
||||||
int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
|
int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
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.
|
* Get bit @b in @bitmap. Returns false if b is out of range.
|
||||||
*/
|
*/
|
||||||
|
@ -590,6 +590,57 @@ test11(const void *opaque)
|
|||||||
return ret;
|
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) \
|
#define TESTBINARYOP(A, B, RES, FUNC) \
|
||||||
testBinaryOpData.a = A; \
|
testBinaryOpData.a = A; \
|
||||||
testBinaryOpData.b = B; \
|
testBinaryOpData.b = B; \
|
||||||
@ -633,6 +684,9 @@ mymain(void)
|
|||||||
TESTBINARYOP("0-3", "0,^0", "0-3", test11);
|
TESTBINARYOP("0-3", "0,^0", "0-3", test11);
|
||||||
TESTBINARYOP("0,2", "1,3", "0,2", test11);
|
TESTBINARYOP("0,2", "1,3", "0,2", test11);
|
||||||
|
|
||||||
|
if (virtTestRun("test12", test12, NULL) < 0)
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user