blob: 4e42862f7b31df7053819ded0959cdfb161ba92b [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2005 The Regents of the University of California.
* This material was produced under U.S. Government contract W-7405-ENG-36
* for Los Alamos National Laboratory, which is operated by the University
* of California for the U.S. Department of Energy. The U.S. Government has
* rights to use, reproduce, and distribute this software. NEITHER THE
* GOVERNMENT NOR THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR
* ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified
* to produce derivative works, such modified software should be clearly
* marked, so as not to confuse it with the version available from LANL.
*
* Additionally, this program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* LA-CC 04-115
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include "compat.h"
#include "bitset.h"
bitset *
bitset_new(int nbits)
{
bitset * b;
b = malloc(sizeof(bitset));
b->bs_nbits = nbits;
b->bs_size = BIT_INDEX(nbits-1) + 1;
b->bs_bits = (bits *)malloc(SIZE_TO_BYTES(b->bs_size));
memset(b->bs_bits, 0, SIZE_TO_BYTES(b->bs_size));
return b;
}
void
bitset_free(bitset *b)
{
free(b->bs_bits);
free(b);
}
void
bitset_copy(bitset *b1, bitset *b2)
{
memcpy(b1->bs_bits, b2->bs_bits, MIN(SIZE_TO_BYTES(b1->bs_size), SIZE_TO_BYTES(b2->bs_size)));
}
bitset *
bitset_dup(bitset *b)
{
bitset *nb = bitset_new(b->bs_nbits);
bitset_copy(nb, b);
return nb;
}
int
bitset_isempty(bitset *b)
{
int i;
for (i = 0; i < b->bs_size; i++)
if (b->bs_bits[i] != 0)
return 0;
return 1;
}
void
bitset_clear(bitset *b)
{
memset(b->bs_bits, 0, SIZE_TO_BYTES(b->bs_size));
}
/*
* Compute logical AND of bitsets
*
* If bitsets are different sizes, create a new bitset that
* is the same size as the larger of the two. The high bits
* will be ANDed with 0.
*/
bitset *
bitset_and(bitset *b1, bitset *b2)
{
bitset * nb;
if (b1->bs_size > b2->bs_size) {
nb = bitset_dup(b1);
bitset_andeq(nb, b2);
} else {
nb = bitset_dup(b2);
bitset_andeq(nb, b1);
}
return nb;
}
/*
* Compute b1 &= b2
*
* If bitsets are different sizes, high bits are assumed
* to be 0.
*/
void
bitset_andeq(bitset *b1, bitset *b2)
{
int i;
for (i = 0; i < MIN(b1->bs_size, b2->bs_size); i++)
b1->bs_bits[i] &= b2->bs_bits[i];
/*
* Mask high bits (if any)
*/
for ( ; i < b1->bs_size; i++)
b1->bs_bits[i] = 0;
}
/*
* Compute b1 &= ~b2
*
* If bitsets are different sizes, high bits are assumed
* to be 0.
*/
void
bitset_andeqnot(bitset *b1, bitset *b2)
{
int i;
for (i = 0; i < MIN(b1->bs_size, b2->bs_size); i++)
b1->bs_bits[i] &= ~b2->bs_bits[i];
/*
* Mask high bits (if any)
*/
for ( ; i < b1->bs_size; i++)
b1->bs_bits[i] = 0;
}
/*
* Compute logical OR of bitsets
*/
bitset *
bitset_or(bitset *b1, bitset *b2)
{
bitset * nb;
if (b1->bs_size > b2->bs_size) {
nb = bitset_dup(b1);
bitset_oreq(nb, b2);
} else {
nb = bitset_dup(b2);
bitset_oreq(nb, b1);
}
return nb;
}
/*
* Compute b1 |= b2
*/
void
bitset_oreq(bitset *b1, bitset *b2)
{
int i;
for (i = 0; i < MIN(b1->bs_size, b2->bs_size); i++)
b1->bs_bits[i] |= b2->bs_bits[i];
/*
* Mask out unused high bits
*/
if (BIT_IN_OBJ(b1->bs_nbits) != 0)
b1->bs_bits[b1->bs_size-1] &= (1 << (BIT_IN_OBJ(b1->bs_nbits-1) + 1)) - 1;
}
/*
* Compute ~b
*/
void
bitset_invert(bitset *b)
{
int i;
for (i = 0; i < b->bs_size; i++)
b->bs_bits[i] = ~b->bs_bits[i];
/*
* Mask out unused high bits
*/
if (BIT_IN_OBJ(b->bs_nbits) != 0)
b->bs_bits[b->bs_size-1] &= (1 << (BIT_IN_OBJ(b->bs_nbits-1) + 1)) - 1;
}
/*
* Test if two bitsets are equal
*
* Bitsets must be the same size
*/
int
bitset_eq(bitset *b1, bitset *b2)
{
int i;
if (b1->bs_nbits != b2->bs_nbits)
return 0;
for (i = 0; i < b1->bs_size; i++)
if (b1->bs_bits[i] != b2->bs_bits[i])
return 0;
return 1;
}
/*
* Test if two bitsets share any bits
*
* If bitsets are different sizes, high bits are assumed
* to be 0.
*/
int
bitset_compare(bitset *b1, bitset *b2)
{
int i;
for (i = 0; i < MIN(b1->bs_size, b2->bs_size); i++)
if ((b1->bs_bits[i] & b2->bs_bits[i]) != 0)
return 1;
return 0;
}
/**
* Add a bit to the set. Bits are numbered from 0.
*/
void
bitset_set(bitset *b, int bit)
{
if (bit < 0 || bit >= b->bs_nbits)
return;
b->bs_bits[BIT_INDEX(bit)] |= (1 << BIT_IN_OBJ(bit));
}
void
bitset_unset(bitset *b, int bit)
{
if (bit < 0 || bit >= b->bs_nbits)
return;
b->bs_bits[BIT_INDEX(bit)] &= ~(1 << BIT_IN_OBJ(bit));
}
int
bitset_test(bitset *b, int bit)
{
bits mask = (1 << BIT_IN_OBJ(bit));
if (bit < 0 || bit >= b->bs_nbits)
return 0;
return (b->bs_bits[BIT_INDEX(bit)] & mask) == mask;
}
/*
* Find the first bit set in the bitset.
*
* NOTE: ffs() assumes an integer argument. If sizeof(bits) is anything
* else this will need to be fixed.
*/
int
bitset_firstset(bitset *b)
{
int i;
for (i = 0; i < b->bs_size; i++)
if (b->bs_bits[i] != 0)
break;
if (i == b->bs_size)
return -1;
return (SIZE_TO_BYTES(i) << 3) + ffs(b->bs_bits[i]) - 1;
}
static char tohex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/**
* Return a string representation of a bitset. We use hex to compress
* the string somewhat and drop leading zeros.
*
* Format is "nnnnnnnn:bbbbbbb..." where "nnnnnnnn" is a hex representation of the
* actual number of bits, and "bbbbb...." are bits in the
* set (in hex).
*/
char *
bitset_to_str(bitset *b)
{
int n;
int nonzero = 0;
int bytes;
int pbit;
int bit;
char * str;
char * s;
unsigned char byte;
if (b == NULL)
return strdup("0:0");
/*
* Find out how many bytes needed (rounded up)
*/
bytes = (b->bs_nbits >> 3) + 1;
str = (char *)malloc((bytes * 2) + 8 + 2);
/*
* Start with actual number of bits (silently truncate to 32 bits)
*/
n = sprintf(str, "%X", b->bs_nbits & 0xffffffff);
s = str + n;
*s++ = ':';
for (pbit = (bytes << 3) - 1; pbit > 0; ) {
for (byte = 0, bit = 3; bit >= 0; bit--, pbit--) {
if (pbit < b->bs_nbits && bitset_test(b, pbit)) {
byte |= (1 << bit);
nonzero = 1;
}
}
if (nonzero) {
*s++ = tohex[byte & 0x0f];
}
}
if (!nonzero)
*s++ = '0';
*s = '\0';
return str;
}
/**
* Convert string into a bitset. Inverse of bitset_to_str().
*
*/
bitset *
str_to_bitset(char *str)
{
int nprocs;
int n;
int pos;
int b;
char * end;
bitset * bp;
if (str == NULL)
return NULL;
end = &str[strlen(str) - 1];
for (nprocs = 0; *str != ':' && *str != '\0' && isxdigit(*str); str++) {
nprocs <<= 4;
nprocs += digittoint(*str);
}
if (*str != ':' || nprocs == 0)
return NULL;
bp = bitset_new(nprocs);
/*
* Easier if we start from end
*/
for (pos = 0; end != str && isxdigit(*end); end--) {
b = digittoint(*end);
for (n = 0; n < 4; n++, pos++) {
if (b & (1 << n)) {
bitset_set(bp, pos);
}
}
}
if (end != str) {
bitset_free(bp);
return NULL;
}
return bp;
}
int
emit_range(char ** str, char sep, int lower, int upper)
{
int n;
if (lower < 0 || upper < lower)
return 0;
if (sep)
*(*str)++ = sep;
if (lower != upper) {
n = sprintf(*str, "%d-%d", lower, upper);
} else {
n = sprintf(*str, "%d", lower);
}
*str += n;
return 1;
}
/*
* Convert bitset to set notation of the form
*
* {0-2,4,5-100}
*/
char *
bitset_to_set(bitset *b)
{
int bit;
int lower;
int upper;
char sep = 0;
char * str;
char * s;
if (b == NULL)
return strdup("{}");
str = s = (char *)malloc(b->bs_nbits * 2 + 3);
*s++ = '{';
for (bit = 0, lower = -1, upper = -1; bit < b->bs_nbits; bit++) {
if (bitset_test(b, bit)) {
if (lower < 0)
lower = bit;
upper = bit;
} else {
if (emit_range(&s, sep, lower, upper))
sep = ',';
lower = bit + 1;
}
}
emit_range(&s, sep, lower, upper);
*s++ = '}';
*s = '\0';
return str;
}
unsigned int
count_bits(bits b)
{
unsigned int n = 0;
while (b != 0) {
n++;
b &= (b-1);
}
return n;
}
/**
* Number of bits in the set (as opposed to the total size of the set)
*/
int
bitset_count(bitset *b)
{
int i;
int count = 0;
for (i = 0; i < b->bs_size; i++)
count += count_bits(b->bs_bits[i]);
return count;
}
/**
* Number of bits this set can represent
*/
int
bitset_size(bitset *b)
{
return b->bs_nbits;
}