/*
test
Use bit map to track sprite allocation. The sprite data is
allocated in an array and tracked using a bit map. A one
on in the bit map shows that the sprite is in use. A zero
on indicates that the sprite data is free and not in use.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEBUG 1
#define TRACE 1
static char const ident[] =
"$Id: msprite.c,v 1.3 2005/09/27 20:28:57 gmiller Exp gmiller $";
#include "debug.h"
const int SHIFT_SIZE[17] =
{ 0, 3, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7 };
// macros
#define ELEMENT_BITS ((sizeof(int)*8))
#define ELEMENT_MASK (ELEMENT_BITS - 1)
#define ELEMENT_SHIFT (SHIFT_SIZE[sizeof(int)])
#define ALL_ELEMENTS_USED (~0)
//
/*
sample line:
// increment variable. (WHAT not HOW)
fubar_variable = - (~fubar_valiable);
*/
typedef enum
{ NO_ERROR = 0,
BAD_SPRITE_PTR = -1,
BAD_SPRITE_NO = -2,
BAD_SPRITE_IS_FREE = -3,
BAD_SPRITE_IS_USED = -4,
BAD_SPRITE_ALL_USED = -5,
BAD_ALL_SPRITES_FREE = -6
} sprite_error;
typedef struct _sprites_
{
int x; // Current Sprite location x,y
int y;
int rows, cols; // Size of Sprite Row x Col
char *elements; // Data to display (size is Row x Col)
int life_value; // Life force
int sprite_number; // Sprite number in set, zero based
} sprite;
typedef struct _allocation_data_
{
int number_of_elements; // number of possible sprites
int first_free; // first element with free bit
int shift_amt; // shift for entry index
int bit_mask; // mask to isolate bit number
int max_entry; // maximum entry in array of bits
int *bit_table; // bits for each possible sprite
int free_cnt; // number of free sprites
int used_cnt; // number of used sprites
} allocation_data;
typedef struct _sprite_tbl_
{
allocation_data salloc; // allocation data
sprite *sprites; // sprite data
} sprite_tbl;
/*
Allocate space to manage a group of "number_of_sprites"
using the defined structures. Allocate space, initalize
memory and return pointer. Return != NULL if no error otherwise
return NULL
Sample usage:
sprite_tbl tbl_ptr;
tbl_ptr = allocate_sprite_table( 1024 );
if ( tbl_ptr == NULL ) {
printf("Table allocation failed.\n");
exit( -1 );
}
*/
sprite_tbl *
allocate_sprite_table (int number_of_sprites)
{
static char my_fn[] = "allocate_sprite_table";
sprite_tbl sample, *tmp_s;
int i;
int last_element_no = number_of_sprites - 1;
enter (my_fn);
// Check size of int on this platform
if ((sizeof (int) + 1) > (sizeof (SHIFT_SIZE) / sizeof (int))) {
printf ("Shift table size exceeded, modify code for this machine.\n");
exit (-1);
}
// Check for number of sprites
if (number_of_sprites <= 0)
rtnval (NULL);
// Allocate space for for table area
tmp_s = (sprite_tbl *) malloc (sizeof (sprite_tbl));
if (tmp_s == NULL)
rtnval (NULL);
// Clear data area
memset (tmp_s, 0, sizeof (sprite_tbl));
// Allocate space for sprites
tmp_s->sprites = calloc (number_of_sprites, sizeof (sprite));
if (tmp_s->sprites == NULL) {
free (tmp_s);
rtnval (NULL);
}
// Initalize sprite numbers
for (i = 0; i < number_of_sprites; i++)
tmp_s->sprites[i].sprite_number = i;
// Set table initial values
tmp_s->salloc.number_of_elements = number_of_sprites;
tmp_s->salloc.shift_amt = ELEMENT_SHIFT; // Shift amount for each "int"
tmp_s->salloc.bit_mask = ELEMENT_MASK; // mask to clear unused bits
// Allocate bit table
//TODO::
tmp_s->salloc.bit_table = (int *) calloc (((number_of_sprites +
(ELEMENT_BITS -
1)) >> ELEMENT_SHIFT),
sizeof (int));
// Allocate the correct number of bits
if (tmp_s->salloc.bit_table == NULL) {
free (tmp_s);
rtnval (NULL);
}
// Set count of free sprites to number of sprites
tmp_s->salloc.free_cnt = number_of_sprites;
//
tmp_s->salloc.max_entry = (last_element_no >> ELEMENT_SHIFT);
// Check bit usage in last element
//
if ((last_element_no & ELEMENT_MASK) != (ELEMENT_BITS - 1)) {
int tmp_bit = ((~0) << ((last_element_no & ELEMENT_MASK) + 1));
/*
last bit used (zero based) and add one to get next power of 2, shift
an all one value to the left to clear the number of bit positions and
then use that to set the last position in the table.
*/
// Fix last element for bits allocated after last element
tmp_s->salloc.bit_table[tmp_s->salloc.max_entry] = (tmp_bit);
}
rtnval (tmp_s);
}
/*
Return a pointer to a free sprite in the passed table. If no
free sprites are found return a NULL, otherwise mark the sprite
as "inuse" and return a pointer to the structure.
Sample usage:
sprite * sp_ptr;
sp_ptr = get_free_sprite( tbl_ptr, &err_flag );
if ( err_flag != NO_ERROR ) {
printf("Get free sprite failed with error %d\n", err_flag);
exit( -1 );
}
*/
sprite *
get_free_sprite (sprite_tbl * stbl, sprite_error * err)
{
static char my_fn[] = "get_free_sprite";
int i, *tmp, mask;
enter (my_fn);
if (stbl == NULL) { // bad ptr
*err = BAD_SPRITE_PTR;
rtnval (NULL);
}
if (stbl->salloc.free_cnt == 0) { // none free
*err = BAD_SPRITE_ALL_USED;
rtnval (NULL);
}
//
tmp = stbl->salloc.bit_table + stbl->salloc.first_free; // point a first bit mask
for (i = stbl->salloc.first_free; i <= stbl->salloc.max_entry; i++, tmp++) { // loop through bit masks
if (*tmp != (~0)) { // All bits on, then all used, otherwise some free
//
int bit_array_index = (i << stbl->salloc.shift_amt); // get bit number of first bit
int bit_offset; // count bits
int mask = 1; // mask for first bit
/*
Loop through all possible bit positions, count bits and shifting mask.
*/
for (bit_offset = 0; bit_offset < ELEMENT_BITS; // loop through bits
//
bit_offset++, mask = mask << 1) { // looking for 0 bits
if (((*tmp) & mask) == 0) { // bit off ??
bit_array_index += bit_offset; // get bit number
*tmp = (*tmp) | mask; // mark bit used
stbl->salloc.used_cnt++; // one more used
stbl->salloc.free_cnt--; // one less free
*err = NO_ERROR;
rtnval (stbl->sprites + bit_array_index); // return pointer to bit data
}
}
*err = BAD_SPRITE_ALL_USED;
rtnval (NULL); // all used .... this means free count is fubar.
}
}
*err = BAD_SPRITE_ALL_USED;
rtnval (NULL); // all used .... this means free count is fubar.
}
/*
Mark a "inuse" sprite as free in the passed table. If the sprite
is not "inuse" or any other error return a nonzero value that
indicates the error.
Sample usage:
sprite_error sp_error;
sp_error = free_sprite( tbl_ptr, 5 );
if ( sp_error != NO_ERROR ) {
printf("Free of sprite failed with error %d\n", sp_error );
exit( -1 );
}
*/
sprite_error
free_sprite (sprite_tbl * stbl, int sprite_number)
{
static char my_fn[] = "free_sprite";
int bit_array_index; // get bit array index
int bit_mask; // get bit mask
enter (my_fn);
if (stbl == NULL) // bad ptr
rtnval (BAD_SPRITE_PTR);
if (stbl->salloc.used_cnt == 0) // none used
rtnval (BAD_ALL_SPRITES_FREE);
if ((sprite_number >= stbl->salloc.number_of_elements) || // out of range
(sprite_number < 0)) // out of range
rtnval (BAD_SPRITE_NO);
// Get mask to isolate correct bit
//
bit_array_index = (sprite_number >> stbl->salloc.shift_amt);
bit_mask = (1 << (sprite_number & (stbl->salloc.bit_mask)));
// Check for bit on
//
if ((stbl->salloc.bit_table[bit_array_index] & bit_mask) != 0) {
//
stbl->salloc.bit_table[bit_array_index] &= ~bit_mask; // turn bit off
stbl->salloc.used_cnt--; // one less used
stbl->salloc.free_cnt++; // one more free
if (bit_array_index < stbl->salloc.first_free) // reset first free if needed
stbl->salloc.first_free = bit_array_index;
rtnval (NO_ERROR);
}
rtnval (BAD_SPRITE_IS_FREE);
}
/*
Get the pointer to an "inuse" sprite in the passed table. If the
sprite is not "inuse" or some other error return a NULL.
Sample usage:
sprite * sp_ptr;
sprite_error err_flag;
sp_ptr = get_used_sprite( tbl_ptr, 5, &err_flag );
if ( err_flag != NO_ERROR ) {
printf("Get pointer to used sprite failed with error %d\n", err_flag );
exit( -1 );
}
*/
sprite *
get_used_sprite (sprite_tbl * stbl, int sprite_number, sprite_error * err)
{
static char my_fn[] = "get_used_sprite";
int bit_array_index; // get bit array index
int bit_mask; // get bit mask
enter (my_fn);
if (stbl == NULL) { // bad ptr
*err = BAD_SPRITE_PTR;
rtnval (NULL);
}
if (stbl->salloc.used_cnt == 0) { // none used
*err = BAD_ALL_SPRITES_FREE;
rtnval (NULL);
}
if ((sprite_number >= stbl->salloc.number_of_elements) || // out of range
(sprite_number < 0)) { // out of range
*err = BAD_SPRITE_NO;
rtnval (NULL);
}
// Get mask to isolate correct bit
//
bit_array_index = (sprite_number >> stbl->salloc.shift_amt);
bit_mask = (1 << (sprite_number & (stbl->salloc.bit_mask)));
// Check for bit on
//
if ((stbl->salloc.bit_table[bit_array_index] & bit_mask) != 0) { // bit on ??
*err = NO_ERROR;
rtnval (stbl->sprites + sprite_number);
}
*err = BAD_SPRITE_IS_FREE;
rtnval (NULL);
}
int
main (int argc, char **argv)
{
static char my_fn[] = "msprite";
sprite_tbl *my_sprites;
sprite *tmp_s;
int i, number;
sprite_error err;
sprite_error *err_ptr = &err;
enter (my_fn);
set_debug ();
Log_debug ("This is the start of the program");
if (argc < 2) {
printf ("%s n\n", argv[0]);
printf (" n - count of sprites\n");
exit (-1);
}
number = atoi (argv[1]);
my_sprites = allocate_sprite_table (number);
if (my_sprites == NULL) {
printf ("Unable to allocate sprite table\n");
exit (-1);
}
for (i = 0; i < (my_sprites->salloc.number_of_elements + 2); i++) {
if ((tmp_s = get_free_sprite (my_sprites, err_ptr)) == NULL)
printf ("Get free failed on try %d with error %d\n", i, err);
}
printf ("After get_free, used = %d, free = %d\n",
my_sprites->salloc.used_cnt, my_sprites->salloc.free_cnt);
for (i = 0; i < (my_sprites->salloc.number_of_elements + 2); i++) {
if ((tmp_s = get_used_sprite (my_sprites, i, err_ptr)) == NULL)
printf ("Get used failed on try %d with error %d\n", i, err);
}
printf ("After get_used, used = %d, free = %d\n",
my_sprites->salloc.used_cnt, my_sprites->salloc.free_cnt);
for (i = 2; i < (my_sprites->salloc.number_of_elements); i++) {
if ((err = free_sprite (my_sprites, i)) != 0)
printf ("Free for sprite %d failed with error %d\n", i, err);
}
printf ("After free_sprite, used = %d, free = %d\n",
my_sprites->salloc.used_cnt, my_sprites->salloc.free_cnt);
for (i = 0; i < 2; i++) {
if ((tmp_s = get_used_sprite (my_sprites, i, err_ptr)) == NULL)
printf ("Get used failed on try %d with error %d\n", i, err);
}
printf ("After 2nd get_free, used = %d, free = %d\n",
my_sprites->salloc.used_cnt, my_sprites->salloc.free_cnt);
rtnval (0);
}
|