#ifndef UCS_BITMAP_H_
#define UCS_BITMAP_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ucs/arch/bitops.h>
#include <ucs/sys/compiler_def.h>
#include <ucs/debug/assert.h>
#include <ucs/sys/preprocessor.h>
BEGIN_C_DECLS
typedef uint64_t ucs_bitmap_word_t;
#define UCS_BITMAP_BITS_IN_WORD \
(sizeof(ucs_bitmap_word_t) * 8)
#define UCS_BITMAP_WORD_MASK \
(~((ucs_bitmap_word_t)0))
#define _UCS_BITMAP_NUM_WORDS(_bitmap) ucs_static_array_size((_bitmap).bits)
#define UCS_BITMAP_NUM_BITS(_bitmap) \
(_UCS_BITMAP_NUM_WORDS(_bitmap) * UCS_BITMAP_BITS_IN_WORD)
#define UCS_BITMAP_WORD_INDEX(_bitmap, _bit_index) \
_ucs_bitmap_word_index(_UCS_BITMAP_NUM_WORDS(_bitmap), (_bit_index))
static UCS_F_ALWAYS_INLINE size_t
_ucs_bitmap_word_index(size_t bitmap_words, size_t bit_index)
{
ucs_assert(bit_index < (bitmap_words * UCS_BITMAP_BITS_IN_WORD));
return bit_index / UCS_BITMAP_BITS_IN_WORD;
}
#define _UCS_BITMAP_BIT_IN_WORD_INDEX(_bit_index) \
((_bit_index) % UCS_BITMAP_BITS_IN_WORD)
#define _UCS_BITMAP_BITS_TO_WORDS(_length) \
((((_length) + (UCS_BITMAP_BITS_IN_WORD - 1)) / UCS_BITMAP_BITS_IN_WORD))
#define _UCS_BITMAP_BIT_INDEX(_bit_in_word_index, _word_index) \
((_word_index) * UCS_BITMAP_BITS_IN_WORD + (_bit_in_word_index))
#define _UCS_BITMAP_WORD(_bitmap, _word_index) ((_bitmap).bits[_word_index])
#define _UCS_BITMAP_INDEX_IN_BOUNDS_CONDITION(_bitmap, _bit_index) \
((_bit_index) < _UCS_BITMAP_NUM_WORDS(_bitmap) * UCS_BITMAP_BITS_IN_WORD)
#define _UCS_BITMAP_WORD_BY_BIT(_bitmap, _bit_index) \
_UCS_BITMAP_WORD((_bitmap), UCS_BITMAP_WORD_INDEX(_bitmap, _bit_index))
#define _UCS_BITMAP_WORD_INDEX0(_bit_index) \
((_bit_index) & ~(UCS_BITMAP_BITS_IN_WORD - 1))
#define _UCS_BITMAP_GET_NEXT_BIT(_bit_index) \
(-2ull << (uint64_t)((_bit_index) & (UCS_BITMAP_BITS_IN_WORD - 1)))
#define _UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) \
for (_word_index = 0; _word_index < _UCS_BITMAP_NUM_WORDS(_bitmap); \
_word_index++)
#define UCS_BITMAP_IS_ZERO_INPLACE(_bitmap) \
ucs_bitmap_is_zero((_bitmap), _UCS_BITMAP_NUM_WORDS(*(_bitmap)))
#define UCS_BITMAP_NOT_INPLACE(_bitmap) \
{ \
size_t _word_index; \
_UCS_BITMAP_FOR_EACH_WORD(*(_bitmap), _word_index) { \
_UCS_BITMAP_WORD(*(_bitmap), _word_index) = \
~_UCS_BITMAP_WORD(*(_bitmap), _word_index); \
} \
}
#define _UCS_BITMAP_OP_INPLACE(_bitmap1, _bitmap2, _op) \
{ \
ucs_typeof(*(_bitmap1)) _bitmap2_copy = (_bitmap2); \
size_t _word_index; \
_UCS_BITMAP_FOR_EACH_WORD(*(_bitmap1), _word_index) { \
_UCS_BITMAP_WORD(*(_bitmap1), _word_index) = \
_UCS_BITMAP_WORD(*(_bitmap1), _word_index) _op \
_UCS_BITMAP_WORD(_bitmap2_copy, _word_index); \
} \
}
#define UCS_BITMAP_AND_INPLACE(_bitmap1, _bitmap2) \
_UCS_BITMAP_OP_INPLACE(_bitmap1, _bitmap2, &)
#define UCS_BITMAP_OR_INPLACE(_bitmap1, _bitmap2) \
_UCS_BITMAP_OP_INPLACE(_bitmap1, _bitmap2, |)
#define UCS_BITMAP_XOR_INPLACE(_bitmap1, _bitmap2) \
_UCS_BITMAP_OP_INPLACE(_bitmap1, _bitmap2, ^)
#define UCS_BITMAP_IS_ZERO(_bitmap, _length) \
UCS_PP_TOKENPASTE3(_ucs_bitmap_, _length, _is_zero)(_bitmap)
#define _UCS_BITMAP_DECLARE_TYPE(_length) \
typedef struct { \
ucs_bitmap_word_t bits[_UCS_BITMAP_BITS_TO_WORDS(_length)]; \
} ucs_bitmap_t(_length); \
\
static inline ucs_bitmap_t(_length) \
_ucs_bitmap_##_length##_not(ucs_bitmap_t(_length) bitmap) \
{ \
UCS_BITMAP_NOT_INPLACE(&bitmap); \
return bitmap; \
} \
\
static inline bool _ucs_bitmap_##_length##_is_zero(ucs_bitmap_t(_length) \
bitmap) \
{ \
return ucs_bitmap_is_zero(&bitmap, \
_UCS_BITMAP_BITS_TO_WORDS(_length)); \
} \
\
static inline ucs_bitmap_t(_length) \
_ucs_bitmap_##_length##_and(ucs_bitmap_t(_length) bitmap1, \
ucs_bitmap_t(_length) bitmap2) \
{ \
UCS_BITMAP_AND_INPLACE(&bitmap1, bitmap2); \
return bitmap1; \
} \
\
static inline ucs_bitmap_t(_length) \
_ucs_bitmap_##_length##_or(ucs_bitmap_t(_length) bitmap1, \
ucs_bitmap_t(_length) bitmap2) \
{ \
UCS_BITMAP_OR_INPLACE(&bitmap1, bitmap2); \
return bitmap1; \
} \
\
static inline ucs_bitmap_t(_length) \
_ucs_bitmap_##_length##_xor(ucs_bitmap_t(_length) bitmap1, \
ucs_bitmap_t(_length) bitmap2) \
{ \
UCS_BITMAP_XOR_INPLACE(&bitmap1, bitmap2); \
return bitmap1; \
}
#define ucs_bitmap_t(_length) UCS_PP_TOKENPASTE3(ucs_bitmap_, _length, _t)
#define UCS_BITMAP_GET(_bitmap, _bit_index) \
(!!(_UCS_BITMAP_WORD_BY_BIT(_bitmap, _bit_index) & \
UCS_BIT(_UCS_BITMAP_BIT_IN_WORD_INDEX(_bit_index))))
#define UCS_BITMAP_SET(_bitmap, _bit_index) \
({ \
_UCS_BITMAP_WORD_BY_BIT(_bitmap, _bit_index) |= UCS_BIT( \
_UCS_BITMAP_BIT_IN_WORD_INDEX(_bit_index)); \
})
#define UCS_BITMAP_UNSET(_bitmap, _bit_index) \
({ \
_UCS_BITMAP_WORD_BY_BIT(_bitmap, _bit_index) &= ~( \
UCS_BIT(_UCS_BITMAP_BIT_IN_WORD_INDEX(_bit_index))); \
})
#define UCS_BITMAP_CLEAR(_bitmap) \
memset((_bitmap)->bits, 0, sizeof((_bitmap)->bits))
#define UCS_BITMAP_ZERO \
{ \
.bits = { 0 } \
}
#define UCS_BITMAP_FFS(_bitmap) \
({ \
size_t _bit_index = UCS_BITMAP_BITS_IN_WORD * \
_UCS_BITMAP_NUM_WORDS(_bitmap); \
size_t _word_index, _temp; \
_UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) { \
_temp = _UCS_BITMAP_WORD(_bitmap, _word_index); \
if (_temp != 0) { \
_bit_index = ucs_ffs64(_temp) + (_word_index * \
UCS_BITMAP_BITS_IN_WORD); \
break; \
} \
} \
_bit_index; \
})
#define UCS_BITMAP_POPCOUNT(_bitmap) \
({ \
size_t _word_index = 0, _popcount = 0; \
_UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) { \
_popcount += ucs_popcount(_UCS_BITMAP_WORD(_bitmap, _word_index)); \
} \
_popcount; \
})
#define UCS_BITMAP_POPCOUNT_UPTO_INDEX(_bitmap, _bit_index) \
({ \
size_t _word_index = 0, _popcount = 0; \
_UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) { \
if ((_bit_index) >= ((_word_index) + 1) * UCS_BITMAP_BITS_IN_WORD) { \
_popcount += ucs_popcount( \
_UCS_BITMAP_WORD(_bitmap, _word_index)); \
} else { \
_popcount += ucs_popcount( \
_UCS_BITMAP_WORD(_bitmap, _word_index) & \
(UCS_MASK((_bit_index) % UCS_BITMAP_BITS_IN_WORD))); \
break; \
} \
} \
_popcount; \
})
#define _UCS_BITMAP_MASK_WORD(_bitmap, _word_index, _mask_index) \
((_mask_index) > (_word_index) * UCS_BITMAP_BITS_IN_WORD) ? \
((((_mask_index) >= ((_word_index) + 1) * UCS_BITMAP_BITS_IN_WORD) ? \
UCS_BITMAP_WORD_MASK : \
UCS_MASK((_mask_index) % UCS_BITMAP_BITS_IN_WORD))) : 0; \
#define UCS_BITMAP_MASK(_bitmap, _mask_index) \
{ \
size_t _word_index = 0; \
\
ucs_assert((_mask_index) < \
_UCS_BITMAP_NUM_WORDS(*_bitmap) * UCS_BITMAP_BITS_IN_WORD); \
UCS_BITMAP_CLEAR(_bitmap); \
_UCS_BITMAP_FOR_EACH_WORD(*_bitmap, _word_index) { \
_UCS_BITMAP_WORD(*_bitmap, _word_index) = \
_UCS_BITMAP_MASK_WORD(*_bitmap, _word_index, (_mask_index)); \
} \
}
#define UCS_BITMAP_SET_ALL(_bitmap) \
{ \
size_t _word_index = 0; \
_UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) { \
_UCS_BITMAP_WORD(_bitmap, _word_index) = UCS_BITMAP_WORD_MASK; \
} \
}
#define UCS_BITMAP_FOR_EACH_BIT(_bitmap, _bit_index) \
for (_bit_index = ucs_bitmap_ffs((_bitmap).bits, \
_UCS_BITMAP_NUM_WORDS(_bitmap), 0); \
_bit_index < \
_UCS_BITMAP_NUM_WORDS(_bitmap) * UCS_BITMAP_BITS_IN_WORD; \
_bit_index = ucs_bitmap_ffs((_bitmap).bits, \
_UCS_BITMAP_NUM_WORDS(_bitmap), \
_bit_index + 1))
#define UCS_BITMAP_COPY(_dest_bitmap, _src_bitmap) \
memcpy((_dest_bitmap).bits, (_src_bitmap).bits, \
_UCS_BITMAP_NUM_WORDS(_src_bitmap));
#define UCS_BITMAP_NOT(_bitmap, _length) \
UCS_PP_TOKENPASTE3(_ucs_bitmap_, _length, _not)(_bitmap)
#define UCS_BITMAP_AND(_bitmap1, _bitmap2, _length) \
UCS_PP_TOKENPASTE3(_ucs_bitmap_, _length, _and) \
(_bitmap1, _bitmap2)
#define UCS_BITMAP_OR(_bitmap1, _bitmap2, _length) \
UCS_PP_TOKENPASTE3(_ucs_bitmap_, _length, _or) \
(_bitmap1, _bitmap2)
#define UCS_BITMAP_XOR(_bitmap1, _bitmap2, _length) \
UCS_PP_TOKENPASTE3(_ucs_bitmap_, _length, _xor) \
(_bitmap1, _bitmap2)
static UCS_F_ALWAYS_INLINE bool
ucs_bitmap_is_zero(const void *bitmap, size_t num_words)
{
size_t i;
for (i = 0; i < num_words; i++) {
if (((ucs_bitmap_word_t *)bitmap)[i]) {
return 0;
}
}
return 1;
}
static UCS_F_ALWAYS_INLINE int
ucs_bitmap_ffs(const ucs_bitmap_word_t *bitmap_words, size_t num_words,
size_t start_index)
{
size_t word_index = start_index / UCS_BITMAP_BITS_IN_WORD;
size_t mask = ~UCS_MASK(start_index % UCS_BITMAP_BITS_IN_WORD);
size_t first_bit_in_word;
while (word_index < num_words) {
if (bitmap_words[word_index] & mask) {
first_bit_in_word = ucs_ffs64(bitmap_words[word_index] & mask);
return _UCS_BITMAP_BIT_INDEX(first_bit_in_word, word_index);
}
mask = UCS_BITMAP_WORD_MASK;
word_index++;
}
return _UCS_BITMAP_BIT_INDEX(0, word_index);
}
_UCS_BITMAP_DECLARE_TYPE(64)
_UCS_BITMAP_DECLARE_TYPE(128)
_UCS_BITMAP_DECLARE_TYPE(256)
END_C_DECLS
#endif