Dynamic vectors.
Overview
Implementation of dynamic vectors. More…
// typedefs typedef void te_vec_item_destroy_fn(const void *item); typedef struct te_vec te_vec; // structs struct te_vec; // global variables te_vec_item_destroy_fn te_vec_item_free_ptr; // global functions void te_vec_set_destroy_fn_safe(te_vec* vec, te_vec_item_destroy_fn* destroy); static size_t te_vec_size(const te_vec* vec); static const void* te_vec_get_immutable(const te_vec* vec, size_t index); static void* te_vec_get_mutable(te_vec* vec, size_t index); static const void* te_vec_get_safe_immutable(const te_vec* vec, size_t index, size_t element_size); static void* te_vec_get_safe_mutable(te_vec* vec, size_t index, size_t element_size); te_errno te_vec_append(te_vec* vec, const void* element); te_errno te_vec_append_vec(te_vec* vec, const te_vec* other); te_errno te_vec_append_array(te_vec* vec, const void* elements, size_t count); te_errno te_vec_append_str_fmt(te_vec* vec, const char* fmt, ...); te_errno void* te_vec_replace(te_vec* vec, size_t index, const void* new_val); void te_vec_transfer(te_vec* vec, size_t index, void* dest); size_t te_vec_transfer_append(te_vec* vec, size_t start_index, size_t count, te_vec* dest_vec); void te_vec_remove(te_vec* vec, size_t start_index, size_t count); static void te_vec_remove_index(te_vec* vec, size_t index); static te_errno te_vec_append_array_safe(te_vec* vec, const void* elements, size_t count, size_t element_size); void te_vec_reset(te_vec* vec); void te_vec_free(te_vec* vec); void te_vec_deep_free(te_vec* vec); te_errno te_vec_append_strarray(te_vec* vec, const char** elements); static size_t te_vec_get_index(const te_vec* vec, const void* ptr); te_errno te_vec_split_string(const char* str, te_vec* strvec, char sep, bool empty_is_none); void te_vec_sort(te_vec* vec, int(*)(const void*elt1, const void*elt2) compar); bool te_vec_search(const te_vec* vec, const void* key, int(*)(const void*key, const void*elt) compar, unsigned int* minpos, unsigned int* maxpos); // macros #define TE_VEC_APPEND(te_vec_, val_) #define TE_VEC_APPEND_ARRAY(te_vec_, elements_, count_) #define TE_VEC_APPEND_RVALUE(te_vec_, type_, val_) #define TE_VEC_FOREACH(te_vec_, elem_) #define TE_VEC_GET(type_, te_vec_, index_) #define TE_VEC_INIT(type_) #define TE_VEC_INIT_AUTOPTR(type_) #define TE_VEC_INIT_COMPLETE(type_, grow_factor_, destroy_) #define TE_VEC_INIT_DESTROY(type_, destroy_) #define TE_VEC_INIT_GROW_FACTOR(type_, grow_factor_) #define TE_VEC_INIT_LIKE(other_) #define te_vec_get(vec_, index_) #define te_vec_get_safe(vec_, index_, element_size_)
Detailed Documentation
Implementation of dynamic vectors.
Example of usage:
// Initialize the dynamic vector to store a value of type int. te_vec vec = TE_VEC_INIT(int) int number = 42; ... // Put a number into the dynamic vector. TE_VEC_APPEND(&vec, number); ... // Copy from a C array int numbers[] = {4, 2}; te_vec_append_array(&vec, numbers, TE_ARRAY_LEN(numbers)); ... // Change the first element. TE_VEC_GET(int, &vec, 0) = 100; ... // Free the memory. te_vec_free(&vec);
Typedefs
typedef void te_vec_item_destroy_fn(const void *item)
Function type for vector element destructors.
The destructor accepts a pointer to a vector element which it is not supposed to modify, not a pointer to a deallocatable memory, so e.g. a destructor that frees a char *
typed element would look like:
static void item_destroy_str(const void *item) { char *buf = *(void * const *)item; free(buf); }
The destructor function shall be prepared to deal correctly with all-zero initialized elements.
Parameters:
item |
A pointer to a vector element data. |
typedef struct te_vec te_vec
Dynamic vector.
Global Variables
te_vec_item_destroy_fn te_vec_item_free_ptr
A destructor to release vector elements that contain a single heap memoy pointer.
Global Functions
static size_t te_vec_size(const te_vec* vec)
Count elements in a dynamic vector.
Parameters:
vec |
Dynamic vector. |
Returns:
Number of elements.
te_errno te_vec_append(te_vec* vec, const void* element)
Append one element to the dynamic array.
If element
is NULL
, the new element will be zeroed.
Parameters:
vec |
Dynamic vector. |
element |
Element to append (may be |
Returns:
Status code (always 0).
te_errno te_vec_append_vec(te_vec* vec, const te_vec* other)
Append elements from other
dynamic array,
Both vectors must have a null element destructor.
Parameters:
vec |
Dynamic vector. |
other |
Other dynamic vector. |
Returns:
Status code (always 0).
te_errno te_vec_append_array(te_vec* vec, const void* elements, size_t count)
Append elements from a plain C array to the dynamic array.
If elements
is NULL
, the news element will be zeroed.
Parameters:
vec |
Dynamic vector. |
elements |
Elements of array (may be |
count |
Number of |
Returns:
Status code (always 0).
te_errno te_vec_append_str_fmt(te_vec* vec, const char* fmt, ...)
Append a formatted C string to the dynamic array.
The string in the vector will be heap-allocated.
Parameters:
vec |
Dynamic vector of C strings. |
fmt |
Format string. |
… |
Format string arguments. |
Returns:
Status code (always 0).
te_errno void* te_vec_replace(te_vec* vec, size_t index, const void* new_val)
Replace the content of index'th
element of vec
with new_val
.
If new_val
is NULL
, the content of the element is zeroed. A destructor function (if it is set) is called for the old content.
If index
is larger than the vec
size, it is grown as needed.
Parameters:
vec |
Dynamic vector. |
index |
Index to replace. |
new_val |
New content (may be |
Returns:
A pointer to the new content of the element.
void te_vec_transfer(te_vec* vec, size_t index, void* dest)
Move the content of a vector element to dest
.
This function is mostly useful for vectors with non-null destructors. Basically, it implements move semantics for vector elements.
If dest
is not NULL
, the content of index'th
element is copied to dest
; destructors are not called.
If dest
is NULL
, the destructor is called on index'th
element.
In both cases the element is zeroed afterwards. This ensures that calling the destructor for the second time would not cause bugs like double-free.
Parameters:
vec |
Dynamic vector. |
index |
Index to move. |
dest |
Destination (may be |
size_t te_vec_transfer_append(te_vec* vec, size_t start_index, size_t count, te_vec* dest_vec)
Move at most count
elements from vec
to dest_vec
.
If dest_vec
is not NULL
, elements starting from start_index
are appended to it and the elements are zeroed like with te_vec_transfer().
If dest_vec
is NULL
, the destructor is called on the elements.
If start_index
+ count
is greater than the vector size, count
is decreased as needed.
dest_vec
must either have a null element destructor or the same destructor as vec
.
Parameters:
vec |
Source vector. |
start_index |
Starting index. |
count |
Number of elements. |
dest_vec |
Destination vector (may be |
Returns:
The number of actually transferred elements.
void te_vec_remove(te_vec* vec, size_t start_index, size_t count)
Remove elements from a vector.
If vec
has a non-null element destructor, it will be called for each element.
If start_index
+ count
is greater than the vector size, count
is decreased as needed.
Parameters:
vec |
Dynamic vector. |
start_index |
Starting index of elements to remove. |
count |
Number of elements to remove. |
static void te_vec_remove_index(te_vec* vec, size_t index)
Remove an element from a vector.
Parameters:
vec |
Dynamic vector. |
index |
Index of an element to remove. |
static te_errno te_vec_append_array_safe(te_vec* vec, const void* elements, size_t count, size_t element_size)
Safe version of te_vec_append_array().
Parameters:
vec |
Dynamic vector. |
elements |
Elements of an array. |
count |
Number of |
element_size |
Size of one element in |
Returns:
Status code (always 0).
void te_vec_reset(te_vec* vec)
Reset a dynamic array.
The number of elements in the array becomes zero. A destructor function is called for each element if it is defined. The memory of the vector itself is not released.
Parameters:
vec |
Dynamic vector. |
See also:
void te_vec_free(te_vec* vec)
Cleanup a dynamic array and free its storage memory.
A destructor function is called for each element if it is defined.
Parameters:
vec |
Dynamic vector. |
void te_vec_deep_free(te_vec* vec)
Free the dynamic array along with its elements.
The function does exactly the same as te_vec_free() unless vec
has a null destructor, in which case it treats elements as pointers to heap memory and free() them.
Deprecated Use te_vec_free() with a proper destructor.
Parameters:
vec |
Dynamic vector of pointers. |
te_errno te_vec_append_strarray(te_vec* vec, const char** elements)
Append to a dynamic array of strings.
The elements in the array will be strdup()’ed.
Parameters:
vec |
Dynamic vector to append the array of strings to. |
elements |
|
Returns:
Status code (always 0).
static size_t te_vec_get_index(const te_vec* vec, const void* ptr)
Return an index of an element of vec
pointed to by ptr
.
Parameters:
vec |
Dynamic vector. |
ptr |
Pointer to the content of some of its elements. |
Returns:
Zero-based index. The result is undefined if ptr
is not pointing to the actual vector data
te_errno te_vec_split_string(const char* str, te_vec* strvec, char sep, bool empty_is_none)
Split a string into chunks separated by sep
.
The copies of the chunks are pushed into the strvec
.
The element size of strvec
must be sizeof(char *)
.
Adjacent separators are never skipped, so e.g. '::
:’ would be split into four chunks using colon as a separator. The only special case is an empty string which may be treated as no chunks depending on empty_is_none
.
Parameters:
str |
String to split. |
strvec |
Target vector for string chunks. The original content is not destroyed, new items are added to the end. |
sep |
Separator character. |
empty_is_none |
If |
Returns:
Status code (always 0).
void te_vec_sort(te_vec* vec, int(*)(const void*elt1, const void*elt2) compar)
Sort the elements of vec
in place according to compar
.
Parameters:
vec |
Vector to sort. |
compar |
Comparison function (as for |
bool te_vec_search(const te_vec* vec, const void* key, int(*)(const void*key, const void*elt) compar, unsigned int* minpos, unsigned int* maxpos)
Search a sorted vector vec
for an item equal to key
using compar
as a comparison function.
The function implements binary search, however unlike C standard bsearch() it can be reliably used on non-unique matches, because it returns the lowest and the highest indices of matching elements.
Mind the order of arguments. compar
expects the first argument to be a key and the second argument to be an array element, for a compatibility with bsearch(). However, the order of arguments of the function itself is reverse wrt bsearch(): the vector goes first and the key follows it for consistency with other vector functions. For cases where the key has the same structure as the array element, this should not matter.
The vector must be sorted in a way compatible with compar
, i.e. by using te_vec_sort() with the same compar
, however, the comparison functions need not to be truly identical: the search comparison function may treat more elements as equal than the sort comparison.
Parameters:
vec |
Vector to search in. |
key |
Key to search. |
compar |
Comparison function (as for |
minpos |
The lowest index of a matching element. |
maxpos |
The highest index of a matchin element. Any of |
Returns:
true
iff an element matching key
is found.
Macros
#define TE_VEC_APPEND(te_vec_, val_)
Add element to the vector’s tail.
Parameters:
te_vec_ |
Dynamic vector. |
val_ |
New element. |
Returns:
Status code (always 0).
#define TE_VEC_APPEND_ARRAY(te_vec_, elements_, count_)
Append elements from a C array to the dynamic vector (safe version).
Parameters:
te_vec_ |
Dynamic vector. |
elements_ |
C array. |
count_ |
Count of |
Returns:
Status code (always 0).
#define TE_VEC_APPEND_RVALUE(te_vec_, type_, val_)
Add element to the vector’s tail.
Parameters:
te_vec_ |
Dynamic vector. |
type_ |
Element type. |
val_ |
New element. |
Returns:
Status code (always 0).
#define TE_VEC_FOREACH(te_vec_, elem_)
Iterate over all elements in a vector.
Example:
struct netinterface { int index; const char *name; }; te_vec vec = TE_VEC_INIT(struct netinterface); ... // Fill vector with values struct netinterface *netif; TE_VEC_FOREACH(&vec, netif) { printf("interface '%s' have index %d", netif->name, netif->index); }
Parameters:
te_vec_ |
Dynamic vector. |
elem_ |
Pointer of type contain in vector. |
#define TE_VEC_GET(type_, te_vec_, index_)
Vector element accessor.
For vectors with a non-null destructor te_vec_replace() should be used instead of mutable TE_VEC_GET(), as it guarantees proper disposal of old element contents.
Parameters:
type_ |
Type of element. |
te_vec_ |
Dynamic vector. |
index_ |
Index of element. |
Returns:
Element of a vector.
#define TE_VEC_INIT(type_)
Vector initializer with the default grow factor.
The element destructor may be later set with te_vec_set_destroy_fn_safe().
Parameters:
type_ |
Element type. |
#define TE_VEC_INIT_AUTOPTR(type_)
Vector initializer for heap-allocated pointers.
The destructor is set to te_vec_item_free_ptr(). Additionally a check is made that type_
is at least the same size as a pointer type.
Parameters:
type_ |
Element type (which must be a pointer type). |
#define TE_VEC_INIT_COMPLETE(type_, grow_factor_, destroy_)
Complete initializer for a te_vec.
Parameters:
type_ |
Element type. |
grow_factor_ |
Grow factor (see TE_DBUF_DEFAULT_GROW_FACTOR). |
destroy_ |
Element destructor (or |
#define TE_VEC_INIT_DESTROY(type_, destroy_)
Vector initializer with a possibly non-null destructor.
Parameters:
type_ |
Element type. |
destroy_ |
Element destructor or |
#define TE_VEC_INIT_GROW_FACTOR(type_, grow_factor_)
Vector initializer with a custom grow factor.
The element destructor may be later set with te_vec_set_destroy_fn_safe().
Most users shall stick to TE_DBUF_DEFAULT_GROW_FACTOR.
Parameters:
type_ |
Element type. |
grow_factor_ |
Grow factor (see TE_DBUF_DEFAULT_GROW_FACTOR). |
#define te_vec_get(vec_, index_)
Access an element of a dynamic vector.
The macro returns either mutable or immutable pointer depending on the constness of vec_
.
Parameters:
vec_ |
Dynamic vector. |
index_ |
Index of element. |
Returns:
Pointer to the content of an element.
#define te_vec_get_safe(vec_, index_, element_size_)
Safe version of te_vec_get().
Parameters:
vec_ |
Dynamic vector. |
index_ |
Index of element. |
element_size_ |
Expected size of type in array. |
Returns:
Pointer to element.