2021-11-21 23:59:44 +00:00
|
|
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
2022-11-02 00:05:16 +00:00
|
|
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
2019-07-09 23:47:48 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
*
|
|
|
|
* Dynamic arrays.
|
|
|
|
*
|
|
|
|
* See @ref Vectors.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef DRGN_VECTOR_H
|
|
|
|
#define DRGN_VECTOR_H
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
2020-09-24 00:02:02 +01:00
|
|
|
#include <stdlib.h> // IWYU pragma: keep
|
|
|
|
#include <string.h> // IWYU pragma: keep
|
2019-07-09 23:47:48 +01:00
|
|
|
|
2023-08-09 05:27:16 +01:00
|
|
|
#include "minmax.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
2019-07-09 23:47:48 +01:00
|
|
|
/**
|
|
|
|
* @ingroup Internals
|
|
|
|
*
|
|
|
|
* @defgroup Vectors Vectors
|
|
|
|
*
|
|
|
|
* Dynamic arrays (a.k.a.\ vectors).
|
|
|
|
*
|
2023-08-09 05:27:16 +01:00
|
|
|
* This is an implementation of generic, strongly-typed vectors.
|
2019-07-09 23:47:48 +01:00
|
|
|
*
|
|
|
|
* A vector is defined with @ref DEFINE_VECTOR(). Each generated vector
|
|
|
|
* interface is prefixed with a given name; the interface documented here uses
|
|
|
|
* the example name @c vector.
|
|
|
|
*
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef DOXYGEN
|
|
|
|
/**
|
2023-08-09 05:27:16 +01:00
|
|
|
* @struct vector
|
|
|
|
*
|
2019-07-09 23:47:48 +01:00
|
|
|
* Vector instance.
|
|
|
|
*
|
|
|
|
* There are no requirements on how this is allocated; it may be global, on the
|
|
|
|
* stack, allocated by @c malloc(), embedded in another structure, etc.
|
|
|
|
*/
|
2023-08-09 05:27:16 +01:00
|
|
|
struct vector;
|
2019-07-09 23:47:48 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize a @ref vector.
|
|
|
|
*
|
|
|
|
* The new vector is empty.
|
2020-07-01 20:37:16 +01:00
|
|
|
*
|
|
|
|
* @sa VECTOR_INIT
|
2019-07-09 23:47:48 +01:00
|
|
|
*/
|
|
|
|
void vector_init(struct vector *vector);
|
|
|
|
|
2023-08-09 05:27:16 +01:00
|
|
|
/** Free memory allocated by a @ref vector. */
|
|
|
|
void vector_deinit(struct vector *vector);
|
|
|
|
|
|
|
|
/** Return the number of entries in a @ref vector. */
|
|
|
|
size_t vector_size(const struct vector *vector);
|
|
|
|
|
|
|
|
/** Return whether a @ref vector is empty. */
|
|
|
|
bool vector_empty(const struct vector *vector);
|
|
|
|
|
2019-07-09 23:47:48 +01:00
|
|
|
/**
|
2023-08-09 05:27:16 +01:00
|
|
|
* Maximum possible number of entries in a @ref vector.
|
2019-07-09 23:47:48 +01:00
|
|
|
*
|
2023-08-09 05:27:16 +01:00
|
|
|
* Attempts to increase the size or capacity beyond this will fail.
|
2019-07-09 23:47:48 +01:00
|
|
|
*/
|
2023-08-09 05:27:16 +01:00
|
|
|
const size_t vector_max_size;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the number of entries in a @ref vector.
|
|
|
|
*
|
|
|
|
* If @p size is greater than the current capacity, this increases the capacity
|
|
|
|
* to at least @p size and reallocates the entries.
|
|
|
|
*
|
|
|
|
* If @p size is greater than the current size, the entries between the old size
|
|
|
|
* and the new size are uninitialized.
|
|
|
|
*
|
|
|
|
* @return @c true on success, @c false on failure.
|
|
|
|
*/
|
|
|
|
bool vector_resize(struct vector *vector, size_t size);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the size of a @ref vector to zero.
|
|
|
|
*
|
|
|
|
* This does not change the capacity or free the entries.
|
|
|
|
*/
|
|
|
|
void vector_clear(struct vector *vector);
|
|
|
|
|
|
|
|
/** Return the number of allocated entries in a @ref vector. */
|
|
|
|
size_t vector_capacity(const struct vector *vector);
|
2019-07-09 23:47:48 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Increase the capacity of a @ref vector.
|
|
|
|
*
|
2023-08-09 05:27:16 +01:00
|
|
|
* If @p capacity is greater than the current capacity, this increases the
|
|
|
|
* capacity to at least @p capacity and reallocates the entries. Otherwise, it
|
|
|
|
* does nothing.
|
2019-07-09 23:47:48 +01:00
|
|
|
*
|
|
|
|
* @return @c true on success, @c false on failure.
|
|
|
|
*/
|
|
|
|
bool vector_reserve(struct vector *vector, size_t capacity);
|
|
|
|
|
2023-08-09 05:27:16 +01:00
|
|
|
/**
|
|
|
|
* Increase the capacity of a @ref vector to accomodate at least one append.
|
|
|
|
*
|
|
|
|
* If the current capacity is equal to the current size, this increases the
|
|
|
|
* capacity by at least one and reallocates the entries. Otherwise, it does
|
|
|
|
* nothing.
|
|
|
|
*
|
|
|
|
* @return @c true on success, @c false on failure.
|
|
|
|
*/
|
|
|
|
bool vector_reserve_for_append(struct vector *vector);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Increase the capacity of a @ref vector to accomodate at least @p n appends.
|
|
|
|
*
|
|
|
|
* If the current capacity minus the current size is not at least @p n, this
|
|
|
|
* increases the capacity by at least @p n and reallocates the entries.
|
|
|
|
* Otherwise, it does nothing.
|
|
|
|
*
|
|
|
|
* @return @c true on success, @c false on failure.
|
|
|
|
*/
|
|
|
|
bool vector_reserve_for_extend(struct vector *vector, size_t n);
|
|
|
|
|
2019-07-09 23:47:48 +01:00
|
|
|
/**
|
|
|
|
* Free unused memory in a @ref vector.
|
|
|
|
*
|
2023-08-09 05:27:16 +01:00
|
|
|
* This may reduce the capacity and reallocate the entries. It may also do
|
|
|
|
* nothing.
|
2019-07-09 23:47:48 +01:00
|
|
|
*/
|
|
|
|
void vector_shrink_to_fit(struct vector *vector);
|
|
|
|
|
2023-08-09 05:27:16 +01:00
|
|
|
/**
|
|
|
|
* Steal the array of entries from a @ref vector.
|
|
|
|
*
|
|
|
|
* This returns the internal array of entries. The vector can no longer be used
|
|
|
|
* except to be passed to @ref vector_deinit(), which will do nothing.
|
|
|
|
*
|
|
|
|
* This can be used to build an array when the size isn't known ahead of time
|
|
|
|
* but won't change after the array is built. For example:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* DEFINE_VECTOR(int_vector, int);
|
|
|
|
*
|
|
|
|
* bool primes_less_than(int n, int **array_ret, size_t *size_ret)
|
|
|
|
* {
|
|
|
|
*
|
|
|
|
* _cleanup_(int_vector_deinit) struct int_vector vector = VECTOR_INIT;
|
|
|
|
* for (int i = 2; i < n; i++) {
|
|
|
|
* if (is_prime(i) && !int_vector_push(&vector, &i))
|
|
|
|
* return false;
|
|
|
|
* }
|
|
|
|
* int_vector_shrink_to_fit(&vector);
|
|
|
|
* int_vector_steal(&vector, array_ret, size_ret);
|
|
|
|
* return true;
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* As demonstrated here, it may be desirable to call @ref vector_shrink_to_fit()
|
|
|
|
* first.
|
|
|
|
*
|
|
|
|
* @param[out] entries_ret Returned array. This must be freed with @c free().
|
|
|
|
* @param[out] size_ret Returned number of entries in array. May be @c NULL.
|
|
|
|
*/
|
|
|
|
void vector_steal(struct vector *vector, entry_type **entries_ret,
|
|
|
|
size_t *size_ret);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the array of entries in a @ref vector.
|
|
|
|
*
|
|
|
|
* The vector may be empty, in which case this is equal to `vector_end(vector)`.
|
|
|
|
*/
|
|
|
|
entry_type *vector_begin(struct vector *vector);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return one past the last entry in a @ref vector.
|
|
|
|
*
|
|
|
|
* The vector may be empty, in which case this is equal to
|
|
|
|
* `vector_begin(vector)`.
|
|
|
|
*/
|
|
|
|
entry_type *vector_end(struct vector *vector);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the first entry in a @ref vector.
|
|
|
|
*
|
|
|
|
* This is equivalent to `vector_at(vector, 0)`. The vector must not be empty
|
|
|
|
* (in contrast to @ref vector_begin()).
|
|
|
|
*/
|
|
|
|
entry_type *vector_first(struct vector *vector);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the last entry in a @ref vector.
|
|
|
|
*
|
|
|
|
* This is equivalent to `vector_at(vector, vector_size(vector) - 1)`. The
|
|
|
|
* vector must not be empty.
|
|
|
|
*/
|
|
|
|
entry_type *vector_last(struct vector *vector);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the entry at the given index in a @ref vector.
|
|
|
|
*
|
|
|
|
* @param[in] i Entry index. Must be less than the size of the vector.
|
|
|
|
*/
|
|
|
|
entry_type *vector_at(struct vector *vector, size_t i);
|
|
|
|
|
2019-07-09 23:47:48 +01:00
|
|
|
/**
|
|
|
|
* Append to a @ref vector.
|
|
|
|
*
|
2023-08-09 05:27:16 +01:00
|
|
|
* This increases vector's size by one. If the current capacity is equal to the
|
|
|
|
* current size, this increases the capacity by at least one and reallocates the
|
|
|
|
* entries.
|
2019-07-09 23:47:48 +01:00
|
|
|
*
|
2023-08-09 05:27:16 +01:00
|
|
|
* @return @c true on success, @c false on failure.
|
2019-07-09 23:47:48 +01:00
|
|
|
*/
|
|
|
|
bool vector_append(struct vector *vector, const entry_type *entry);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Append an uninitialized entry to a @ref vector.
|
|
|
|
*
|
|
|
|
* Like @ref vector_append(), but return a pointer to the new (uninitialized)
|
|
|
|
* entry.
|
|
|
|
*
|
2023-08-09 05:27:16 +01:00
|
|
|
* @return The new entry on success, @c NULL on failure.
|
2019-07-09 23:47:48 +01:00
|
|
|
*/
|
|
|
|
entry_type *vector_append_entry(struct vector *vector);
|
|
|
|
|
2023-08-09 05:27:16 +01:00
|
|
|
/**
|
|
|
|
* Append all of the entries from one vector to another.
|
|
|
|
*
|
|
|
|
* @param[in] dst Vector to append to.
|
|
|
|
* @param[in] src Source vector. This is not modified.
|
|
|
|
* @return @c true on success, @c false on failure.
|
|
|
|
*/
|
|
|
|
bool vector_extend(struct vector *dst, const struct vector *src);
|
|
|
|
|
2019-07-09 23:47:48 +01:00
|
|
|
/**
|
|
|
|
* Remove and return the last entry in a @ref vector.
|
|
|
|
*
|
2023-08-09 05:27:16 +01:00
|
|
|
* The vector must not be empty. This decreases the size by one. It does not
|
|
|
|
* change the capacity or reallocate the entries.
|
2019-07-09 23:47:48 +01:00
|
|
|
*
|
|
|
|
* @return A pointer to the removed entry, which remains valid until another
|
2023-08-09 05:27:16 +01:00
|
|
|
* entry is inserted in its place or the entries are reallocated.
|
2019-07-09 23:47:48 +01:00
|
|
|
*/
|
|
|
|
entry_type *vector_pop(struct vector *vector);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Define a vector type without defining its functions.
|
|
|
|
*
|
|
|
|
* This is useful when the vector type must be defined in one place (e.g., a
|
|
|
|
* header) but the interface is defined elsewhere (e.g., a source file) with
|
|
|
|
* @ref DEFINE_VECTOR_FUNCTIONS(). Otherwise, just use @ref DEFINE_VECTOR().
|
|
|
|
*
|
|
|
|
* @sa DEFINE_VECTOR()
|
|
|
|
*/
|
|
|
|
#define DEFINE_VECTOR_TYPE(vector, entry_type) \
|
|
|
|
typedef typeof(entry_type) vector##_entry_type; \
|
|
|
|
\
|
|
|
|
struct vector { \
|
2023-08-09 05:27:16 +01:00
|
|
|
vector##_entry_type *_data; \
|
|
|
|
size_t _size; \
|
|
|
|
size_t _capacity; \
|
2023-08-02 22:54:59 +01:00
|
|
|
}; \
|
|
|
|
struct DEFINE_VECTOR_needs_semicolon
|
2019-07-09 23:47:48 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Define the functions for a vector.
|
|
|
|
*
|
|
|
|
* The vector type must have already been defined with @ref
|
|
|
|
* DEFINE_VECTOR_TYPE().
|
|
|
|
*
|
|
|
|
* Unless the type and function definitions must be in separate places, use @ref
|
|
|
|
* DEFINE_VECTOR() instead.
|
|
|
|
*
|
|
|
|
* @sa DEFINE_VECTOR()
|
|
|
|
*/
|
|
|
|
#define DEFINE_VECTOR_FUNCTIONS(vector) \
|
2021-02-21 11:16:23 +00:00
|
|
|
__attribute__((__unused__)) \
|
2019-07-09 23:47:48 +01:00
|
|
|
static void vector##_init(struct vector *vector) \
|
|
|
|
{ \
|
2023-08-09 05:27:16 +01:00
|
|
|
vector->_data = NULL; \
|
|
|
|
vector->_size = vector->_capacity = 0; \
|
2019-07-09 23:47:48 +01:00
|
|
|
} \
|
|
|
|
\
|
2021-02-21 11:16:23 +00:00
|
|
|
__attribute__((__unused__)) \
|
2019-07-09 23:47:48 +01:00
|
|
|
static void vector##_deinit(struct vector *vector) \
|
|
|
|
{ \
|
2023-08-09 05:27:16 +01:00
|
|
|
free(vector->_data); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
|
|
|
static size_t vector##_size(const struct vector *vector) \
|
|
|
|
{ \
|
|
|
|
return vector->_size; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
|
|
|
static bool vector##_empty(const struct vector *vector) \
|
|
|
|
{ \
|
|
|
|
return vector->_size == 0; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static const size_t vector##_max_size = \
|
|
|
|
PTRDIFF_MAX / sizeof(vector##_entry_type); \
|
|
|
|
\
|
|
|
|
static size_t vector##_capacity(const struct vector *vector) \
|
|
|
|
{ \
|
|
|
|
return vector->_capacity; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static bool vector##_reallocate(struct vector *vector, size_t capacity) \
|
|
|
|
{ \
|
|
|
|
void *new_data = realloc(vector->_data, \
|
|
|
|
capacity * sizeof(vector##_entry_type)); \
|
|
|
|
if (!new_data) \
|
|
|
|
return false; \
|
|
|
|
vector->_data = new_data; \
|
|
|
|
vector->_capacity = capacity; \
|
|
|
|
return true; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static bool vector##_reserve_for_extend(struct vector *vector, size_t n) \
|
|
|
|
{ \
|
|
|
|
size_t size = vector##_size(vector); \
|
|
|
|
if (n <= vector##_capacity(vector) - size) \
|
|
|
|
return true; \
|
|
|
|
if (n > vector##_max_size - size) \
|
|
|
|
return false; \
|
|
|
|
size_t new_capacity = size + max(size, n); \
|
|
|
|
if (new_capacity < size || new_capacity > vector##_max_size) \
|
|
|
|
new_capacity = vector##_max_size; \
|
|
|
|
return vector##_reallocate(vector, new_capacity); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
|
|
|
static bool vector##_resize(struct vector *vector, size_t size) \
|
|
|
|
{ \
|
|
|
|
if (vector->_size < size \
|
|
|
|
&& !vector##_reserve_for_extend(vector, size - vector->_size)) \
|
|
|
|
return false; \
|
|
|
|
vector->_size = size; \
|
|
|
|
return true; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
|
|
|
static void vector##_clear(struct vector *vector) \
|
|
|
|
{ \
|
|
|
|
vector->_size = 0; \
|
2019-07-09 23:47:48 +01:00
|
|
|
} \
|
|
|
|
\
|
2021-02-21 11:16:23 +00:00
|
|
|
__attribute__((__unused__)) \
|
2019-07-09 23:47:48 +01:00
|
|
|
static bool vector##_reserve(struct vector *vector, size_t capacity) \
|
|
|
|
{ \
|
2023-08-09 05:27:16 +01:00
|
|
|
if (capacity <= vector##_capacity(vector)) \
|
|
|
|
return true; \
|
|
|
|
if (capacity > vector##_max_size) \
|
|
|
|
return false; \
|
|
|
|
return vector##_reallocate(vector, capacity); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static bool vector##_reserve_for_append(struct vector *vector) \
|
|
|
|
{ \
|
|
|
|
return vector##_reserve_for_extend(vector, 1); \
|
2019-07-09 23:47:48 +01:00
|
|
|
} \
|
|
|
|
\
|
2021-02-21 11:16:23 +00:00
|
|
|
__attribute__((__unused__)) \
|
2019-07-09 23:47:48 +01:00
|
|
|
static void vector##_shrink_to_fit(struct vector *vector) \
|
|
|
|
{ \
|
2023-08-09 05:27:16 +01:00
|
|
|
size_t size = vector##_size(vector); \
|
|
|
|
if (vector->_capacity <= size) \
|
|
|
|
return; \
|
|
|
|
if (size > 0) { \
|
|
|
|
vector##_reallocate(vector, size); \
|
|
|
|
} else { \
|
|
|
|
free(vector->_data); \
|
|
|
|
vector->_data = NULL; \
|
|
|
|
vector->_capacity = 0; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
|
|
|
static void vector##_steal(struct vector *vector, \
|
|
|
|
vector##_entry_type **entries_ret, size_t *size_ret) \
|
|
|
|
{ \
|
|
|
|
*entries_ret = vector->_data; \
|
|
|
|
if (size_ret) \
|
|
|
|
*size_ret = vector->_size; \
|
|
|
|
vector->_data = NULL; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static vector##_entry_type *vector##_begin(struct vector *vector) \
|
|
|
|
{ \
|
|
|
|
return vector->_data; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
|
|
|
static vector##_entry_type *vector##_end(struct vector *vector) \
|
|
|
|
{ \
|
|
|
|
return add_to_possibly_null_pointer(vector##_begin(vector), \
|
|
|
|
vector##_size(vector)); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
|
|
|
static vector##_entry_type *vector##_first(struct vector *vector) \
|
|
|
|
{ \
|
|
|
|
return vector##_begin(vector); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
|
|
|
static vector##_entry_type *vector##_last(struct vector *vector) \
|
|
|
|
{ \
|
|
|
|
return vector##_begin(vector) + vector##_size(vector) - 1; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
|
|
|
static vector##_entry_type *vector##_at(struct vector *vector, size_t i) \
|
|
|
|
{ \
|
|
|
|
return vector##_begin(vector) + i; \
|
2019-07-09 23:47:48 +01:00
|
|
|
} \
|
|
|
|
\
|
|
|
|
static vector##_entry_type *vector##_append_entry(struct vector *vector) \
|
|
|
|
{ \
|
2023-08-09 05:27:16 +01:00
|
|
|
if (!vector##_reserve_for_append(vector)) \
|
2019-07-09 23:47:48 +01:00
|
|
|
return NULL; \
|
2023-08-09 05:27:16 +01:00
|
|
|
return vector##_begin(vector) + vector->_size++; \
|
2019-07-09 23:47:48 +01:00
|
|
|
} \
|
|
|
|
\
|
2021-02-21 11:16:23 +00:00
|
|
|
__attribute__((__unused__)) \
|
2019-07-09 23:47:48 +01:00
|
|
|
static bool vector##_append(struct vector *vector, \
|
|
|
|
const vector##_entry_type *entry) \
|
|
|
|
{ \
|
2023-08-09 05:27:16 +01:00
|
|
|
vector##_entry_type *new_entry = vector##_append_entry(vector); \
|
2019-07-09 23:47:48 +01:00
|
|
|
if (!new_entry) \
|
|
|
|
return false; \
|
|
|
|
memcpy(new_entry, entry, sizeof(*entry)); \
|
|
|
|
return true; \
|
|
|
|
} \
|
|
|
|
\
|
2021-02-21 11:16:23 +00:00
|
|
|
__attribute__((__unused__)) \
|
2023-08-09 05:27:16 +01:00
|
|
|
static bool vector##_extend(struct vector *dst, const struct vector *src) \
|
|
|
|
{ \
|
|
|
|
if (src->_size == 0) \
|
|
|
|
return true; \
|
|
|
|
if (!vector##_reserve_for_extend(dst, src->_size)) \
|
|
|
|
return false; \
|
|
|
|
memcpy(vector##_end(dst), vector##_begin((struct vector *)src), \
|
|
|
|
src->_size * sizeof(vector##_entry_type)); \
|
|
|
|
dst->_size += src->_size; \
|
|
|
|
return true; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
__attribute__((__unused__)) \
|
2019-07-09 23:47:48 +01:00
|
|
|
static vector##_entry_type *vector##_pop(struct vector *vector) \
|
|
|
|
{ \
|
2023-08-09 05:27:16 +01:00
|
|
|
return vector##_begin(vector) + --vector->_size; \
|
2023-08-02 22:54:59 +01:00
|
|
|
} \
|
|
|
|
struct DEFINE_VECTOR_needs_semicolon
|
2019-07-09 23:47:48 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Define a vector interface.
|
|
|
|
*
|
|
|
|
* This macro defines a vector type along with its functions.
|
|
|
|
*
|
|
|
|
* @param[in] vector Name of the type to define. This is prefixed to all of the
|
|
|
|
* types and functions defined for that type.
|
|
|
|
* @param[in] entry_type Type of entries in the vector.
|
|
|
|
*/
|
|
|
|
#define DEFINE_VECTOR(vector, entry_type) \
|
2023-08-02 22:54:59 +01:00
|
|
|
DEFINE_VECTOR_TYPE(vector, entry_type); \
|
2019-07-09 23:47:48 +01:00
|
|
|
DEFINE_VECTOR_FUNCTIONS(vector)
|
|
|
|
|
2020-07-01 20:37:16 +01:00
|
|
|
/**
|
|
|
|
* Empty vector initializer.
|
|
|
|
*
|
|
|
|
* This can be used to initialize a vector when declaring it.
|
|
|
|
*
|
|
|
|
* @sa vector_init()
|
|
|
|
*/
|
|
|
|
#define VECTOR_INIT { NULL }
|
|
|
|
|
2023-08-09 05:27:16 +01:00
|
|
|
/**
|
|
|
|
* Iterate over every entry in a @ref vector.
|
|
|
|
*
|
|
|
|
* This is roughly equivalent to
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* for (entry_type *it = vector_begin(vector), *end = vector_end(vector);
|
|
|
|
* it != end; it++)
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* Except that @p vector is only evaluated once.
|
|
|
|
*
|
|
|
|
* @param[in] vector_type Name of vector type.
|
|
|
|
* @param[out] it Name of iteration variable.
|
|
|
|
* @param[in] vector Vector to iterate over.
|
|
|
|
*/
|
|
|
|
#define vector_for_each(vector_type, it, vector) \
|
|
|
|
for (vector_type##_entry_type *it, \
|
|
|
|
*it##__end = ({ \
|
|
|
|
struct vector_type *it##__vector = (vector); \
|
|
|
|
it = vector_type##_begin(it##__vector); \
|
|
|
|
vector_type##_end(it##__vector); \
|
|
|
|
}); \
|
|
|
|
it != it##__end; it++)
|
|
|
|
|
2019-07-09 23:47:48 +01:00
|
|
|
/** @} */
|
|
|
|
|
|
|
|
#endif /* DRGN_VECTOR_H */
|