Compile Time Generic Dynamic Vector in C.
On it's own, no code is being compiled. You first have to include and implement a vector of your desires. For that, there are two macros.
#include "vec.h"
VEC_INCLUDE(N, A, T, M);
VEC_IMPLEMENT(N, A, T, M, F);
N
- Name - the resulting name of the vector structA
- Abbreviation - functions get prefixed with thatT
- Type - the type of your elements within the vectorM
- Mode - storage type, eitherBY_VAL
(by value) orBY_REF
(by reference)F
- Free - provide a freeing function for your elements, if available
VEC_INCLUDE(VecU8, vec_u8, unsigned char, BY_VAL);
VEC_IMPLEMENT(VecU8, vec_u8, unsigned char, BY_VAL, 0);
VEC_INCLUDE(VecSize, vec_size, size_t, BY_VAL);
VEC_IMPLEMENT(VecSize, vec_size, size_t, BY_VAL, 0);
VEC_INCLUDE(Vec2U8, vec2_u8, VecU8, BY_VAL);
VEC_IMPLEMENT(Vec2U8, vec2_u8, VecU8, BY_VAL, vec_u8_free);
VEC_INCLUDE(Vec2U8, vec2_u8, VecU8, BY_REF);
VEC_IMPLEMENT(Vec2U8, vec2_u8, VecU8, BY_REF, vec_u8_free);
- Both
BY_VAL
andBY_REF
can be used on either basic types or (complex) structs. Either way, if you (e.g.) push back a value, its content is copied - Generally speaking, I'd use the latter when dealing with structs where
sizeof struct > sizeof(void *)
. - I went ahead and compared the very basic performance between the two approaches here.
- Compiler optimized code
- Flexibility, reusability (generics / templates)
- Type safety
- Maintenance challenges
- Debugging difficulties
- Compilation overhead
$ cd examples && make
(binaries in subfolder "bin") -> WIP, I want to add more examples
$ cd test && make
(binaries in subfolder "bin") -> WIP, I want to add more tests to make the vector bug free- Ignore the
compile_flags.txt
files -> I added those only so that my LSP knows what's up.
The A##
means the A
specified in the two macros.
A##_zero
set vector to zero without freeingA##_clear
clear vector but keep capacityA##_length
return length of of the vector in itemsA##_capacity
return capacity of the vectorA##_empty
return if it's emptyA##_resize
resize vector to optimal given length in itemsA##_free
free all memory usedA##_reserved
return bytes allocatedA##_reserve
reserve more memory in itemsA##_shrink
shrinks vector to minimal possible capacityA##_set_at
overwrite item at index, free any previous itemA##_push_front
insert item in the frontA##_push_back
insert item at the backA##_push_at
insert item after indexA##_pop_front
pop item in the frontA##_pop_back
pop item at the backA##_get_at
get item at indexA##_get_front
get item in the frontA##_get_back
get item at the backA##_swap
swap two items by indexA##_reverse
reverse the vectorA##_iter_begin
return beginning iteratorA##_iter_end
return end of iterator
There are various settings one can adjust to fit the vector to their needs. To use those, I strongly recommend the following:
- In header files (using the
INCLUDE
macro) ->#define
the respective settings before includingvec.h
. Before the end of your header#undef
them, so that other possible vectors that may create a vector of such a "modified" vector with custom settings reverts back to the defaults - In source files (using the
IMPLEMENT
macro) ->#define
the respective settings after you included your custom vector header and have them be equally set.
VEC_SETTINGS_KEEP_ZERO_END
number; specify how much zero memory should be kept at the end when reserving memory (e.g. string implementation)VEC_SETTINGS_STRUCT_ITEMS
literal; specify the name of theitems
placeholder to something else, if you so desire (e.g. string implementation, where it makes more sense to use another literal besides the previously mentioned for the string placeholder)VEC_SETTINGS_DEFAULT_SIZE
number; specify how many item spaces shall be reserved minimally
- add
pop_at
pop item at index - add
emplace
insert item before index - add stuff that allows to pop/push/insert/emplace an entire array, or a subsection...
- if we pushed from the front, then N.first can actually be reduced, instead of moving everything one back!
- bundle the snippets I copied around used for freeing into it's own function
- comparing stuff requiring a comparing function: cmp, find, match, rfind, rmatch, invert
- cat, back/at/front, pop_at, pop_slice, apply