experimental generic type-safe container data structures for C
Generic types provided are: vector, list, product, sum, and maybe. The generic types are based on structures defined in macros. They take typedef names as arguments and define a generic container with this element type:
vec(int)* vi; // pointer to a vector of ints
There is also support for arrays and strings. Arrays are just regular C arrays but we provide functions such as array_slice that perform bounds checking. A string is a vector of char with null-termination.
All container types preserve information about the type of the elements and also have bounds checking, i.e. out-of-bounds accesses trap at run-time (with UBSan).
Interoperability works by providing access to the underlying elements. For example, vec_access provides access to an lvalue for the underlying element of a vector and vec_array provides access to an array representing the complete vector. This array is a VLA, so accesses are also checked when using UBSan. A string type is defined as vector of char with null termination. The underlying array can be passed as an argument to C functions, because the array decays to a pointer.
(the need to declare the types upfront will go away with C23)
https://godbolt.org/z/Eos9E5s9o
vec_decl(int);
vec(int)* v = vec_alloc(int);
vec_push(int, &v, 1);
vec_push(int, &v, 3);
vec_access(int, v, 1)++;
vec_access(int, v, 10) = 1; // run-time error!
free(v);
https://godbolt.org/z/6oo6131jr
https://godbolt.org/z/Evsfhv3no
typedef string* string_ptr;
vec_decl(string_ptr)
vec(string_ptr)* s = vec_alloc(string_ptr);
vec_push(string_ptr, &s, string_init(" Du!"));
vec_push(string_ptr, &s, string_init("Hallo"));
int cmp2(const string_ptr* a, const string_ptr* b)
{
return strcmp(string_cstr(*a), string_cstr(*b));
}
vec_sort(s, cmp2);
while (0 < vec_length(s))
free(vec_pop(string_ptr, &s));
free(s);
string* s = string_init("hallo");
auto slice = &array_slice(string_cstr(s), 1, 1 + 3);
(*slice)[0] = 'A';
(*slice)[1] = 'L';
(*slice)[2] = 'L';
char buf[sizeof(int)];
poke(int, &buf, 1);