In order to learn macros in C I decided to make a generic data structures generator for other projects that I have in C.
The main macros are the following:
CONTAINER_GENERATE(C, P, PFX, SNAME, FMOD, T) ....
CONTAINER_GENERATE_SOURCE(C, P, PFX, SNAME, FMOD, T) ....
CONTAINER_GENERATE_HEADER(C, P, PFX, SNAME, FMOD, T) ....
Where:
- C - The container you want;
- Currently available are
LIST
,STACK
andQUEUE
;
- Currently available are
- P - If you want your data structure's fields visible;
PRIVATE
orPUBLIC
. Hides the structure definition in the source file;- Only makes a difference in the macros
2
and3
;
- PFX - Functions prefix, or namespace;
- SNAME - Structure name (
typedef SNAME##_s SNAME;
); - FMOD - Functions modifier;
- Currently I've been using
static
with macro1
;
- Currently I've been using
- T - Your data type to be worked with.
And here is the source file:
macro_containers.h
#ifndef MACRO_CONTAINERS
#define MACRO_CONTAINERS
#define CONCATH_(C, P) C##_GENERATE_HEADER##_##P
#define CONCATC_(C, P) C##_GENERATE_SOURCE##_##P
#define CONCATH(C, P) CONCATH_(C, P)
#define CONCATC(C, P) CONCATC_(C, P)
#define CONTAINER_GENERATE(C, P, PFX, SNAME, FMOD, T) \
CONTAINER_GENERATE_HEADER(C, P, PFX, SNAME, FMOD, T) \
CONTAINER_GENERATE_SOURCE(C, P, PFX, SNAME, FMOD, T)
#define CONTAINER_GENERATE_HEADER(C, P, PFX, SNAME, FMOD, T) \
CONCATH(C, P) \
(PFX, SNAME, FMOD, T)
#define CONTAINER_GENERATE_SOURCE(C, P, PFX, SNAME, FMOD, T) \
CONCATC(C, P) \
(PFX, SNAME, FMOD, T)
/*****************************************************************************/
/********************************************************************** LIST */
/*****************************************************************************/
/* PRIVATE *******************************************************************/
#define LIST_GENERATE_HEADER_PRIVATE(PFX, SNAME, FMOD, T) \
LIST_GENERATE_HEADER(PFX, SNAME, FMOD, T)
#define LIST_GENERATE_SOURCE_PRIVATE(PFX, SNAME, FMOD, T) \
LIST_GENERATE_STRUCT(PFX, SNAME, FMOD, T) \
LIST_GENERATE_SOURCE(PFX, SNAME, FMOD, T)
/* PUBLIC ********************************************************************/
#define LIST_GENERATE_HEADER_PUBLIC(PFX, SNAME, FMOD, T) \
LIST_GENERATE_STRUCT(PFX, SNAME, FMOD, T) \
LIST_GENERATE_HEADER(PFX, SNAME, FMOD, T)
#define LIST_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, T) \
LIST_GENERATE_SOURCE(PFX, SNAME, FMOD, T)
/* STRUCT ********************************************************************/
#define LIST_GENERATE_STRUCT(PFX, SNAME, FMOD, T) \
\
struct SNAME##_s \
{ \
T *buffer; \
size_t capacity; \
size_t count; \
};
/* HEADER ********************************************************************/
#define LIST_GENERATE_HEADER(PFX, SNAME, FMOD, T) \
\
typedef struct SNAME##_s SNAME; \
\
FMOD SNAME *PFX##_new(size_t size); \
FMOD void PFX##_free(SNAME *list); \
FMOD bool PFX##_push_front(SNAME *list, T element); \
FMOD bool PFX##_push(SNAME *list, T element, size_t index); \
FMOD bool PFX##_push_back(SNAME *list, T element); \
FMOD bool PFX##_pop_front(SNAME *list); \
FMOD bool PFX##_pop(SNAME *list, size_t index); \
FMOD bool PFX##_pop_back(SNAME *list); \
FMOD bool PFX##_insert_if(SNAME *list, T element, size_t index, bool condition); \
FMOD bool PFX##_remove_if(SNAME *list, size_t index, bool condition); \
FMOD T PFX##_back(SNAME *list); \
FMOD T PFX##_get(SNAME *list, size_t index); \
FMOD T PFX##_front(SNAME *list); \
FMOD bool PFX##_empty(SNAME *list); \
FMOD bool PFX##_full(SNAME *list); \
FMOD size_t PFX##_count(SNAME *list); \
FMOD size_t PFX##_capacity(SNAME *list);
/* SOURCE ********************************************************************/
#define LIST_GENERATE_SOURCE(PFX, SNAME, FMOD, T) \
\
FMOD bool PFX##_grow(SNAME *list); \
\
FMOD SNAME *PFX##_new(size_t size) \
{ \
if (size < 1) \
return NULL; \
\
SNAME *list = malloc(sizeof(SNAME)); \
\
if (!list) \
return NULL; \
\
list->buffer = malloc(sizeof(T) * size); \
\
if (!list->buffer) \
{ \
free(list); \
return NULL; \
} \
\
for (size_t i = 0; i < size; i++) \
{ \
list->buffer[i] = 0; \
} \
\
list->capacity = size; \
list->count = 0; \
\
return list; \
} \
\
FMOD void PFX##_free(SNAME *list) \
{ \
free(list->buffer); \
free(list); \
} \
\
FMOD bool PFX##_push_front(SNAME *list, T element) \
{ \
if (PFX##_full(list)) \
{ \
if (!PFX##_grow(list)) \
return false; \
} \
\
if (!PFX##_empty(list)) \
{ \
for (size_t i = list->count; i > 0; i--) \
{ \
list->buffer[i] = list->buffer[i - 1]; \
} \
} \
\
list->buffer[0] = element; \
\
list->count++; \
\
return true; \
} \
\
FMOD bool PFX##_push(SNAME *list, T element, size_t index) \
{ \
if (index > list->count) \
return false; \
\
if (index == 0) \
{ \
return PFX##_push_front(list, element); \
} \
else if (index == list->count) \
{ \
return PFX##_push_back(list, element); \
} \
\
if (PFX##_full(list)) \
{ \
if (!PFX##_grow(list)) \
return false; \
} \
\
for (size_t i = list->count; i > index; i--) \
{ \
list->buffer[i] = list->buffer[i - 1]; \
} \
\
list->buffer[index] = element; \
\
list->count++; \
\
return true; \
} \
\
FMOD bool PFX##_push_back(SNAME *list, T element) \
{ \
if (PFX##_full(list)) \
{ \
if (!PFX##_grow(list)) \
return false; \
} \
\
list->buffer[list->count++] = element; \
\
return true; \
} \
\
FMOD bool PFX##_pop_front(SNAME *list) \
{ \
if (PFX##_empty(list)) \
return false; \
\
for (size_t i = 0; i < list->count; i++) \
{ \
list->buffer[i] = list->buffer[i + 1]; \
} \
\
list->buffer[--list->count] = 0; \
\
return true; \
} \
\
FMOD bool PFX##_pop(SNAME *list, size_t index) \
{ \
if (PFX##_empty(list)) \
return false; \
\
if (index == 0) \
{ \
return PFX##_pop_front(list); \
} \
else if (index == list->count - 1) \
{ \
return PFX##_pop_back(list); \
} \
\
for (size_t i = index; i < list->count - 1; i++) \
{ \
list->buffer[i] = list->buffer[i + 1]; \
} \
\
list->buffer[--list->count] = 0; \
\
return true; \
} \
\
FMOD bool PFX##_pop_back(SNAME *list) \
{ \
if (PFX##_empty(list)) \
return false; \
\
list->buffer[--list->count] = 0; \
\
return true; \
} \
\
FMOD bool PFX##_insert_if(SNAME *list, T element, size_t index, bool condition) \
{ \
if (condition) \
return PFX##_push(list, element, index); \
\
return false; \
} \
\
FMOD bool PFX##_remove_if(SNAME *list, size_t index, bool condition) \
{ \
if (condition) \
return PFX##_pop(list, index); \
\
return false; \
} \
\
FMOD T PFX##_front(SNAME *list) \
{ \
if (PFX##_empty(list)) \
return 0; \
\
return list->buffer[0]; \
} \
\
FMOD T PFX##_get(SNAME *list, size_t index) \
{ \
if (index >= list->count) \
return 0; \
\
if (PFX##_empty(list)) \
return 0; \
\
return list->buffer[index]; \
} \
\
FMOD T PFX##_back(SNAME *list) \
{ \
if (PFX##_empty(list)) \
return 0; \
\
return list->buffer[list->count - 1]; \
} \
\
FMOD bool PFX##_empty(SNAME *list) \
{ \
return list->count == 0; \
} \
\
FMOD bool PFX##_full(SNAME *list) \
{ \
return list->count >= list->capacity; \
} \
\
FMOD size_t PFX##_count(SNAME *list) \
{ \
return list->count; \
} \
\
FMOD size_t PFX##_capacity(SNAME *list) \
{ \
return list->capacity; \
} \
\
FMOD bool PFX##_grow(SNAME *list) \
{ \
size_t new_capacity = list->capacity * 2; \
\
T *new_buffer = realloc(list->buffer, sizeof(T) * new_capacity); \
\
if (!new_buffer) \
return false; \
\
list->buffer = new_buffer; \
list->capacity = new_capacity; \
\
return true; \
}
/*****************************************************************************/
/********************************************************************* STACK */
/*****************************************************************************/
/* PRIVATE *******************************************************************/
#define STACK_GENERATE_HEADER_PRIVATE(PFX, SNAME, FMOD, T) \
STACK_GENERATE_HEADER(PFX, SNAME, FMOD, T)
#define STACK_GENERATE_SOURCE_PRIVATE(PFX, SNAME, FMOD, T) \
STACK_GENERATE_STRUCT(PFX, SNAME, FMOD, T) \
STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, T)
/* PUBLIC ********************************************************************/
#define STACK_GENERATE_HEADER_PUBLIC(PFX, SNAME, FMOD, T) \
STACK_GENERATE_STRUCT(PFX, SNAME, FMOD, T) \
STACK_GENERATE_HEADER(PFX, SNAME, FMOD, T)
#define STACK_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, T) \
STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, T)
/* STRUCT ********************************************************************/
#define STACK_GENERATE_STRUCT(PFX, SNAME, FMOD, T) \
\
struct SNAME##_s \
{ \
T *buffer; \
size_t capacity; \
size_t count; \
}; \
\
/* HEADER ********************************************************************/
#define STACK_GENERATE_HEADER(PFX, SNAME, FMOD, T) \
\
typedef struct SNAME##_s SNAME; \
\
FMOD SNAME *PFX##_new(size_t size); \
FMOD void PFX##_free(SNAME *stack); \
FMOD bool PFX##_push(SNAME *stack, T element); \
FMOD bool PFX##_pop(SNAME *stack); \
FMOD T PFX##_top(SNAME *stack); \
FMOD bool PFX##_push_if(SNAME *stack, T element, bool condition); \
FMOD bool PFX##_pop_if(SNAME *stack, bool condition); \
FMOD bool PFX##_empty(SNAME *stack); \
FMOD bool PFX##_full(SNAME *stack); \
FMOD size_t PFX##_count(SNAME *stack); \
FMOD size_t PFX##_capacity(SNAME *stack);
/* SOURCE ********************************************************************/
#define STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, T) \
\
FMOD bool PFX##_grow(SNAME *stack); \
\
FMOD SNAME *PFX##_new(size_t size) \
{ \
if (size < 1) \
return NULL; \
\
SNAME *stack = malloc(sizeof(SNAME)); \
\
if (!stack) \
return NULL; \
\
stack->buffer = malloc(sizeof(T) * size); \
\
if (!stack->buffer) \
{ \
free(stack); \
return NULL; \
} \
\
for (size_t i = 0; i < size; i++) \
{ \
stack->buffer[i] = 0; \
} \
\
stack->capacity = size; \
stack->count = 0; \
\
return stack; \
} \
\
FMOD void PFX##_free(SNAME *stack) \
{ \
free(stack->buffer); \
free(stack); \
} \
\
FMOD bool PFX##_push(SNAME *stack, T element) \
{ \
if (PFX##_full(stack)) \
{ \
if (!PFX##_grow(stack)) \
return false; \
} \
\
stack->buffer[stack->count++] = element; \
\
return true; \
} \
\
FMOD bool PFX##_pop(SNAME *stack) \
{ \
if (PFX##_empty(stack)) \
return false; \
\
stack->buffer[--stack->count] = 0; \
\
return true; \
} \
\
FMOD T PFX##_top(SNAME *stack) \
{ \
if (PFX##_empty(stack)) \
return 0; \
\
return stack->buffer[stack->count - 1]; \
} \
\
FMOD bool PFX##_push_if(SNAME *stack, T element, bool condition) \
{ \
if (condition) \
return PFX##_push(stack, element); \
\
return false; \
} \
\
FMOD bool PFX##_pop_if(SNAME *stack, bool condition) \
{ \
if (condition) \
return PFX##_pop(stack); \
\
return false; \
} \
\
FMOD bool PFX##_empty(SNAME *stack) \
{ \
return stack->count == 0; \
} \
\
FMOD bool PFX##_full(SNAME *stack) \
{ \
return stack->count >= stack->capacity; \
} \
\
FMOD size_t PFX##_count(SNAME *stack) \
{ \
return stack->count; \
} \
\
FMOD size_t PFX##_capacity(SNAME *stack) \
{ \
return stack->capacity; \
} \
\
FMOD bool PFX##_grow(SNAME *stack) \
{ \
size_t new_capacity = stack->capacity * 2; \
\
T *new_buffer = realloc(stack->buffer, sizeof(T) * new_capacity); \
\
if (!new_buffer) \
return false; \
\
stack->buffer = new_buffer; \
stack->capacity = new_capacity; \
\
return true; \
}
/*****************************************************************************/
/********************************************************************* QUEUE */
/*****************************************************************************/
/* PRIVATE *******************************************************************/
#define QUEUE_GENERATE_HEADER_PRIVATE(PFX, SNAME, FMOD, T) \
QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, T)
#define QUEUE_GENERATE_SOURCE_PRIVATE(PFX, SNAME, FMOD, T) \
QUEUE_GENERATE_STRUCT(PFX, SNAME, FMOD, T) \
QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, T)
/* PUBLIC ********************************************************************/
#define QUEUE_GENERATE_HEADER_PUBLIC(PFX, SNAME, FMOD, T) \
QUEUE_GENERATE_STRUCT(PFX, SNAME, FMOD, T) \
QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, T)
#define QUEUE_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, T) \
QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, T)
/* STRUCT ********************************************************************/
#define QUEUE_GENERATE_STRUCT(PFX, SNAME, FMOD, T) \
\
struct SNAME##_s \
{ \
T *buffer; \
size_t capacity; \
size_t count; \
size_t front; \
size_t rear; \
};
/* HEADER ********************************************************************/
#define QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, T) \
\
typedef struct SNAME##_s SNAME; \
\
FMOD SNAME *PFX##_new(size_t size); \
FMOD void PFX##_free(SNAME *queue); \
FMOD bool PFX##_enqueue(SNAME *queue, T element); \
FMOD bool PFX##_dequeue(SNAME *queue); \
FMOD T PFX##_peek(SNAME *queue); \
FMOD bool PFX##_enqueue_if(SNAME *queue, T element, bool condition); \
FMOD bool PFX##_dequeue_if(SNAME *queue, bool condition); \
FMOD bool PFX##_empty(SNAME *queue); \
FMOD bool PFX##_full(SNAME *queue); \
FMOD size_t PFX##_count(SNAME *queue); \
FMOD size_t PFX##_capacity(SNAME *queue);
/* SOURCE ********************************************************************/
#define QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, T) \
\
FMOD bool PFX##_grow(SNAME *queue); \
\
FMOD SNAME *PFX##_new(size_t size) \
{ \
if (size < 1) \
return NULL; \
\
SNAME *queue = malloc(sizeof(SNAME)); \
\
if (!queue) \
return NULL; \
\
queue->buffer = malloc(sizeof(T) * size); \
\
if (!queue->buffer) \
{ \
free(queue); \
return NULL; \
} \
\
for (size_t i = 0; i < size; i++) \
{ \
queue->buffer[i] = 0; \
} \
\
queue->capacity = size; \
queue->count = 0; \
queue->front = 0; \
queue->rear = 0; \
\
return queue; \
} \
\
FMOD void PFX##_free(SNAME *queue) \
{ \
free(queue->buffer); \
free(queue); \
} \
\
FMOD bool PFX##_enqueue(SNAME *queue, T element) \
{ \
if (PFX##_full(queue)) \
{ \
if (!PFX##_grow(queue)) \
return false; \
} \
\
queue->buffer[queue->rear] = element; \
\
queue->rear = (queue->rear == queue->capacity - 1) ? 0 : queue->rear + 1; \
queue->count++; \
\
return true; \
} \
\
FMOD bool PFX##_dequeue(SNAME *queue) \
{ \
if (PFX##_empty(queue)) \
return false; \
\
queue->buffer[queue->front] = 0; \
\
queue->front = (queue->front == queue->capacity - 1) ? 0 : queue->front + 1; \
queue->count--; \
\
return true; \
} \
\
FMOD T PFX##_peek(SNAME *queue) \
{ \
if (PFX##_empty(queue)) \
return 0; \
\
return queue->buffer[queue->front]; \
} \
\
FMOD bool PFX##_enqueue_if(SNAME *queue, T element, bool condition) \
{ \
if (condition) \
return PFX##_enqueue(queue, element); \
\
return false; \
} \
\
FMOD bool PFX##_dequeue_if(SNAME *queue, bool condition) \
{ \
if (condition) \
return PFX##_dequeue(queue); \
\
return false; \
} \
\
FMOD bool PFX##_empty(SNAME *queue) \
{ \
return queue->count == 0; \
} \
\
FMOD bool PFX##_full(SNAME *queue) \
{ \
return queue->count >= queue->capacity; \
} \
\
FMOD size_t PFX##_count(SNAME *queue) \
{ \
return queue->count; \
} \
\
FMOD size_t PFX##_capacity(SNAME *queue) \
{ \
return queue->capacity; \
} \
\
FMOD bool PFX##_grow(SNAME *queue) \
{ \
\
size_t new_capacity = queue->capacity * 2; \
\
T *new_buffer = malloc(sizeof(T) * new_capacity); \
\
if (!new_buffer) \
return false; \
\
for (size_t i = queue->front, j = 0; j < queue->count; i = (i + 1) % queue->capacity, j++) \
{ \
new_buffer[j] = queue->buffer[i]; \
} \
\
free(queue->buffer); \
\
queue->buffer = new_buffer; \
queue->capacity = new_capacity; \
queue->front = 0; \
queue->rear = queue->count; \
\
return true; \
}
#endif /* MACRO_CONTAINERS */
Here are some examples:
- I want a list of type double, and I want to use it only in this file
- In source file:
MACRO_GENERATE(LIST, PUBLIC, dl, dlist, static, double)
- Note that
PUBLIC
orPRIVATE
makes no difference, but you must specify one or the other dlist *list = dl_new(100);
- In source file:
- I want a queue called
queue_line
of typeperson_t
with hidden struct fields- In source file:
MACRO_GENERATE_SOURCE(QUEUE, PRIVATE, q, queue_line, , person_t)
- In header file:
MACRO_GENERATE_HEADER(QUEUE, PRIVATE, q, queue_line, , person_t)
- Note here that you can (and should) omit
static
without a problem queue_line *queue = q_new(120);
queue->count; // Error
size_t total_elements = q_count(queue); // OK
- In source file:
- I want a stack of type
const char *
and I want access to its fields- In source file:
MACRO_GENERATE_SOURCE(STACK, PUBLIC, stk, my_stack, , const char *)
- In header file:
MACRO_GENERATE_HEADER(STACK, PUBLIC, stk, my_stack, , const char *)
my_stack *stack = stk_new(80);
for (size_t i = 0; i < stack->count; i++) ... // OK
- In source file: