-
-
Save danielchasehooper/a646a109b62441ca1b4d75d94436b5cf to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// Type safe generic data structures demo | |
// | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <stddef.h> | |
#include <assert.h> | |
#include <string.h> | |
#include "stb_ds.h" | |
// | |
// The List data structure | |
// | |
typedef struct ListNode ListNode; | |
struct ListNode { | |
ListNode *next; | |
// change the alignment to suit your needs | |
// how to make alignemnt unique per data type is possible but left as an excersice for the reader | |
char data[] __attribute__((aligned(8))); | |
}; | |
#define List(type) union { \ | |
ListNode *head; \ | |
type *payload; \ | |
} | |
#define list_alloc_front(list) \ | |
((__typeof__((list)->payload))_list_alloc_front(&((list)->head), sizeof(*(list)->payload))) | |
#define list_prepend(list, item) \ | |
*list_alloc_front(list) = item | |
#define list_data_first(l) (__typeof__((l)->payload))((l)->head ? (l)->head->data : NULL) | |
#define list_for(it, l) for(__typeof__((l)->payload) it = list_data_first(l); it != NULL; it = list_data_next(it)) | |
void *_list_alloc_front(ListNode **head, size_t data_size) { | |
// I recommend using an arena allocator instead of malloc, | |
// I use malloc here just for familiarity | |
ListNode *node = malloc(sizeof(*node) + data_size); | |
assert(node); | |
node->next = *head; | |
*head = node; | |
return node->data; | |
} | |
void *list_data_next(void *data) { | |
assert(data); | |
ListNode *node = (char *)data - offsetof(ListNode, data); | |
node = node->next; | |
return node ? node->data : NULL; | |
} | |
// | |
// Usage demo starts here | |
// | |
typedef struct { | |
int value; | |
} Foo; | |
int main(int argc, char *argv[]) { | |
List(Foo) foo_list = {0}; | |
list_prepend(&foo_list, (Foo){ 3 }); | |
list_prepend(&foo_list, (Foo){ 2 }); | |
// If you wanted to initialize the data in place: | |
Foo *new_foo = list_alloc_front(&foo_list); | |
new_foo->value = 1; | |
// these won't compile, which is good! | |
// int *my_int = list_alloc_front(&foo_list); | |
// list_prepend(&foo_list, 7); | |
list_for(item, &foo_list) { | |
// `item` is of type `Foo *` | |
printf("%i\n", item->value); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment