Memory efficient C queues

About tiny tiny C code:

If I wanted to use a set amount of memory, like

unsigned char byteMem[2048]

in which to store and manipulate a number of byte queues; my standard C approach would be to create a set of structs the let me pool out chunks of memory from the space for the byte queues to work in.

I am not having luck finding references on how to keep the most possible usable space for my queues to use.

2 questions:

- What are some good books or other reading on memory efficient C code?

- Have I missed some easy optimizations in the following code?

The QueueSlot uses 8 bits for a queue identifier and 8 bits for storing a value. Is better memory efficiency just a matter of using more of memory for data storage?

Feel free to chop out most of this in replies:

I wrote some some C code that is straight forward enough

-------------------------------------------------------------------------- /* compactqueues.h

*/

//A place to store the queues typedef struct {

int dataLength; unsigned char* data;

} Store;

// A memory layout for a queue slot // A tag and a value // This approach is decidely in favor of very dynamic behavior sacrificing some // memory space for tagging. But any queue can easily grow to any size // permitted by the buffer limit. typedef struct {

unsigned char slotTag : 8; unsigned char slotValue : 8;

} QueueSlot;

//A queue in this approach needs to have //a distinct tag value //a headIndex for implicit queue ordering //and access to the buffer typedef struct {

unsigned char myTag : 4; int headIndex; Store *storeAccess;

} Queue;

//This is a convenience collection to pool access to the //management bits typedef struct { Queue *queuePool; unsigned char *queueMarkers; unsigned char poolSize; Store *storeKeeper; } QueueKeeper;

// An initialization function // To scrub the store buffer to 0's void initQueuePool();

Queue * create_queue();

void destroy_queue(Queue * q);

void enqueue_byte(Queue * q, unsigned char b);

unsigned char dequeue_byte(Queue * aQueue);

------------------------------------------------------------------------------------------- /* compactqueues.c

*/ #include "CompactQueue.h" #include //#include

//#define DEFAULT_STORE_SIZE 2048

//unsigned short externStoreSize = DEFAULT_STORE_SIZE;

//unsigned char TagGenerator = 0;

QueueKeeper* externQueueKeeper;

void on_out_of_memory() {

fprintf( stdout, "Out of memory! \n" );

while (1) { //dont return? well ok then

} }

void on_illegal_operation() { fprintf( stdout, "Illegal operation! \n" );

while (1) { //dont return? well ok then

}

} void initQueuePool() {

if ( externQueueKeeper ) { //Scrub the marker slots to 0 for ( short i=0; i< externQueueKeeper->poolSize; ++i ) { externQueueKeeper->queueMarkers[i] = 0; }

//Scrub the data slots to 0 if ( externQueueKeeper->storeKeeper ) {

Store* localStoreAccess = externQueueKeeper->storeKeeper; unsigned char* store = localStoreAccess->data;

if (store) {

QueueSlot * asSlot = (QueueSlot*) store;

int slotCount = localStoreAccess->dataLength / sizeof(QueueSlot) ;

for ( int i=0;i< slotCount; ++i) {

asSlot->slotTag = 0; asSlot->slotValue = 0; //fprintf( stdout, "Clear QueueSlots - Slot - %i, Value - %i \n", asSlot->slotTag, asSlot->slotValue );

++asSlot; } } } } }

Queue* create_queue() {

if ( !externQueueKeeper ) return 0;

short indexToTake = -1;

for ( short i=0; i< externQueueKeeper->poolSize; ++i ) { if ( externQueueKeeper->queueMarkers[i] == 0 ) { indexToTake = i; //fprintf(stdout, "indexToTake - %i\n", indexToTake ); break; }

}

if ( indexToTake > -1 ) { externQueueKeeper->queueMarkers[indexToTake] = 1; externQueueKeeper->queuePool[indexToTake].myTag = indexToTake + 1; externQueueKeeper->queuePool[indexToTake].headIndex = 0; externQueueKeeper->queuePool[indexToTake].storeAccess = externQueueKeeper->storeKeeper; return &(externQueueKeeper->queuePool[indexToTake]); }

return 0; }

void destroy_queue(Queue * q) {

if ( q && q->storeAccess ) {

Store* localStoreAccess = q->storeAccess; unsigned char* store = localStoreAccess->data;

if (store) {

QueueSlot * asSlot = (QueueSlot*) store;

int slotCount = localStoreAccess->dataLength / sizeof(QueueSlot) ;

int headOffset = q->headIndex; int slotsFreed = 0; for ( int i=0 ;i < slotCount; ++i) {

QueueSlot* currentSlot = (asSlot + headOffset%slotCount);

if ( currentSlot->slotTag == q->myTag ) { currentSlot->slotTag = 0; currentSlot->slotValue = 0; ++slotsFreed; }

} //fprintf( stdout, "Destroying Queue - %i. %i slots left in use are now free.\n", q->myTag, slotsFreed );

//Reset Queue for reuse from the pool. externQueueKeeper->queueMarkers[q->myTag] = 0; q->headIndex = 0; q->myTag = 0; q->storeAccess = 0;

//now the queue for pool slot can be found for use again

}

} }

void enqueue_byte(Queue * q, unsigned char b) {

if ( q && q->storeAccess ) {

Store* localStoreAccess = q->storeAccess; unsigned char* store = localStoreAccess->data;

if (store) {

QueueSlot * asSlot = (QueueSlot*) store;

int slotCount = localStoreAccess->dataLength / sizeof(QueueSlot) ;

int headOffset = q->headIndex; int slotUsed = -1; for ( int i=0 ;i < slotCount; ++i) { int currentIndex = (i + headOffset%slotCount); QueueSlot* currentSlot = (asSlot + headOffset%slotCount);

if ( currentSlot->slotTag == 0 ) { slotUsed = currentIndex; currentSlot->slotTag = q->myTag;// this slot know belongs to the queue passed in currentSlot->slotValue = b;

//fprintf( stdout, "Slot %i belongs to queue- %i, with Value - %i \n", currentIndex, currentSlot->slotTag, currentSlot->slotValue ); break; }

++asSlot; }

if ( slotUsed == -1 ) { fprintf( stdout, "No Slot open. Enqueue failed \n" ); on_out_of_memory(); }

} }

}

unsigned char dequeue_byte(Queue * q) {

unsigned char dequeueduchar = 0;

if ( q && q->storeAccess ) {

Store* localStoreAccess = q->storeAccess; unsigned char* store = localStoreAccess->data;

if ( store ) {

QueueSlot * asSlot = (QueueSlot*) store;

int slotCount = localStoreAccess->dataLength / sizeof(QueueSlot) ; int headOffset = q->headIndex;

unsigned char seeking = 1; //first seek the bit to dequeue, then try to update the headIndex

for ( int i=0;i< slotCount; ++i) { int currentIndex = (i + headOffset%slotCount); QueueSlot* currentSlot = (asSlot + headOffset%slotCount); //find the first slot with myTag as the slotTag value //use mod to do a complete loop around starting from the headIndex if ( seeking ) {

if ( currentSlot->slotTag == q->myTag ) { dequeueduchar = currentSlot->slotValue;

//free the slot for use currentSlot->slotValue = 0; currentSlot->slotTag = 0; q->headIndex = 0; //this will get updated to the true next headIndex if there really is a next one, if not then it should be 0 anyway //fprintf( stdout, "Free slot %i from Queue- %i, returning Value

- %i \n", currentIndex, currentSlot->slotTag, dequeueduchar ); seeking = 0; } } else {

if ( currentSlot->slotTag == q->myTag ) {

q->headIndex = currentIndex; //fprintf( stdout, "Updating headIndex of Queue- %i to slot - %i \n", q->myTag, currentIndex );

return dequeueduchar; } }

++asSlot; }

//if ( q->headIndex == 0 ) // fprintf( stdout, "Reseting headIndex of Queue- %i to slot 0 \n", q->myTag );

//if nothing to dequeue for given queue if ( seeking == 1 ) on_illegal_operation();

} }

return dequeueduchar; }

------------------------------------------------------------------------------------------- /* main.c - Test it out

*/

#include #include "CompactQueue.h"

extern QueueKeeper* externQueueKeeper; //extern unsigned short externStoreSize;

int main (int argc, const char * argv[]) {

Store aStore; const int storeSize = 2048; //aStore.dataLength = externStoreSize; unsigned char storeData[storeSize]; aStore.dataLength = storeSize; aStore.data = storeData; const unsigned char poolSize = 64;

//setup the zooKeeper, I mean queueKeeper QueueKeeper aQueueKeeper;

Queue aQueuePool[poolSize]; unsigned char queueMarkers[poolSize]; aQueueKeeper.queuePool = aQueuePool; aQueueKeeper.queueMarkers = queueMarkers; aQueueKeeper.poolSize = poolSize; aQueueKeeper.storeKeeper = &aStore; externQueueKeeper = &aQueueKeeper; initQueuePool();

//Queues in action

Queue* q1 = create_queue(); Queue* q2 = create_queue();

enqueue_byte(q1, 0); enqueue_byte(q1, 1);

enqueue_byte(q2, 3); enqueue_byte(q1, 2); enqueue_byte(q2, 4);

printf("%d ", dequeue_byte(q1)); printf("%d\n", dequeue_byte(q1)); enqueue_byte(q1, 5); enqueue_byte(q2, 6);

printf("%d ", dequeue_byte(q1)); printf("%d\n", dequeue_byte(q1)); destroy_queue(q1); printf("%d ", dequeue_byte(q2)); printf("%d ", dequeue_byte(q2)); printf("%d\n", dequeue_byte(q2)); destroy_queue(q2);

return 0; }

Reply to
Iggins
Loading thread data ...

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.