view src/base/vec.h @ 173:800a02381024

all: Clean up includes
author Lewin Bormann <lbo@spheniscida.de>
date Mon, 09 Sep 2019 19:53:57 +0200
parents 08d010255027
children
line wrap: on
line source

#ifndef base_vec_h
#define base_vec_h

#include <stdbool.h>
#include <stdlib.h>

/**
 * @file vec.h
 * @addtogroup base-vec
 * @{
 * @brief Simple growable contiguous vector/array implementation.
 */

/**
 * @brief A vector of n elements of each size bytes starting at base.
 *
 * At the cost of access performance we optimize for memory by fitting yvec_t
 * into 16 bytes.
 *
 * All yvec_t values must be initialized using YVEC_INIT, YVEC_NEW, yvec_init,
 * or yvec_new before use; even before calling functions like yvec_copy().
 */
typedef struct {
    /// Start of vector.
    void *base;
    /// Total capacity.
    size_t cap : 24;
    /// Current length.
    size_t len : 24;
    /// Size of each element.
    size_t size : 16;
} yvec_t;

typedef const char yconstchar;

/// Initialize a vector pointed to by `vecp` with `n` elements of type `TYPE`.
#define YVEC_INIT(vecp, n, TYPE) yvec_init(vecp, sizeof(TYPE), n)

/// Retrieve the element at `index` of type `TYPE`, casting the result to
/// `TYPE*`.
#define YVEC_AT(vecp, index, TYPE) ((TYPE *)yvec_at(vecp, index))

/// Append an element (elemp is pointer to the element) to a `yvec_t` (vecp is
/// a pointer to the vector), asserting that the size of the element type is
/// the same as the one expected by the vector.
#define YVEC_PUSH(vecp, elemp) \
    (assert((vecp)->size == sizeof(*(elemp))), yvec_push(vecp, (void *)(elemp)))

/// Create a new vector from `src` with `len` elements of `TYPE`.
#define YVEC_NEW(src, len, TYPE) yvec_new(src, sizeof(TYPE), len)

/**
 * @brief Initialize a new vector and return it, from an array of `len`
 * elements of each `size` bytes. Use `YVEC_NEW()` to directly specify the type
 * of the array.
 */
yvec_t yvec_new(void *src, size_t size, size_t len);

/**
 * @brief Initialize a vector with `n` elements of `size` bytes each. See also
 * `YVEC_INIT()`. The vector is guaranteed to only contain zero values. The
 * initial length is 0. The next `size` appends are "free" (they won't allocate
 * more memory).
 */
void yvec_init(yvec_t *vec, size_t size, size_t len);

/**
 * @brief Remove an element and returns true if the vector had at least one
 * element. The element is stored into `dst`, which must point to a memory area
 * of at least `vec->size` bytes.
 */
bool yvec_pop(yvec_t *vec, void *dst);

/**
 * @brief Append an element. See also `yvec_push()`, which asserts that the
 * element size matches the size expected by the vector. Returns the index of
 * the pushed element.
 *
 * Elements are appended at `vec[vec.len]`. Use `yvec_resize()` to change the
 * length.
 */
size_t yvec_push(yvec_t *vec, const void *element);

/**
 * @brief Append several elements from a raw array. The size of elements must
 * be equal to `vec->size`.
 */
void yvec_push_multi(yvec_t *vec, const void *elements, size_t n);

/**
 * @brief Prepend an element to the vector.
 */
void yvec_push_front(yvec_t* vec, const void *element);

/**
 * @brief Prepend multiple elements to the vector.
 */
void yvec_push_front_multi(yvec_t* vec, const void *element, size_t n);

/**
 * @brief Reverse a vec in-place.
 */
void yvec_reverse(yvec_t* vec);

/**
 * @brief Append `v2` to `v1`, leaving `v2` untouched.
 */
void yvec_append(yvec_t *v1, yvec_t *v2);

/**
 * @brief Resize a vector, growing it if needed. `yvec_resize` never releases
 * memory. It is valid to call `yvec_resize()` on a null, i.e. initialized,
 * vector.
 */
void yvec_resize(yvec_t *vec, size_t new_size);

/**
 * @brief Retrieve element at `index`. See also `YVEC_AT()`.
 *
 * Returns `NULL` if the index is out of bounds. Check `vec->len` for the
 * current length.
 */
void *yvec_at(yvec_t *vec, size_t index);

/**
 * @brief Copy the entire contents to a new yvec. `dst` is destroyed before
 * copying.
 */
void yvec_copy(yvec_t *src, yvec_t *dst);

/**
 * @brief Return a copy of `src` (the full buffer is copied).
 */
yvec_t yvec_clone(yvec_t *src);

/**
 * @brief Deallocate a vector. Resets all fields to 0.
 */
void yvec_destroy(yvec_t *vec);

/**
 * @}
 */
#endif