solidc
Robust collection of general-purpose cross-platform C libraries and data structures designed for rapid and safe development in C
Loading...
Searching...
No Matches
dynarray.c
1#include "../include/dynarray.h"
2
3#include <stdio.h> // for fprintf, stderr
4#include <stdlib.h> // for malloc, realloc, free
5#include <string.h> // for memcpy, memmove
6
13static inline size_t calculate_growth(size_t current, size_t element_size) {
14 // Check for potential overflow in growth calculation
15 if (current > SIZE_MAX / DYNARRAY_GROWTH_NUMERATOR) {
16 return 0; // Overflow would occur
17 }
18
19 size_t new_capacity = (current * DYNARRAY_GROWTH_NUMERATOR) / DYNARRAY_GROWTH_DENOMINATOR;
20
21 // Ensure we actually grow (handle rounding down)
22 if (new_capacity <= current) {
23 new_capacity = current + 1;
24 }
25
26 // Check if allocation would overflow
27 if (new_capacity > SIZE_MAX / element_size) {
28 return 0; // Would overflow
29 }
30
31 return new_capacity;
32}
33
34bool dynarray_init(dynarray_t* arr, size_t element_size, size_t initial_capacity) {
35 if (arr == NULL || element_size == 0) {
36 return false;
37 }
38
39 if (initial_capacity == 0) {
40 initial_capacity = DYNARRAY_INITIAL_CAPACITY;
41 }
42
43 // Check for potential overflow
44 if (initial_capacity > SIZE_MAX / element_size) {
45 return false;
46 }
47
48 void* data = malloc(element_size * initial_capacity);
49 if (data == NULL) {
50 return false;
51 }
52
53 *arr = (dynarray_t){
54 .data = data,
55 .size = 0,
56 .capacity = initial_capacity,
57 .element_size = element_size,
58 };
59
60 return true;
61}
62
64 if (arr == NULL) {
65 return;
66 }
67
68 free(arr->data);
69 *arr = (dynarray_t){0}; // Zero out the structure
70}
71
72bool dynarray_push(dynarray_t* arr, const void* element) {
73 if (arr == NULL || element == NULL) {
74 return false;
75 }
76
77 // Check if we need to grow
78 if (arr->size >= arr->capacity) {
79 size_t new_capacity = calculate_growth(arr->capacity, arr->element_size);
80 if (new_capacity == 0) {
81 return false;
82 }
83
84 if (!dynarray_reserve(arr, new_capacity)) {
85 return false;
86 }
87 }
88
89 // Copy element to the end
90 unsigned char* dest = (unsigned char*)arr->data + (arr->size * arr->element_size);
91 memcpy(dest, element, arr->element_size);
92 arr->size++;
93
94 return true;
95}
96
97bool dynarray_pop(dynarray_t* arr, void* out_element) {
98 if (arr == NULL || arr->size == 0) {
99 return false;
100 }
101
102 arr->size--;
103
104 // Copy element if requested
105 if (out_element != NULL) {
106 const unsigned char* src = (const unsigned char*)arr->data + (arr->size * arr->element_size);
107 memcpy(out_element, src, arr->element_size);
108 }
109
110 // Shrink if usage drops below threshold and we have significant unused capacity
112 size_t new_capacity = arr->capacity / DYNARRAY_GROWTH_DENOMINATOR;
113 if (new_capacity < DYNARRAY_INITIAL_CAPACITY) {
114 new_capacity = DYNARRAY_INITIAL_CAPACITY;
115 }
116
117 // Ignore failure - shrinking is optional optimization
118 (void)dynarray_reserve(arr, new_capacity);
119 }
120
121 return true;
122}
123
124void* dynarray_get(const dynarray_t* arr, size_t index) {
125 if (arr == NULL || index >= arr->size) {
126 return NULL;
127 }
128 return (unsigned char*)arr->data + (index * arr->element_size);
129}
130
131bool dynarray_set(dynarray_t* arr, size_t index, const void* element) {
132 if (arr == NULL || element == NULL || index >= arr->size) {
133 return false;
134 }
135
136 unsigned char* dest = (unsigned char*)arr->data + (index * arr->element_size);
137 memcpy(dest, element, arr->element_size);
138
139 return true;
140}
141
142bool dynarray_reserve(dynarray_t* arr, size_t new_capacity) {
143 if (arr == NULL) {
144 return false;
145 }
146
147 // Don't shrink below current size
148 if (new_capacity < arr->size) {
149 new_capacity = arr->size;
150 }
151
152 // No-op if already at desired capacity
153 if (new_capacity == arr->capacity) {
154 return true;
155 }
156
157 // Check for overflow
158 if (new_capacity > SIZE_MAX / arr->element_size) {
159 return false;
160 }
161
162 void* new_data = realloc(arr->data, new_capacity * arr->element_size);
163 if (new_data == NULL && new_capacity > 0) {
164 return false;
165 }
166
167 arr->data = new_data;
168 arr->capacity = new_capacity;
169
170 return true;
171}
172
174 if (arr == NULL) {
175 return false;
176 }
177
178 // Ensure we keep at least the initial capacity to avoid degenerate behavior
179 size_t target_capacity = arr->size > DYNARRAY_INITIAL_CAPACITY ? arr->size : DYNARRAY_INITIAL_CAPACITY;
180
181 return dynarray_reserve(arr, target_capacity);
182}
183
185 if (arr == NULL) {
186 return;
187 }
188
189 arr->size = 0;
190 // Note: We deliberately don't free memory here - capacity remains unchanged
191}
bool dynarray_push(dynarray_t *arr, const void *element)
Definition dynarray.c:72
#define DYNARRAY_INITIAL_CAPACITY
Definition dynarray.h:22
bool dynarray_set(dynarray_t *arr, size_t index, const void *element)
Definition dynarray.c:131
bool dynarray_pop(dynarray_t *arr, void *out_element)
Definition dynarray.c:97
bool dynarray_shrink_to_fit(dynarray_t *arr)
Definition dynarray.c:173
void * dynarray_get(const dynarray_t *arr, size_t index)
Definition dynarray.c:124
bool dynarray_init(dynarray_t *arr, size_t element_size, size_t initial_capacity)
Definition dynarray.c:34
void dynarray_clear(dynarray_t *arr)
Definition dynarray.c:184
#define DYNARRAY_GROWTH_NUMERATOR
Definition dynarray.h:18
void dynarray_free(dynarray_t *arr)
Definition dynarray.c:63
#define DYNARRAY_SHRINK_THRESHOLD
Definition dynarray.h:25
bool dynarray_reserve(dynarray_t *arr, size_t new_capacity)
Definition dynarray.c:142
size_t size
Definition dynarray.h:36
size_t element_size
Definition dynarray.h:40
size_t capacity
Definition dynarray.h:38
void * data
Definition dynarray.h:34