1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
/* Copyright (C) CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
/*!
* \brief Simple write-once allocation-optimal dynamic array.
*
* Include it into your .c file
*
* prefix - identifier prefix, e.g. ptr -> struct ptr_dynarray, ptr_dynarray_add(), ...
* ntype - data type to be stored. Let it be a number, pointer or small struct
* initial_capacity - how many data items will be allocated on stack and copied with assignment
*
* prefix_dynarray_add() - add a data item
* prefix_dynarray_fix() - call EVERYTIME the array is copied from some already invalid stack
* prefix_dynarray_free() - call EVERYTIME you dismiss all copies of the array
*
*/
#include <stdlib.h>
#include <assert.h>
#pragma once
#define DYNARRAY_VISIBILITY_STATIC static
#define DYNARRAY_VISIBILITY_PUBLIC
#define DYNARRAY_VISIBILITY_LIBRARY __public__
#define dynarray_declare(prefix, ntype, visibility, initial_capacity) \
typedef struct prefix ## _dynarray { \
ssize_t capacity; \
ssize_t size; \
ntype *(*arr)(struct prefix ## _dynarray *dynarray); \
ntype init[initial_capacity]; \
ntype *_arr; \
} prefix ## _dynarray_t; \
\
visibility ntype *prefix ## _dynarray_arr(prefix ## _dynarray_t *dynarray); \
visibility void prefix ## _dynarray_add(prefix ## _dynarray_t *dynarray, \
ntype const *to_add); \
visibility void prefix ## _dynarray_free(prefix ## _dynarray_t *dynarray);
#define dynarray_foreach(prefix, ntype, ptr, array) \
for (ntype *ptr = prefix ## _dynarray_arr(&(array)); \
ptr < prefix ## _dynarray_arr(&(array)) + (array).size; ptr++)
#define dynarray_define(prefix, ntype, visibility) \
\
static void prefix ## _dynarray_free__(struct prefix ## _dynarray *dynarray) \
{ \
if (dynarray->capacity > sizeof(dynarray->init) / sizeof(*dynarray->init)) { \
free(dynarray->_arr); \
} \
} \
\
__attribute__((unused)) \
visibility ntype *prefix ## _dynarray_arr(struct prefix ## _dynarray *dynarray) \
{ \
assert(dynarray->size <= dynarray->capacity); \
return (dynarray->capacity <= sizeof(dynarray->init) / sizeof(*dynarray->init) ? \
dynarray->init : dynarray->_arr); \
} \
\
static ntype *prefix ## _dynarray_arr_init__(struct prefix ## _dynarray *dynarray) \
{ \
assert(dynarray->capacity == sizeof(dynarray->init) / sizeof(*dynarray->init)); \
return dynarray->init; \
} \
\
static ntype *prefix ## _dynarray_arr_arr__(struct prefix ## _dynarray *dynarray) \
{ \
assert(dynarray->capacity > sizeof(dynarray->init) / sizeof(*dynarray->init)); \
return dynarray->_arr; \
} \
\
__attribute__((unused)) \
visibility void prefix ## _dynarray_add(struct prefix ## _dynarray *dynarray, \
ntype const *to_add) \
{ \
if (dynarray->capacity < 0) { \
return; \
} \
if (dynarray->capacity == 0) { \
dynarray->capacity = sizeof(dynarray->init) / sizeof(*dynarray->init); \
dynarray->arr = prefix ## _dynarray_arr_init__; \
} \
if (dynarray->size >= dynarray->capacity) { \
ssize_t new_capacity = dynarray->capacity * 2 + 1; \
ntype *new_arr = calloc(new_capacity, sizeof(ntype)); \
if (new_arr == NULL) { \
prefix ## _dynarray_free__(dynarray); \
dynarray->capacity = dynarray->size = -1; \
return; \
} \
if (dynarray->capacity > 0) { \
memcpy(new_arr, prefix ## _dynarray_arr(dynarray), \
dynarray->capacity * sizeof(ntype)); \
} \
prefix ## _dynarray_free__(dynarray); \
dynarray->_arr = new_arr; \
dynarray->capacity = new_capacity; \
dynarray->arr = prefix ## _dynarray_arr_arr__; \
} \
prefix ## _dynarray_arr(dynarray)[dynarray->size++] = *to_add; \
} \
\
__attribute__((unused)) \
visibility void prefix ## _dynarray_free(struct prefix ## _dynarray *dynarray) \
{ \
prefix ## _dynarray_free__(dynarray); \
memset(dynarray, 0, sizeof(*dynarray)); \
}
|