blob: 69d7029c763a8e97dd1626c1600037acf328dceb [file] [log] [blame]
/*****************************************************************************\
* bitstring.c - bitmap manipulation functions
*****************************************************************************
* See comments about origin, limitations, and internal structure in
* bitstring.h.
*
* Copyright (C) 2002 The Regents of the University of California.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Jim Garlick <garlick@llnl.gov>, Morris Jette <jette1@llnl.gov>
* UCRL-CODE-226842.
*
* This file is part of SLURM, a resource management program.
* For details, see <http://www.llnl.gov/linux/slurm/>.
*
* SLURM is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with SLURM; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "src/common/bitstring.h"
#include "src/common/macros.h"
#include "src/common/xmalloc.h"
/*
* Define slurm-specific aliases for use by plugins, see slurm_xlator.h
* for details.
*/
strong_alias(bit_alloc, slurm_bit_alloc);
strong_alias(bit_test, slurm_bit_test);
strong_alias(bit_set, slurm_bit_set);
strong_alias(bit_clear, slurm_bit_clear);
strong_alias(bit_nclear, slurm_bit_nclear);
strong_alias(bit_nset, slurm_bit_nset);
strong_alias(bit_ffc, slurm_bit_ffc);
strong_alias(bit_ffs, slurm_bit_ffs);
strong_alias(bit_free, slurm_bit_free);
strong_alias(bit_realloc, slurm_bit_realloc);
strong_alias(bit_size, slurm_bit_size);
strong_alias(bit_and, slurm_bit_and);
strong_alias(bit_not, slurm_bit_not);
strong_alias(bit_or, slurm_bit_or);
strong_alias(bit_set_count, slurm_bit_set_count);
strong_alias(bit_clear_count, slurm_bit_clear_count);
strong_alias(bit_nset_max_count,slurm_bit_nset_max_count);
strong_alias(int_and_set_count, slurm_int_and_set_count);
strong_alias(bit_rotate_copy, slurm_bit_rotate_copy);
strong_alias(bit_rotate, slurm_bit_rotate);
strong_alias(bit_fmt, slurm_bit_fmt);
strong_alias(bit_unfmt, slurm_bit_unfmt);
strong_alias(bitfmt2int, slurm_bitfmt2int);
strong_alias(bit_fmt_hexmask, slurm_bit_fmt_hexmask);
strong_alias(bit_unfmt_hexmask, slurm_bit_unfmt_hexmask);
strong_alias(bit_fmt_binmask, slurm_bit_fmt_binmask);
strong_alias(bit_unfmt_binmask, slurm_bit_unfmt_binmask);
strong_alias(bit_fls, slurm_bit_fls);
strong_alias(bit_fill_gaps, slurm_bit_fill_gaps);
strong_alias(bit_super_set, slurm_bit_super_set);
strong_alias(bit_overlap, slurm_bit_overlap);
strong_alias(bit_equal, slurm_bit_equal);
strong_alias(bit_copy, slurm_bit_copy);
strong_alias(bit_pick_cnt, slurm_bit_pick_cnt);
strong_alias(bit_nffc, slurm_bit_nffc);
strong_alias(bit_noc, slurm_bit_noc);
strong_alias(bit_nffs, slurm_bit_nffs);
strong_alias(bit_copybits, slurm_bit_copybits);
strong_alias(bit_get_bit_num, slurm_bit_get_bit_num);
strong_alias(bit_get_pos_num, slurm_bit_get_pos_num);
/*
* Allocate a bitstring.
* nbits (IN) valid bits in new bitstring, initialized to all clear
* RETURN new bitstring
*/
bitstr_t *
bit_alloc(bitoff_t nbits)
{
bitstr_t *new;
new = (bitstr_t *)calloc(_bitstr_words(nbits), sizeof(bitstr_t));
if (new) {
_bitstr_magic(new) = BITSTR_MAGIC;
_bitstr_bits(new) = nbits;
}
return new;
}
/*
* Reallocate a bitstring (expand or contract size).
* b (IN) pointer to old bitstring
* nbits (IN) valid bits in new bitstr
* RETURN new bitstring
*/
bitstr_t *
bit_realloc(bitstr_t *b, bitoff_t nbits)
{
bitoff_t obits;
bitstr_t *new = NULL;
_assert_bitstr_valid(b);
obits = _bitstr_bits(b);
new = realloc(b, _bitstr_words(nbits) * sizeof(bitstr_t));
if (new) {
_assert_bitstr_valid(new);
_bitstr_bits(new) = nbits;
if (nbits > obits)
bit_nclear(new, obits, nbits - 1);
}
return new;
}
/*
* Free a bitstr.
* b (IN/OUT) bitstr to be freed
*/
void
bit_free(bitstr_t *b)
{
assert(b);
assert(_bitstr_magic(b) == BITSTR_MAGIC);
_bitstr_magic(b) = 0;
free(b);
}
/*
* Return the number of possible bits in a bitstring.
* b (IN) bitstring to check
* RETURN number of bits allocated
*/
bitoff_t
bit_size(bitstr_t *b)
{
_assert_bitstr_valid(b);
return _bitstr_bits(b);
}
/*
* Is bit N of bitstring b set?
* b (IN) bitstring to test
* bit (IN) bit position to test
* RETURN 1 if bit set, 0 if clear
*/
int
bit_test(bitstr_t *b, bitoff_t bit)
{
_assert_bitstr_valid(b);
_assert_bit_valid(b, bit);
return ((b[_bit_word(bit)] & _bit_mask(bit)) ? 1 : 0);
}
/*
* Set bit N of bitstring.
* b (IN) target bitstring
* bit (IN) bit position to set
*/
void
bit_set(bitstr_t *b, bitoff_t bit)
{
_assert_bitstr_valid(b);
_assert_bit_valid(b, bit);
b[_bit_word(bit)] |= _bit_mask(bit);
}
/*
* Clear bit N of bitstring
* b (IN) target bitstring
* bit (IN) bit position to clear
*/
void
bit_clear(bitstr_t *b, bitoff_t bit)
{
_assert_bitstr_valid(b);
_assert_bit_valid(b, bit);
b[_bit_word(bit)] &= ~_bit_mask(bit);
}
/*
* Set bits start ... stop in bitstring
* b (IN) target bitstring
* start (IN) starting (low numbered) bit position
* stop (IN) ending (higher numbered) bit position
*/
void
bit_nset(bitstr_t *b, bitoff_t start, bitoff_t stop)
{
_assert_bitstr_valid(b);
_assert_bit_valid(b, start);
_assert_bit_valid(b, stop);
while (start <= stop && start % 8 > 0) /* partial first byte? */
bit_set(b, start++);
while (stop >= start && (stop+1) % 8 > 0) /* partial last byte? */
bit_set(b, stop--);
if (stop > start) { /* now do whole bytes */
assert((stop-start+1) % 8 == 0);
memset(_bit_byteaddr(b, start), 0xff, (stop-start+1) / 8);
}
}
/*
* Clear bits start ... stop in bitstring
* b (IN) target bitstring
* start (IN) starting (low numbered) bit position
* stop (IN) ending (higher numbered) bit position
*/
void
bit_nclear(bitstr_t *b, bitoff_t start, bitoff_t stop)
{
_assert_bitstr_valid(b);
_assert_bit_valid(b, start);
_assert_bit_valid(b, stop);
while (start <= stop && start % 8 > 0) /* partial first byte? */
bit_clear(b, start++);
while (stop >= start && (stop+1) % 8 > 0)/* partial last byte? */
bit_clear(b, stop--);
if (stop > start) { /* now do whole bytes */
assert((stop-start+1) % 8 == 0);
memset(_bit_byteaddr(b, start), 0, (stop-start+1) / 8);
}
}
/*
* Find first bit clear in bitstring.
* b (IN) bitstring to search
* nbits (IN) number of bits to search
* RETURN resulting bit position (-1 if none found)
*/
bitoff_t
bit_ffc(bitstr_t *b)
{
bitoff_t bit = 0, value = -1;
_assert_bitstr_valid(b);
while (bit < _bitstr_bits(b) && value == -1) {
int word = _bit_word(bit);
if (b[word] == BITSTR_MAXPOS) {
bit += sizeof(bitstr_t)*8;
continue;
}
while (bit < _bitstr_bits(b) && _bit_word(bit) == word) {
if (!bit_test(b, bit)) {
value = bit;
break;
}
bit++;
}
}
return value;
}
/* Find the first n contiguous bits clear in b.
* b (IN) bitstring to search
* n (IN) number of bits needed
* RETURN position of first bit in range (-1 if none found)
*/
bitoff_t
bit_nffc(bitstr_t *b, int n)
{
bitoff_t value = -1;
bitoff_t bit;
int cnt = 0;
_assert_bitstr_valid(b);
assert(n > 0 && n < _bitstr_bits(b));
for (bit = 0; bit < _bitstr_bits(b); bit++) {
if (bit_test(b, bit)) { /* fail */
cnt = 0;
} else {
cnt++;
if (cnt >= n) {
value = bit - (cnt - 1);
break;
}
}
}
return value;
}
/* Find n contiguous bits clear in b starting at some offset.
* b (IN) bitstring to search
* n (IN) number of bits needed
* seed (IN) position at which to begin search
* RETURN position of first bit in range (-1 if none found)
*/
bitoff_t
bit_noc(bitstr_t *b, int n, int seed)
{
bitoff_t value = -1;
bitoff_t bit;
int cnt = 0;
_assert_bitstr_valid(b);
assert(n > 0 && n <= _bitstr_bits(b));
if ((seed + n) >= _bitstr_bits(b))
seed = _bitstr_bits(b); /* skip offset test, too small */
for (bit = seed; bit < _bitstr_bits(b); bit++) { /* start at offset */
if (bit_test(b, bit)) { /* fail */
cnt = 0;
} else {
cnt++;
if (cnt >= n) {
value = bit - (cnt - 1);
return value;
}
}
}
cnt = 0; /* start at beginning */
for (bit = 0; bit < _bitstr_bits(b); bit++) {
if (bit_test(b, bit)) { /* fail */
if (bit >= seed)
break;
cnt = 0;
} else {
cnt++;
if (cnt >= n) {
value = bit - (cnt - 1);
return value;
}
}
}
return -1;
}
/* Find the first n contiguous bits set in b.
* b (IN) bitstring to search
* n (IN) number of bits needed
* RETURN position of first bit in range (-1 if none found)
*/
bitoff_t
bit_nffs(bitstr_t *b, int n)
{
bitoff_t value = -1;
bitoff_t bit;
int cnt = 0;
_assert_bitstr_valid(b);
assert(n > 0 && n <= _bitstr_bits(b));
for (bit = 0; bit <= _bitstr_bits(b) - n; bit++) {
if (!bit_test(b, bit)) { /* fail */
cnt = 0;
} else {
cnt++;
if (cnt >= n) {
value = bit - (cnt - 1);
break;
}
}
}
return value;
}
/*
* Find first bit set in b.
* b (IN) bitstring to search
* RETURN resulting bit position (-1 if none found)
*/
bitoff_t
bit_ffs(bitstr_t *b)
{
bitoff_t bit = 0, value = -1;
_assert_bitstr_valid(b);
while (bit < _bitstr_bits(b) && value == -1) {
int word = _bit_word(bit);
if (b[word] == 0) {
bit += sizeof(bitstr_t)*8;
continue;
}
while (bit < _bitstr_bits(b) && _bit_word(bit) == word) {
if (bit_test(b, bit)) {
value = bit;
break;
}
bit++;
}
}
return value;
}
/*
* Find last bit set in b.
* b (IN) bitstring to search
* RETURN resulting bit position (-1 if none found)
*/
bitoff_t
bit_fls(bitstr_t *b)
{
bitoff_t bit, value = -1;
int word;
_assert_bitstr_valid(b);
if (_bitstr_bits(b) == 0) /* empty bitstring */
return -1;
bit = _bitstr_bits(b) - 1; /* zero origin */
while (bit >= 0 && /* test partitial words */
(_bit_word(bit) == _bit_word(bit + 1))) {
if (bit_test(b, bit)) {
value = bit;
break;
}
bit--;
}
while (bit >= 0 && value == -1) { /* test whole words */
word = _bit_word(bit);
if (b[word] == 0) {
bit -= sizeof(bitstr_t) * 8;
continue;
}
while (bit >= 0) {
if (bit_test(b, bit)) {
value = bit;
break;
}
bit--;
}
}
return value;
}
/*
* set all bits between the first and last bits set (i.e. fill in the gaps
* to make set bits contiguous)
*/
void
bit_fill_gaps(bitstr_t *b) {
bitoff_t first, last;
_assert_bitstr_valid(b);
first = bit_ffs(b);
if (first == -1)
return;
last = bit_fls(b);
bit_nset(b, first, last);
return;
}
/*
* return 1 if all bits set in b1 are also set in b2, 0 0therwise
*/
int
bit_super_set(bitstr_t *b1, bitstr_t *b2) {
bitoff_t bit;
_assert_bitstr_valid(b1);
_assert_bitstr_valid(b2);
assert(_bitstr_bits(b1) == _bitstr_bits(b2));
for (bit = 0; bit < _bitstr_bits(b1); bit += sizeof(bitstr_t)*8) {
if (b1[_bit_word(bit)] != (b1[_bit_word(bit)] &
b2[_bit_word(bit)]))
return 0;
}
return 1;
}
/*
* return 1 if b1 and b2 are identical, 0 otherwise
*/
extern int
bit_equal(bitstr_t *b1, bitstr_t *b2)
{
bitoff_t bit;
_assert_bitstr_valid(b1);
_assert_bitstr_valid(b2);
if (_bitstr_bits(b1) != _bitstr_bits(b2))
return 0;
for (bit = 0; bit < _bitstr_bits(b1); bit += sizeof(bitstr_t)*8) {
if (b1[_bit_word(bit)] != b2[_bit_word(bit)])
return 0;
}
return 1;
}
/*
* b1 &= b2
* b1 (IN/OUT) first string
* b2 (IN) second bitstring
*/
void
bit_and(bitstr_t *b1, bitstr_t *b2) {
bitoff_t bit;
_assert_bitstr_valid(b1);
_assert_bitstr_valid(b2);
assert(_bitstr_bits(b1) == _bitstr_bits(b2));
for (bit = 0; bit < _bitstr_bits(b1); bit += sizeof(bitstr_t)*8)
b1[_bit_word(bit)] &= b2[_bit_word(bit)];
}
/*
* b1 = ~b1 one's complement
* b1 (IN/OUT) first bitmap
*/
void
bit_not(bitstr_t *b) {
bitoff_t bit;
_assert_bitstr_valid(b);
for (bit = 0; bit < _bitstr_bits(b); bit += sizeof(bitstr_t)*8)
b[_bit_word(bit)] = ~b[_bit_word(bit)];
}
/*
* b1 |= b2
* b1 (IN/OUT) first bitmap
* b2 (IN) second bitmap
*/
void
bit_or(bitstr_t *b1, bitstr_t *b2) {
bitoff_t bit;
_assert_bitstr_valid(b1);
_assert_bitstr_valid(b2);
assert(_bitstr_bits(b1) == _bitstr_bits(b2));
for (bit = 0; bit < _bitstr_bits(b1); bit += sizeof(bitstr_t)*8)
b1[_bit_word(bit)] |= b2[_bit_word(bit)];
}
/*
* return a copy of the supplied bitmap
*/
bitstr_t *
bit_copy(bitstr_t *b)
{
bitstr_t *new;
int newsize_bits;
size_t len = 0; /* Number of bytes to memcpy() */
_assert_bitstr_valid(b);
newsize_bits = bit_size(b);
len = (_bitstr_words(newsize_bits) - BITSTR_OVERHEAD)*sizeof(bitstr_t);
new = bit_alloc(newsize_bits);
if (new)
memcpy(&new[BITSTR_OVERHEAD], &b[BITSTR_OVERHEAD], len);
return new;
}
void
bit_copybits(bitstr_t *dest, bitstr_t *src)
{
int len;
_assert_bitstr_valid(dest);
_assert_bitstr_valid(src);
assert(bit_size(src) == bit_size(dest));
len = (_bitstr_words(bit_size(src)) - BITSTR_OVERHEAD)*sizeof(bitstr_t);
memcpy(&dest[BITSTR_OVERHEAD], &src[BITSTR_OVERHEAD], len);
}
#if !defined(USE_64BIT_BITSTR)
/*
* Returns the hamming weight (i.e. the number of bits set) in a word.
* NOTE: This routine borrowed from Linux 2.4.9 <linux/bitops.h>.
*/
static uint32_t
hweight(uint32_t w)
{
uint32_t res;
res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
res = (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
return res;
}
#else
/*
* A 64 bit version crafted from 32-bit one borrowed above.
*/
static uint64_t
hweight(uint64_t w)
{
uint64_t res;
res = (w & 0x5555555555555555) + ((w >> 1) & 0x5555555555555555);
res = (res & 0x3333333333333333) + ((res >> 2) & 0x3333333333333333);
res = (res & 0x0F0F0F0F0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F0F0F0F0F);
res = (res & 0x00FF00FF00FF00FF) + ((res >> 8) & 0x00FF00FF00FF00FF);
res = (res & 0x0000FFFF0000FFFF) + ((res >> 16) & 0x0000FFFF0000FFFF);
res = (res & 0x00000000FFFFFFFF) + ((res >> 32) & 0x00000000FFFFFFFF);
return res;
}
#endif /* !USE_64BIT_BITSTR */
/*
* Count the number of bits set in bitstring.
* b (IN) bitstring to check
* RETURN count of set bits
*/
int
bit_set_count(bitstr_t *b)
{
int count = 0;
bitoff_t bit;
_assert_bitstr_valid(b);
for (bit = 0; bit < _bitstr_bits(b); bit += sizeof(bitstr_t)*8)
count += hweight(b[_bit_word(bit)]);
return count;
}
/*
* return number of bits set in b1 that are also set in b2, 0 if no overlap
*/
extern int
bit_overlap(bitstr_t *b1, bitstr_t *b2)
{
int count = 0;
bitoff_t bit;
_assert_bitstr_valid(b1);
_assert_bitstr_valid(b2);
assert(_bitstr_bits(b1) == _bitstr_bits(b2));
for (bit = 0; bit < _bitstr_bits(b1); bit += sizeof(bitstr_t)*8)
count += hweight(b1[_bit_word(bit)] & b2[_bit_word(bit)]);
return count;
}
/*
* Count the number of bits clear in bitstring.
* b (IN) bitstring to check
* RETURN count of clear bits
*/
int
bit_clear_count(bitstr_t *b)
{
_assert_bitstr_valid(b);
return (_bitstr_bits(b) - bit_set_count(b));
}
/* Return the count of the largest number of contiguous bits set in b.
* b (IN) bitstring to search
* RETURN the largest number of contiguous bits set in b
*/
int
bit_nset_max_count(bitstr_t *b)
{
bitoff_t bit;
int cnt = 0;
int maxcnt = 0;
uint32_t bitsize;
_assert_bitstr_valid(b);
bitsize = _bitstr_bits(b);
for (bit = 0; bit < bitsize; bit++) {
if (!bit_test(b, bit)) { /* no longer continuous */
cnt = 0;
} else {
cnt++;
if (cnt > maxcnt) {
maxcnt = cnt;
}
}
if (cnt == 0 && ((bitsize - bit) < maxcnt)) {
break; /* already found max */
}
}
return maxcnt;
}
/*
* And an integer vector and a bitstring and sum the elements corresponding
* to set entries in b2: SUM(i1 & b2)
* Note: if b2 is longer than i1, then elements are wrapped into i1
* i1 (IN) integer vector
* b2 (IN) bitstring
*/
int
int_and_set_count(int *i1, int ilen, bitstr_t *b2) {
bitoff_t bit;
int sum;
_assert_bitstr_valid(b2);
sum = 0;
for (bit = 0; bit < _bitstr_bits(b2); bit++) {
if (bit_test(b2, bit))
sum += i1[bit % ilen];
}
return(sum);
}
/*
* rotate b1 by n bits returning a rotated copy
* b1 (IN) bitmap to rotate
* n (IN) rotation distance (+ = rotate left, - = rotate right)
* nbits (IN) size of the new copy (in which the rotation occurs)
* note: nbits must be >= bit_size(b1)
* RETURN new rotated bitmap
*/
bitstr_t *
bit_rotate_copy(bitstr_t *b1, int n, bitoff_t nbits) {
bitoff_t bit, dst;
bitstr_t *new;
bitoff_t bitsize;
bitoff_t deltasize, wrapbits;
_assert_bitstr_valid(b1);
bitsize = bit_size(b1);
assert(nbits >= bitsize);
deltasize = nbits - bitsize;
/* normalize n to a single positive rotation */
n = n % nbits;
if (n < 0) {
n += nbits;
}
wrapbits = 0; /* number of bits that will wrap around */
if (n > deltasize) {
wrapbits = n - deltasize;
}
new = bit_alloc(nbits);
bit_nclear(new,0,nbits-1);
/* bits shifting up */
for (bit = 0; bit < (bitsize-wrapbits); bit++) {
if (bit_test(b1, bit))
bit_set(new, bit+n);
}
/* continue bit into wrap-around bits, if any */
for (dst = 0; bit < bitsize; bit++, dst++) {
if (bit_test(b1, bit))
bit_set(new, dst);
}
return(new);
}
/*
* rotate b1 by n bits
* b1 (IN/OUT) bitmap to rotate
* n (IN) rotation distance (+ = rotate left, - = rotate right)
*/
void
bit_rotate(bitstr_t *b1, int n) {
uint32_t bitsize;
bitstr_t *new;
if (n == 0)
return;
_assert_bitstr_valid(b1);
bitsize = bit_size(b1);
new = bit_rotate_copy(b1, n, bitsize);
bit_copybits(b1, new);
bit_free(new);
}
/*
* build a bitmap containing the first nbits of b which are set
*/
bitstr_t *
bit_pick_cnt(bitstr_t *b, bitoff_t nbits) {
bitoff_t bit = 0, new_bits, count = 0;
bitstr_t *new;
_assert_bitstr_valid(b);
if (_bitstr_bits(b) < nbits)
return NULL;
new = bit_alloc(bit_size(b));
if (new == NULL)
return NULL;
while ((bit < _bitstr_bits(b)) && (count < nbits)) {
int word = _bit_word(bit);
if (b[word] == 0) {
bit += sizeof(bitstr_t)*8;
continue;
}
new_bits = hweight(b[word]);
if ((count + new_bits) <= nbits) {
new[word] = b[word];
count += new_bits;
bit += sizeof(bitstr_t)*8;
continue;
}
while ((bit < _bitstr_bits(b)) && (count < nbits)) {
if (bit_test(b, bit)) {
bit_set(new, bit);
count++;
}
bit++;
}
}
if (count < nbits) {
bit_free (new);
new = NULL;
}
return new;
}
/*
* XXX the relationship between stdint types and "unsigned [long] long"
* types is architecture/compiler dependent, so this may have to be tweaked.
*/
#ifdef USE_64BIT_BITSTR
#define BITSTR_RANGE_FMT "%llu-%llu,"
#define BITSTR_SINGLE_FMT "%llu,"
#else
#define BITSTR_RANGE_FMT "%u-%u,"
#define BITSTR_SINGLE_FMT "%u,"
#endif
/*
* Convert to range string format, e.g. 0-5,42
*/
char *
bit_fmt(char *str, int len, bitstr_t *b)
{
int count = 0, ret, word;
bitoff_t start, bit;
_assert_bitstr_valid(b);
assert(len > 0);
*str = '\0';
for (bit = 0; bit < _bitstr_bits(b); ) {
word = _bit_word(bit);
if (b[word] == 0) {
bit += sizeof(bitstr_t)*8;
continue;
}
if (bit_test(b, bit)) {
count++;
start = bit;
while (bit+1 < _bitstr_bits(b) && bit_test(b, bit+1))
bit++;
if (bit == start) /* add single bit position */
ret = snprintf(str+strlen(str),
len-strlen(str),
BITSTR_SINGLE_FMT, start);
else /* add bit position range */
ret = snprintf(str+strlen(str),
len-strlen(str),
BITSTR_RANGE_FMT, start, bit);
assert(ret != -1);
}
bit++;
}
if (count > 0)
str[strlen(str) - 1] = '\0'; /* zap trailing comma */
if (count > 1) { /* add braces */
assert(strlen(str) + 3 < len);
memmove(str + 1, str, strlen(str));
str[0] = '[';
strcat(str, "]");
}
return str;
}
int
bit_unfmt(bitstr_t *b, char *str)
{
int *intvec, *p, rc = 0;
_assert_bitstr_valid(b);
intvec = bitfmt2int(str);
if (intvec == NULL)
return -1;
bit_nclear(b, 0, _bitstr_bits(b) - 1);
for (p = intvec; *p != -1; p += 2) {
if ((*p < 0) || (*p >= _bitstr_bits(b))
|| (*(p + 1) < 0) || (*(p + 1) >= _bitstr_bits(b))) {
rc = -1;
break;
}
bit_nset(b, *p, *(p + 1));
}
xfree(intvec);
return rc;
}
/*
* bitfmt2int - convert a string describing bitmap (output from bit_fmt,
* e.g. "0-30,45,50-60") into an array of integer (start/end) pairs
* terminated by -1 (e.g. "0, 30, 45, 45, 50, 60, -1")
* input: bitmap string as produced by bitstring.c : bitfmt
* output: an array of integers
* NOTE: the caller must xfree the returned memory
*/
int *
bitfmt2int (char *bit_str_ptr)
{
int *bit_int_ptr, i, bit_inx, size, sum, start_val;
if (bit_str_ptr == NULL)
return NULL;
size = strlen (bit_str_ptr) + 1;
bit_int_ptr = xmalloc ( sizeof (int) *
(size * 2 + 1)); /* more than enough space */
bit_inx = sum = 0;
start_val = -1;
for (i = 0; i < size; i++) {
if (bit_str_ptr[i] >= '0' &&
bit_str_ptr[i] <= '9'){
sum = (sum * 10) + (bit_str_ptr[i] - '0');
}
else if (bit_str_ptr[i] == '-') {
start_val = sum;
sum = 0;
}
else if (bit_str_ptr[i] == ',' ||
bit_str_ptr[i] == '\0') {
if (i == 0)
break;
if (start_val == -1)
start_val = sum;
bit_int_ptr[bit_inx++] = start_val;
bit_int_ptr[bit_inx++] = sum;
start_val = -1;
sum = 0;
}
}
assert(bit_inx < (size*2+1));
bit_int_ptr[bit_inx] = -1;
return bit_int_ptr;
}
/* bit_fmt_hexmask
*
* Given a bitstr_t, allocate and return a string in the form of:
* "0x0123ABC\0"
* ^ ^
* | |
* MSB LSB
* bitmap (IN) bitmap to format
* RETURN formatted string
*/
char * bit_fmt_hexmask(bitstr_t * bitmap)
{
char *retstr, *ptr;
char current;
bitoff_t i;
bitoff_t bitsize = bit_size(bitmap);
/* 4 bits per ASCII '0'-'F' */
bitoff_t charsize = (bitsize + 3) / 4;
retstr = xmalloc(charsize + 3);
retstr[0] = '0';
retstr[1] = 'x';
retstr[charsize + 2] = '\0';
ptr = &retstr[charsize + 1];
for (i=0; i < bitsize;) {
current = 0;
if ( bit_test(bitmap,i++)) current |= 0x1;
if ((i < bitsize) && bit_test(bitmap,i++)) current |= 0x2;
if ((i < bitsize) && bit_test(bitmap,i++)) current |= 0x4;
if ((i < bitsize) && bit_test(bitmap,i++)) current |= 0x8;
if (current <= 9) {
current += '0';
} else {
current += 'A' - 10;
}
*ptr-- = current;
}
return retstr;
}
/* bit_unfmt_hexmask
*
* Given a hex mask string "0x0123ABC\0", convert to a bitstr_t *
* ^ ^
* | |
* MSB LSB
* bitmap (OUT) bitmap to update
* str (IN) hex mask string to unformat
*/
int bit_unfmt_hexmask(bitstr_t * bitmap, const char* str)
{
int bit_index = 0, len = strlen(str);
int rc = 0;
const char *curpos = str + len - 1;
char current;
bitoff_t bitsize = bit_size(bitmap);
if (strncmp(str, "0x", 2) == 0) { /* Bypass 0x */
str += 2;
len -= 2;
}
while(curpos >= str) {
current = (int) *curpos;
if (isxdigit(current)) { /* valid hex digit */
if (isdigit(current)) {
current -= '0';
} else {
current = toupper(current);
current -= 'A' - 10;
}
} else { /* not a valid hex digit */
current = 0;
rc = -1;
}
if ((current & 1) && (bit_index < bitsize))
bit_set(bitmap, bit_index);
if ((current & 2) && (bit_index+1 < bitsize))
bit_set(bitmap, bit_index+1);
if ((current & 4) && (bit_index+2 < bitsize))
bit_set(bitmap, bit_index+2);
if ((current & 8) && (bit_index+3 < bitsize))
bit_set(bitmap, bit_index+3);
len--;
curpos--;
bit_index+=4;
}
return rc;
}
/* bit_fmt_binmask
*
* Given a bitstr_t, allocate and return a binary string in the form of:
* "0001010\0"
* ^ ^
* | |
* MSB LSB
* bitmap (IN) bitmap to format
* RETURN formatted string
*/
char * bit_fmt_binmask(bitstr_t * bitmap)
{
char *retstr, *ptr;
char current;
bitoff_t i;
bitoff_t bitsize = bit_size(bitmap);
/* 1 bits per ASCII '0'-'1' */
bitoff_t charsize = bitsize;
retstr = xmalloc(charsize + 1);
retstr[charsize] = '\0';
ptr = &retstr[charsize - 1];
for (i=0; i < bitsize;) {
current = 0;
if (bit_test(bitmap,i++)) current |= 0x1;
current += '0';
*ptr-- = current;
}
return retstr;
}
/* bit_unfmt_binmask
*
* Given a binary mask string "0001010\0", convert to a bitstr_t *
* ^ ^
* | |
* MSB LSB
* bitmap (OUT) bitmap to update
* str (IN) hex mask string to unformat
*/
int bit_unfmt_binmask(bitstr_t * bitmap, const char* str)
{
int bit_index = 0, len = strlen(str);
const char *curpos = str + len - 1;
char current;
bitoff_t bitsize = bit_size(bitmap);
while(curpos >= str) {
current = (int) *curpos;
current -= '0';
if ((current & 1) && (bit_index < bitsize))
bit_set(bitmap, bit_index);
len--;
curpos--;
bit_index++;
}
return 0;
}
/* Find the bit set at pos (0 - bitstr_bits) in bitstr b.
* b (IN) bitstring to search
* pos (IN) bit to search for
* RETURN number bit is set in bitstring (-1 on error)
*/
bitoff_t
bit_get_bit_num(bitstr_t *b, int pos)
{
bitoff_t bit;
int cnt = 0;
bitoff_t bit_cnt;
_assert_bitstr_valid(b);
bit_cnt = _bitstr_bits(b);
assert(pos <= bit_cnt);
for (bit = 0; bit < bit_cnt; bit++) {
if (bit_test(b, bit)) { /* we got one */
if(cnt == pos)
break;
cnt++;
}
}
if(bit >= bit_cnt)
bit = -1;
return bit;
}
/* Find want nth the bit pos is set in bitstr b.
* b (IN) bitstring to search
* pos (IN) bit to search to
* RETURN number bit is set in bitstring (-1 on error)
*/
int
bit_get_pos_num(bitstr_t *b, bitoff_t pos)
{
bitoff_t bit;
int cnt = -1;
bitoff_t bit_cnt;
_assert_bitstr_valid(b);
bit_cnt = _bitstr_bits(b);
assert(pos <= bit_cnt);
if (!bit_test(b, pos)) {
error("bit %d not set", pos);
return cnt;
}
for (bit = 0; bit <= pos; bit++) {
if (bit_test(b, bit)) { /* we got one */
cnt++;
}
}
return cnt;
}