You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ravi/mir/mir-bitmap.h

336 lines
10 KiB

/* This file is a part of MIR project.
Copyright (C) 2018-2021 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
#ifndef MIR_BITMAP_H
#define MIR_BITMAP_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <limits.h>
#include "mir-varr.h"
#define FALSE 0
#define TRUE 1
#if !defined(BITMAP_ENABLE_CHECKING) && !defined(NDEBUG)
#define BITMAP_ENABLE_CHECKING
#endif
#ifndef BITMAP_ENABLE_CHECKING
#define BITMAP_ASSERT(EXPR, OP) ((void) (EXPR))
#else
static inline void mir_bitmap_assert_fail (const char *op) {
fprintf (stderr, "wrong %s for a bitmap", op);
assert (0);
}
#define BITMAP_ASSERT(EXPR, OP) (void) ((EXPR) ? 0 : (mir_bitmap_assert_fail (#OP), 0))
#endif
#define BITMAP_WORD_BITS 64
typedef uint64_t bitmap_el_t;
DEF_VARR (bitmap_el_t);
typedef VARR (bitmap_el_t) * bitmap_t;
typedef const VARR (bitmap_el_t) * const_bitmap_t;
static inline bitmap_t bitmap_create2 (size_t init_bits_num) {
bitmap_t bm;
VARR_CREATE (bitmap_el_t, bm, (init_bits_num + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS);
return bm;
}
static inline bitmap_t bitmap_create (void) { return bitmap_create2 (0); }
static inline void bitmap_destroy (bitmap_t bm) { VARR_DESTROY (bitmap_el_t, bm); }
static inline void bitmap_clear (bitmap_t bm) { VARR_TRUNC (bitmap_el_t, bm, 0); }
static inline void bitmap_expand (bitmap_t bm, size_t nb) {
size_t i, len = VARR_LENGTH (bitmap_el_t, bm);
size_t new_len = (nb + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS;
for (i = len; i < new_len; i++) VARR_PUSH (bitmap_el_t, bm, (bitmap_el_t) 0);
}
static inline int bitmap_bit_p (const_bitmap_t bm, size_t nb) {
size_t nw, sh, len = VARR_LENGTH (bitmap_el_t, bm);
bitmap_el_t *addr = VARR_ADDR (bitmap_el_t, bm);
if (nb >= BITMAP_WORD_BITS * len) return 0;
nw = nb / BITMAP_WORD_BITS;
sh = nb % BITMAP_WORD_BITS;
return (addr[nw] >> sh) & 1;
}
static inline int bitmap_set_bit_p (bitmap_t bm, size_t nb) {
size_t nw, sh;
bitmap_el_t *addr;
int res;
bitmap_expand (bm, nb + 1);
addr = VARR_ADDR (bitmap_el_t, bm);
nw = nb / BITMAP_WORD_BITS;
sh = nb % BITMAP_WORD_BITS;
res = ((addr[nw] >> sh) & 1) == 0;
addr[nw] |= (bitmap_el_t) 1 << sh;
return res;
}
static inline int bitmap_clear_bit_p (bitmap_t bm, size_t nb) {
size_t nw, sh, len = VARR_LENGTH (bitmap_el_t, bm);
bitmap_el_t *addr = VARR_ADDR (bitmap_el_t, bm);
int res;
if (nb >= BITMAP_WORD_BITS * len) return 0;
nw = nb / BITMAP_WORD_BITS;
sh = nb % BITMAP_WORD_BITS;
res = (addr[nw] >> sh) & 1;
addr[nw] &= ~((bitmap_el_t) 1 << sh);
return res;
}
static inline int bitmap_set_or_clear_bit_range_p (bitmap_t bm, size_t nb, size_t len, int set_p) {
size_t nw, lsh, rsh, range_len;
bitmap_el_t mask, *addr;
int res = 0;
bitmap_expand (bm, nb + len);
addr = VARR_ADDR (bitmap_el_t, bm);
while (len > 0) {
nw = nb / BITMAP_WORD_BITS;
lsh = nb % BITMAP_WORD_BITS;
rsh = len >= BITMAP_WORD_BITS - lsh ? 0 : BITMAP_WORD_BITS - (nb + len) % BITMAP_WORD_BITS;
mask = ((~(bitmap_el_t) 0) >> (rsh + lsh)) << lsh;
if (set_p) {
res |= (~addr[nw] & mask) != 0;
addr[nw] |= mask;
} else {
res |= (addr[nw] & mask) != 0;
addr[nw] &= ~mask;
}
range_len = BITMAP_WORD_BITS - rsh - lsh;
len -= range_len;
nb += range_len;
}
return res;
}
static inline int bitmap_set_bit_range_p (bitmap_t bm, size_t nb, size_t len) {
return bitmap_set_or_clear_bit_range_p (bm, nb, len, TRUE);
}
static inline int bitmap_clear_bit_range_p (bitmap_t bm, size_t nb, size_t len) {
return bitmap_set_or_clear_bit_range_p (bm, nb, len, FALSE);
}
static inline void bitmap_copy (bitmap_t dst, const_bitmap_t src) {
size_t dst_len = VARR_LENGTH (bitmap_el_t, dst);
size_t src_len = VARR_LENGTH (bitmap_el_t, src);
if (dst_len >= src_len)
VARR_TRUNC (bitmap_el_t, dst, src_len);
else
bitmap_expand (dst, src_len * BITMAP_WORD_BITS);
memcpy (VARR_ADDR (bitmap_el_t, dst), VARR_ADDR (bitmap_el_t, src),
src_len * sizeof (bitmap_el_t));
}
static inline int bitmap_equal_p (const_bitmap_t bm1, const_bitmap_t bm2) {
const_bitmap_t temp_bm;
size_t i, temp_len, bm1_len = VARR_LENGTH (bitmap_el_t, bm1);
size_t bm2_len = VARR_LENGTH (bitmap_el_t, bm2);
bitmap_el_t *addr1, *addr2;
if (bm1_len > bm2_len) {
temp_bm = bm1;
bm1 = bm2;
bm2 = temp_bm;
temp_len = bm1_len;
bm1_len = bm2_len;
bm2_len = temp_len;
}
addr1 = VARR_ADDR (bitmap_el_t, bm1);
addr2 = VARR_ADDR (bitmap_el_t, bm2);
if (memcmp (addr1, addr2, bm1_len * sizeof (bitmap_el_t)) != 0) return FALSE;
for (i = bm1_len; i < bm2_len; i++)
if (addr2[i] != 0) return FALSE;
return TRUE;
}
static inline int bitmap_intersect_p (const_bitmap_t bm1, const_bitmap_t bm2) {
size_t i, min_len, bm1_len = VARR_LENGTH (bitmap_el_t, bm1);
size_t bm2_len = VARR_LENGTH (bitmap_el_t, bm2);
bitmap_el_t *addr1 = VARR_ADDR (bitmap_el_t, bm1);
bitmap_el_t *addr2 = VARR_ADDR (bitmap_el_t, bm2);
min_len = bm1_len <= bm2_len ? bm1_len : bm2_len;
for (i = 0; i < min_len; i++)
if ((addr1[i] & addr2[i]) != 0) return TRUE;
return FALSE;
}
static inline int bitmap_empty_p (const_bitmap_t bm) {
size_t i, len = VARR_LENGTH (bitmap_el_t, bm);
bitmap_el_t *addr = VARR_ADDR (bitmap_el_t, bm);
for (i = 0; i < len; i++)
if (addr[i] != 0) return FALSE;
return TRUE;
}
static inline bitmap_el_t bitmap_el_max2 (bitmap_el_t el1, bitmap_el_t el2) {
return el1 < el2 ? el2 : el1;
}
static inline bitmap_el_t bitmap_el_max3 (bitmap_el_t el1, bitmap_el_t el2, bitmap_el_t el3) {
if (el1 <= el2) return el2 < el3 ? el3 : el2;
return el1 < el3 ? el3 : el1;
}
/* Return the number of bits set in BM. */
static inline size_t bitmap_bit_count (const_bitmap_t bm) {
size_t i, len = VARR_LENGTH (bitmap_el_t, bm);
bitmap_el_t el, *addr = VARR_ADDR (bitmap_el_t, bm);
size_t count = 0;
for (i = 0; i < len; i++) {
if ((el = addr[i]) != 0) {
for (; el != 0; el >>= 1)
if (el & 1) count++;
}
}
return count;
}
static inline int bitmap_op2 (bitmap_t dst, const_bitmap_t src1, const_bitmap_t src2,
bitmap_el_t (*op) (bitmap_el_t, bitmap_el_t)) {
size_t i, len, bound, src1_len, src2_len;
bitmap_el_t old, *dst_addr, *src1_addr, *src2_addr;
int change_p = FALSE;
src1_len = VARR_LENGTH (bitmap_el_t, src1);
src2_len = VARR_LENGTH (bitmap_el_t, src2);
len = bitmap_el_max2 (src1_len, src2_len);
bitmap_expand (dst, len * BITMAP_WORD_BITS);
dst_addr = VARR_ADDR (bitmap_el_t, dst);
src1_addr = VARR_ADDR (bitmap_el_t, src1);
src2_addr = VARR_ADDR (bitmap_el_t, src2);
for (bound = i = 0; i < len; i++) {
old = dst_addr[i];
if ((dst_addr[i] = op (i >= src1_len ? 0 : src1_addr[i], i >= src2_len ? 0 : src2_addr[i]))
!= 0)
bound = i + 1;
if (old != dst_addr[i]) change_p = TRUE;
}
VARR_TRUNC (bitmap_el_t, dst, bound);
return change_p;
}
static inline bitmap_el_t bitmap_el_and (bitmap_el_t el1, bitmap_el_t el2) { return el1 & el2; }
static inline int bitmap_and (bitmap_t dst, bitmap_t src1, bitmap_t src2) {
return bitmap_op2 (dst, src1, src2, bitmap_el_and);
}
static inline bitmap_el_t bitmap_el_and_compl (bitmap_el_t el1, bitmap_el_t el2) {
return el1 & ~el2;
}
static inline int bitmap_and_compl (bitmap_t dst, bitmap_t src1, bitmap_t src2) {
return bitmap_op2 (dst, src1, src2, bitmap_el_and_compl);
}
static inline bitmap_el_t bitmap_el_ior (bitmap_el_t el1, bitmap_el_t el2) { return el1 | el2; }
static inline int bitmap_ior (bitmap_t dst, bitmap_t src1, bitmap_t src2) {
return bitmap_op2 (dst, src1, src2, bitmap_el_ior);
}
static inline int bitmap_op3 (bitmap_t dst, const_bitmap_t src1, const_bitmap_t src2,
const_bitmap_t src3,
bitmap_el_t (*op) (bitmap_el_t, bitmap_el_t, bitmap_el_t)) {
size_t i, len, bound, src1_len, src2_len, src3_len;
bitmap_el_t old, *dst_addr, *src1_addr, *src2_addr, *src3_addr;
int change_p = FALSE;
src1_len = VARR_LENGTH (bitmap_el_t, src1);
src2_len = VARR_LENGTH (bitmap_el_t, src2);
src3_len = VARR_LENGTH (bitmap_el_t, src3);
len = bitmap_el_max3 (src1_len, src2_len, src3_len);
bitmap_expand (dst, len * BITMAP_WORD_BITS);
dst_addr = VARR_ADDR (bitmap_el_t, dst);
src1_addr = VARR_ADDR (bitmap_el_t, src1);
src2_addr = VARR_ADDR (bitmap_el_t, src2);
src3_addr = VARR_ADDR (bitmap_el_t, src3);
for (bound = i = 0; i < len; i++) {
old = dst_addr[i];
if ((dst_addr[i] = op (i >= src1_len ? 0 : src1_addr[i], i >= src2_len ? 0 : src2_addr[i],
i >= src3_len ? 0 : src3_addr[i]))
!= 0)
bound = i + 1;
if (old != dst_addr[i]) change_p = TRUE;
}
VARR_TRUNC (bitmap_el_t, dst, bound);
return change_p;
}
static inline bitmap_el_t bitmap_el_ior_and (bitmap_el_t el1, bitmap_el_t el2, bitmap_el_t el3) {
return el1 | (el2 & el3);
}
/* DST = SRC1 | (SRC2 & SRC3). Return true if DST changed. */
static inline int bitmap_ior_and (bitmap_t dst, bitmap_t src1, bitmap_t src2, bitmap_t src3) {
return bitmap_op3 (dst, src1, src2, src3, bitmap_el_ior_and);
}
static inline bitmap_el_t bitmap_el_ior_and_compl (bitmap_el_t el1, bitmap_el_t el2,
bitmap_el_t el3) {
return el1 | (el2 & ~el3);
}
/* DST = SRC1 | (SRC2 & ~SRC3). Return true if DST changed. */
static inline int bitmap_ior_and_compl (bitmap_t dst, bitmap_t src1, bitmap_t src2, bitmap_t src3) {
return bitmap_op3 (dst, src1, src2, src3, bitmap_el_ior_and_compl);
}
typedef struct {
bitmap_t bitmap;
size_t nbit;
} bitmap_iterator_t;
static inline void bitmap_iterator_init (bitmap_iterator_t *iter, bitmap_t bitmap) {
iter->bitmap = bitmap;
iter->nbit = 0;
}
static inline int bitmap_iterator_next (bitmap_iterator_t *iter, size_t *nbit) {
const size_t el_bits_num = sizeof (bitmap_el_t) * CHAR_BIT;
size_t curr_nel = iter->nbit / el_bits_num, len = VARR_LENGTH (bitmap_el_t, iter->bitmap);
bitmap_el_t el, *addr = VARR_ADDR (bitmap_el_t, iter->bitmap);
for (; curr_nel < len; curr_nel++, iter->nbit = curr_nel * el_bits_num)
if ((el = addr[curr_nel]) != 0)
for (el >>= iter->nbit % el_bits_num; el != 0; el >>= 1, iter->nbit++)
if (el & 1) {
*nbit = iter->nbit++;
return TRUE;
}
return FALSE;
}
#define FOREACH_BITMAP_BIT(iter, bitmap, nbit) \
for (bitmap_iterator_init (&iter, bitmap); bitmap_iterator_next (&iter, &nbit);)
#endif /* #ifndef MIR_BITMAP_H */