Skip to content

Instantly share code, notes, and snippets.

@tkafka
Created December 7, 2013 23:10
Show Gist options
  • Save tkafka/7851091 to your computer and use it in GitHub Desktop.
Save tkafka/7851091 to your computer and use it in GitHub Desktop.
OMG, ringbuffer in C macros :)
#include <stdlib.h>
#include <memory.h>
#include <malloc.h>
#ifndef _ringbuffer_h
#define _ringbuffer_h
// semantics: buffer goes from start to end-1, start == end -> empty or full, see 'full' flag
#define ringBuffer_typedef(T, NAME) \
typedef struct { \
int count; \
int size; \
int start; \
int end; \
bool full; \
T* elems; \
} NAME
#define ringBufferInit(BUF_PTR, BUF_LENGTH, BUF_ENTRY_TYPE, BUF_TYPE) \
assert(BUF_LENGTH > 0); \
BUF_TYPE t; \
BUF_PTR = &t; \
BUF_PTR->size = BUF_LENGTH; \
BUF_PTR->count = 0; \
BUF_PTR->start = 0; \
BUF_PTR->end = 0; \
BUF_PTR->full = false; \
BUF_PTR->elems = (BUF_ENTRY_TYPE*)malloc(BUF_PTR->size * sizeof(BUF_ENTRY_TYPE)); \
memset(BUF_PTR->elems, 0, BUF_PTR->size * sizeof(BUF_ENTRY_TYPE))
#define ringBufferDestroy(BUF) free(BUF->elems)
#define ringBufferNextStartIndex(BUF) ((BUF->start + 1) % BUF->size)
#define ringBufferNextEndIndex(BUF) ((BUF->end + 1) % BUF->size)
#define ringBufferIsEmpty(BUF) (BUF->end == BUF->start && !BUF->full)
#define ringBufferIsFull(BUF) (BUF->full)
#define ringBufferReset(BUF, ELEM) \
BUF->count = 0; \
BUF->start = 0; \
BUF->end = 0; \
BUF->full = false
#define ringBufferWrite(BUF, ELEM) \
BUF->elems[BUF->end] = ELEM; \
BUF->end = ringBufferNextEndIndex(BUF); \
if (!BUF->full) { \
BUF->count++; \
if (BUF->end == BUF->start) { \
BUF->full = true; \
} \
} else { \
BUF->start = ringBufferNextStartIndex(BUF); \
}
#define ringBufferRead(BUF, I, ELEM) \
assert(I < BUF->count); \
ELEM = BUF->elems[(BUF->start + I) % BUF->size]
#define ringBufferForEach(BUF, item) \
for(int keep = 1, \
count = 0, \
i = BUF->start;\
keep && ((BUF->full) ? (count==0 || i != BUF->end) : i != BUF->end); \
keep = !keep, i = (i + 1) % BUF->size, count++) \
for(item = BUF->elems[i]; keep; keep = !keep)
#define ringBufferForEachRaw(BUF, item) \
for(int keep = 1, \
i = 0;\
keep && i < BUF->size; \
keep = !keep, i++) \
for(item = BUF->elems[i]; keep; keep = !keep)
#endif
#include <SDKDDKVer.h>
#include <stdio.h>
#include <tchar.h>
#include <assert.h>
#include "lib/c-generic-ring-buffer/ringbuffer.h"
ringBuffer_typedef(int, IntBuffer);
void printIntBufferRaw(IntBuffer* buffer, char* message) {
int item;
printf("%s: (raw)[", message);
ringBufferForEachRaw(buffer, item) {
printf("%d ", item);
}
printf("]\n");
}
void printIntBufferNice(IntBuffer* buffer, char* message) {
int item;
printf("%s: [", message);
ringBufferForEach(buffer, item) {
printf("%d ", item);
}
printf("]\n");
}
void printIntBuffer(IntBuffer* buffer, char* message) {
printIntBufferNice(buffer, message);
printIntBufferRaw(buffer, message);
}
int _tmain(int argc, _TCHAR* argv[])
{
// Declare vars.
IntBuffer* myBuffer;
ringBufferInit(myBuffer, 4, int, IntBuffer);
printIntBuffer(myBuffer, "after init");
ringBufferWrite(myBuffer, 1);
printIntBuffer(myBuffer, "after 1 item");
ringBufferWrite(myBuffer, 2);
printIntBuffer(myBuffer, "after 2 items");
ringBufferWrite(myBuffer, 3);
printIntBuffer(myBuffer, "after 3 items");
ringBufferWrite(myBuffer, 4);
printIntBuffer(myBuffer, "after 4 items");
int item;
ringBufferRead(myBuffer, 0, item);
printf("1st: %d\n", item);
assert(item == 1);
ringBufferRead(myBuffer, 1, item);
printf("2nd: %d\n", item);
assert(item == 2);
ringBufferRead(myBuffer, 2, item);
printf("3rd: %d\n", item);
assert(item == 3);
ringBufferRead(myBuffer, 3, item);
printf("4th: %d\n", item);
assert(item == 4);
ringBufferWrite(myBuffer, 5);
printIntBuffer(myBuffer, "after 5 items:");
ringBufferWrite(myBuffer, 6);
printIntBuffer(myBuffer, "after 6 items:");
ringBufferRead(myBuffer, 2, item);
assert(item == 5);
ringBufferRead(myBuffer, 3, item);
assert(item == 6);
ringBufferDestroy(myBuffer);
printf("All tests passed.\n");
return 0;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment