Skip to content

Instantly share code, notes, and snippets.

@ForgotMyCode
Created April 4, 2023 01:14
Show Gist options
  • Save ForgotMyCode/5b2b814cb6970c3901df77793fb0f247 to your computer and use it in GitHub Desktop.
Save ForgotMyCode/5b2b814cb6970c3901df77793fb0f247 to your computer and use it in GitHub Desktop.
Generic Linked List in C (Experimental)
#include <stdlib.h>
#define INTERNAL__CONCAT_2ARGS(LHS, RHS) LHS##RHS
#define INTERNAL__CONCAT_3ARGS(A, B, C) A##B##C
#define INTERNAL__MAKE_INNER_TYPENAME(LL_DECLNAME, TYPE) INTERNAL__CONCAT_3ARGS(INTERNAL__, LL_DECLNAME, INNER_TYPE)
#define INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(LL_DECLNAME, FUNCTION_NAME) INTERNAL__CONCAT_3ARGS(INTERNAL__, LL_DECLNAME, FUNCTION_NAME)
#define INTERNAL__MAKE_INTERNAL_NODE_NAME(LL_DECLNAME) INTERNAL__CONCAT_3ARGS(INTERNAL__, LL_DECLNAME, _LL_Node)
#define INTERNAL__MAKE_INTERNAL_STRUCTED_NAME(LL_DECLNAME) INTERNAL__CONCAT_3ARGS(INTERNAL__STRUCTED_, LL_DECLNAME, _LL_Type)
#define INTERNAL__MAKE_INTERNAL_STRUCTED_NODE_NAME(LL_DECLNAME) INTERNAL__CONCAT_3ARGS(INTERNAL__STRUCTED_, LL_DECLNAME, _LL_Node)
#define LL_DECLARE(TYPE, DECLNAME) \
typedef TYPE INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE); \
\
typedef struct INTERNAL__MAKE_INTERNAL_STRUCTED_NODE_NAME(DECLNAME) { \
struct INTERNAL__MAKE_INTERNAL_STRUCTED_NODE_NAME(DECLNAME)* next; \
struct INTERNAL__MAKE_INTERNAL_STRUCTED_NODE_NAME(DECLNAME)* prev; \
INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE) value; \
} INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME); \
\
typedef struct INTERNAL__MAKE_INTERNAL_STRUCTED_NAME(DECLNAME) { \
INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME)* head; \
INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME)* tail; \
unsigned long long size; \
\
void (*internal__push_back)(struct INTERNAL__MAKE_INTERNAL_STRUCTED_NAME(DECLNAME)*, INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE)); \
INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE)(*internal__pop_back)(struct INTERNAL__MAKE_INTERNAL_STRUCTED_NAME(DECLNAME)*); \
void (*internal__push_front)(struct INTERNAL__MAKE_INTERNAL_STRUCTED_NAME(DECLNAME)*, INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE)); \
INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE)(*internal__pop_front)(struct INTERNAL__MAKE_INTERNAL_STRUCTED_NAME(DECLNAME)*); \
} DECLNAME; \
\
INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME)* INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(DECLNAME, NEW_NODE)( \
INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME)* prev, \
INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME)* next, \
INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE) value \
) { \
INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME)* newNode = (INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME)*) calloc(1, sizeof(INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME))); \
newNode->value = value; \
newNode->prev = prev; \
newNode->next = next; \
return newNode; \
} \
\
void INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(DECLNAME, PUSH_BACK)(DECLNAME* instance, INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE) value) { \
if(instance->tail) { \
instance->tail->next = INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(DECLNAME, NEW_NODE)(instance->tail, NULL, value); \
instance->tail = instance->tail->next; \
} \
else { \
instance->tail = INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(DECLNAME, NEW_NODE)(NULL, NULL, value); \
instance->head = instance->tail; \
} \
++instance->size; \
} \
\
INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE) INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(DECLNAME, POP_BACK)(DECLNAME* instance) { \
INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME)* removedNode = instance->tail; \
instance->tail = instance->tail->prev; \
INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE) ret = removedNode->value; \
free(removedNode); \
\
if(instance->tail) { \
instance->tail->next = NULL; \
} \
else { \
instance->head = NULL; \
} \
--instance->size; \
return ret; \
} \
\
void INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(DECLNAME, PUSH_FRONT)(DECLNAME* instance, INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE) value) { \
if(instance->head) { \
instance->head->prev = INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(DECLNAME, NEW_NODE)(NULL, instance->head, value); \
instance->head = instance->head->prev; \
} \
else { \
instance->head = INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(DECLNAME, NEW_NODE)(NULL, NULL, value); \
instance->tail = instance->head; \
} \
++instance->size; \
} \
\
INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE) INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(DECLNAME, POP_FRONT)(DECLNAME* instance) { \
INTERNAL__MAKE_INTERNAL_NODE_NAME(DECLNAME)* removedNode = instance->head; \
instance->head = instance->head->next; \
INTERNAL__MAKE_INNER_TYPENAME(DECLNAME, TYPE) ret = removedNode->value; \
free(removedNode); \
\
if(instance->head) { \
instance->head->prev = NULL; \
} \
else { \
instance->tail = NULL; \
} \
--instance->size; \
return ret; \
}
#define LL_MAKE_INSTANCE(LL_DECLNAME, VARIABLE_NAME) \
LL_DECLNAME VARIABLE_NAME; \
{ \
(VARIABLE_NAME).head = NULL; \
(VARIABLE_NAME).tail = NULL; \
(VARIABLE_NAME).size = 0ULL; \
(VARIABLE_NAME).internal__push_back = &INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(LL_DECLNAME, PUSH_BACK); \
(VARIABLE_NAME).internal__pop_back = &INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(LL_DECLNAME, POP_BACK); \
(VARIABLE_NAME).internal__push_front = &INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(LL_DECLNAME, PUSH_FRONT); \
(VARIABLE_NAME).internal__pop_front = &INTERNAL__MAKE_INTERNAL_FUNCTION_NAME(LL_DECLNAME, POP_FRONT); \
}
#define LL_DESTRUCT(LL_INSTANCE) {\
while((LL_INSTANCE).head) { \
(LL_INSTANCE).tail = head; \
(LL_INSTANCE).head = (LL_INSTANCE).head->next; \
free((LL_INSTANCE).tail); \
} \
(LL_INSTANCE).tail = NULL; \
(LL_INSTANCE).size = 0ULL; \
}
#define LL_GET_SIZE(LL_INSTANCE) \
(LL_INSTANCE).size
#define LL_PUSH_BACK(LL_INSTANCE, VALUE) \
(LL_INSTANCE).internal__push_back(&(LL_INSTANCE), VALUE)
#define LL_POP_BACK(LL_INSTANCE) \
(LL_INSTANCE).internal__pop_back(&(LL_INSTANCE))
#define LL_PUSH_FRONT(LL_INSTANCE, VALUE) \
(LL_INSTANCE).internal__push_front(&(LL_INSTANCE), VALUE)
#define LL_POP_FRONT(LL_INSTANCE) \
(LL_INSTANCE).internal__pop_front(&(LL_INSTANCE))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment