Skip to content

Instantly share code, notes, and snippets.

@icebarf
Last active April 28, 2024 15:28
Show Gist options
  • Save icebarf/4ad8208d990b3a6222e15ee972aecbc2 to your computer and use it in GitHub Desktop.
Save icebarf/4ad8208d990b3a6222e15ee972aecbc2 to your computer and use it in GitHub Desktop.
A meme generic linked list implementation in C.
#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;
}
#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, &copy); \
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
@thunar-66
Copy link

thats good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment