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 NULL).

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 NULL).

count

Number of elements.

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 NULL).

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 NULL).

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 NULL).

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 elements.

element_size

Size of one element in elements.

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:

te_vec_free()

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

NULL terminated array of strings

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 true, empty string is treated as having no chunks (so strvec is not changed). Otherwise, an empty string is treated as having a single empty chunk.

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 qsort).

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 bsearch).

minpos

The lowest index of a matching element.

maxpos

The highest index of a matchin element. Any of minpos and maxpos may be NULL. If they are both NULL, the function just checks for an existence of a matching element.

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 elements

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 NULL).

#define TE_VEC_INIT_DESTROY(type_, destroy_)

Vector initializer with a possibly non-null destructor.

Parameters:

type_

Element type.

destroy_

Element destructor or NULL.

#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.