2010-05-21 04:23:48 +00:00
|
|
|
/*
|
2014-03-07 13:38:51 +00:00
|
|
|
* virbitmap.c: Simple bitmap operations
|
2010-05-21 04:23:48 +00:00
|
|
|
*
|
2013-02-02 00:33:18 +00:00
|
|
|
* Copyright (C) 2010-2013 Red Hat, Inc.
|
2010-05-21 04:23:48 +00:00
|
|
|
* Copyright (C) 2010 Novell, Inc.
|
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-05-21 04:23:48 +00:00
|
|
|
*
|
|
|
|
* Author: Jim Fehlig <jfehlig@novell.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
2012-12-04 11:56:32 +00:00
|
|
|
#include "virbitmap.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-09-14 07:46:57 +00:00
|
|
|
#include "c-ctype.h"
|
2012-10-25 00:44:27 +00:00
|
|
|
#include "count-one-bits.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2017-08-23 07:12:10 +00:00
|
|
|
#include "virutil.h"
|
2013-07-04 10:02:00 +00:00
|
|
|
#include "virerror.h"
|
2010-05-21 04:23:48 +00:00
|
|
|
|
2013-05-24 07:19:51 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
2010-05-21 04:23:48 +00:00
|
|
|
struct _virBitmap {
|
2012-09-14 07:46:56 +00:00
|
|
|
size_t max_bit;
|
|
|
|
size_t map_len;
|
2016-03-18 14:41:59 +00:00
|
|
|
size_t map_alloc;
|
2011-02-10 10:11:15 +00:00
|
|
|
unsigned long *map;
|
2010-05-21 04:23:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-02-10 10:11:15 +00:00
|
|
|
#define VIR_BITMAP_BITS_PER_UNIT ((int) sizeof(unsigned long) * CHAR_BIT)
|
2010-05-21 04:23:48 +00:00
|
|
|
#define VIR_BITMAP_UNIT_OFFSET(b) ((b) / VIR_BITMAP_BITS_PER_UNIT)
|
|
|
|
#define VIR_BITMAP_BIT_OFFSET(b) ((b) % VIR_BITMAP_BITS_PER_UNIT)
|
2011-02-10 10:11:15 +00:00
|
|
|
#define VIR_BITMAP_BIT(b) (1UL << VIR_BITMAP_BIT_OFFSET(b))
|
2010-05-21 04:23:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-01-30 10:19:59 +00:00
|
|
|
* virBitmapNewQuiet:
|
2010-05-21 04:23:48 +00:00
|
|
|
* @size: number of bits
|
|
|
|
*
|
|
|
|
* Allocate a bitmap capable of containing @size bits.
|
|
|
|
*
|
2016-07-06 12:02:27 +00:00
|
|
|
* Returns a pointer to the allocated bitmap or NULL if either memory cannot be
|
|
|
|
* allocated or size is 0. Does not report libvirt errors.
|
2010-05-21 04:23:48 +00:00
|
|
|
*/
|
2015-01-30 10:19:59 +00:00
|
|
|
virBitmapPtr
|
|
|
|
virBitmapNewQuiet(size_t size)
|
2010-05-21 04:23:48 +00:00
|
|
|
{
|
|
|
|
virBitmapPtr bitmap;
|
|
|
|
size_t sz;
|
|
|
|
|
2015-01-30 10:19:59 +00:00
|
|
|
if (SIZE_MAX - VIR_BITMAP_BITS_PER_UNIT < size || size == 0)
|
2010-05-21 04:23:48 +00:00
|
|
|
return NULL;
|
|
|
|
|
2015-08-24 13:54:26 +00:00
|
|
|
sz = VIR_DIV_UP(size, VIR_BITMAP_BITS_PER_UNIT);
|
2010-05-21 04:23:48 +00:00
|
|
|
|
2015-01-30 10:19:59 +00:00
|
|
|
if (VIR_ALLOC_QUIET(bitmap) < 0)
|
2010-05-21 04:23:48 +00:00
|
|
|
return NULL;
|
|
|
|
|
2015-01-30 10:19:59 +00:00
|
|
|
if (VIR_ALLOC_N_QUIET(bitmap->map, sz) < 0) {
|
2010-05-21 04:23:48 +00:00
|
|
|
VIR_FREE(bitmap);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-09-14 07:46:56 +00:00
|
|
|
bitmap->max_bit = size;
|
|
|
|
bitmap->map_len = sz;
|
2016-03-18 14:41:59 +00:00
|
|
|
bitmap->map_alloc = sz;
|
2010-05-21 04:23:48 +00:00
|
|
|
return bitmap;
|
|
|
|
}
|
|
|
|
|
2015-01-30 10:19:59 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virBitmapNew:
|
|
|
|
* @size: number of bits
|
|
|
|
*
|
|
|
|
* Allocate a bitmap capable of containing @size bits.
|
|
|
|
*
|
2016-07-06 12:02:27 +00:00
|
|
|
* Returns a pointer to the allocated bitmap or NULL if either memory cannot be
|
|
|
|
* allocated or size is 0. Reports libvirt errors.
|
2015-01-30 10:19:59 +00:00
|
|
|
*/
|
|
|
|
virBitmapPtr
|
|
|
|
virBitmapNew(size_t size)
|
|
|
|
{
|
|
|
|
virBitmapPtr ret;
|
|
|
|
|
|
|
|
if (!(ret = virBitmapNewQuiet(size)))
|
|
|
|
virReportOOMError();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-18 14:41:59 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-21 04:23:48 +00:00
|
|
|
/**
|
|
|
|
* virBitmapFree:
|
|
|
|
* @bitmap: previously allocated bitmap
|
|
|
|
*
|
2012-09-14 07:46:56 +00:00
|
|
|
* Free @bitmap previously allocated by virBitmapNew.
|
2010-05-21 04:23:48 +00:00
|
|
|
*/
|
|
|
|
void virBitmapFree(virBitmapPtr bitmap)
|
|
|
|
{
|
|
|
|
if (bitmap) {
|
|
|
|
VIR_FREE(bitmap->map);
|
|
|
|
VIR_FREE(bitmap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-06 15:09:32 +00:00
|
|
|
|
|
|
|
int virBitmapCopy(virBitmapPtr dst, virBitmapPtr src)
|
|
|
|
{
|
2012-09-14 07:46:56 +00:00
|
|
|
if (dst->max_bit != src->max_bit) {
|
2012-09-06 15:09:32 +00:00
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-09-14 07:46:56 +00:00
|
|
|
memcpy(dst->map, src->map, src->map_len * sizeof(src->map[0]));
|
2012-09-06 15:09:32 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-21 04:23:48 +00:00
|
|
|
/**
|
|
|
|
* virBitmapSetBit:
|
|
|
|
* @bitmap: Pointer to bitmap
|
|
|
|
* @b: bit position to set
|
|
|
|
*
|
|
|
|
* Set bit position @b in @bitmap
|
|
|
|
*
|
|
|
|
* Returns 0 on if bit is successfully set, -1 on error.
|
|
|
|
*/
|
|
|
|
int virBitmapSetBit(virBitmapPtr bitmap, size_t b)
|
|
|
|
{
|
2012-09-14 07:46:56 +00:00
|
|
|
if (bitmap->max_bit <= b)
|
2010-05-21 04:23:48 +00:00
|
|
|
return -1;
|
|
|
|
|
2011-02-10 10:11:15 +00:00
|
|
|
bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] |= VIR_BITMAP_BIT(b);
|
2010-05-21 04:23:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:41:59 +00:00
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
{
|
2017-01-30 12:52:02 +00:00
|
|
|
size_t new_len = VIR_DIV_UP(b + 1, VIR_BITMAP_BITS_PER_UNIT);
|
2016-03-18 14:41:59 +00:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-21 04:23:48 +00:00
|
|
|
/**
|
|
|
|
* virBitmapClearBit:
|
|
|
|
* @bitmap: Pointer to bitmap
|
|
|
|
* @b: bit position to clear
|
|
|
|
*
|
|
|
|
* Clear bit position @b in @bitmap
|
|
|
|
*
|
|
|
|
* Returns 0 on if bit is successfully clear, -1 on error.
|
|
|
|
*/
|
|
|
|
int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
|
|
|
|
{
|
2012-09-14 07:46:56 +00:00
|
|
|
if (bitmap->max_bit <= b)
|
2010-05-21 04:23:48 +00:00
|
|
|
return -1;
|
|
|
|
|
2011-02-10 10:11:15 +00:00
|
|
|
bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] &= ~VIR_BITMAP_BIT(b);
|
2010-05-21 04:23:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:41:59 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-14 07:46:57 +00:00
|
|
|
/* Helper function. caller must ensure b < bitmap->max_bit */
|
|
|
|
static bool virBitmapIsSet(virBitmapPtr bitmap, size_t b)
|
|
|
|
{
|
|
|
|
return !!(bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] & VIR_BITMAP_BIT(b));
|
|
|
|
}
|
|
|
|
|
2015-03-11 15:41:57 +00:00
|
|
|
/**
|
|
|
|
* virBitmapIsBitSet:
|
|
|
|
* @bitmap: Pointer to bitmap
|
|
|
|
* @b: bit position to get
|
|
|
|
*
|
|
|
|
* Get setting of bit position @b in @bitmap.
|
|
|
|
*
|
|
|
|
* If @b is in the range of @bitmap, returns the value of the bit.
|
|
|
|
* Otherwise false is returned.
|
|
|
|
*/
|
|
|
|
bool virBitmapIsBitSet(virBitmapPtr bitmap, size_t b)
|
|
|
|
{
|
|
|
|
if (bitmap->max_bit <= b)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return virBitmapIsSet(bitmap, b);
|
|
|
|
}
|
|
|
|
|
2010-05-21 04:23:48 +00:00
|
|
|
/**
|
|
|
|
* virBitmapGetBit:
|
|
|
|
* @bitmap: Pointer to bitmap
|
|
|
|
* @b: bit position to get
|
|
|
|
* @result: bool pointer to receive bit setting
|
|
|
|
*
|
|
|
|
* Get setting of bit position @b in @bitmap and store in @result
|
|
|
|
*
|
|
|
|
* On success, @result will contain the setting of @b and 0 is
|
|
|
|
* returned. On failure, -1 is returned and @result is unchanged.
|
|
|
|
*/
|
|
|
|
int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result)
|
|
|
|
{
|
2012-09-14 07:46:56 +00:00
|
|
|
if (bitmap->max_bit <= b)
|
2010-05-21 04:23:48 +00:00
|
|
|
return -1;
|
|
|
|
|
2012-09-14 07:46:57 +00:00
|
|
|
*result = virBitmapIsSet(bitmap, b);
|
2010-05-21 04:23:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2011-02-09 12:14:51 +00:00
|
|
|
|
|
|
|
/**
|
2017-08-22 06:30:43 +00:00
|
|
|
* virBitmapToString:
|
2011-02-09 12:14:51 +00:00
|
|
|
* @bitmap: Pointer to bitmap
|
2017-08-21 06:37:30 +00:00
|
|
|
* @prefix: Whether to prepend "0x"
|
2017-08-23 07:09:17 +00:00
|
|
|
* @trim: Whether to output only the minimum required characters
|
2011-02-09 12:14:51 +00:00
|
|
|
*
|
|
|
|
* Convert @bitmap to printable string.
|
|
|
|
*
|
|
|
|
* Returns pointer to the string or NULL on error.
|
|
|
|
*/
|
2017-08-21 06:37:30 +00:00
|
|
|
char *
|
2017-08-22 06:30:43 +00:00
|
|
|
virBitmapToString(virBitmapPtr bitmap,
|
2017-08-23 07:09:17 +00:00
|
|
|
bool prefix,
|
|
|
|
bool trim)
|
2011-02-09 12:14:51 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
size_t sz;
|
2017-08-23 07:09:17 +00:00
|
|
|
size_t len;
|
|
|
|
size_t diff;
|
|
|
|
char *ret = NULL;
|
2011-02-09 12:14:51 +00:00
|
|
|
|
2017-08-21 06:37:30 +00:00
|
|
|
if (prefix)
|
|
|
|
virBufferAddLit(&buf, "0x");
|
2011-02-09 12:14:51 +00:00
|
|
|
|
2012-09-14 07:46:56 +00:00
|
|
|
sz = bitmap->map_len;
|
2011-02-09 12:14:51 +00:00
|
|
|
|
|
|
|
while (sz--) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%0*lx",
|
2011-02-09 12:14:51 +00:00
|
|
|
VIR_BITMAP_BITS_PER_UNIT / 4,
|
|
|
|
bitmap->map[sz]);
|
|
|
|
}
|
|
|
|
|
2017-08-21 06:38:34 +00:00
|
|
|
virBufferCheckError(&buf);
|
2017-08-23 07:09:17 +00:00
|
|
|
ret = virBufferContentAndReset(&buf);
|
|
|
|
if (!ret)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!trim)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (bitmap->max_bit != bitmap->map_len * VIR_BITMAP_BITS_PER_UNIT) {
|
|
|
|
char *tmp = ret;
|
|
|
|
|
|
|
|
if (prefix)
|
|
|
|
tmp += 2;
|
|
|
|
|
|
|
|
len = strlen(tmp);
|
|
|
|
sz = VIR_DIV_UP(bitmap->max_bit, 4);
|
|
|
|
diff = len - sz;
|
|
|
|
|
|
|
|
if (diff)
|
|
|
|
memmove(tmp, tmp + diff, sz + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2011-02-09 12:14:51 +00:00
|
|
|
}
|
2012-09-14 07:46:57 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2014-06-05 10:42:40 +00:00
|
|
|
* If bitmap is NULL or it has no bits set, an empty string is returned.
|
|
|
|
*
|
2012-09-14 07:46:57 +00:00
|
|
|
* 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;
|
|
|
|
bool first = true;
|
|
|
|
int start, cur, prev;
|
|
|
|
|
2014-06-05 10:42:40 +00:00
|
|
|
if (!bitmap || (cur = virBitmapNextSetBit(bitmap, -1)) < 0) {
|
2013-05-24 07:19:51 +00:00
|
|
|
char *ret;
|
|
|
|
ignore_value(VIR_STRDUP(ret, ""));
|
|
|
|
return ret;
|
|
|
|
}
|
2012-09-14 07:46:57 +00:00
|
|
|
|
|
|
|
start = prev = cur;
|
|
|
|
while (prev >= 0) {
|
|
|
|
cur = virBitmapNextSetBit(bitmap, prev);
|
|
|
|
|
|
|
|
if (cur == prev + 1) {
|
|
|
|
prev = cur;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cur < 0 or cur > prev + 1 */
|
|
|
|
|
|
|
|
if (!first)
|
|
|
|
virBufferAddLit(&buf, ",");
|
|
|
|
else
|
|
|
|
first = false;
|
|
|
|
|
|
|
|
if (prev == start)
|
|
|
|
virBufferAsprintf(&buf, "%d", start);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&buf, "%d-%d", start, prev);
|
|
|
|
|
|
|
|
start = prev = cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virBufferFreeAndReset(&buf);
|
2014-06-05 09:24:24 +00:00
|
|
|
virReportOOMError();
|
2012-09-14 07:46:57 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-06-17 12:38:11 +00:00
|
|
|
* virBitmapParseSeparator:
|
2012-09-14 07:46:57 +00:00
|
|
|
* @str: points to a string representing a human-readable bitmap
|
2013-01-23 14:18:09 +00:00
|
|
|
* @terminator: character separating the bitmap to parse
|
2012-09-14 07:46:57 +00:00
|
|
|
* @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.
|
|
|
|
*
|
2013-01-23 14:18:09 +00:00
|
|
|
* To allow parsing of bitmaps within larger strings it is possible to set
|
|
|
|
* a termination character in the argument @terminator. When the character
|
|
|
|
* in @terminator is encountered in @str, the parsing of the bitmap stops.
|
|
|
|
* Pass 0 as @terminator if it is not needed. Whitespace characters may not
|
|
|
|
* be used as terminators.
|
|
|
|
*
|
2016-06-17 12:11:55 +00:00
|
|
|
* Returns 0 on success, or -1 in case of error.
|
2012-09-14 07:46:57 +00:00
|
|
|
*/
|
2013-01-23 14:18:09 +00:00
|
|
|
int
|
2016-06-17 12:38:11 +00:00
|
|
|
virBitmapParseSeparator(const char *str,
|
|
|
|
char terminator,
|
|
|
|
virBitmapPtr *bitmap,
|
|
|
|
size_t bitmapSize)
|
2012-09-14 07:46:57 +00:00
|
|
|
{
|
|
|
|
bool neg = false;
|
2013-08-19 14:08:24 +00:00
|
|
|
const char *cur = str;
|
2012-09-14 07:46:57 +00:00
|
|
|
char *tmp;
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
|
|
|
int start, last;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
2013-08-19 14:08:24 +00:00
|
|
|
if (!(*bitmap = virBitmapNew(bitmapSize)))
|
2012-09-14 07:46:57 +00:00
|
|
|
return -1;
|
|
|
|
|
2013-08-19 14:08:24 +00:00
|
|
|
if (!str)
|
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
2013-08-19 14:08:24 +00:00
|
|
|
virSkipSpaces(&cur);
|
2012-09-14 07:46:57 +00:00
|
|
|
|
2013-08-19 14:08:24 +00:00
|
|
|
if (*cur == '\0')
|
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
2013-01-23 14:18:09 +00:00
|
|
|
while (*cur != 0 && *cur != terminator) {
|
2012-09-14 07:46:57 +00:00
|
|
|
/*
|
|
|
|
* 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))
|
2013-08-16 10:22:32 +00:00
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
|
|
|
if (virStrToLong_i(cur, &tmp, 10, &start) < 0)
|
2013-08-16 10:22:32 +00:00
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
if (start < 0)
|
2013-08-16 10:22:32 +00:00
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
|
|
|
cur = tmp;
|
|
|
|
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
|
2013-01-23 14:18:09 +00:00
|
|
|
if (*cur == ',' || *cur == 0 || *cur == terminator) {
|
2012-09-14 07:46:57 +00:00
|
|
|
if (neg) {
|
2013-08-16 10:22:32 +00:00
|
|
|
if (virBitmapClearBit(*bitmap, start) < 0)
|
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
} else {
|
2013-08-16 10:22:32 +00:00
|
|
|
if (virBitmapSetBit(*bitmap, start) < 0)
|
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
}
|
|
|
|
} else if (*cur == '-') {
|
|
|
|
if (neg)
|
2013-08-16 10:22:32 +00:00
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
|
|
|
cur++;
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
|
|
|
|
if (virStrToLong_i(cur, &tmp, 10, &last) < 0)
|
2013-08-16 10:22:32 +00:00
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
if (last < start)
|
2013-08-16 10:22:32 +00:00
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
|
|
|
cur = tmp;
|
|
|
|
|
|
|
|
for (i = start; i <= last; i++) {
|
2013-08-16 10:22:32 +00:00
|
|
|
if (virBitmapSetBit(*bitmap, i) < 0)
|
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*cur == ',') {
|
|
|
|
cur++;
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
neg = false;
|
2013-01-23 14:18:09 +00:00
|
|
|
} else if (*cur == 0 || *cur == terminator) {
|
2012-09-14 07:46:57 +00:00
|
|
|
break;
|
|
|
|
} else {
|
2013-08-16 10:22:32 +00:00
|
|
|
goto error;
|
2012-09-14 07:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-17 12:11:55 +00:00
|
|
|
return 0;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
error:
|
2013-08-19 14:08:24 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Failed to parse bitmap '%s'"), str);
|
2012-09-14 07:46:57 +00:00
|
|
|
virBitmapFree(*bitmap);
|
|
|
|
*bitmap = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-06-17 12:38:11 +00:00
|
|
|
/**
|
|
|
|
* 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 0 on success, or -1 in case of error.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virBitmapParse(const char *str,
|
|
|
|
virBitmapPtr *bitmap,
|
|
|
|
size_t bitmapSize)
|
|
|
|
{
|
2016-06-17 12:56:45 +00:00
|
|
|
return virBitmapParseSeparator(str, '\0', bitmap, bitmapSize);
|
2016-06-17 12:38:11 +00:00
|
|
|
}
|
|
|
|
|
2016-06-17 13:12:02 +00:00
|
|
|
/**
|
|
|
|
* virBitmapParseUnlimited:
|
|
|
|
* @str: points to a string representing a human-readable bitmap
|
|
|
|
*
|
|
|
|
* This function is the counterpart of virBitmapFormat. This function creates
|
|
|
|
* a bitmap, in which bits are set according to the content of @str.
|
|
|
|
*
|
|
|
|
* The bitmap is expanded to accomodate all the bits.
|
|
|
|
*
|
|
|
|
* @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.
|
|
|
|
*
|
2017-03-22 13:39:53 +00:00
|
|
|
* Returns @bitmap on success, or NULL in case of error
|
2016-06-17 13:12:02 +00:00
|
|
|
*/
|
2017-03-22 13:39:53 +00:00
|
|
|
virBitmapPtr
|
|
|
|
virBitmapParseUnlimited(const char *str)
|
2016-06-17 13:12:02 +00:00
|
|
|
{
|
2017-03-22 13:39:53 +00:00
|
|
|
virBitmapPtr bitmap;
|
2016-06-17 13:12:02 +00:00
|
|
|
bool neg = false;
|
|
|
|
const char *cur = str;
|
|
|
|
char *tmp;
|
|
|
|
size_t i;
|
|
|
|
int start, last;
|
|
|
|
|
2017-03-22 13:39:53 +00:00
|
|
|
if (!(bitmap = virBitmapNewEmpty()))
|
|
|
|
return NULL;
|
2016-06-17 13:12:02 +00:00
|
|
|
|
|
|
|
if (!str)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
|
|
|
|
if (*cur == '\0')
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
while (*cur != 0) {
|
|
|
|
/*
|
|
|
|
* 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 error;
|
|
|
|
|
|
|
|
if (virStrToLong_i(cur, &tmp, 10, &start) < 0)
|
|
|
|
goto error;
|
|
|
|
if (start < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
cur = tmp;
|
|
|
|
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
|
|
|
|
if (*cur == ',' || *cur == 0) {
|
|
|
|
if (neg) {
|
2017-03-22 13:39:53 +00:00
|
|
|
if (virBitmapClearBitExpand(bitmap, start) < 0)
|
2016-06-17 13:12:02 +00:00
|
|
|
goto error;
|
|
|
|
} else {
|
2017-03-22 13:39:53 +00:00
|
|
|
if (virBitmapSetBitExpand(bitmap, start) < 0)
|
2016-06-17 13:12:02 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else if (*cur == '-') {
|
|
|
|
if (neg)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
cur++;
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
|
|
|
|
if (virStrToLong_i(cur, &tmp, 10, &last) < 0)
|
|
|
|
goto error;
|
|
|
|
if (last < start)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
cur = tmp;
|
|
|
|
|
|
|
|
for (i = start; i <= last; i++) {
|
2017-03-22 13:39:53 +00:00
|
|
|
if (virBitmapSetBitExpand(bitmap, i) < 0)
|
2016-06-17 13:12:02 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*cur == ',') {
|
|
|
|
cur++;
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
neg = false;
|
|
|
|
} else if (*cur == 0) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-22 13:39:53 +00:00
|
|
|
return bitmap;
|
2016-06-17 13:12:02 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
2017-03-21 17:51:11 +00:00
|
|
|
_("Failed to parse bitmap '%s'"), NULLSTR(str));
|
2017-03-22 13:39:53 +00:00
|
|
|
virBitmapFree(bitmap);
|
|
|
|
return NULL;
|
2016-06-17 13:12:02 +00:00
|
|
|
}
|
|
|
|
|
2012-09-14 07:46:57 +00:00
|
|
|
/**
|
|
|
|
* virBitmapNewCopy:
|
|
|
|
* @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 virBitmapNewCopy(virBitmapPtr src)
|
|
|
|
{
|
|
|
|
virBitmapPtr dst;
|
|
|
|
|
|
|
|
if ((dst = virBitmapNew(src->max_bit)) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (virBitmapCopy(dst, src) != 0) {
|
|
|
|
virBitmapFree(dst);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBitmapNewData:
|
|
|
|
* @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.
|
|
|
|
*/
|
2016-09-29 10:56:58 +00:00
|
|
|
virBitmapPtr virBitmapNewData(const void *data, int len)
|
2012-09-14 07:46:57 +00:00
|
|
|
{
|
|
|
|
virBitmapPtr bitmap;
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i, j;
|
2012-09-18 19:53:15 +00:00
|
|
|
unsigned long *p;
|
2016-09-29 10:56:58 +00:00
|
|
|
const unsigned char *bytes = data;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
|
|
|
bitmap = virBitmapNew(len * CHAR_BIT);
|
|
|
|
if (!bitmap)
|
|
|
|
return NULL;
|
|
|
|
|
2012-09-18 19:53:15 +00:00
|
|
|
/* le64toh is not provided by gnulib, so we do the conversion by hand */
|
|
|
|
p = bitmap->map;
|
|
|
|
for (i = j = 0; i < len; i++, j++) {
|
|
|
|
if (j == sizeof(*p)) {
|
|
|
|
j = 0;
|
|
|
|
p++;
|
|
|
|
}
|
2012-09-18 23:20:03 +00:00
|
|
|
*p |= (unsigned long) bytes[i] << (j * CHAR_BIT);
|
2012-09-18 19:53:15 +00:00
|
|
|
}
|
2012-09-14 07:46:57 +00:00
|
|
|
|
|
|
|
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
|
2015-05-21 16:25:36 +00:00
|
|
|
* lower bits. This function allocates @data.
|
2012-09-14 07:46:57 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 otherwise.
|
|
|
|
*/
|
|
|
|
int virBitmapToData(virBitmapPtr bitmap, unsigned char **data, int *dataLen)
|
|
|
|
{
|
2015-07-02 14:46:46 +00:00
|
|
|
ssize_t len;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
2015-07-02 14:46:46 +00:00
|
|
|
if ((len = virBitmapLastSetBit(bitmap)) < 0)
|
|
|
|
len = 1;
|
|
|
|
else
|
|
|
|
len = (len + CHAR_BIT) / CHAR_BIT;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC_N(*data, len) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*dataLen = len;
|
|
|
|
|
2015-05-21 16:25:36 +00:00
|
|
|
virBitmapToDataBuf(bitmap, *data, *dataLen);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBitmapToDataBuf:
|
|
|
|
* @bytes: pointer to memory to fill
|
|
|
|
* @len: len of @bytes in byte
|
|
|
|
*
|
|
|
|
* Convert a bitmap to a chunk of data containing bits information.
|
|
|
|
* Data consists of sequential bytes, with lower bytes containing
|
|
|
|
* lower bits.
|
|
|
|
*/
|
|
|
|
void virBitmapToDataBuf(virBitmapPtr bitmap,
|
|
|
|
unsigned char *bytes,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
unsigned long *l;
|
|
|
|
size_t i, j;
|
|
|
|
|
|
|
|
memset(bytes, 0, len);
|
|
|
|
|
2012-09-18 19:53:15 +00:00
|
|
|
/* htole64 is not provided by gnulib, so we do the conversion by hand */
|
|
|
|
l = bitmap->map;
|
|
|
|
for (i = j = 0; i < len; i++, j++) {
|
|
|
|
if (j == sizeof(*l)) {
|
|
|
|
j = 0;
|
|
|
|
l++;
|
|
|
|
}
|
|
|
|
bytes[i] = *l >> (j * CHAR_BIT);
|
|
|
|
}
|
2012-09-14 07:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-09-14 07:46:57 +00:00
|
|
|
|
2015-01-20 18:41:08 +00:00
|
|
|
if (!b1 && !b2)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!b1 || !b2)
|
|
|
|
return false;
|
|
|
|
|
2012-09-14 07:46:57 +00:00
|
|
|
if (b1->max_bit > b2->max_bit) {
|
|
|
|
tmp = b1;
|
|
|
|
b1 = b2;
|
|
|
|
b2 = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now b1 is the smaller one, if not equal */
|
|
|
|
|
|
|
|
for (i = 0; i < b1->map_len; i++) {
|
|
|
|
if (b1->map[i] != b2->map[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i < b2->map_len; i++) {
|
|
|
|
if (b2->map[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t virBitmapSize(virBitmapPtr bitmap)
|
|
|
|
{
|
|
|
|
return bitmap->max_bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBitmapSetAll:
|
|
|
|
* @bitmap: the bitmap
|
|
|
|
*
|
|
|
|
* set all bits in @bitmap.
|
|
|
|
*/
|
|
|
|
void virBitmapSetAll(virBitmapPtr bitmap)
|
|
|
|
{
|
2012-10-25 00:44:27 +00:00
|
|
|
int tail = bitmap->max_bit % VIR_BITMAP_BITS_PER_UNIT;
|
|
|
|
|
2012-09-14 07:46:57 +00:00
|
|
|
memset(bitmap->map, 0xff,
|
|
|
|
bitmap->map_len * (VIR_BITMAP_BITS_PER_UNIT / CHAR_BIT));
|
2012-10-25 00:44:27 +00:00
|
|
|
|
|
|
|
/* Ensure tail bits are clear. */
|
|
|
|
if (tail)
|
|
|
|
bitmap->map[bitmap->map_len - 1] &=
|
|
|
|
-1UL >> (VIR_BITMAP_BITS_PER_UNIT - tail);
|
2012-09-14 07:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBitmapClearAll:
|
|
|
|
* @bitmap: the bitmap
|
|
|
|
*
|
|
|
|
* clear all bits in @bitmap.
|
|
|
|
*/
|
|
|
|
void virBitmapClearAll(virBitmapPtr bitmap)
|
|
|
|
{
|
|
|
|
memset(bitmap->map, 0,
|
|
|
|
bitmap->map_len * (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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-09-14 07:46:57 +00:00
|
|
|
int unusedBits;
|
|
|
|
size_t sz;
|
|
|
|
|
|
|
|
unusedBits = bitmap->map_len * VIR_BITMAP_BITS_PER_UNIT - bitmap->max_bit;
|
|
|
|
|
|
|
|
sz = bitmap->map_len;
|
|
|
|
if (unusedBits > 0)
|
|
|
|
sz--;
|
|
|
|
|
|
|
|
for (i = 0; i < sz; i++)
|
|
|
|
if (bitmap->map[i] != -1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (unusedBits > 0) {
|
2012-11-28 06:15:38 +00:00
|
|
|
if ((bitmap->map[sz] & ((1UL << (VIR_BITMAP_BITS_PER_UNIT - unusedBits)) - 1))
|
|
|
|
!= ((1UL << (VIR_BITMAP_BITS_PER_UNIT - unusedBits)) - 1))
|
2012-09-14 07:46:57 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-05 18:06:16 +00:00
|
|
|
/**
|
|
|
|
* virBitmapIsAllClear:
|
|
|
|
* @bitmap: the bitmap to check
|
|
|
|
*
|
|
|
|
* check if all bits in @bitmap are clear
|
|
|
|
*/
|
|
|
|
bool virBitmapIsAllClear(virBitmapPtr bitmap)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-04-05 18:06:16 +00:00
|
|
|
|
|
|
|
for (i = 0; i < bitmap->map_len; i++)
|
|
|
|
if (bitmap->map[i] != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-09-14 07:46:57 +00:00
|
|
|
/**
|
|
|
|
* virBitmapNextSetBit:
|
|
|
|
* @bitmap: the bitmap
|
|
|
|
* @pos: the position after which to search for a set bit
|
|
|
|
*
|
2013-02-02 00:33:18 +00:00
|
|
|
* Search for the first set bit after position @pos in bitmap @bitmap.
|
2012-09-14 07:46:57 +00:00
|
|
|
* @pos can be -1 to search for the first set bit. Position starts
|
|
|
|
* at 0.
|
|
|
|
*
|
2013-02-02 00:33:18 +00:00
|
|
|
* Returns the position of the found bit, or -1 if no bit found.
|
2012-09-14 07:46:57 +00:00
|
|
|
*/
|
2013-02-02 00:33:18 +00:00
|
|
|
ssize_t
|
|
|
|
virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos)
|
2012-09-14 07:46:57 +00:00
|
|
|
{
|
2012-10-25 00:44:27 +00:00
|
|
|
size_t nl;
|
|
|
|
size_t nb;
|
2012-09-14 07:46:57 +00:00
|
|
|
unsigned long bits;
|
|
|
|
|
|
|
|
if (pos < 0)
|
|
|
|
pos = -1;
|
|
|
|
|
|
|
|
pos++;
|
|
|
|
|
|
|
|
if (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 << nb) - 1);
|
|
|
|
|
2014-11-13 14:28:18 +00:00
|
|
|
while (bits == 0 && ++nl < bitmap->map_len)
|
2012-09-14 07:46:57 +00:00
|
|
|
bits = bitmap->map[nl];
|
|
|
|
|
|
|
|
if (bits == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return ffsl(bits) - 1 + nl * VIR_BITMAP_BITS_PER_UNIT;
|
|
|
|
}
|
2012-10-25 00:44:27 +00:00
|
|
|
|
2014-11-04 02:44:39 +00:00
|
|
|
/**
|
|
|
|
* virBitmapLastSetBit:
|
|
|
|
* @bitmap: the bitmap
|
|
|
|
*
|
|
|
|
* Search for the last set bit in bitmap @bitmap.
|
|
|
|
*
|
|
|
|
* Returns the position of the found bit, or -1 if no bit is set.
|
|
|
|
*/
|
|
|
|
ssize_t
|
|
|
|
virBitmapLastSetBit(virBitmapPtr bitmap)
|
|
|
|
{
|
|
|
|
ssize_t i;
|
|
|
|
int unusedBits;
|
|
|
|
ssize_t sz;
|
2016-07-06 12:02:26 +00:00
|
|
|
unsigned long bits;
|
|
|
|
|
|
|
|
/* If bitmap is empty then there is no set bit */
|
|
|
|
if (bitmap->map_len == 0)
|
|
|
|
return -1;
|
2014-11-04 02:44:39 +00:00
|
|
|
|
|
|
|
unusedBits = bitmap->map_len * VIR_BITMAP_BITS_PER_UNIT - bitmap->max_bit;
|
|
|
|
|
|
|
|
sz = bitmap->map_len - 1;
|
|
|
|
if (unusedBits > 0) {
|
|
|
|
bits = bitmap->map[sz] & (VIR_BITMAP_BIT(VIR_BITMAP_BITS_PER_UNIT - unusedBits) - 1);
|
|
|
|
if (bits != 0)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
sz--;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; sz >= 0; sz--) {
|
|
|
|
bits = bitmap->map[sz];
|
|
|
|
if (bits != 0)
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
|
2016-07-06 12:02:26 +00:00
|
|
|
/* Only reached if no set bit was found */
|
|
|
|
return -1;
|
2014-11-04 02:44:39 +00:00
|
|
|
|
|
|
|
found:
|
|
|
|
for (i = VIR_BITMAP_BITS_PER_UNIT - 1; i >= 0; i--) {
|
|
|
|
if (bits & 1UL << i)
|
|
|
|
return i + sz * VIR_BITMAP_BITS_PER_UNIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-02-02 00:33:18 +00:00
|
|
|
/**
|
|
|
|
* virBitmapNextClearBit:
|
|
|
|
* @bitmap: the bitmap
|
|
|
|
* @pos: the position after which to search for a clear bit
|
|
|
|
*
|
|
|
|
* Search for the first clear bit after position @pos in bitmap @bitmap.
|
|
|
|
* @pos can be -1 to search for the first set bit. Position starts
|
|
|
|
* at 0.
|
|
|
|
*
|
|
|
|
* Returns the position of the found bit, or -1 if no bit found.
|
|
|
|
*/
|
|
|
|
ssize_t
|
|
|
|
virBitmapNextClearBit(virBitmapPtr bitmap, ssize_t pos)
|
|
|
|
{
|
|
|
|
size_t nl;
|
|
|
|
size_t nb;
|
|
|
|
unsigned long bits;
|
|
|
|
|
|
|
|
if (pos < 0)
|
|
|
|
pos = -1;
|
|
|
|
|
|
|
|
pos++;
|
|
|
|
|
|
|
|
if (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 << nb) - 1);
|
|
|
|
|
2014-11-13 14:28:18 +00:00
|
|
|
while (bits == 0 && ++nl < bitmap->map_len)
|
2013-02-02 00:33:18 +00:00
|
|
|
bits = ~bitmap->map[nl];
|
|
|
|
|
|
|
|
if (nl == bitmap->map_len - 1) {
|
|
|
|
/* Ensure tail bits are ignored. */
|
|
|
|
int tail = bitmap->max_bit % VIR_BITMAP_BITS_PER_UNIT;
|
|
|
|
|
|
|
|
if (tail)
|
|
|
|
bits &= -1UL >> (VIR_BITMAP_BITS_PER_UNIT - tail);
|
|
|
|
}
|
|
|
|
if (bits == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return ffsl(bits) - 1 + nl * VIR_BITMAP_BITS_PER_UNIT;
|
|
|
|
}
|
|
|
|
|
2012-10-25 00:44:27 +00:00
|
|
|
/* Return the number of bits currently set in the map. */
|
|
|
|
size_t
|
|
|
|
virBitmapCountBits(virBitmapPtr bitmap)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
size_t ret = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < bitmap->map_len; i++)
|
|
|
|
ret += count_one_bits_l(bitmap->map[i]);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2014-06-05 09:23:28 +00:00
|
|
|
|
2017-08-23 07:12:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virBitmapNewString:
|
|
|
|
* @string: the string to be converted to a bitmap
|
|
|
|
*
|
|
|
|
* Allocate a bitmap from a string of hexadecimal data.
|
|
|
|
*
|
|
|
|
* Returns a pointer to the allocated bitmap or NULL if
|
|
|
|
* memory cannot be allocated.
|
|
|
|
*/
|
|
|
|
virBitmapPtr
|
|
|
|
virBitmapNewString(const char *string)
|
|
|
|
{
|
|
|
|
virBitmapPtr bitmap;
|
|
|
|
size_t i = 0;
|
|
|
|
size_t len = strlen(string);
|
|
|
|
|
|
|
|
if (strspn(string, "0123456789abcdefABCDEF") != len) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Invalid hexadecimal string '%s'"), string);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bitmap = virBitmapNew(len * 4);
|
|
|
|
if (!bitmap)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
unsigned long nibble = virHexToBin(string[len - i - 1]);
|
|
|
|
nibble <<= VIR_BITMAP_BIT_OFFSET(i * 4);
|
|
|
|
bitmap->map[VIR_BITMAP_UNIT_OFFSET(i * 4)] |= nibble;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bitmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-05 09:23:28 +00:00
|
|
|
/**
|
2017-08-23 07:05:41 +00:00
|
|
|
* virBitmapDataFormat:
|
2014-06-05 09:23:28 +00:00
|
|
|
* @data: the data
|
|
|
|
* @len: length of @data in bytes
|
|
|
|
*
|
|
|
|
* Convert a chunk of data containing bits information to a human
|
|
|
|
* readable string, e.g.: 0-1,4
|
|
|
|
*
|
|
|
|
* Returns: a string representation of the data, or NULL on error
|
|
|
|
*/
|
|
|
|
char *
|
2017-08-23 07:05:41 +00:00
|
|
|
virBitmapDataFormat(const void *data,
|
|
|
|
int len)
|
2014-06-05 09:23:28 +00:00
|
|
|
{
|
|
|
|
virBitmapPtr map = NULL;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (!(map = virBitmapNewData(data, len)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ret = virBitmapFormat(map);
|
|
|
|
virBitmapFree(map);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-07-23 15:37:19 +00:00
|
|
|
|
|
|
|
bool
|
|
|
|
virBitmapOverlaps(virBitmapPtr b1,
|
|
|
|
virBitmapPtr b2)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (b1->max_bit > b2->max_bit) {
|
|
|
|
virBitmapPtr tmp = b1;
|
|
|
|
b1 = b2;
|
|
|
|
b2 = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < b1->map_len; i++) {
|
|
|
|
if (b1->map[i] & b2->map[i])
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2016-01-07 14:45:39 +00:00
|
|
|
|
|
|
|
/**
|
2017-07-12 11:30:47 +00:00
|
|
|
* virBitmapIntersect:
|
|
|
|
* @a: bitmap, modified to contain result
|
|
|
|
* @b: bitmap
|
2016-01-07 14:45:39 +00:00
|
|
|
*
|
2017-07-12 11:30:47 +00:00
|
|
|
* Performs intersection of two bitmaps: a = intersect(a, b)
|
2016-01-07 14:45:39 +00:00
|
|
|
*/
|
|
|
|
void
|
2017-07-12 11:30:47 +00:00
|
|
|
virBitmapIntersect(virBitmapPtr a,
|
|
|
|
virBitmapPtr b)
|
2016-01-07 14:45:39 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
size_t max = a->map_len;
|
|
|
|
|
|
|
|
if (max > b->map_len)
|
|
|
|
max = b->map_len;
|
|
|
|
|
|
|
|
for (i = 0; i < max; i++)
|
2017-07-12 11:30:47 +00:00
|
|
|
a->map[i] &= b->map[i];
|
2016-01-07 14:45:39 +00:00
|
|
|
}
|
2017-10-05 13:09:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBitmapSubtract:
|
|
|
|
* @a: minuend/result
|
|
|
|
* @b: subtrahend
|
|
|
|
*
|
|
|
|
* Performs subtraction of two bitmaps: a = a - b
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBitmapSubtract(virBitmapPtr a,
|
|
|
|
virBitmapPtr b)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
size_t max = a->map_len;
|
|
|
|
|
|
|
|
if (max > b->map_len)
|
|
|
|
max = b->map_len;
|
|
|
|
|
|
|
|
for (i = 0; i < max; i++)
|
|
|
|
a->map[i] &= ~b->map[i];
|
|
|
|
}
|
2017-11-09 15:12:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBitmapShrink:
|
|
|
|
* @map: Pointer to bitmap
|
|
|
|
* @b: last bit position to be excluded from bitmap
|
|
|
|
*
|
|
|
|
* Resizes the bitmap so that no more than @b bits will fit into it. Nothing
|
|
|
|
* will change if the size is already smaller than @b.
|
|
|
|
*
|
|
|
|
* NB: Does not adjust the map->map_len so that a subsequent virBitmapExpand
|
|
|
|
* doesn't necessarily need to reallocate.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBitmapShrink(virBitmapPtr map,
|
|
|
|
size_t b)
|
|
|
|
{
|
|
|
|
if (!map)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (map->max_bit >= b)
|
|
|
|
map->max_bit = b;
|
|
|
|
}
|