63#ifndef DYNAMIC_ARRAY_H
64#define DYNAMIC_ARRAY_H
78#define DA_MALLOC malloc
83#define DA_REALLOC realloc
93#define DA_ASSERT assert
100 #define DA_DEF extern
110#ifndef DA_ATOMIC_REFCOUNT
111#define DA_ATOMIC_REFCOUNT 0
117#if DA_ATOMIC_REFCOUNT && __STDC_VERSION__ < 201112L
118 #error "DA_ATOMIC_REFCOUNT requires C11 or later for atomic support (compile with -std=c11 or later)"
122#if DA_ATOMIC_REFCOUNT
123 #include <stdatomic.h>
124 #define DA_ATOMIC_INT _Atomic int
125 #define DA_ATOMIC_FETCH_ADD(ptr, val) atomic_fetch_add(ptr, val)
126 #define DA_ATOMIC_FETCH_SUB(ptr, val) atomic_fetch_sub(ptr, val)
127 #define DA_ATOMIC_LOAD(ptr) atomic_load(ptr)
128 #define DA_ATOMIC_STORE(ptr, val) atomic_store(ptr, val)
130 #define DA_ATOMIC_INT int
131 #define DA_ATOMIC_FETCH_ADD(ptr, val) (*(ptr) += (val), *(ptr) - (val))
132 #define DA_ATOMIC_FETCH_SUB(ptr, val) (*(ptr) -= (val), *(ptr) + (val))
133 #define DA_ATOMIC_LOAD(ptr) (*(ptr))
134 #define DA_ATOMIC_STORE(ptr, val) (*(ptr) = (val))
138#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L && !defined(__STDC_NO_TYPEOF__)
139 #define DA_TYPEOF(x) typeof(x)
140 #define DA_HAS_TYPEOF 1
141#elif defined(__cplusplus) && __cplusplus >= 201103L
142 #define DA_TYPEOF(x) decltype(x)
143 #define DA_HAS_TYPEOF 1
144#elif (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
145 #define DA_TYPEOF(x) typeof(x)
146 #define DA_HAS_TYPEOF 1
148 #define DA_HAS_TYPEOF 0
151#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
153 #define DA_HAS_AUTO 1
154#elif defined(__cplusplus) && __cplusplus >= 201103L
156 #define DA_HAS_AUTO 1
157#elif (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
158 #define DA_AUTO __auto_type
159 #define DA_HAS_AUTO 1
161 #define DA_HAS_AUTO 0
164#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
165 #define DA_GENERIC(x, ...) _Generic((x), __VA_ARGS__)
166 #define DA_HAS_GENERIC 1
168 #define DA_HAS_GENERIC 0
172 #define DA_SUPPORT_TYPE_INFERENCE 1
173 #define DA_MAKE_VAR_WITH_INFERRED_TYPE(name, initializer) DA_AUTO (name) = (initializer);
175 #define DA_SUPPORT_TYPE_INFERENCE 1
176 #define DA_MAKE_VAR_WITH_INFERRED_TYPE(name, initializer) DA_TYPEOF(initializer) (name) = (initializer);
178 #define DA_SUPPORT_TYPE_INFERENCE 0
198 void (*retain_fn)(
void*);
199 void (*release_fn)(
void*);
260DA_DEF
da_array da_create(
int element_size,
int initial_capacity,
void (*retain_fn)(
void*),
void (*release_fn)(
void*));
700DA_DEF
da_array da_map(
da_array arr,
void (*mapper)(
const void* src,
void* dst,
void* context),
void* context);
726 void (*reducer)(
void* accumulator,
const void* element,
void* context),
void* context);
802DA_DEF
int da_find_index(
da_array arr,
int (*predicate)(
const void* element,
void* context),
void* context);
822DA_DEF
int da_contains(
da_array arr,
int (*predicate)(
const void* element,
void* context),
void* context);
844DA_DEF
void da_sort(
da_array arr,
int (*compare)(
const void* a,
const void* b,
void* context),
void* context);
1244#define DA_NEW(T) da_new(sizeof(T))
1245#define DA_CREATE(T, cap, retain_fn, release_fn) da_create(sizeof(T), cap, retain_fn, release_fn)
1247#define DA_PUSH_TYPED(arr, val, T) do { T _temp = (val); da_push(arr, (void*)&_temp); } while(0)
1248#define DA_PUT_TYPED(arr, i, val, T) do { T _temp = (val); da_set(arr, i, (void*)&_temp); } while(0)
1249#define DA_INSERT_TYPED(arr, i, val, T) do { T _temp = (val); da_insert(arr, i, (void*)&_temp); } while(0)
1251#if DA_SUPPORT_TYPE_INFERENCE
1252 #define DA_PUSH_INFERRED(arr, val) do { DA_MAKE_VAR_WITH_INFERRED_TYPE(_temp, val); da_push(arr, (void*)&_temp); } while(0)
1253 #define DA_PUT_INFERRED(arr, i, val) do { DA_MAKE_VAR_WITH_INFERRED_TYPE(_temp, val); da_set(arr, i, (void*)&_temp); } while(0)
1254 #define DA_INSERT_INFERRED(arr, i, val) do { DA_MAKE_VAR_WITH_INFERRED_TYPE(_temp, val); da_insert(arr, i, (void*)&_temp); } while(0)
1257#if DA_SUPPORT_TYPE_INFERENCE && !defined(DA_NOT_USE_TYPE_GENERIC)
1258 #define DA_PUSH(arr, val) DA_PUSH_INFERRED(arr, val)
1259 #define DA_PUT(arr, i, val) DA_PUT_INFERRED(arr, i, val)
1260 #define DA_INSERT(arr, i, val) DA_INSERT_INFERRED(arr, i, val)
1262 #define DA_PUSH(arr, val, T) DA_PUSH_TYPED(arr, val, T)
1263 #define DA_PUT(arr, i, val, T) DA_PUT_TYPED(arr, i, val, T)
1264 #define DA_INSERT(arr, i, val, T) DA_INSERT_TYPED(arr, i, val, T)
1267#define DA_LENGTH(arr) da_length(arr)
1268#define DA_CAPACITY(arr) da_capacity(arr)
1269#define DA_AT(arr, i, T) (*(T*)da_get(arr, i))
1270#define DA_POP(arr, out_ptr) da_pop(arr, out_ptr)
1271#define DA_REMOVE(arr, i, out_ptr) da_remove(arr, i, out_ptr)
1272#define DA_CLEAR(arr) da_clear(arr)
1273#define DA_RESERVE(arr, cap) da_reserve(arr, cap)
1274#define DA_RESIZE(arr, len) da_resize(arr, len)
1275#define DA_TRIM(arr, cap) da_trim(arr, cap)
1276#define DA_SHRINK_TO_FIT(arr) da_trim(arr, da_length(arr))
1277#define DA_PEEK(arr, T) (*(T*)da_peek(arr))
1278#define DA_PEEK_FIRST(arr, T) (*(T*)da_peek_first(arr))
1423#define DA_BUILDER_CREATE(T) da_builder_create(sizeof(T))
1425#define DA_BUILDER_APPEND_TYPED(builder, val, T) do { T _temp = (val); da_builder_append(builder, (void*)&_temp); } while(0)
1426#define DA_BUILDER_PUT_TYPED(builder, i, val, T) do { T _temp = (val); da_builder_set(builder, i, (void*)&_temp); } while(0)
1428#if DA_SUPPORT_TYPE_INFERENCE
1429 #define DA_BUILDER_APPEND_INFERRED(builder, val) \
1430 do { DA_MAKE_VAR_WITH_INFERRED_TYPE(_temp, val); da_builder_append(builder, (void*)&_temp); } while(0)
1431 #define DA_BUILDER_PUT_INFERRED(builder, i, val) \
1432 do { DA_MAKE_VAR_WITH_INFERRED_TYPE(_temp, val); da_builder_set(builder, i, (void*)&_temp); } while(0)
1435#if DA_SUPPORT_TYPE_INFERENCE && !defined(DA_NOT_USE_TYPE_GENERIC)
1436 #define DA_BUILDER_APPEND(builder, val) DA_BUILDER_APPEND_INFERRED(builder, val)
1437 #define DA_BUILDER_PUT(builder, i, val) DA_BUILDER_PUT_INFERRED(builder, i, val)
1439 #define DA_BUILDER_APPEND(builder, val, T) DA_BUILDER_APPEND_TYPED(builder, val, T)
1440 #define DA_BUILDER_PUT(builder, i, val, T) DA_BUILDER_PUT_TYPED(builder, i, val, T)
1445#define DA_BUILDER_LEN(builder) da_builder_length(builder)
1446#define DA_BUILDER_CAP(builder) da_builder_capacity(builder)
1447#define DA_BUILDER_AT(builder, i, T) (*(T*)da_builder_get(builder, i))
1448#define DA_BUILDER_CLEAR(builder) da_builder_clear(builder)
1449#define DA_BUILDER_TO_ARRAY(builder) da_builder_to_array(builder, NULL, NULL)
1450#define DA_BUILDER_TO_ARRAY_MANAGED(builder, retain_fn, release_fn) da_builder_to_array(builder, retain_fn, release_fn)
1453#ifdef DA_IMPLEMENTATION
1455static int da_grow_capacity(
int current_capacity,
int min_needed) {
1456 int new_capacity = current_capacity;
1460 while (new_capacity < min_needed) {
1461 new_capacity += DA_GROWTH;
1465 if (new_capacity == 0) new_capacity = 1;
1466 while (new_capacity < min_needed) {
1471 return new_capacity;
1474static int da_builder_grow_capacity(
int current_capacity,
int min_needed) {
1476 int new_capacity = current_capacity;
1477 if (new_capacity == 0) new_capacity = 1;
1478 while (new_capacity < min_needed) {
1481 return new_capacity;
1503DA_DEF
da_array da_create(
int element_size,
int initial_capacity,
void (*retain_fn)(
void*),
void (*release_fn)(
void*)) {
1517 if (initial_capacity > 0) {
1531 int old_count = DA_ATOMIC_FETCH_SUB(&(*arr)->ref_count, 1);
1533 if (old_count == 1) {
1534 if ((*arr)->data && (*arr)->release_fn) {
1536 for (
int i = 0; i < (*arr)->length; i++) {
1537 void* element_ptr = (
char*)(*arr)->data + (i * (*arr)->element_size);
1538 (*arr)->release_fn(element_ptr);
1552 DA_ATOMIC_FETCH_ADD(&arr->
ref_count, 1);
1558 DA_ASSERT(index >= 0 && index < arr->length);
1570 DA_ASSERT(index >= 0 && index < arr->length);
1592 int new_capacity = da_grow_capacity(arr->
capacity, arr->
length + 1);
1612 DA_ASSERT(index >= 0 && index <= arr->length);
1616 int new_capacity = da_grow_capacity(arr->
capacity, arr->
length + 1);
1623 if (index < arr->length) {
1627 memmove(dest, src, bytes_to_move);
1644 DA_ASSERT(index >= 0 && index < arr->length);
1659 if (index < arr->length - 1) {
1663 memmove(dest, src, bytes_to_move);
1691 for (
int i = 0; i < arr->
length; i++) {
1714 if (new_capacity > arr->
capacity) {
1729 if (new_length < arr->length) {
1732 for (
int i = new_length; i < arr->
length; i++) {
1737 }
else if (new_length > arr->
length) {
1741 memset(start, 0, bytes_to_zero);
1744 arr->
length = new_length;
1751 if (new_capacity < arr->capacity) {
1752 if (new_capacity == 0) {
1770 if (src->
length == 0)
return;
1775 int new_capacity = da_grow_capacity(dest->
capacity, new_length);
1787 for (
int i = dest->
length; i < new_length; i++) {
1793 dest->
length = new_length;
1808 result->
length = total_length;
1814 if (total_length > 0) {
1831 for (
int i = 0; i < result->
length; i++) {
1837 result->
data = NULL;
1854 builder->
data = NULL;
1864 int new_capacity = da_builder_grow_capacity(builder->
capacity, builder->
length + 1);
1879 if (new_capacity > builder->
capacity) {
1891 if (arr->
length == 0)
return;
1895 if (new_length > builder->
capacity) {
1896 int new_capacity = da_builder_grow_capacity(builder->
capacity, new_length);
1905 builder->
length = new_length;
1932 for (
int i = 0; i < arr->
length; i++) {
1960 if ((*builder)->data) {
1979 DA_ASSERT(index >= 0 && index < builder->length);
1986 DA_ASSERT(index >= 0 && index < builder->length);
2011 if (count == 0)
return;
2014 int new_length = arr->
length + count;
2016 int new_capacity = da_grow_capacity(arr->
capacity, new_length);
2028 for (
int i = arr->
length; i < new_length; i++) {
2034 arr->
length = new_length;
2042 if (count == 0)
return;
2045 int new_length = arr->
length + count;
2047 int new_capacity = da_grow_capacity(arr->
capacity, new_length);
2054 for (
int i = 0; i < count; i++) {
2058 arr->
length = new_length;
2063 DA_ASSERT(start >= 0 && start <= arr->length);
2064 DA_ASSERT(end >= start && end <= arr->length);
2066 int slice_length = end - start;
2073 result->
length = slice_length;
2079 if (slice_length > 0) {
2089 for (
int i = 0; i < result->
length; i++) {
2095 result->
data = NULL;
2103 DA_ASSERT(start >= 0 && start < arr->length);
2105 DA_ASSERT(start + count <= arr->length);
2107 if (count == 0)
return;
2109 int end = start + count;
2113 for (
int i = start; i < end; i++) {
2120 if (end < arr->length) {
2124 memmove(dest, src, bytes_to_move);
2133 if (arr->
length <= 1)
return;
2139 for (
int i = 0; i < arr->
length / 2; i++) {
2140 int j = arr->
length - 1 - i;
2198 for (
int i = 0; i < result->
length; i++) {
2204 result->
data = NULL;
2218 for (
int i = 0; i < arr->
length; i++) {
2220 if (predicate(element_ptr, context)) {
2250 for (
int i = 0; i < arr->
length; i++) {
2253 mapper(src_ptr, dst_ptr, context);
2256 result->
data = NULL;
2263 void (*reducer)(
void* accumulator,
const void* element,
void* context),
void* context) {
2273 for (
int i = 0; i < arr->
length; i++) {
2275 reducer(result, element_ptr, context);
2288 for (
int i = 0; i < arr->
length; i++) {
2290 if (predicate(element_ptr, context)) {
2304 int (*compare)(
const void* a,
const void* b,
void* context);
2312static int da_sort_compare_wrapper(
const void* a,
const void* b) {
2314 return ctx->compare(a, b, ctx->user_context);
2317DA_DEF
void da_sort(
da_array arr,
int (*compare)(
const void* a,
const void* b,
void* context),
void* context) {
2327 da_sort_global_context = &sort_ctx;
2333 da_sort_global_context = NULL;
#define DA_ATOMIC_INT
Enable atomic reference counting (default: 0)
Definition dynamic_array.h:124
DA_DEF void * da_get(da_array arr, int index)
Gets a pointer to an element at the specified index.
Definition dynamic_array.h:1556
DA_DEF void * da_data(da_array arr)
Gets direct pointer to the underlying data array.
Definition dynamic_array.h:1562
DA_DEF void da_set(da_array arr, int index, const void *element)
Sets the value of an element at the specified index.
Definition dynamic_array.h:1567
DA_DEF da_array da_create(int element_size, int initial_capacity, void(*retain_fn)(void *), void(*release_fn)(void *))
Creates a new dynamic array with full configuration.
Definition dynamic_array.h:1503
DA_DEF void da_release(da_array *arr)
Releases a reference to an array, potentially freeing it.
Definition dynamic_array.h:1527
DA_DEF da_array da_new(int element_size)
Creates a new dynamic array (simple version for general use)
Definition dynamic_array.h:1486
DA_DEF da_array da_retain(da_array arr)
Increments reference count for sharing an array.
Definition dynamic_array.h:1550
DA_DEF void da_remove(da_array arr, int index, void *out)
Removes and optionally returns an element at the specified index.
Definition dynamic_array.h:1642
DA_DEF void * da_peek(da_array arr)
Gets a pointer to the last element without removing it.
Definition dynamic_array.h:1994
DA_DEF void * da_peek_first(da_array arr)
Gets a pointer to the first element without removing it.
Definition dynamic_array.h:2000
DA_DEF void da_insert(da_array arr, int index, const void *element)
Inserts an element at the specified index.
Definition dynamic_array.h:1609
DA_DEF void da_clear(da_array arr)
Removes all elements from the array.
Definition dynamic_array.h:1686
DA_DEF void da_push(da_array arr, const void *element)
Appends an element to the end of the array.
Definition dynamic_array.h:1587
DA_DEF void da_pop(da_array arr, void *out)
Removes and optionally returns the last element.
Definition dynamic_array.h:1669
DA_DEF da_array da_slice(da_array arr, int start, int end)
Creates a new array containing elements from a range [start, end)
Definition dynamic_array.h:2061
DA_DEF void da_reduce(da_array arr, const void *initial, void *result, void(*reducer)(void *accumulator, const void *element, void *context), void *context)
Reduces array to single value using accumulator function.
Definition dynamic_array.h:2262
DA_DEF int da_contains(da_array arr, int(*predicate)(const void *element, void *context), void *context)
Check if array contains element matching predicate.
Definition dynamic_array.h:2298
DA_DEF void da_reserve(da_array arr, int new_capacity)
Ensures the array has at least the specified capacity.
Definition dynamic_array.h:1710
DA_DEF void da_remove_range(da_array arr, int start, int count)
Removes multiple consecutive elements from the array.
Definition dynamic_array.h:2101
DA_DEF da_array da_filter(da_array arr, int(*predicate)(const void *element, void *context), void *context)
Creates a new array containing elements that pass a predicate test.
Definition dynamic_array.h:2210
DA_DEF da_array da_copy(da_array arr)
Creates a complete copy of an existing array.
Definition dynamic_array.h:2175
DA_DEF da_array da_concat(da_array arr1, da_array arr2)
Creates a new array by concatenating two arrays.
Definition dynamic_array.h:1796
DA_DEF int da_capacity(da_array arr)
Gets the current allocated capacity of the array.
Definition dynamic_array.h:1705
DA_DEF void da_sort(da_array arr, int(*compare)(const void *a, const void *b, void *context), void *context)
Sort array elements using comparison function.
Definition dynamic_array.h:2317
DA_DEF da_array da_map(da_array arr, void(*mapper)(const void *src, void *dst, void *context), void *context)
Creates a new array by transforming each element using a mapper function.
Definition dynamic_array.h:2230
DA_DEF void da_append_raw(da_array arr, const void *data, int count)
Appends raw C array data to the dynamic array.
Definition dynamic_array.h:2006
DA_DEF int da_find_index(da_array arr, int(*predicate)(const void *element, void *context), void *context)
Find index of first element matching predicate.
Definition dynamic_array.h:2284
DA_DEF void da_reverse(da_array arr)
Reverses all elements in the array in place.
Definition dynamic_array.h:2130
DA_DEF int da_is_empty(da_array arr)
Checks if the array is empty.
Definition dynamic_array.h:2279
DA_DEF void da_resize(da_array arr, int new_length)
Changes the array length, growing or shrinking as needed.
Definition dynamic_array.h:1721
DA_DEF void da_fill(da_array arr, const void *element, int count)
Fills the array with multiple copies of an element.
Definition dynamic_array.h:2037
DA_DEF int da_length(da_array arr)
Gets the current number of elements in the array.
Definition dynamic_array.h:1700
DA_DEF void da_append_array(da_array dest, da_array src)
Appends all elements from source array to destination array.
Definition dynamic_array.h:1765
DA_DEF void da_trim(da_array arr, int new_capacity)
Reduces the array's allocated capacity to a specific size.
Definition dynamic_array.h:1747
DA_DEF void da_swap(da_array arr, int i, int j)
Swaps two elements at the specified indices.
Definition dynamic_array.h:2154
DA_DEF void da_builder_clear(da_builder builder)
Removes all elements from the builder.
Definition dynamic_array.h:1951
DA_DEF da_array da_builder_to_array(da_builder *builder, void(*retain_fn)(void *), void(*release_fn)(void *))
Converts builder to a ref-counted array with exact capacity.
Definition dynamic_array.h:1908
DA_DEF void da_builder_destroy(da_builder *builder)
Destroys a builder and frees its memory.
Definition dynamic_array.h:1956
DA_DEF da_builder da_builder_create(int element_size)
Creates a new array builder for efficient construction.
Definition dynamic_array.h:1845
DA_DEF void da_builder_append_array(da_builder builder, da_array arr)
Appends all elements from an array to the builder.
Definition dynamic_array.h:1886
DA_DEF void da_builder_append(da_builder builder, const void *element)
Appends an element to the builder.
Definition dynamic_array.h:1859
DA_DEF void da_builder_reserve(da_builder builder, int new_capacity)
Ensures the builder has at least the specified capacity.
Definition dynamic_array.h:1875
DA_DEF int da_builder_capacity(da_builder builder)
Gets the current allocated capacity of the builder.
Definition dynamic_array.h:1972
DA_DEF void da_builder_set(da_builder builder, int index, const void *element)
Sets the value of an element at the specified index.
Definition dynamic_array.h:1983
DA_DEF void * da_builder_get(da_builder builder, int index)
Gets a pointer to an element at the specified index.
Definition dynamic_array.h:1977
DA_DEF int da_builder_length(da_builder builder)
Gets the current number of elements in the builder.
Definition dynamic_array.h:1967
#define DA_REALLOC
Custom memory reallocator (default: realloc)
Definition dynamic_array.h:83
#define DA_MALLOC
Custom memory allocator (default: malloc)
Definition dynamic_array.h:78
#define DA_FREE
Custom memory deallocator (default: free)
Definition dynamic_array.h:88
#define DA_ASSERT
Custom assertion macro (default: assert)
Definition dynamic_array.h:93
Reference-counted dynamic array structure.
Definition dynamic_array.h:192
void * data
Pointer to element data.
Definition dynamic_array.h:197
int element_size
Size of each element in bytes.
Definition dynamic_array.h:196
void(* release_fn)(void *)
Optional release function called when elements removed (NULL if not needed)
Definition dynamic_array.h:199
int capacity
Allocated capacity.
Definition dynamic_array.h:195
int length
Current number of elements.
Definition dynamic_array.h:194
DA_ATOMIC_INT ref_count
Reference count (atomic if DA_ATOMIC_REFCOUNT=1)
Definition dynamic_array.h:193
void(* retain_fn)(void *)
Optional retain function called when elements added (NULL if not needed)
Definition dynamic_array.h:198
ArrayBuffer-style builder for efficient array construction.
Definition dynamic_array.h:208
int length
Current number of elements.
Definition dynamic_array.h:209
int element_size
Size of each element in bytes.
Definition dynamic_array.h:211
void * data
Pointer to element data.
Definition dynamic_array.h:212
int capacity
Allocated capacity.
Definition dynamic_array.h:210
Definition dynamic_array.h:2303