Simple generic macro-generated containers












0












$begingroup$


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:




  1. CONTAINER_GENERATE(C, P, PFX, SNAME, FMOD, T) ....

  2. CONTAINER_GENERATE_SOURCE(C, P, PFX, SNAME, FMOD, T) ....

  3. CONTAINER_GENERATE_HEADER(C, P, PFX, SNAME, FMOD, T) ....


Where:





  • C - The container you want;


    • Currently available are LIST, STACK and QUEUE;




  • P - If you want your data structure's fields visible;



    • PRIVATE or PUBLIC. Hides the structure definition in the source file;

    • Only makes a difference in the macros 2 and 3;




  • PFX - Functions prefix, or namespace;


  • SNAME - Structure name (typedef SNAME##_s SNAME;);


  • FMOD - Functions modifier;


    • Currently I've been using static with macro 1;




  • 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 or PRIVATE makes no difference, but you must specify one or the other

    • dlist *list = dl_new(100);



  • I want a queue called queue_line of type person_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



  • 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











share









$endgroup$

















    0












    $begingroup$


    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:




    1. CONTAINER_GENERATE(C, P, PFX, SNAME, FMOD, T) ....

    2. CONTAINER_GENERATE_SOURCE(C, P, PFX, SNAME, FMOD, T) ....

    3. CONTAINER_GENERATE_HEADER(C, P, PFX, SNAME, FMOD, T) ....


    Where:





    • C - The container you want;


      • Currently available are LIST, STACK and QUEUE;




    • P - If you want your data structure's fields visible;



      • PRIVATE or PUBLIC. Hides the structure definition in the source file;

      • Only makes a difference in the macros 2 and 3;




    • PFX - Functions prefix, or namespace;


    • SNAME - Structure name (typedef SNAME##_s SNAME;);


    • FMOD - Functions modifier;


      • Currently I've been using static with macro 1;




    • 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 or PRIVATE makes no difference, but you must specify one or the other

      • dlist *list = dl_new(100);



    • I want a queue called queue_line of type person_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



    • 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











    share









    $endgroup$















      0












      0








      0





      $begingroup$


      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:




      1. CONTAINER_GENERATE(C, P, PFX, SNAME, FMOD, T) ....

      2. CONTAINER_GENERATE_SOURCE(C, P, PFX, SNAME, FMOD, T) ....

      3. CONTAINER_GENERATE_HEADER(C, P, PFX, SNAME, FMOD, T) ....


      Where:





      • C - The container you want;


        • Currently available are LIST, STACK and QUEUE;




      • P - If you want your data structure's fields visible;



        • PRIVATE or PUBLIC. Hides the structure definition in the source file;

        • Only makes a difference in the macros 2 and 3;




      • PFX - Functions prefix, or namespace;


      • SNAME - Structure name (typedef SNAME##_s SNAME;);


      • FMOD - Functions modifier;


        • Currently I've been using static with macro 1;




      • 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 or PRIVATE makes no difference, but you must specify one or the other

        • dlist *list = dl_new(100);



      • I want a queue called queue_line of type person_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



      • 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











      share









      $endgroup$




      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:




      1. CONTAINER_GENERATE(C, P, PFX, SNAME, FMOD, T) ....

      2. CONTAINER_GENERATE_SOURCE(C, P, PFX, SNAME, FMOD, T) ....

      3. CONTAINER_GENERATE_HEADER(C, P, PFX, SNAME, FMOD, T) ....


      Where:





      • C - The container you want;


        • Currently available are LIST, STACK and QUEUE;




      • P - If you want your data structure's fields visible;



        • PRIVATE or PUBLIC. Hides the structure definition in the source file;

        • Only makes a difference in the macros 2 and 3;




      • PFX - Functions prefix, or namespace;


      • SNAME - Structure name (typedef SNAME##_s SNAME;);


      • FMOD - Functions modifier;


        • Currently I've been using static with macro 1;




      • 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 or PRIVATE makes no difference, but you must specify one or the other

        • dlist *list = dl_new(100);



      • I want a queue called queue_line of type person_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



      • 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









      c collections macros





      share












      share










      share



      share










      asked 9 mins ago









      LeoVenLeoVen

      62




      62






















          0






          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213553%2fsimple-generic-macro-generated-containers%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213553%2fsimple-generic-macro-generated-containers%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Ottavio Pratesi

          Tricia Helfer

          15 giugno