Last active
September 18, 2023 01:35
-
-
Save cwchentw/f8de0dee9110ca601b60f74ffe5c3e9e to your computer and use it in GitHub Desktop.
Generic Queue by C Macro (Apache 2.0)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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