Last active
March 14, 2021 00:55
-
-
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.
This file contains 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 <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