/*
 * Bitfield
 * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
 *
 * This software may be distributed under the terms of the BSD license.
 * See README for more details.
 */

#include "includes.h"

#include "common.h"
#include "bitfield.h"


struct bitfield {
	u8 *bits;
	size_t max_bits;
};


struct bitfield * bitfield_alloc(size_t max_bits)
{
	struct bitfield *bf;

	bf = os_zalloc(sizeof(*bf) + (max_bits + 7) / 8);
	if (bf == NULL)
		return NULL;
	bf->bits = (u8 *) (bf + 1);
	bf->max_bits = max_bits;
	return bf;
}


void bitfield_free(struct bitfield *bf)
{
	os_free(bf);
}


void bitfield_set(struct bitfield *bf, size_t bit)
{
	if (bit >= bf->max_bits)
		return;
	bf->bits[bit / 8] |= BIT(bit % 8);
}


void bitfield_clear(struct bitfield *bf, size_t bit)
{
	if (bit >= bf->max_bits)
		return;
	bf->bits[bit / 8] &= ~BIT(bit % 8);
}


int bitfield_is_set(struct bitfield *bf, size_t bit)
{
	if (bit >= bf->max_bits)
		return 0;
	return !!(bf->bits[bit / 8] & BIT(bit % 8));
}


static int first_zero(u8 val)
{
	int i;
	for (i = 0; i < 8; i++) {
		if (!(val & 0x01))
			return i;
		val >>= 1;
	}
	return -1;
}


int bitfield_get_first_zero(struct bitfield *bf)
{
	size_t i;
	for (i = 0; i <= (bf->max_bits + 7) / 8; i++) {
		if (bf->bits[i] != 0xff)
			break;
	}
	if (i > (bf->max_bits + 7) / 8)
		return -1;
	i = i * 8 + first_zero(bf->bits[i]);
	if (i >= bf->max_bits)
		return -1;
	return i;
}