#include "src/include/pmix_config.h"
#include <limits.h>
#include <stdio.h>
#include "pmix_common.h"
#include "src/class/pmix_bitmap.h"
#define SIZE_OF_BASE_TYPE 64
static void pmix_bitmap_construct(pmix_bitmap_t *bm);
static void pmix_bitmap_destruct(pmix_bitmap_t *bm);
PMIX_CLASS_INSTANCE(pmix_bitmap_t, pmix_object_t, pmix_bitmap_construct, pmix_bitmap_destruct);
static void pmix_bitmap_construct(pmix_bitmap_t *bm)
{
bm->bitmap = NULL;
bm->array_size = 0;
bm->max_size = INT_MAX;
}
static void pmix_bitmap_destruct(pmix_bitmap_t *bm)
{
if (NULL != bm->bitmap) {
free(bm->bitmap);
bm->bitmap = NULL;
}
}
int pmix_bitmap_set_max_size(pmix_bitmap_t *bm, int max_size)
{
if (NULL == bm) {
return PMIX_ERR_BAD_PARAM;
}
bm->max_size = (int) (((size_t) max_size + SIZE_OF_BASE_TYPE - 1) / SIZE_OF_BASE_TYPE);
return PMIX_SUCCESS;
}
int pmix_bitmap_init(pmix_bitmap_t *bm, int size)
{
if ((size <= 0) || (NULL == bm) || (size > bm->max_size)) {
return PMIX_ERR_BAD_PARAM;
}
bm->array_size = (int) (((size_t) size + SIZE_OF_BASE_TYPE - 1) / SIZE_OF_BASE_TYPE);
if (NULL != bm->bitmap) {
free(bm->bitmap);
if (bm->max_size < bm->array_size)
bm->max_size = bm->array_size;
}
bm->bitmap = (uint64_t *) malloc(bm->array_size * sizeof(uint64_t));
if (NULL == bm->bitmap) {
return PMIX_ERR_OUT_OF_RESOURCE;
}
pmix_bitmap_clear_all_bits(bm);
return PMIX_SUCCESS;
}
int pmix_bitmap_set_bit(pmix_bitmap_t *bm, int bit)
{
int index, offset, new_size;
if ((bit < 0) || (NULL == bm) || (bit > bm->max_size)) {
return PMIX_ERR_BAD_PARAM;
}
index = bit / SIZE_OF_BASE_TYPE;
offset = bit % SIZE_OF_BASE_TYPE;
if (index >= bm->array_size) {
new_size = index + 1;
if (new_size > bm->max_size)
new_size = bm->max_size;
bm->bitmap = (uint64_t *) realloc(bm->bitmap, new_size * sizeof(uint64_t));
if (NULL == bm->bitmap) {
return PMIX_ERR_OUT_OF_RESOURCE;
}
memset(&bm->bitmap[bm->array_size], 0, (new_size - bm->array_size) * sizeof(uint64_t));
bm->array_size = new_size;
}
bm->bitmap[index] |= (1UL << offset);
return PMIX_SUCCESS;
}
int pmix_bitmap_clear_bit(pmix_bitmap_t *bm, int bit)
{
int index, offset;
if ((bit < 0) || NULL == bm || (bit >= (bm->array_size * SIZE_OF_BASE_TYPE))) {
return PMIX_ERR_BAD_PARAM;
}
index = bit / SIZE_OF_BASE_TYPE;
offset = bit % SIZE_OF_BASE_TYPE;
bm->bitmap[index] &= ~(1UL << offset);
return PMIX_SUCCESS;
}
bool pmix_bitmap_is_set_bit(pmix_bitmap_t *bm, int bit)
{
int index, offset;
if ((bit < 0) || NULL == bm || (bit >= (bm->array_size * SIZE_OF_BASE_TYPE))) {
return false;
}
index = bit / SIZE_OF_BASE_TYPE;
offset = bit % SIZE_OF_BASE_TYPE;
if (0 != (bm->bitmap[index] & (1UL << offset))) {
return true;
}
return false;
}
int pmix_bitmap_clear_all_bits(pmix_bitmap_t *bm)
{
if (NULL == bm) {
return PMIX_ERR_BAD_PARAM;
}
memset(bm->bitmap, 0, bm->array_size * sizeof(uint64_t));
return PMIX_SUCCESS;
}
int pmix_bitmap_set_all_bits(pmix_bitmap_t *bm)
{
if (NULL == bm) {
return PMIX_ERR_BAD_PARAM;
}
memset(bm->bitmap, 0xff, bm->array_size * sizeof(uint64_t));
return PMIX_SUCCESS;
}
int pmix_bitmap_find_and_set_first_unset_bit(pmix_bitmap_t *bm, int *position)
{
int i = 0;
uint64_t temp, all_ones = 0xffffffffffffffffUL;
if (NULL == bm) {
return PMIX_ERR_BAD_PARAM;
}
*position = 0;
while ((i < bm->array_size) && (bm->bitmap[i] == all_ones)) {
++i;
}
if (i == bm->array_size) {
*position = bm->array_size * SIZE_OF_BASE_TYPE;
return pmix_bitmap_set_bit(bm, *position);
}
temp = bm->bitmap[i];
bm->bitmap[i] |= (bm->bitmap[i] + 1);
temp ^= bm->bitmap[i];
while (!(temp & 0x1)) {
++(*position);
temp >>= 1;
}
(*position) += i * SIZE_OF_BASE_TYPE;
return PMIX_SUCCESS;
}
int pmix_bitmap_bitwise_and_inplace(pmix_bitmap_t *dest, pmix_bitmap_t *right)
{
int i;
if (NULL == dest || NULL == right) {
return PMIX_ERR_BAD_PARAM;
}
if (dest->array_size != right->array_size) {
return PMIX_ERR_BAD_PARAM;
}
for (i = 0; i < dest->array_size; ++i) {
dest->bitmap[i] &= right->bitmap[i];
}
return PMIX_SUCCESS;
}
int pmix_bitmap_bitwise_or_inplace(pmix_bitmap_t *dest, pmix_bitmap_t *right)
{
int i;
if (NULL == dest || NULL == right) {
return PMIX_ERR_BAD_PARAM;
}
if (dest->array_size != right->array_size) {
return PMIX_ERR_BAD_PARAM;
}
for (i = 0; i < dest->array_size; ++i) {
dest->bitmap[i] |= right->bitmap[i];
}
return PMIX_SUCCESS;
}
int pmix_bitmap_bitwise_xor_inplace(pmix_bitmap_t *dest, pmix_bitmap_t *right)
{
int i;
if (NULL == dest || NULL == right) {
return PMIX_ERR_BAD_PARAM;
}
if (dest->array_size != right->array_size) {
return PMIX_ERR_BAD_PARAM;
}
for (i = 0; i < dest->array_size; ++i) {
dest->bitmap[i] ^= right->bitmap[i];
}
return PMIX_SUCCESS;
}
bool pmix_bitmap_are_different(pmix_bitmap_t *left, pmix_bitmap_t *right)
{
int i;
if (NULL == left || NULL == right) {
return PMIX_ERR_BAD_PARAM;
}
if (pmix_bitmap_size(left) != pmix_bitmap_size(right)) {
return true;
}
for (i = 0; i < left->array_size; ++i) {
if (left->bitmap[i] != right->bitmap[i]) {
return true;
}
}
return false;
}
char *pmix_bitmap_get_string(pmix_bitmap_t *bitmap)
{
int i;
char *bitmap_str = NULL;
if (NULL == bitmap) {
return NULL;
}
bitmap_str = malloc(bitmap->array_size * SIZE_OF_BASE_TYPE + 1);
if (NULL == bitmap_str) {
return NULL;
}
bitmap_str[bitmap->array_size * SIZE_OF_BASE_TYPE] = '\0';
for (i = 0; i < (bitmap->array_size * SIZE_OF_BASE_TYPE); ++i) {
if (pmix_bitmap_is_set_bit(bitmap, i)) {
bitmap_str[i] = 'X';
} else {
bitmap_str[i] = '_';
}
}
return bitmap_str;
}
int pmix_bitmap_num_unset_bits(pmix_bitmap_t *bm, int len)
{
return (len - pmix_bitmap_num_set_bits(bm, len));
}
int pmix_bitmap_num_set_bits(pmix_bitmap_t *bm, int len)
{
int i, cnt = 0;
uint64_t val;
int i_len = len / SIZE_OF_BASE_TYPE + (len % SIZE_OF_BASE_TYPE == 0 ? 0 : 1);
#if PMIX_ENABLE_DEBUG
if ((len < 0) || NULL == bm || (len >= (bm->array_size * SIZE_OF_BASE_TYPE))) {
return 0;
}
#endif
for (i = 0; i < i_len; ++i) {
if (0 == (val = bm->bitmap[i]))
continue;
if (i == i_len - 1 && len % SIZE_OF_BASE_TYPE != 0) {
val = val & ((1 << (len - i * SIZE_OF_BASE_TYPE)) - 1);
if (0 == val)
continue;
}
for (; val; cnt++) {
val &= val - 1;
}
}
return cnt;
}
bool pmix_bitmap_is_clear(pmix_bitmap_t *bm)
{
int i;
for (i = 0; i < bm->array_size; ++i) {
if (0 != bm->bitmap[i]) {
return false;
}
}
return true;
}