A dynamic array based on stb stretchy buffer (see Acknowledgments section).
Adds some more functionality known from c++ std::vector, mainly the ability to insert/remove elements at any index.
#include<stdio.h>#defineVECTOR_IMPLEMENTATION#include"vector.h"intmain ()
{
int*v=vector_init (7, 5, 16, 8);
vector_push (v, 25);
vector_push (v, 13);
printf ("v = { ");
for (size_ti=0; i<vector_size (v); ++i)
printf ("%d, ", v[i]);
printf ("}\n");
vector_free (v);
}Output:
v = { 7, 5, 16, 8, 25, 13, }
VECTOR_IMPLEMENTATION must be defined in one source file to define the functions.
Note: you can still include multiple files that include the vector.h header after this macro:
#defineVECTOR_IMPLEMENTATION#include"vector.h"#include"other_file_that_also_includes_vector.h"And the implementation will only be triggered by the first inclusion.
#defineVECTOR(T) T *This is used to be clear about something being a vector and not just a pointer in source code.
/** * Parameters: * v - vector * e - element * n - number of elements * i - index of element * T - type * ... - initializer list elements *//* Gets the number of elements in the vector. */#definevector_size(v)
/* Gets the number of elements that fit in the vector. */#definevector_capacity(v)
/* Checks if the vector is empty. */#definevector_empty(v)
/* If I is negative `vector_size (v) - i`, otherwise just unchanged I. */#definevector_idx(v, i)
/* Checks if I is a valid index (see vector_idx) */#definevector_idx_valid(v, i)
/* Gets a reference to the element at index I with bounds checking. If I is a negative number, gets the element at `vector_size(v) - i`. If I is out of bounds the result is NULL. */#definevector_at(v, i)
/* Increases the capacity of the vector the fit at least N elements. */#definevector_reserve(v, n)
/* Reduces the vectors capacity to its size. */#definevector_shrink_to_fit(v)
/* Gets the last element of the vector. */#definevector_back(v)
/* Gets a pointer past the last element of the vector. */#definevector_end(v)
/* Compares two vector byte-wise. Behaves like `strcmp` on a null-terminated version of the vectors data. */#definevector_compare(v1, v2)
/* Appends an element to the vector. */#definevector_push(v, e)
/* For vectors of structures or unions, appends a new element to the vector and constructs it in-place, variadic arguments are passed as initializer list for struct or union. */#definevector_emplace_back(v, ...)
/* Appends the items from another vector to the vector. */#definevector_push_vector(v, other)
/* Gets and removes the last element of the vector. */#definevector_pop(v)
/* Inserts a new element into the vector at position I. */#definevector_insert(v, i, e)
/* Like vector_emplace_back but the new element is inserted at position I. */#definevector_emplace(v, i, ...)
/* Removes the element at position I from the vector. */#definevector_remove(v, i)
/* Removes N elements from the vector, starting at position I. */#definevector_erase(v, i, n)
/* Clears the contents of the vector. */#definevector_clear(v)
/* Resizes the vector. */#definevector_resize(v, n)
/* Creates a new empty vector. */#definevector_create(T, n)
/* Creates a new vector with elements {X, ...} and the type of X as element type. */#definevector_init(x, ...)
/* Creates a vector with the first N elements form the buffer pointed to by P. */#definevector_create_from(p, n)
/* Frees the vector. */#definevector_free(v)
/* Create a new vector with the same elements as the input vector */#definevector_copy_construct(v)
/* Copy data from SRC to DST */#definevector_copy(dst, src)
/* Iterate over the vector, IT recieves a pointer to each element */#definevector_for_each(v, it)
/* Creates a vector from `v[b:e]`. B and E may be negative (see vector_idx). If B or E are out of bounds they get clamped into the valid range. */#definevector_slice(v, b, e)
/* Given a list of indices, creates a vector from `v` with the elements at at the given indices. Indices can be in any order and be repeated and may not be negative (the value INT_MIN can not be used). There is no bounds checking on the indices. Example: VECTOR(int) vec = vector_init (1, 2, 3); // = {1, 2, 3} VECOTR(int) reversed = vector_select (vec, 2, 1, 0); // = {3, 2, 1} VECOTR(int) reversed = vector_select (vec, -1, -2, -3); // = {3, 2, 1} VECTOR(int) only_two = vector_select (vec, 1, 1, 1); // = {2, 2, 2} VECTOR(int) twice = vector_select (vec, 0, 1, 2, 0, 1, 2); // = {1, 2, 3, 1, 2, 3} Note: the variadic arguments are always read as integers! */#definevector_select(v, ...)Most of these may be called with v being a null pointer, in this case they will either
Return
0/NULL:vector_size,vector_capacity,vector_end,vector_copy_construct,vector_idx_valid,vector_at,vector_slice,vector_selectReturn
1:vector_emptyDo nothing:
vector_shrink_to_fit,vector_insert,vector_emplace,vector_remove,vector_erase,vector_clear,vector_freeCreate a new vector:
vector_reserve,vector_push,vector_emplace_back,vector_copy,vector_push_vector
The only exceptions are vector_back and vector_pop which will cause a segmentation fault.
vector_idx (NULL, -n) will result in (size_t)-n (overflows into a huge number).
For vector_compare and other in vector_push_vector, NULL is just an empty vector.
By default vector_emplace_back, vector_emplace, vector_for_each and vector_init are only defined if __GNUC__ is defined.
vector_emplace_back, vector_emplace and vector_for_each can be enabled by defining VECTOR__DECLTYPE(x), which gives the type of x.
If your compiler does support statement expressions, vector_init can be enabled by defining VECTOR__HAS_STATEMENT_EXPRS.
static_vector.h contains utilities to create vectors with a static capacity inside existing buffers.
#include<assert.h>#defineVECTOR_IMPLEMENTATION#include"static_vector.h"structBig_Type {
size_ta;
size_tb;
};
intmain(void) {
enum {
CAPACITY=10,
SMALL=3
};
structBig_Typebuf[VECTOR_STATIC_SIZE(structBig_Type, CAPACITY)];
structBig_Type*vec=vector_create_static(buf);
assert(vector_capacity(vec) ==CAPACITY);
// the header of the vector also holds 2 `size_t`s so it's 1 extra element.assert(vector_static_size(vec) ==CAPACITY+1);
vec=vector_create_static_sized(buf, SMALL);
assert(vector_capacity(vec) ==SMALL);
assert(vector_static_size(vec) ==SMALL+1);
}/* Number of elements of type T required to hold the header of a vector. */#defineVECTOR__HEAD_SPACE(T)
/* Number of elements an array of T needs to hold a vector of T with capacity N. */#defineVECTOR_STATIC_SIZE(T, n)
/* Creates a vector in the static array V. */#definevector_create_static(v)
/* Creates a static vector with a capacity of N in the buffer pointer to by V. */#definevector_create_static_sized(v, n)
/* Number of elements the static vector occupies (including its header). */#definevector_static_size(v)Static vectors use the same functions as normal vectors. There are no checks whether a operation exceeds the static capacity of the vector, instead these operations will try to reallocate and crash.
Based on an old version of stb, its implementation has since evolved quite a lot (and is no longer even named stretchy buffer).