mirror of https://gitee.com/openkylin/libvirt.git
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
|
||||
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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue