| /* Licensed under LGPLv2.1+ - see LICENSE file for details */ |
| |
| #include "config.h" |
| |
| #include <ccan/bitmap.h> |
| |
| #include <assert.h> |
| |
| #define BIT_ALIGN_DOWN(n) ((n) & ~(BITMAP_WORD_BITS - 1)) |
| #define BIT_ALIGN_UP(n) BIT_ALIGN_DOWN((n) + BITMAP_WORD_BITS - 1) |
| |
| void bitmap_zero_range(bitmap *bmap, 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(bmap, n) &= ~bitmap_bswap(headmask & tailmask); |
| return; |
| } |
| |
| if (an > n) |
| BITMAP_WORD(bmap, n) &= ~bitmap_bswap(headmask); |
| |
| if (am > an) |
| memset(&BITMAP_WORD(bmap, an), 0, |
| (am - an) / BITMAP_WORD_BITS * sizeof(bitmap_word)); |
| |
| if (m > am) |
| BITMAP_WORD(bmap, m) &= ~bitmap_bswap(tailmask); |
| } |
| |
| void bitmap_fill_range(bitmap *bmap, 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(bmap, n) |= bitmap_bswap(headmask & tailmask); |
| return; |
| } |
| |
| if (an > n) |
| BITMAP_WORD(bmap, n) |= bitmap_bswap(headmask); |
| |
| if (am > an) |
| memset(&BITMAP_WORD(bmap, an), 0xff, |
| (am - an) / BITMAP_WORD_BITS * sizeof(bitmap_word)); |
| |
| if (m > am) |
| BITMAP_WORD(bmap, 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 *bmap, |
| 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(bmap, n)); |
| |
| w &= (headmask & tailmask); |
| |
| return w ? am + bitmap_clz(w) : m; |
| } |
| |
| if (an > n) { |
| bitmap_word w = bitmap_bswap(BITMAP_WORD(bmap, n)); |
| |
| w &= headmask; |
| |
| if (w) |
| return BIT_ALIGN_DOWN(n) + bitmap_clz(w); |
| } |
| |
| while (an < am) { |
| bitmap_word w = bitmap_bswap(BITMAP_WORD(bmap, an)); |
| |
| if (w) |
| return an + bitmap_clz(w); |
| |
| an += BITMAP_WORD_BITS; |
| } |
| |
| if (m > am) { |
| bitmap_word w = bitmap_bswap(BITMAP_WORD(bmap, m)); |
| |
| w &= tailmask; |
| |
| if (w) |
| return am + bitmap_clz(w); |
| } |
| |
| return m; |
| } |