Skip to content

Instantly share code, notes, and snippets.

@cwchentw
Last active September 18, 2023 01:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cwchentw/f8de0dee9110ca601b60f74ffe5c3e9e to your computer and use it in GitHub Desktop.
Save cwchentw/f8de0dee9110ca601b60f74ffe5c3e9e to your computer and use it in GitHub Desktop.
Generic Queue by C Macro (Apache 2.0)
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include "queue.h"
queue_declare(int);
int main(void)
{
bool failed = false;
// Queue: NULL
queue_class(int) *q = queue_new(int,
(queue_params(int)) { .item_free = NULL });
if (!q) {
perror("Failed to allocate queue q");
return false;
}
// Queue: 9 -> NULL
if (!queue_enqueue(int, q, 9)) {
failed = true;
goto QUEUE_FREE;
}
// Queue: 9 -> 5 -> NULL
if (!queue_enqueue(int, q, 5)) {
failed = true;
goto QUEUE_FREE;
}
// Queue: 9 -> 5 -> 7 -> NULL
if (!queue_enqueue(int, q, 7)) {
failed = true;
goto QUEUE_FREE;
}
// Queue: 5 -> 7 -> NULL
if (queue_dequeue(int, q) != 9) {
failed = true;
goto QUEUE_FREE;
}
// Queue: 7 -> NULL
if (queue_dequeue(int, q) != 5) {
failed = true;
goto QUEUE_FREE;
}
// Queue: NULL
if (queue_dequeue(int, q) != 7) {
failed = true;
goto QUEUE_FREE;
}
if (!queue_is_empty(int, q)) {
failed = true;
goto QUEUE_FREE;
}
QUEUE_FREE:
queue_free(int, q);
if (failed) {
return 1;
}
return 0;
}
#ifndef QUEUE_H
#define QUEUE_H
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*freeFn) (void *);
#define queue_node(type) queue_##type##_node
#define queue_node_declare(type) \
typedef struct queue_##type##_node_s queue_node(type); \
struct queue_##type##_node_s { \
type data; \
queue_node(type) *prev; \
queue_node(type) *next; \
};
#define queue_class(type) queue_##type
#define queue_class_declare(type) \
typedef struct queue_##type##_s queue_class(type); \
struct queue_##type##_s { \
freeFn item_free; \
queue_node(type) *head; \
queue_node(type) *tail; \
};
#define queue_node_new_declare(type) \
queue_node(type) * queue_node_##type##_new(type data) \
{ \
queue_node(type) * node = malloc(sizeof(queue_node(type))); \
if (!node) { \
return node; \
} \
node->data = data; \
node->prev = NULL; \
node->next = NULL; \
return node; \
}
#define queue_node_new(type, data) \
queue_node_##type##_new(data)
#define queue_params(type) queue_##type##_params
#define queue_params_declare(type) \
typedef struct queue_##type##_params_s queue_params(type); \
struct queue_##type##_params_s { \
freeFn item_free; \
};
#define queue_class_new_declare(type) \
queue_class(type) * queue_##type##_new(queue_params(type) params) \
{ \
queue_class(type) * q = malloc(sizeof(queue_class(type))); \
if (!q) { \
return q; \
} \
q->item_free = params.item_free; \
q->head = NULL; \
q->tail = NULL; \
return q; \
}
#define queue_class_free_declare(type) \
void queue_##type##_free(void *self) \
{ \
if (!self) { \
return; \
} \
queue_node(type) *curr = ((queue_class(type) *) self)->head; \
freeFn fn = ((queue_class(type) *) self)->item_free; \
queue_node(type) *temp; \
while (curr) { \
temp = curr; \
curr = curr->next; \
if (fn) { \
fn(temp->data); \
} \
free(temp); \
} \
free(self); \
}
#define queue_class_is_empty_declare(type) \
bool queue_##type##_is_empty(queue_class(type) *self) \
{ \
assert(self); \
return !(self->head) ? true : false; \
}
#define queue_class_peek_declare(type) \
type queue_##type##_peek(queue_class(type) *self) \
{ \
assert(self); \
return self->head->data; \
}
#define queue_class_enqueue_declare(type) \
bool queue_##type##_enqueue(queue_class(type) *self, type data) \
{ \
assert(self); \
queue_node(type) *node = queue_node_new(type, data); \
if (!node) { \
return false; \
} \
if (!(self->tail)) { \
self->head = node; \
self->tail = node; \
return true; \
} \
self->tail->next = node; \
node->prev = self->tail; \
self->tail = node; \
return true; \
}
#define queue_class_dequeue_declare(type) \
type queue_##type##_dequeue(queue_class(type) *self) \
{ \
assert(self); \
if (self->head == self->tail) { \
type popped = self->head->data; \
free(self->head); \
self->head = NULL; \
self->tail = NULL; \
return popped; \
} \
queue_node(type) *curr = self->head; \
type popped = curr->data; \
self->head = curr->next; \
free(curr); \
return popped; \
}
#define queue_declare(type) \
queue_node_declare(type) \
queue_class_declare(type) \
queue_node_new_declare(type) \
queue_params_declare(type) \
queue_class_new_declare(type) \
queue_class_free_declare(type) \
queue_class_is_empty_declare(type) \
queue_class_peek_declare(type) \
queue_class_enqueue_declare(type) \
queue_class_dequeue_declare(type)
#define queue_new(type, item_free) \
queue_##type##_new(item_free)
#define queue_free(type, self) \
queue_##type##_free(self)
#define queue_is_empty(type, self) \
queue_##type##_is_empty(self)
#define queue_peek(type, self) \
queue_##type##_peek(self)
#define queue_enqueue(type, self, data) \
queue_##type##_enqueue(self, data)
#define queue_dequeue(type, self) \
queue_##type##_dequeue(self)
#ifdef __cplusplus
}
#endif
#endif // QUEUE_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment