Skip to content

Instantly share code, notes, and snippets.

@mrtrizer
Last active March 14, 2021 00:55
Show Gist options
  • Save mrtrizer/26da92f85828bc9316b525d0764e8666 to your computer and use it in GitHub Desktop.
Save mrtrizer/26da92f85828bc9316b525d0764e8666 to your computer and use it in GitHub Desktop.
C language type save containers. Requires GNU C11 (--std=gnu11) because of using typeof(). The benefit of this solution is compilation error if container type is wrong, or container item is of wrong type. The main idea is using function pointer to contain both type of container and type of container items.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
unsigned int size;
void (*destructor)();
int length;
int reserved;
char* bytes;
} ABVector;
typedef struct
{
unsigned int size;
void (*destructor)();
} ABList;
#define DEFAULT_RESERVED 10
inline static void* __pushVector(void* vectorPtr)
{
ABVector* vector = vectorPtr;
if (vector->length >= vector->reserved)
{
vector->reserved += DEFAULT_RESERVED;
vector->bytes = realloc(vector->bytes, vector->reserved * vector->size);
}
printf("Vector! %d / %d\n", vector->length, vector->reserved);
return &vector->bytes[vector->length++ * vector->size];
}
inline static void* __beginVector(void* vectorPtr)
{
return ((ABVector*)vectorPtr)->bytes;
}
inline static void* __endVector(void* vectorPtr)
{
ABVector* vector = vectorPtr;
return vector->bytes + vector->length * vector->size;
}
inline static void* __nextVector(void* vectorPtr, void* ptr)
{
return ptr + ((ABVector*)vectorPtr)->size;
}
inline static int __lengthVector(void* vectorPtr)
{
return ((ABVector*)vectorPtr)->length;
}
inline static void* __getVector(void* vectorPtr, int index)
{
ABVector* vector = vectorPtr;
return &vector->bytes[vector->size * index];
}
inline static void* __pushList(void* listPtr)
{
ABList* list = listPtr;
printf("List! %d\n", list->size);
return NULL;
}
ABVector* __initABVector(ABVector* vector, int size, void (*destructor)(void*))
{
vector->size = size;
vector->length = 0;
vector->reserved = DEFAULT_RESERVED;
vector->destructor = destructor;
vector->bytes = malloc(size * vector->reserved);
return vector;
}
void __deinitVector(void* vectorPtr)
{
ABVector* vector = vectorPtr;
if (vector->destructor == NULL)
return;
for(int i = 0; i < vector->length; i++)
{
vector->destructor(__getVector(vector, i));
}
}
ABList* __initABList(ABList* list, int size, void (*destructor)(void*))
{
list->size = size;
list->destructor = destructor;
return list;
}
void __deinitList(void* list)
{
// not implemented
}
#define PUSH(X) (typeof(X(0))*) _Generic(( X ), \
typeof(X(0)) (*) (ABVector*) : __pushVector, \
typeof(X(0)) (*) (ABList*) : __pushList )(X)
#define BEGIN(X) (typeof(X(0))*) _Generic(( X ), \
typeof(X(0)) (*) (ABVector*) : __beginVector )(X)
#define END(X) (typeof(X(0))*) _Generic(( X ), \
typeof(X(0)) (*) (ABVector*) : __endVector )(X)
#define NEXT(X, ptr) (typeof(X(0))*) _Generic(( X ), \
typeof(X(0)) (*) (ABVector*) : __nextVector )(X, ptr)
#define LENGTH(X) _Generic(( X ), \
typeof(X(0)) (*) (ABVector*) : __lengthVector )(X)
#define GET(X, index) (typeof(X(0))*) _Generic(( X ), \
typeof(X(0)) (*) (ABVector*) : __getVector )(X, index)
#define ABV(t) typeof((t (*) (ABVector*))(NULL))
#define ABL(t) typeof((t (*) (ABList*))(NULL))
#define INIT_ABVECTOR(ptr, t, destructor) ( (t (*) (ABVector*)) __initABVector(ptr, sizeof(t), destructor))
#define INIT_ABLIST(ptr, t, destructor) ( (t (*) (ABList*)) __initABList(ptr, sizeof(t), destructor))
#define CREATE_ABVECTOR(t, destructor) INIT_ABVECTOR(malloc(sizeof(ABVector)), t, destructor)
#define CREATE_ABLIST(t, destructor) INIT_ABLIST(malloc(sizeof(ABList)), t, destructor)
#define DEINIT(X) _Generic(( X ), \
typeof(X(0)) (*) (ABVector*) : __deinitVector, \
typeof(X(0)) (*) (ABList*) : __deinitList )(X)
#define DESTROY(X) DEINIT(X), free(X)
#define auto __auto_type
void someDestructor(void* item)
{
printf("Destroy: %s\n", *(char**)item);
}
void printValues(ABV(float) numbers)
{
for (float* iter = BEGIN(numbers); iter != END(numbers); iter = NEXT(numbers, iter))
printf("Val: %f\n", *iter);
for (int i = 0; i < LENGTH(numbers); i++)
printf("Val: %f\n", *GET(numbers, i));
}
int main(void)
{
ABVector stringsVLocal;
ABV(char*) stringsV = INIT_ABVECTOR(&stringsVLocal, char*, someDestructor);
*PUSH( stringsV ) = "test1";
*PUSH( stringsV ) = "test2";
*PUSH( stringsV ) = "test3";
for (int i = 0; i < LENGTH(stringsV); i++)
printf("Val: %s\n", *GET(stringsV, i));
DEINIT(stringsV);
auto numbersV = CREATE_ABVECTOR(float, NULL);
for (int i = 0; i < 20; i++)
*PUSH( numbersV ) = i;
printValues(numbersV);
DESTROY(numbersV);
auto numbersL = CREATE_ABLIST(int, NULL);
PUSH( numbersL );
DESTROY(numbersL);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment