Last active
April 28, 2024 15:28
-
-
Save icebarf/4ad8208d990b3a6222e15ee972aecbc2 to your computer and use it in GitHub Desktop.
A meme generic linked list implementation in C.
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
#include "generic_list.h" | |
#include <string.h> | |
#define UNUSED(X) (void)X | |
// supply your own | |
typedef struct iNode | |
{ | |
size_t index; | |
struct iNode *next; | |
int value; | |
} iNode; | |
// generate functions for our own struct | |
list_gen (iNode, int, iNode); | |
// or use a default generated one | |
// generates a default struct with tag: node_suffix | |
// and containing a `value` member of type Value_t | |
// here, a struct node_str is generated which contains a next pointer | |
// and a value field with type char* | |
list_def_default_struct_gen (char *, str); | |
// generate for default type | |
list_gen (struct node_str, char *, str); | |
int | |
add (int a, int b) | |
{ | |
return a + b; | |
} | |
int | |
twice (int a) | |
{ | |
return a * 2; | |
} | |
char * | |
read_line () | |
{ | |
size_t bytes = 100; | |
char *line = calloc (bytes, sizeof (char)); | |
int c = 0; | |
size_t i = 0; | |
while ((c = fgetc (stdin)) != '\n') | |
{ | |
if (i >= bytes) | |
{ | |
char *temp = realloc (line, bytes * 2); | |
if (temp != NULL) | |
{ | |
line = temp; | |
bytes *= 2; | |
} | |
else | |
{ | |
fprintf (stderr, | |
"Error allocating buffer, i : %zu, c = " | |
"%d, bytes to allocate: %zu\n", | |
i, c, bytes * 2); | |
return line; | |
} | |
} | |
if (c == EOF) | |
break; | |
line[i] = c; | |
i++; | |
} | |
if (i >= bytes) | |
{ | |
char *temp = realloc (line, bytes + 2); | |
if (temp != NULL) | |
{ | |
line = temp; | |
bytes += 2; | |
} | |
else | |
{ | |
fprintf (stderr, | |
"Error allocating buffer, i : %zu, c = " | |
"%d, bytes to allocate: %zu\n", | |
i, c, bytes + 2); | |
return line; | |
} | |
} | |
line[i] = 0; | |
return line; | |
} | |
__attribute__ ((warn_unused_result)) iNode * | |
read_and_create_list (void) | |
{ | |
char *str = read_line (); | |
if (str == NULL) | |
return NULL; | |
char *number = strtok (str, " "); | |
if (number == NULL) | |
return NULL; | |
iNode *head = NULL; | |
while (number != NULL) | |
{ | |
if (list_append (iNode, strtol (number, NULL, 10), &head) == NULL) | |
{ | |
list_free (iNode, head); | |
return NULL; | |
} | |
number = strtok (NULL, " "); | |
} | |
free (str); | |
return head; | |
} | |
int | |
main (int argc, char **argv) | |
{ | |
UNUSED (argc); | |
UNUSED (argv); | |
iNode *head = list_create (iNode, 1); | |
if (head == NULL) | |
return 1; | |
for (int i = 2; i < 6; i++) | |
if (list_append (iNode, i, &head) == NULL) | |
return 1; | |
list_iter (iNode, node, head) | |
printf ("index: %zu\nvalue: %d\n\n", node->index, node->value); | |
printf ("\nsum: %d\n", fold (iNode, 0, add, head)); | |
list_free (iNode, head); | |
iNode *list = read_and_create_list (); | |
if (list == NULL) | |
return 1; | |
list_iter (iNode, n, list) | |
printf ("index: %zu\nvalue: %d\n\n", n->index, n->value); | |
list_free (iNode, list); | |
puts ("kek wat\n"); | |
iNode *new_list = iterate (iNode, 1, 10, twice); | |
list_iter (iNode, n, new_list) | |
printf ("index: %zu\nvalue: %d\n\n", n->index, n->value); | |
list_free (iNode, new_list); | |
return 0; | |
} |
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
#ifndef GENERIC_LIST_ICEBARF_TROLLING | |
#define GENERIC_LIST_ICEBARF_TROLLING | |
#include <assert.h> | |
#include <stdbool.h> | |
#include <stddef.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
/* These functions take lists that must have atleast | |
* the following fields in them | |
* - index (default type is size_t in generated structure) | |
* - value | |
* - next (pointer to next node of the list) | |
*/ | |
#define list_iter(T, node, head) \ | |
for (T *node = (head); node != NULL; node = node->next) | |
#define list_def_default_struct_gen(Value_t, suffix) \ | |
struct node_##suffix \ | |
{ \ | |
size_t index; \ | |
Value_t value; \ | |
struct node_##suffix *next; \ | |
} | |
#define list_create_gen(List_t, Value_t, suffix) \ | |
List_t *list_create_##suffix (Value_t v) \ | |
{ \ | |
List_t *node = calloc (1, sizeof (*node)); \ | |
assert (node != NULL); \ | |
node->value = v; \ | |
return node; \ | |
} | |
#define list_free_gen(List_t, suffix) \ | |
void list_free_##suffix (List_t *head) \ | |
{ \ | |
List_t *temp = NULL; \ | |
while (head != NULL) \ | |
{ \ | |
temp = head->next; \ | |
free (head); \ | |
head = temp; \ | |
} \ | |
} | |
#define list_prepend_gen(List_t, Value_t, suffix) \ | |
List_t *list_prepend_##suffix (Value_t v, List_t *old_head) \ | |
{ \ | |
List_t *new_head = list_create_##suffix (v); \ | |
new_head->next = old_head; \ | |
list_iter (List_t, temp, new_head->next) temp->index++; \ | |
return new_head; \ | |
} | |
#define list_append_gen(List_t, Value_t, suffix) \ | |
List_t *list_append_##suffix (Value_t v, List_t **head) \ | |
{ \ | |
List_t *last = list_create_##suffix (v); \ | |
if (*head != NULL) \ | |
{ \ | |
List_t *temp = *head; \ | |
for (; temp->next != NULL; temp = temp->next) \ | |
; \ | |
temp->next = last; \ | |
last->index = temp->index + 1; \ | |
} \ | |
if (*head == NULL) \ | |
*head = last; \ | |
return last; \ | |
} | |
#define list_node_at_gen(List_t, suffix) \ | |
List_t *list_node_at_##suffix (size_t index, List_t *head) \ | |
{ \ | |
list_iter (List_t, node, head) \ | |
{ \ | |
if (node->index == index) \ | |
return node; \ | |
} \ | |
return NULL; \ | |
} | |
#define list_get_gen(List_t, Value_t, suffix) \ | |
Value_t list_get_##suffix (size_t index, List_t *head) \ | |
{ \ | |
List_t *temp = list_node_at_##suffix (index, head); \ | |
if (temp == NULL) \ | |
{ \ | |
fprintf (stderr, "Item at index '%zu' does not exist\n", \ | |
index); \ | |
exit (EXIT_FAILURE); \ | |
} \ | |
return temp->value; \ | |
} | |
#define list_copy_gen(List_t, suffix) \ | |
List_t *list_copy_##suffix (List_t *head) \ | |
{ \ | |
List_t *copy = list_create_##suffix (head->value); \ | |
list_iter (List_t, node, head->next) \ | |
list_append_##suffix (node->value, ©); \ | |
return copy; \ | |
} | |
#define list_length_gen(List_t, suffix) \ | |
size_t list_length_##suffix (List_t *head) \ | |
{ \ | |
size_t count = 0; \ | |
list_iter (List_t, node, head) count++; \ | |
return count; \ | |
} | |
#define foreach_gen(List_t, Value_t, suffix) \ | |
void foreach_##suffix (List_t *head, void (*f) (Value_t)) \ | |
{ \ | |
list_iter (List_t, node, head) f (node->value); \ | |
} | |
#define map_gen(List_t, Value_t, suffix) \ | |
List_t *map_##suffix (List_t *head, void (*f) (Value_t), bool atSource) \ | |
{ \ | |
List_t *copy = head; \ | |
if (!atSource) \ | |
copy = list_copy_##suffix (head); \ | |
list_iter (List_t, node, copy) f (node->value); \ | |
return copy; \ | |
} | |
#define fold_gen(List_t, Value_t, suffix) \ | |
Value_t fold_##suffix (Value_t start, Value_t (*f) (Value_t, Value_t), \ | |
List_t *head) \ | |
{ \ | |
Value_t acc = start; \ | |
list_iter (List_t, node, head) acc = f (acc, node->value); \ | |
return acc; \ | |
} | |
#define iterate_gen(List_t, Value_t, suffix) \ | |
List_t *iterate_##suffix (Value_t s, size_t len, Value_t (*f) (Value_t)) \ | |
{ \ | |
List_t *list = list_create_##suffix (s); \ | |
Value_t res = s; \ | |
for (size_t i = 0; i < len; i++) \ | |
{ \ | |
list_append_##suffix (f (res), &list); \ | |
res = f (res); \ | |
} \ | |
return list; \ | |
} | |
// clang-format off | |
#define list_gen(List_t, Value_t, suffix) \ | |
list_create_gen (List_t, Value_t, suffix) \ | |
list_free_gen (List_t, suffix) \ | |
list_prepend_gen (List_t, Value_t,suffix) \ | |
list_append_gen (List_t, Value_t, suffix) \ | |
list_node_at_gen (List_t, suffix) \ | |
list_get_gen (List_t, Value_t, suffix) \ | |
list_copy_gen(List_t, suffix) \ | |
list_length_gen (List_t, suffix) \ | |
\ | |
foreach_gen(List_t, Value_t, suffix) \ | |
map_gen(List_t, Value_t, suffix) \ | |
fold_gen(List_t, Value_t, suffix) \ | |
iterate_gen(List_t, Value_t, suffix) | |
// clang-format on | |
#define list_create(S, val) list_create_##S (val) | |
#define list_prepend(S, val, head) list_prepend_##S (val, head) | |
#define list_append(S, val, head) list_append_##S (val, head) | |
#define list_node_at(S, index, head) list_node_at_##S (index, head) | |
#define list_get(S, index, head) list_length_##S (index, head) | |
#define list_copy(S, head) list_copy_##S (head) | |
#define list_length(S, arg) list_length_##S (arg) | |
#define list_free(S, arg) list_free_##S (arg) | |
#define foreach(S, head, fn) foreach_##S (head, fn) | |
#define map(S, head, fn, src) map_##S (head, fn, src) | |
#define fold(S, start, fn, head) fold_##S (start, fn, head) | |
#define iterate(S, start, len, fn) iterate_##S (start, len, fn) | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thats good