diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index 550d7ce2c397ca1a61cff78ce690edfe54e2f6a4..6cb2d0e6a7daa934bed4a22fb2c75983397d4775 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -64,6 +64,19 @@ struct HBitmapIter { */ HBitmap *hbitmap_alloc(uint64_t size, int granularity); +/** + * hbitmap_merge: + * @a: The bitmap to store the result in. + * @b: The bitmap to merge into @a. + * @return true if the merge was successful, + * false if it was not attempted. + * + * Merge two bitmaps together. + * A := A (BITOR) B. + * B is left unmodified. + */ +bool hbitmap_merge(HBitmap *a, const HBitmap *b); + /** * hbitmap_empty: * @hb: HBitmap to operate on. diff --git a/util/hbitmap.c b/util/hbitmap.c index 5b786134007b42a4752a060849e421aed92f6c7c..150d6e98b78cf75392edd7d83c78a59dea0ddcdc 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -399,3 +399,36 @@ HBitmap *hbitmap_alloc(uint64_t size, int granularity) hb->levels[0][0] |= 1UL << (BITS_PER_LONG - 1); return hb; } + +/** + * Given HBitmaps A and B, let A := A (BITOR) B. + * Bitmap B will not be modified. + * + * @return true if the merge was successful, + * false if it was not attempted. + */ +bool hbitmap_merge(HBitmap *a, const HBitmap *b) +{ + int i; + uint64_t j; + + if ((a->size != b->size) || (a->granularity != b->granularity)) { + return false; + } + + if (hbitmap_count(b) == 0) { + return true; + } + + /* This merge is O(size), as BITS_PER_LONG and HBITMAP_LEVELS are constant. + * It may be possible to improve running times for sparsely populated maps + * by using hbitmap_iter_next, but this is suboptimal for dense maps. + */ + for (i = HBITMAP_LEVELS - 1; i >= 0; i--) { + for (j = 0; j < a->sizes[i]; j++) { + a->levels[i][j] |= b->levels[i][j]; + } + } + + return true; +}