dynamic_array.h v0.3.1
Reference-counted dynamic arrays for C
Loading...
Searching...
No Matches
dynamic_array.h
Go to the documentation of this file.
1
63#ifndef DYNAMIC_ARRAY_H
64#define DYNAMIC_ARRAY_H
65
66#include <stdlib.h>
67#include <string.h>
68#include <assert.h>
69
77#ifndef DA_MALLOC
78#define DA_MALLOC malloc
79#endif
80
82#ifndef DA_REALLOC
83#define DA_REALLOC realloc
84#endif
85
87#ifndef DA_FREE
88#define DA_FREE free
89#endif
90
92#ifndef DA_ASSERT
93#define DA_ASSERT assert
94#endif
95
96#ifndef DA_DEF
97 #ifdef DA_STATIC
98 #define DA_DEF static
99 #else
100 #define DA_DEF extern
101 #endif
102#endif
103
110#ifndef DA_ATOMIC_REFCOUNT
111#define DA_ATOMIC_REFCOUNT 0
112#endif
113
// end of config group
115
116/* Check C11 support for atomic operations */
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)"
119#endif
120
121/* atomic operations */
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)
129#else
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))
135#endif
136
137/* Detect C23/C++11 auto support (preferred) or typeof fallback */
138#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L && !defined(__STDC_NO_TYPEOF__)
139 #define DA_TYPEOF(x) typeof(x) /* the C23 typeof keyword */
140 #define DA_HAS_TYPEOF 1
141#elif defined(__cplusplus) && __cplusplus >= 201103L
142 #define DA_TYPEOF(x) decltype(x) /* the C++ decltype keyword */
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
147#else
148 #define DA_HAS_TYPEOF 0
149#endif
150
151#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
152 #define DA_AUTO auto /* the C23 auto keyword */
153 #define DA_HAS_AUTO 1
154#elif defined(__cplusplus) && __cplusplus >= 201103L
155 #define DA_AUTO auto /* the C++ auto keyword */
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
160#else
161 #define DA_HAS_AUTO 0
162#endif
163
164#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
165 #define DA_GENERIC(x, ...) _Generic((x), __VA_ARGS__)
166 #define DA_HAS_GENERIC 1
167#else
168 #define DA_HAS_GENERIC 0
169#endif
170
171#if DA_HAS_AUTO
172 #define DA_SUPPORT_TYPE_INFERENCE 1
173 #define DA_MAKE_VAR_WITH_INFERRED_TYPE(name, initializer) DA_AUTO (name) = (initializer);
174#elif DA_HAS_TYPEOF
175 #define DA_SUPPORT_TYPE_INFERENCE 1
176 #define DA_MAKE_VAR_WITH_INFERRED_TYPE(name, initializer) DA_TYPEOF(initializer) (name) = (initializer);
177#else
178 #define DA_SUPPORT_TYPE_INFERENCE 0
179#endif
180
192typedef struct {
194 int length;
197 void *data;
198 void (*retain_fn)(void*);
199 void (*release_fn)(void*);
201
208typedef struct {
209 int length;
212 void *data;
214
// end of types group
216
238DA_DEF da_array da_new(int element_size);
239
260DA_DEF da_array da_create(int element_size, int initial_capacity, void (*retain_fn)(void*), void (*release_fn)(void*));
261
275DA_DEF void da_release(da_array* arr);
276
290DA_DEF da_array da_retain(da_array arr);
291
// end of array_lifecycle group
293
313DA_DEF void* da_get(da_array arr, int index);
314
329DA_DEF void* da_data(da_array arr);
330
344DA_DEF void da_set(da_array arr, int index, const void* element);
345
// end of array_access group
347
367DA_DEF void da_push(da_array arr, const void* element);
368
385DA_DEF void da_insert(da_array arr, int index, const void* element);
386
402DA_DEF void da_remove(da_array arr, int index, void* out);
403
418DA_DEF void da_pop(da_array arr, void* out);
419
431DA_DEF void da_clear(da_array arr);
432
446DA_DEF void* da_peek(da_array arr);
447
461DA_DEF void* da_peek_first(da_array arr);
462
// end of array_modification group
464
482DA_DEF int da_length(da_array arr);
483
493DA_DEF int da_capacity(da_array arr);
494
510DA_DEF void da_reserve(da_array arr, int new_capacity);
511
527DA_DEF void da_resize(da_array arr, int new_length);
528
544DA_DEF void da_trim(da_array arr, int new_capacity);
545
561DA_DEF void da_append_array(da_array dest, da_array src);
562
581DA_DEF da_array da_concat(da_array arr1, da_array arr2);
582
597DA_DEF void da_append_raw(da_array arr, const void* data, int count);
598
613DA_DEF void da_fill(da_array arr, const void* element, int count);
614
631DA_DEF da_array da_slice(da_array arr, int start, int end);
632
650DA_DEF da_array da_copy(da_array arr);
651
675DA_DEF da_array da_filter(da_array arr, int (*predicate)(const void* element, void* context), void* context);
676
700DA_DEF da_array da_map(da_array arr, void (*mapper)(const void* src, void* dst, void* context), void* context);
701
725DA_DEF void da_reduce(da_array arr, const void* initial, void* result,
726 void (*reducer)(void* accumulator, const void* element, void* context), void* context);
727
742DA_DEF void da_remove_range(da_array arr, int start, int count);
743
755DA_DEF void da_reverse(da_array arr);
756
769DA_DEF void da_swap(da_array arr, int i, int j);
770
783DA_DEF int da_is_empty(da_array arr);
784
802DA_DEF int da_find_index(da_array arr, int (*predicate)(const void* element, void* context), void* context);
803
822DA_DEF int da_contains(da_array arr, int (*predicate)(const void* element, void* context), void* context);
823
844DA_DEF void da_sort(da_array arr, int (*compare)(const void* a, const void* b, void* context), void* context);
845
// end of array_utility group
847
869DA_DEF da_builder da_builder_create(int element_size);
870
890DA_DEF da_array da_builder_to_array(da_builder* builder, void (*retain_fn)(void*), void (*release_fn)(void*));
891
903DA_DEF void da_builder_clear(da_builder builder);
904
917DA_DEF void da_builder_destroy(da_builder* builder);
918
// end of builder_lifecycle group
920
941DA_DEF void da_builder_append(da_builder builder, const void* element);
942
960DA_DEF void da_builder_reserve(da_builder builder, int new_capacity);
961
978DA_DEF void da_builder_append_array(da_builder builder, da_array arr);
979
// end of builder_modification group
981
993DA_DEF int da_builder_length(da_builder builder);
994
1000DA_DEF int da_builder_capacity(da_builder builder);
1001
1009DA_DEF void* da_builder_get(da_builder builder, int index);
1010
1018DA_DEF void da_builder_set(da_builder builder, int index, const void* element);
1019
// end of builder_utility group
1021
// end of array_macros group
1243
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)
1246
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)
1250
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)
1255#endif
1256
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)
1261#else
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)
1265#endif
1266
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))
1279
1423#define DA_BUILDER_CREATE(T) da_builder_create(sizeof(T))
1424
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)
1427
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)
1433#endif
1434
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)
1438#else
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)
1441#endif
// end of builder_macros group
1443
1444
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)
1451
1452/* Implementation */
1453#ifdef DA_IMPLEMENTATION
1454
1455static int da_grow_capacity(int current_capacity, int min_needed) {
1456 int new_capacity = current_capacity;
1457
1458#ifdef DA_GROWTH
1459 /* Fixed growth strategy */
1460 while (new_capacity < min_needed) {
1461 new_capacity += DA_GROWTH;
1462 }
1463#else
1464 /* Doubling strategy */
1465 if (new_capacity == 0) new_capacity = 1;
1466 while (new_capacity < min_needed) {
1467 new_capacity *= 2;
1468 }
1469#endif
1470
1471 return new_capacity;
1472}
1473
1474static int da_builder_grow_capacity(int current_capacity, int min_needed) {
1475 /* Builders always use doubling strategy for fast construction */
1476 int new_capacity = current_capacity;
1477 if (new_capacity == 0) new_capacity = 1;
1478 while (new_capacity < min_needed) {
1479 new_capacity *= 2;
1480 }
1481 return new_capacity;
1482}
1483
1484/* Array Implementation */
1485
1486DA_DEF da_array da_new(int element_size) {
1487 DA_ASSERT(element_size > 0);
1488
1489 da_array arr = (da_array)DA_MALLOC(sizeof(da_array_t));
1490 DA_ASSERT(arr != NULL);
1491
1492 DA_ATOMIC_STORE(&arr->ref_count, 1);
1493 arr->length = 0;
1494 arr->capacity = 0; /* Deferred allocation */
1495 arr->element_size = element_size;
1496 arr->retain_fn = NULL;
1497 arr->release_fn = NULL;
1498 arr->data = NULL;
1499
1500 return arr;
1501}
1502
1503DA_DEF da_array da_create(int element_size, int initial_capacity, void (*retain_fn)(void*), void (*release_fn)(void*)) {
1504 DA_ASSERT(element_size > 0);
1505 DA_ASSERT(initial_capacity >= 0);
1506
1507 da_array arr = (da_array)DA_MALLOC(sizeof(da_array_t));
1508 DA_ASSERT(arr != NULL);
1509
1510 DA_ATOMIC_STORE(&arr->ref_count, 1);
1511 arr->length = 0;
1512 arr->capacity = initial_capacity;
1513 arr->element_size = element_size;
1514 arr->retain_fn = retain_fn;
1515 arr->release_fn = release_fn;
1516
1517 if (initial_capacity > 0) {
1518 arr->data = DA_MALLOC(initial_capacity * element_size);
1519 DA_ASSERT(arr->data != NULL);
1520 } else {
1521 arr->data = NULL;
1522 }
1523
1524 return arr;
1525}
1526
1527DA_DEF void da_release(da_array* arr) {
1528 DA_ASSERT(arr != NULL);
1529 DA_ASSERT(*arr != NULL);
1530
1531 int old_count = DA_ATOMIC_FETCH_SUB(&(*arr)->ref_count, 1);
1532
1533 if (old_count == 1) { /* We were the last reference */
1534 if ((*arr)->data && (*arr)->release_fn) {
1535 /* Call release function on each element before freeing */
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);
1539 }
1540 }
1541 if ((*arr)->data) {
1542 DA_FREE((*arr)->data);
1543 }
1544 DA_FREE(*arr);
1545 }
1546
1547 *arr = NULL; /* Always NULL the pointer for safety */
1548}
1549
1551 DA_ASSERT(arr != NULL);
1552 DA_ATOMIC_FETCH_ADD(&arr->ref_count, 1);
1553 return arr;
1554}
1555
1556DA_DEF void* da_get(da_array arr, int index) {
1557 DA_ASSERT(arr != NULL);
1558 DA_ASSERT(index >= 0 && index < arr->length);
1559 return (char*)arr->data + (index * arr->element_size);
1560}
1561
1562DA_DEF void* da_data(da_array arr) {
1563 DA_ASSERT(arr != NULL);
1564 return arr->data;
1565}
1566
1567DA_DEF void da_set(da_array arr, int index, const void* element) {
1568 DA_ASSERT(arr != NULL);
1569 DA_ASSERT(element != NULL);
1570 DA_ASSERT(index >= 0 && index < arr->length);
1571
1572 void* dest = (char*)arr->data + (index * arr->element_size);
1573
1574 /* Call release function on the old element before overwriting */
1575 if (arr->release_fn) {
1576 arr->release_fn(dest);
1577 }
1578
1579 memcpy(dest, element, arr->element_size);
1580
1581 /* Call retain function on the newly set element */
1582 if (arr->retain_fn) {
1583 arr->retain_fn(dest);
1584 }
1585}
1586
1587DA_DEF void da_push(da_array arr, const void* element) {
1588 DA_ASSERT(arr != NULL);
1589 DA_ASSERT(element != NULL);
1590
1591 if (arr->length >= arr->capacity) {
1592 int new_capacity = da_grow_capacity(arr->capacity, arr->length + 1);
1593 arr->data = DA_REALLOC(arr->data, new_capacity * arr->element_size);
1594 DA_ASSERT(arr->data != NULL);
1595 arr->capacity = new_capacity;
1596 }
1597
1598 void* dest = (char*)arr->data + (arr->length * arr->element_size);
1599 memcpy(dest, element, arr->element_size);
1600
1601 /* Call retain function on the newly added element */
1602 if (arr->retain_fn) {
1603 arr->retain_fn(dest);
1604 }
1605
1606 arr->length++;
1607}
1608
1609DA_DEF void da_insert(da_array arr, int index, const void* element) {
1610 DA_ASSERT(arr != NULL);
1611 DA_ASSERT(element != NULL);
1612 DA_ASSERT(index >= 0 && index <= arr->length);
1613
1614 /* Grow array if needed */
1615 if (arr->length >= arr->capacity) {
1616 int new_capacity = da_grow_capacity(arr->capacity, arr->length + 1);
1617 arr->data = DA_REALLOC(arr->data, new_capacity * arr->element_size);
1618 DA_ASSERT(arr->data != NULL);
1619 arr->capacity = new_capacity;
1620 }
1621
1622 /* Shift elements to the right if not inserting at the end */
1623 if (index < arr->length) {
1624 void* src = (char*)arr->data + (index * arr->element_size);
1625 void* dest = (char*)arr->data + ((index + 1) * arr->element_size);
1626 int bytes_to_move = (arr->length - index) * arr->element_size;
1627 memmove(dest, src, bytes_to_move);
1628 }
1629
1630 /* Insert the new element */
1631 void* insert_pos = (char*)arr->data + (index * arr->element_size);
1632 memcpy(insert_pos, element, arr->element_size);
1633
1634 /* Call retain function on the newly inserted element */
1635 if (arr->retain_fn) {
1636 arr->retain_fn(insert_pos);
1637 }
1638
1639 arr->length++;
1640}
1641
1642DA_DEF void da_remove(da_array arr, int index, void* out) {
1643 DA_ASSERT(arr != NULL);
1644 DA_ASSERT(index >= 0 && index < arr->length);
1645
1646 void* element_ptr = (char*)arr->data + (index * arr->element_size);
1647
1648 /* Copy element to output if requested */
1649 if (out != NULL) {
1650 memcpy(out, element_ptr, arr->element_size);
1651 }
1652
1653 /* Call destructor on the removed element */
1654 if (arr->release_fn) {
1655 arr->release_fn(element_ptr);
1656 }
1657
1658 /* Shift elements to the left if not removing the last element */
1659 if (index < arr->length - 1) {
1660 void* dest = (char*)arr->data + (index * arr->element_size);
1661 void* src = (char*)arr->data + ((index + 1) * arr->element_size);
1662 int bytes_to_move = (arr->length - index - 1) * arr->element_size;
1663 memmove(dest, src, bytes_to_move);
1664 }
1665
1666 arr->length--;
1667}
1668
1669DA_DEF void da_pop(da_array arr, void* out) {
1670 DA_ASSERT(arr != NULL);
1671 DA_ASSERT(arr->length > 0);
1672
1673 arr->length--;
1674
1675 void* src = (char*)arr->data + (arr->length * arr->element_size);
1676 if (out != NULL) {
1677 memcpy(out, src, arr->element_size);
1678 }
1679
1680 /* Call release function on the popped element */
1681 if (arr->release_fn) {
1682 arr->release_fn(src);
1683 }
1684}
1685
1686DA_DEF void da_clear(da_array arr) {
1687 DA_ASSERT(arr != NULL);
1688
1689 /* Call release function on all elements before clearing */
1690 if (arr->release_fn && arr->data) {
1691 for (int i = 0; i < arr->length; i++) {
1692 void* element_ptr = (char*)arr->data + (i * arr->element_size);
1693 arr->release_fn(element_ptr);
1694 }
1695 }
1696
1697 arr->length = 0;
1698}
1699
1700DA_DEF int da_length(da_array arr) {
1701 DA_ASSERT(arr != NULL);
1702 return arr->length;
1703}
1704
1705DA_DEF int da_capacity(da_array arr) {
1706 DA_ASSERT(arr != NULL);
1707 return arr->capacity;
1708}
1709
1710DA_DEF void da_reserve(da_array arr, int new_capacity) {
1711 DA_ASSERT(arr != NULL);
1712 DA_ASSERT(new_capacity >= 0);
1713
1714 if (new_capacity > arr->capacity) {
1715 arr->data = DA_REALLOC(arr->data, new_capacity * arr->element_size);
1716 DA_ASSERT(arr->data != NULL);
1717 arr->capacity = new_capacity;
1718 }
1719}
1720
1721DA_DEF void da_resize(da_array arr, int new_length) {
1722 DA_ASSERT(arr != NULL);
1723 DA_ASSERT(new_length >= 0);
1724
1725 if (new_length > arr->capacity) {
1726 da_reserve(arr, new_length);
1727 }
1728
1729 if (new_length < arr->length) {
1730 /* Call destructor on elements being removed */
1731 if (arr->release_fn && arr->data) {
1732 for (int i = new_length; i < arr->length; i++) {
1733 void* element_ptr = (char*)arr->data + (i * arr->element_size);
1734 arr->release_fn(element_ptr);
1735 }
1736 }
1737 } else if (new_length > arr->length) {
1738 /* Zero-fill new elements */
1739 void* start = (char*)arr->data + (arr->length * arr->element_size);
1740 int bytes_to_zero = (new_length - arr->length) * arr->element_size;
1741 memset(start, 0, bytes_to_zero);
1742 }
1743
1744 arr->length = new_length;
1745}
1746
1747DA_DEF void da_trim(da_array arr, int new_capacity) {
1748 DA_ASSERT(arr != NULL);
1749 DA_ASSERT(new_capacity >= arr->length);
1750
1751 if (new_capacity < arr->capacity) {
1752 if (new_capacity == 0) {
1753 if (arr->data) {
1754 DA_FREE(arr->data);
1755 arr->data = NULL;
1756 }
1757 } else {
1758 arr->data = DA_REALLOC(arr->data, new_capacity * arr->element_size);
1759 DA_ASSERT(arr->data != NULL);
1760 }
1761 arr->capacity = new_capacity;
1762 }
1763}
1764
1765DA_DEF void da_append_array(da_array dest, da_array src) {
1766 DA_ASSERT(dest != NULL);
1767 DA_ASSERT(src != NULL);
1768 DA_ASSERT(dest->element_size == src->element_size);
1769
1770 if (src->length == 0) return; /* Nothing to append */
1771
1772 /* Ensure dest has enough capacity */
1773 int new_length = dest->length + src->length;
1774 if (new_length > dest->capacity) {
1775 int new_capacity = da_grow_capacity(dest->capacity, new_length);
1776 dest->data = DA_REALLOC(dest->data, new_capacity * dest->element_size);
1777 DA_ASSERT(dest->data != NULL);
1778 dest->capacity = new_capacity;
1779 }
1780
1781 /* Copy all elements from src to end of dest */
1782 void* dest_ptr = (char*)dest->data + (dest->length * dest->element_size);
1783 memcpy(dest_ptr, src->data, src->length * src->element_size);
1784
1785 /* Call retain function on all copied elements */
1786 if (dest->retain_fn) {
1787 for (int i = dest->length; i < new_length; i++) {
1788 void* element_ptr = (char*)dest->data + (i * dest->element_size);
1789 dest->retain_fn(element_ptr);
1790 }
1791 }
1792
1793 dest->length = new_length;
1794}
1795
1797 DA_ASSERT(arr1 != NULL);
1798 DA_ASSERT(arr2 != NULL);
1799 DA_ASSERT(arr1->element_size == arr2->element_size);
1800
1801 int total_length = arr1->length + arr2->length;
1802
1803 /* Create new array with exact capacity */
1804 da_array result = (da_array)DA_MALLOC(sizeof(da_array_t));
1805 DA_ASSERT(result != NULL);
1806
1807 DA_ATOMIC_STORE(&result->ref_count, 1);
1808 result->length = total_length;
1809 result->capacity = total_length; /* Exact capacity */
1810 result->element_size = arr1->element_size;
1811 result->retain_fn = arr1->retain_fn; /* Inherit retain function from first array */
1812 result->release_fn = arr1->release_fn; /* Inherit release function from first array */
1813
1814 if (total_length > 0) {
1815 result->data = DA_MALLOC(total_length * result->element_size);
1816 DA_ASSERT(result->data != NULL);
1817
1818 /* Copy arr1 elements first */
1819 if (arr1->length > 0) {
1820 memcpy(result->data, arr1->data, arr1->length * result->element_size);
1821 }
1822
1823 /* Copy arr2 elements after arr1 */
1824 if (arr2->length > 0) {
1825 void* dest_ptr = (char*)result->data + (arr1->length * result->element_size);
1826 memcpy(dest_ptr, arr2->data, arr2->length * result->element_size);
1827 }
1828
1829 /* Call retain function on all copied elements */
1830 if (result->retain_fn) {
1831 for (int i = 0; i < result->length; i++) {
1832 void* element_ptr = (char*)result->data + (i * result->element_size);
1833 result->retain_fn(element_ptr);
1834 }
1835 }
1836 } else {
1837 result->data = NULL;
1838 }
1839
1840 return result;
1841}
1842
1843/* Builder Implementation */
1844
1845DA_DEF da_builder da_builder_create(int element_size) {
1846 DA_ASSERT(element_size > 0);
1847
1848 da_builder builder = (da_builder)DA_MALLOC(sizeof(da_builder_t));
1849 DA_ASSERT(builder != NULL);
1850
1851 builder->length = 0;
1852 builder->capacity = 0;
1853 builder->element_size = element_size;
1854 builder->data = NULL;
1855
1856 return builder;
1857}
1858
1859DA_DEF void da_builder_append(da_builder builder, const void* element) {
1860 DA_ASSERT(builder != NULL);
1861 DA_ASSERT(element != NULL);
1862
1863 if (builder->length >= builder->capacity) {
1864 int new_capacity = da_builder_grow_capacity(builder->capacity, builder->length + 1);
1865 builder->data = DA_REALLOC(builder->data, new_capacity * builder->element_size);
1866 DA_ASSERT(builder->data != NULL);
1867 builder->capacity = new_capacity;
1868 }
1869
1870 void* dest = (char*)builder->data + (builder->length * builder->element_size);
1871 memcpy(dest, element, builder->element_size);
1872 builder->length++;
1873}
1874
1875DA_DEF void da_builder_reserve(da_builder builder, int new_capacity) {
1876 DA_ASSERT(builder != NULL);
1877 DA_ASSERT(new_capacity >= 0);
1878
1879 if (new_capacity > builder->capacity) {
1880 builder->data = DA_REALLOC(builder->data, new_capacity * builder->element_size);
1881 DA_ASSERT(builder->data != NULL);
1882 builder->capacity = new_capacity;
1883 }
1884}
1885
1887 DA_ASSERT(builder != NULL);
1888 DA_ASSERT(arr != NULL);
1889 DA_ASSERT(builder->element_size == arr->element_size);
1890
1891 if (arr->length == 0) return; /* Nothing to append */
1892
1893 /* Ensure enough capacity */
1894 int new_length = builder->length + arr->length;
1895 if (new_length > builder->capacity) {
1896 int new_capacity = da_builder_grow_capacity(builder->capacity, new_length);
1897 builder->data = DA_REALLOC(builder->data, new_capacity * builder->element_size);
1898 DA_ASSERT(builder->data != NULL);
1899 builder->capacity = new_capacity;
1900 }
1901
1902 /* Copy all elements from array at once */
1903 void* dest_ptr = (char*)builder->data + (builder->length * builder->element_size);
1904 memcpy(dest_ptr, arr->data, arr->length * arr->element_size);
1905 builder->length = new_length;
1906}
1907
1908DA_DEF da_array da_builder_to_array(da_builder* builder, void (*retain_fn)(void*), void (*release_fn)(void*)) {
1909 DA_ASSERT(builder != NULL);
1910 DA_ASSERT(*builder != NULL);
1911
1912 da_builder b = *builder;
1913
1914 /* Create new da_array */
1915 da_array arr = (da_array)DA_MALLOC(sizeof(da_array_t));
1916 DA_ASSERT(arr != NULL);
1917
1918 DA_ATOMIC_STORE(&arr->ref_count, 1);
1919 arr->length = b->length;
1920 arr->capacity = b->length; /* Exact capacity = length */
1921 arr->element_size = b->element_size;
1922 arr->retain_fn = retain_fn;
1923 arr->release_fn = release_fn;
1924
1925 if (b->length > 0) {
1926 /* Shrink to exact size */
1927 arr->data = DA_REALLOC(b->data, b->length * b->element_size);
1928 DA_ASSERT(arr->data != NULL);
1929
1930 /* Call retain function on all elements in the new array */
1931 if (arr->retain_fn) {
1932 for (int i = 0; i < arr->length; i++) {
1933 void* element_ptr = (char*)arr->data + (i * arr->element_size);
1934 arr->retain_fn(element_ptr);
1935 }
1936 }
1937 } else {
1938 arr->data = NULL;
1939 if (b->data) {
1940 DA_FREE(b->data);
1941 }
1942 }
1943
1944 /* Free builder */
1945 DA_FREE(b);
1946 *builder = NULL;
1947
1948 return arr;
1949}
1950
1951DA_DEF void da_builder_clear(da_builder builder) {
1952 DA_ASSERT(builder != NULL);
1953 builder->length = 0;
1954}
1955
1956DA_DEF void da_builder_destroy(da_builder* builder) {
1957 DA_ASSERT(builder != NULL);
1958 DA_ASSERT(*builder != NULL);
1959
1960 if ((*builder)->data) {
1961 DA_FREE((*builder)->data);
1962 }
1963 DA_FREE(*builder);
1964 *builder = NULL;
1965}
1966
1967DA_DEF int da_builder_length(da_builder builder) {
1968 DA_ASSERT(builder != NULL);
1969 return builder->length;
1970}
1971
1972DA_DEF int da_builder_capacity(da_builder builder) {
1973 DA_ASSERT(builder != NULL);
1974 return builder->capacity;
1975}
1976
1977DA_DEF void* da_builder_get(da_builder builder, int index) {
1978 DA_ASSERT(builder != NULL);
1979 DA_ASSERT(index >= 0 && index < builder->length);
1980 return (char*)builder->data + (index * builder->element_size);
1981}
1982
1983DA_DEF void da_builder_set(da_builder builder, int index, const void* element) {
1984 DA_ASSERT(builder != NULL);
1985 DA_ASSERT(element != NULL);
1986 DA_ASSERT(index >= 0 && index < builder->length);
1987
1988 void* dest = (char*)builder->data + (index * builder->element_size);
1989 memcpy(dest, element, builder->element_size);
1990}
1991
1992/* Additional Array Functions Implementation */
1993
1994DA_DEF void* da_peek(da_array arr) {
1995 DA_ASSERT(arr != NULL);
1996 DA_ASSERT(arr->length > 0);
1997 return (char*)arr->data + ((arr->length - 1) * arr->element_size);
1998}
1999
2000DA_DEF void* da_peek_first(da_array arr) {
2001 DA_ASSERT(arr != NULL);
2002 DA_ASSERT(arr->length > 0);
2003 return arr->data;
2004}
2005
2006DA_DEF void da_append_raw(da_array arr, const void* data, int count) {
2007 DA_ASSERT(arr != NULL);
2008 DA_ASSERT(data != NULL);
2009 DA_ASSERT(count >= 0);
2010
2011 if (count == 0) return; /* Nothing to append */
2012
2013 /* Ensure enough capacity */
2014 int new_length = arr->length + count;
2015 if (new_length > arr->capacity) {
2016 int new_capacity = da_grow_capacity(arr->capacity, new_length);
2017 arr->data = DA_REALLOC(arr->data, new_capacity * arr->element_size);
2018 DA_ASSERT(arr->data != NULL);
2019 arr->capacity = new_capacity;
2020 }
2021
2022 /* Copy all elements at once */
2023 void* dest_ptr = (char*)arr->data + (arr->length * arr->element_size);
2024 memcpy(dest_ptr, data, count * arr->element_size);
2025
2026 /* Call retain function on all copied elements */
2027 if (arr->retain_fn) {
2028 for (int i = arr->length; i < new_length; i++) {
2029 void* element_ptr = (char*)arr->data + (i * arr->element_size);
2030 arr->retain_fn(element_ptr);
2031 }
2032 }
2033
2034 arr->length = new_length;
2035}
2036
2037DA_DEF void da_fill(da_array arr, const void* element, int count) {
2038 DA_ASSERT(arr != NULL);
2039 DA_ASSERT(element != NULL);
2040 DA_ASSERT(count >= 0);
2041
2042 if (count == 0) return; /* Nothing to fill */
2043
2044 /* Ensure enough capacity */
2045 int new_length = arr->length + count;
2046 if (new_length > arr->capacity) {
2047 int new_capacity = da_grow_capacity(arr->capacity, new_length);
2048 arr->data = DA_REALLOC(arr->data, new_capacity * arr->element_size);
2049 DA_ASSERT(arr->data != NULL);
2050 arr->capacity = new_capacity;
2051 }
2052
2053 /* Fill elements one by one */
2054 for (int i = 0; i < count; i++) {
2055 void* dest_ptr = (char*)arr->data + ((arr->length + i) * arr->element_size);
2056 memcpy(dest_ptr, element, arr->element_size);
2057 }
2058 arr->length = new_length;
2059}
2060
2061DA_DEF da_array da_slice(da_array arr, int start, int end) {
2062 DA_ASSERT(arr != NULL);
2063 DA_ASSERT(start >= 0 && start <= arr->length);
2064 DA_ASSERT(end >= start && end <= arr->length);
2065
2066 int slice_length = end - start;
2067
2068 /* Create new array with exact capacity */
2069 da_array result = (da_array)DA_MALLOC(sizeof(da_array_t));
2070 DA_ASSERT(result != NULL);
2071
2072 DA_ATOMIC_STORE(&result->ref_count, 1);
2073 result->length = slice_length;
2074 result->capacity = slice_length; /* Exact capacity */
2075 result->element_size = arr->element_size;
2076 result->retain_fn = arr->retain_fn; /* Inherit retain function */
2077 result->release_fn = arr->release_fn; /* Inherit release function */
2078
2079 if (slice_length > 0) {
2080 result->data = DA_MALLOC(slice_length * result->element_size);
2081 DA_ASSERT(result->data != NULL);
2082
2083 /* Copy slice elements */
2084 void* src_ptr = (char*)arr->data + (start * arr->element_size);
2085 memcpy(result->data, src_ptr, slice_length * arr->element_size);
2086
2087 /* Call retain function on all copied elements */
2088 if (result->retain_fn) {
2089 for (int i = 0; i < result->length; i++) {
2090 void* element_ptr = (char*)result->data + (i * result->element_size);
2091 result->retain_fn(element_ptr);
2092 }
2093 }
2094 } else {
2095 result->data = NULL;
2096 }
2097
2098 return result;
2099}
2100
2101DA_DEF void da_remove_range(da_array arr, int start, int count) {
2102 DA_ASSERT(arr != NULL);
2103 DA_ASSERT(start >= 0 && start < arr->length);
2104 DA_ASSERT(count >= 0);
2105 DA_ASSERT(start + count <= arr->length);
2106
2107 if (count == 0) return; /* Nothing to remove */
2108
2109 int end = start + count;
2110
2111 /* Call destructor on elements being removed */
2112 if (arr->release_fn) {
2113 for (int i = start; i < end; i++) {
2114 void* element_ptr = (char*)arr->data + (i * arr->element_size);
2115 arr->release_fn(element_ptr);
2116 }
2117 }
2118
2119 /* Shift elements after the range to the left */
2120 if (end < arr->length) {
2121 void* dest = (char*)arr->data + (start * arr->element_size);
2122 void* src = (char*)arr->data + (end * arr->element_size);
2123 int bytes_to_move = (arr->length - end) * arr->element_size;
2124 memmove(dest, src, bytes_to_move);
2125 }
2126
2127 arr->length -= count;
2128}
2129
2130DA_DEF void da_reverse(da_array arr) {
2131 DA_ASSERT(arr != NULL);
2132
2133 if (arr->length <= 1) return; /* Nothing to reverse */
2134
2135 char* temp = (char*)DA_MALLOC(arr->element_size);
2136 DA_ASSERT(temp != NULL);
2137
2138 /* Swap elements from both ends moving toward center */
2139 for (int i = 0; i < arr->length / 2; i++) {
2140 int j = arr->length - 1 - i;
2141
2142 char* left = (char*)arr->data + (i * arr->element_size);
2143 char* right = (char*)arr->data + (j * arr->element_size);
2144
2145 /* Three-way swap using temp buffer */
2146 memcpy(temp, left, arr->element_size);
2147 memcpy(left, right, arr->element_size);
2148 memcpy(right, temp, arr->element_size);
2149 }
2150
2151 DA_FREE(temp);
2152}
2153
2154DA_DEF void da_swap(da_array arr, int i, int j) {
2155 DA_ASSERT(arr != NULL);
2156 DA_ASSERT(i >= 0 && i < arr->length);
2157 DA_ASSERT(j >= 0 && j < arr->length);
2158
2159 if (i == j) return; /* No-op if same index */
2160
2161 char* temp = (char*)DA_MALLOC(arr->element_size);
2162 DA_ASSERT(temp != NULL);
2163
2164 char* elem_i = (char*)arr->data + (i * arr->element_size);
2165 char* elem_j = (char*)arr->data + (j * arr->element_size);
2166
2167 /* Three-way swap */
2168 memcpy(temp, elem_i, arr->element_size);
2169 memcpy(elem_i, elem_j, arr->element_size);
2170 memcpy(elem_j, temp, arr->element_size);
2171
2172 DA_FREE(temp);
2173}
2174
2176 DA_ASSERT(arr != NULL);
2177
2178 /* Create new array with exact capacity = length */
2179 da_array result = (da_array)DA_MALLOC(sizeof(da_array_t));
2180 DA_ASSERT(result != NULL);
2181
2182 DA_ATOMIC_STORE(&result->ref_count, 1);
2183 result->length = arr->length;
2184 result->capacity = arr->length; /* Exact capacity for efficiency */
2185 result->element_size = arr->element_size;
2186 result->retain_fn = arr->retain_fn; /* Inherit retain function */
2187 result->release_fn = arr->release_fn; /* Inherit release function */
2188
2189 if (arr->length > 0) {
2190 result->data = DA_MALLOC(arr->length * arr->element_size);
2191 DA_ASSERT(result->data != NULL);
2192
2193 /* Copy all elements */
2194 memcpy(result->data, arr->data, arr->length * arr->element_size);
2195
2196 /* Call retain function on all copied elements */
2197 if (result->retain_fn) {
2198 for (int i = 0; i < result->length; i++) {
2199 void* element_ptr = (char*)result->data + (i * result->element_size);
2200 result->retain_fn(element_ptr);
2201 }
2202 }
2203 } else {
2204 result->data = NULL;
2205 }
2206
2207 return result;
2208}
2209
2210DA_DEF da_array da_filter(da_array arr, int (*predicate)(const void* element, void* context), void* context) {
2211 DA_ASSERT(arr != NULL);
2212 DA_ASSERT(predicate != NULL);
2213
2214 /* Use builder for single-pass filtering */
2216
2217 /* Single pass: test and append matching elements */
2218 for (int i = 0; i < arr->length; i++) {
2219 void* element_ptr = (char*)arr->data + (i * arr->element_size);
2220 if (predicate(element_ptr, context)) {
2221 da_builder_append(builder, element_ptr);
2222 }
2223 }
2224
2225 /* Convert builder to array with exact capacity, inherit destructor */
2226 da_array result = da_builder_to_array(&builder, arr->retain_fn, arr->release_fn);
2227 return result;
2228}
2229
2230DA_DEF da_array da_map(da_array arr, void (*mapper)(const void* src, void* dst, void* context), void* context) {
2231 DA_ASSERT(arr != NULL);
2232 DA_ASSERT(mapper != NULL);
2233
2234 /* Create new array with same length and exact capacity */
2235 da_array result = (da_array)DA_MALLOC(sizeof(da_array_t));
2236 DA_ASSERT(result != NULL);
2237
2238 DA_ATOMIC_STORE(&result->ref_count, 1);
2239 result->length = arr->length;
2240 result->capacity = arr->length; /* Exact capacity for efficiency */
2241 result->element_size = arr->element_size;
2242 result->retain_fn = arr->retain_fn; /* Inherit retain function */
2243 result->release_fn = arr->release_fn; /* Inherit release function */
2244
2245 if (arr->length > 0) {
2246 result->data = DA_MALLOC(arr->length * arr->element_size);
2247 DA_ASSERT(result->data != NULL);
2248
2249 /* Transform each element */
2250 for (int i = 0; i < arr->length; i++) {
2251 void* src_ptr = (char*)arr->data + (i * arr->element_size);
2252 void* dst_ptr = (char*)result->data + (i * arr->element_size);
2253 mapper(src_ptr, dst_ptr, context);
2254 }
2255 } else {
2256 result->data = NULL;
2257 }
2258
2259 return result;
2260}
2261
2262DA_DEF void da_reduce(da_array arr, const void* initial, void* result,
2263 void (*reducer)(void* accumulator, const void* element, void* context), void* context) {
2264 DA_ASSERT(arr != NULL);
2265 DA_ASSERT(initial != NULL);
2266 DA_ASSERT(result != NULL);
2267 DA_ASSERT(reducer != NULL);
2268
2269 /* Initialize result with initial value */
2270 memcpy(result, initial, arr->element_size);
2271
2272 /* Apply reducer to each element */
2273 for (int i = 0; i < arr->length; i++) {
2274 void* element_ptr = (char*)arr->data + (i * arr->element_size);
2275 reducer(result, element_ptr, context);
2276 }
2277}
2278
2279DA_DEF int da_is_empty(da_array arr) {
2280 DA_ASSERT(arr != NULL);
2281 return arr->length == 0;
2282}
2283
2284DA_DEF int da_find_index(da_array arr, int (*predicate)(const void* element, void* context), void* context) {
2285 DA_ASSERT(arr != NULL);
2286 DA_ASSERT(predicate != NULL);
2287
2288 for (int i = 0; i < arr->length; i++) {
2289 void* element_ptr = (char*)arr->data + (i * arr->element_size);
2290 if (predicate(element_ptr, context)) {
2291 return i;
2292 }
2293 }
2294
2295 return -1; // Not found
2296}
2297
2298DA_DEF int da_contains(da_array arr, int (*predicate)(const void* element, void* context), void* context) {
2299 return da_find_index(arr, predicate, context) != -1;
2300}
2301
2302// Helper structure for qsort context
2304 int (*compare)(const void* a, const void* b, void* context);
2305 void* user_context;
2306};
2307
2308// Global context for qsort (not thread-safe, but qsort isn't either)
2309static struct da_sort_context* da_sort_global_context = NULL;
2310
2311// qsort comparison wrapper
2312static int da_sort_compare_wrapper(const void* a, const void* b) {
2313 struct da_sort_context* ctx = (struct da_sort_context*)da_sort_global_context;
2314 return ctx->compare(a, b, ctx->user_context);
2315}
2316
2317DA_DEF void da_sort(da_array arr, int (*compare)(const void* a, const void* b, void* context), void* context) {
2318 DA_ASSERT(arr != NULL);
2319 DA_ASSERT(compare != NULL);
2320
2321 if (arr->length <= 1) {
2322 return; // Already sorted or empty
2323 }
2324
2325 // Set up global context for qsort wrapper
2326 struct da_sort_context sort_ctx = { compare, context };
2327 da_sort_global_context = &sort_ctx;
2328
2329 // Use standard library qsort
2330 qsort(arr->data, arr->length, arr->element_size, da_sort_compare_wrapper);
2331
2332 // Clean up global context
2333 da_sort_global_context = NULL;
2334}
2335
2336#endif /* DA_IMPLEMENTATION */
2337
2338#endif /* DYNAMIC_ARRAY_H */
#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