Commit f591ef48 authored by David Gibson's avatar David Gibson Committed by Rusty Russell

bitmap: Implement bitmap_ffs()

This adds a bitmap_ffs() function to find the first (by the usual bitmap
bit ordering) 1 bit in a bitmap between two given bits.
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent b9c9f5d9
...@@ -58,3 +58,68 @@ void bitmap_fill_range(bitmap *bitmap, unsigned long n, unsigned long m) ...@@ -58,3 +58,68 @@ void bitmap_fill_range(bitmap *bitmap, unsigned long n, unsigned long m)
if (m > am) if (m > am)
BITMAP_WORD(bitmap, m) |= bitmap_bswap(tailmask); BITMAP_WORD(bitmap, m) |= bitmap_bswap(tailmask);
} }
static int bitmap_clz(bitmap_word w)
{
#if HAVE_BUILTIN_CLZL
return __builtin_clzl(w);
#else
int lz = 0;
bitmap_word mask = 1UL << (BITMAP_WORD_BITS - 1);
while (!(w & mask)) {
lz++;
mask >>= 1;
}
return lz;
#endif
}
unsigned long bitmap_ffs(const bitmap *bitmap,
unsigned long n, unsigned long m)
{
unsigned long an = BIT_ALIGN_UP(n);
unsigned long am = BIT_ALIGN_DOWN(m);
bitmap_word headmask = -1ULL >> (n % BITMAP_WORD_BITS);
bitmap_word tailmask = ~(-1ULL >> (m % BITMAP_WORD_BITS));
assert(m >= n);
if (am < an) {
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, n));
w &= (headmask & tailmask);
return w ? am + bitmap_clz(w) : m;
}
if (an > n) {
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, n));
w &= headmask;
if (w)
return BIT_ALIGN_DOWN(n) + bitmap_clz(w);
}
while (an < am) {
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, an));
if (w)
return an + bitmap_clz(w);
an += BITMAP_WORD_BITS;
}
if (m > am) {
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, m));
w &= tailmask;
if (w)
return am + bitmap_clz(w);
}
return m;
}
...@@ -187,6 +187,9 @@ static inline bool bitmap_empty(const bitmap *bitmap, unsigned long nbits) ...@@ -187,6 +187,9 @@ static inline bool bitmap_empty(const bitmap *bitmap, unsigned long nbits)
return true; return true;
} }
unsigned long bitmap_ffs(const bitmap *bitmap,
unsigned long n, unsigned long m);
/* /*
* Allocation functions * Allocation functions
*/ */
......
#include <ccan/bitmap/bitmap.h>
#include <ccan/tap/tap.h>
#include <ccan/array_size/array_size.h>
#include <ccan/foreach/foreach.h>
#include <ccan/bitmap/bitmap.c>
int bitmap_sizes[] = {
1, 2, 3, 4, 5, 6, 7, 8,
16, 17, 24, 32, 33,
64, 65, 127, 128, 129,
1023, 1024, 1025,
};
#define NSIZES ARRAY_SIZE(bitmap_sizes)
#define ok_eq(a, b) \
ok((a) == (b), "%s [%u] == %s [%u]", \
#a, (unsigned)(a), #b, (unsigned)(b))
static void test_size(int nbits)
{
BITMAP_DECLARE(bitmap, nbits);
int i;
bitmap_zero(bitmap, nbits);
ok_eq(bitmap_ffs(bitmap, 0, nbits), nbits);
for (i = 0; i < nbits; i++) {
bitmap_zero(bitmap, nbits);
bitmap_set_bit(bitmap, i);
ok_eq(bitmap_ffs(bitmap, 0, nbits), i);
ok_eq(bitmap_ffs(bitmap, i, nbits), i);
ok_eq(bitmap_ffs(bitmap, i + 1, nbits), nbits);
bitmap_zero(bitmap, nbits);
bitmap_fill_range(bitmap, i, nbits);
ok_eq(bitmap_ffs(bitmap, 0, nbits), i);
ok_eq(bitmap_ffs(bitmap, i, nbits), i);
ok_eq(bitmap_ffs(bitmap, i + 1, nbits), (i + 1));
ok_eq(bitmap_ffs(bitmap, nbits - 1, nbits), (nbits - 1));
if (i > 0) {
ok_eq(bitmap_ffs(bitmap, 0, i), i);
ok_eq(bitmap_ffs(bitmap, 0, i - 1), (i - 1));
}
if (i > 0) {
bitmap_zero(bitmap, nbits);
bitmap_fill_range(bitmap, 0, i);
ok_eq(bitmap_ffs(bitmap, 0, nbits), 0);
ok_eq(bitmap_ffs(bitmap, i - 1, nbits), (i - 1));
ok_eq(bitmap_ffs(bitmap, i, nbits), nbits);
}
}
}
int main(void)
{
int i;
/* Too complicated to work out the exact number */
plan_no_plan();
for (i = 0; i < NSIZES; i++) {
diag("Testing %d-bit bitmap", bitmap_sizes[i]);
test_size(bitmap_sizes[i]);
}
/* This exits depending on whether all tests passed */
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment