43 #ifdef __cplusplus |
42 #ifdef __cplusplus |
44 extern "C" { |
43 extern "C" { |
45 #endif |
44 #endif |
46 |
45 |
47 /** |
46 /** |
48 * The maximum item size in an array list that fits into stack buffer when swapped. |
47 * The maximum item size in an array list that fits into stack buffer |
49 */ |
48 * when swapped. |
50 extern unsigned cx_array_swap_sbo_size; |
49 */ |
|
50 extern const unsigned cx_array_swap_sbo_size; |
51 |
51 |
52 /** |
52 /** |
53 * Declares variables for an array that can be used with the convenience macros. |
53 * Declares variables for an array that can be used with the convenience macros. |
54 * |
54 * |
|
55 * @par Examples |
|
56 * @code |
|
57 * // integer array with at most 255 elements |
|
58 * CX_ARRAY_DECLARE_SIZED(int, myarray, uint8_t) |
|
59 * |
|
60 * // array of MyObject* pointers where size and capacity are stored as unsigned int |
|
61 * CX_ARRAY_DECLARE_SIZED(MyObject*, objects, unsigned int) |
|
62 * |
|
63 * // initializing code |
|
64 * cx_array_initialize(myarray, 16); // reserve space for 16 |
|
65 * cx_array_initialize(objects, 100); // reserve space for 100 |
|
66 * @endcode |
|
67 * |
|
68 * @param type the type of the data |
|
69 * @param name the name of the array |
|
70 * @param size_type the type of the size (should be uint8_t, uint16_t, uint32_t, or size_t) |
|
71 * |
|
72 * @see cx_array_initialize() |
55 * @see cx_array_simple_add() |
73 * @see cx_array_simple_add() |
56 * @see cx_array_simple_copy() |
74 * @see cx_array_simple_copy() |
57 * @see cx_array_initialize() |
|
58 * @see cx_array_simple_add_sorted() |
75 * @see cx_array_simple_add_sorted() |
59 * @see cx_array_simple_insert_sorted() |
76 * @see cx_array_simple_insert_sorted() |
60 */ |
77 */ |
61 #define CX_ARRAY_DECLARE(type, name) \ |
78 #define CX_ARRAY_DECLARE_SIZED(type, name, size_type) \ |
62 type * name; \ |
79 type * name; \ |
63 size_t name##_size; \ |
80 /** Array size. */ size_type name##_size; \ |
64 size_t name##_capacity |
81 /** Array capacity. */ size_type name##_capacity |
65 |
82 |
66 /** |
83 /** |
67 * Initializes an array declared with CX_ARRAY_DECLARE(). |
84 * Declares variables for an array that can be used with the convenience macros. |
|
85 * |
|
86 * The size and capacity variables will have @c size_t type. |
|
87 * Use #CX_ARRAY_DECLARE_SIZED() to specify a different type. |
|
88 * |
|
89 * @par Examples |
|
90 * @code |
|
91 * // int array |
|
92 * CX_ARRAY_DECLARE(int, myarray) |
|
93 * |
|
94 * // initializing code |
|
95 * cx_array_initialize(myarray, 32); // reserve space for 32 |
|
96 * @endcode |
|
97 * |
|
98 * @param type the type of the data |
|
99 * @param name the name of the array |
|
100 * |
|
101 * @see cx_array_initialize() |
|
102 * @see cx_array_simple_add() |
|
103 * @see cx_array_simple_copy() |
|
104 * @see cx_array_simple_add_sorted() |
|
105 * @see cx_array_simple_insert_sorted() |
|
106 */ |
|
107 #define CX_ARRAY_DECLARE(type, name) CX_ARRAY_DECLARE_SIZED(type, name, size_t) |
|
108 |
|
109 /** |
|
110 * Initializes an array with the given capacity. |
|
111 * |
|
112 * The type of the capacity depends on the type used during declaration. |
|
113 * |
|
114 * @par Examples |
|
115 * @code |
|
116 * CX_ARRAY_DECLARE_SIZED(int, arr1, uint8_t) |
|
117 * CX_ARRAY_DECLARE(int, arr2) // size and capacity are implicitly size_t |
|
118 * |
|
119 * // initializing code |
|
120 * cx_array_initialize(arr1, 500); // error: maximum for uint8_t is 255 |
|
121 * cx_array_initialize(arr2, 500); // OK |
|
122 * @endcode |
|
123 * |
68 * |
124 * |
69 * The memory for the array is allocated with stdlib malloc(). |
125 * The memory for the array is allocated with stdlib malloc(). |
70 * @param array the array |
126 * @param array the name of the array |
71 * @param capacity the initial capacity |
127 * @param capacity the initial capacity |
|
128 * @see cx_array_initialize_a() |
|
129 * @see CX_ARRAY_DECLARE_SIZED() |
|
130 * @see CX_ARRAY_DECLARE() |
72 */ |
131 */ |
73 #define cx_array_initialize(array, capacity) \ |
132 #define cx_array_initialize(array, capacity) \ |
74 array##_capacity = capacity; \ |
133 array##_capacity = capacity; \ |
75 array##_size = 0; \ |
134 array##_size = 0; \ |
76 array = malloc(sizeof(array[0]) * capacity) |
135 array = malloc(sizeof(array[0]) * capacity) |
77 |
136 |
78 /** |
137 /** |
|
138 * Initializes an array with the given capacity using the specified allocator. |
|
139 * |
|
140 * @par Example |
|
141 * @code |
|
142 * CX_ARRAY_DECLARE(int, myarray) |
|
143 * |
|
144 * |
|
145 * const CxAllocator *al = // ... |
|
146 * cx_array_initialize_a(al, myarray, 128); |
|
147 * // ... |
|
148 * cxFree(al, myarray); // don't forget to free with same allocator |
|
149 * @endcode |
|
150 * |
|
151 * The memory for the array is allocated with stdlib malloc(). |
|
152 * @param allocator (@c CxAllocator*) the allocator |
|
153 * @param array the name of the array |
|
154 * @param capacity the initial capacity |
|
155 * @see cx_array_initialize() |
|
156 * @see CX_ARRAY_DECLARE_SIZED() |
|
157 * @see CX_ARRAY_DECLARE() |
|
158 */ |
|
159 #define cx_array_initialize_a(allocator, array, capacity) \ |
|
160 array##_capacity = capacity; \ |
|
161 array##_size = 0; \ |
|
162 array = cxMalloc(allocator, sizeof(array[0]) * capacity) |
|
163 |
|
164 /** |
79 * Defines a reallocation mechanism for arrays. |
165 * Defines a reallocation mechanism for arrays. |
|
166 * You can create your own, use cx_array_reallocator(), or |
|
167 * use the #cx_array_default_reallocator. |
80 */ |
168 */ |
81 struct cx_array_reallocator_s { |
169 struct cx_array_reallocator_s { |
82 /** |
170 /** |
83 * Reallocates space for the given array. |
171 * Reallocates space for the given array. |
84 * |
172 * |
118 */ |
209 */ |
119 size_t int2; |
210 size_t int2; |
120 }; |
211 }; |
121 |
212 |
122 /** |
213 /** |
|
214 * Typedef for the array reallocator struct. |
|
215 */ |
|
216 typedef struct cx_array_reallocator_s CxArrayReallocator; |
|
217 |
|
218 /** |
123 * A default stdlib-based array reallocator. |
219 * A default stdlib-based array reallocator. |
124 */ |
220 */ |
125 extern struct cx_array_reallocator_s *cx_array_default_reallocator; |
221 extern CxArrayReallocator *cx_array_default_reallocator; |
126 |
222 |
127 /** |
223 /** |
128 * Return codes for array functions. |
224 * Creates a new array reallocator. |
129 */ |
225 * |
130 enum cx_array_result { |
226 * When @p allocator is @c NULL, the stdlib default allocator will be used. |
131 CX_ARRAY_SUCCESS, |
227 * |
132 CX_ARRAY_REALLOC_NOT_SUPPORTED, |
228 * When @p stackmem is not @c NULL, the reallocator is supposed to be used |
133 CX_ARRAY_REALLOC_FAILED, |
229 * @em only for the specific array that is initially located at @p stackmem. |
134 }; |
230 * When reallocation is needed, the reallocator checks, if the array is |
|
231 * still located at @p stackmem and copies the contents to the heap. |
|
232 * |
|
233 * @note Invoking this function with both arguments @c NULL will return a |
|
234 * reallocator that behaves like #cx_array_default_reallocator. |
|
235 * |
|
236 * @param allocator the allocator this reallocator shall be based on |
|
237 * @param stackmem the address of the array when the array is initially located |
|
238 * on the stack or shall not reallocated in place |
|
239 * @return an array reallocator |
|
240 */ |
|
241 CxArrayReallocator cx_array_reallocator( |
|
242 const struct cx_allocator_s *allocator, |
|
243 const void *stackmem |
|
244 ); |
|
245 |
|
246 /** |
|
247 * Reserves memory for additional elements. |
|
248 * |
|
249 * This function checks if the @p capacity of the array is sufficient to hold |
|
250 * at least @p size plus @p elem_count elements. If not, a reallocation is |
|
251 * performed with the specified @p reallocator. |
|
252 * You can create your own reallocator by hand, use #cx_array_default_reallocator, |
|
253 * or use the convenience function cx_array_reallocator() to create a custom reallocator. |
|
254 * |
|
255 * This function can be useful to replace subsequent calls to cx_array_copy() |
|
256 * with one single cx_array_reserve() and then - after guaranteeing a |
|
257 * sufficient capacity - use simple memmove() or memcpy(). |
|
258 * |
|
259 * The @p width in bytes refers to the size and capacity. |
|
260 * Both must have the same width. |
|
261 * Supported are 0, 1, 2, and 4, as well as 8 if running on a 64 bit |
|
262 * architecture. If set to zero, the native word width is used. |
|
263 * |
|
264 * @param array a pointer to the target array |
|
265 * @param size a pointer to the size of the array |
|
266 * @param capacity a pointer to the capacity of the array |
|
267 * @param width the width in bytes for the @p size and @p capacity or zero for default |
|
268 * @param elem_size the size of one element |
|
269 * @param elem_count the number of expected additional elements |
|
270 * @param reallocator the array reallocator to use |
|
271 * (@c NULL defaults to #cx_array_default_reallocator) |
|
272 * @retval zero success |
|
273 * @retval non-zero failure |
|
274 * @see cx_array_reallocator() |
|
275 */ |
|
276 cx_attr_nonnull_arg(1, 2, 3) |
|
277 int cx_array_reserve( |
|
278 void **array, |
|
279 void *size, |
|
280 void *capacity, |
|
281 unsigned width, |
|
282 size_t elem_size, |
|
283 size_t elem_count, |
|
284 CxArrayReallocator *reallocator |
|
285 ); |
135 |
286 |
136 /** |
287 /** |
137 * Copies elements from one array to another. |
288 * Copies elements from one array to another. |
138 * |
289 * |
139 * The elements are copied to the \p target array at the specified \p index, |
290 * The elements are copied to the @p target array at the specified @p index, |
140 * overwriting possible elements. The \p index does not need to be in range of |
291 * overwriting possible elements. The @p index does not need to be in range of |
141 * the current array \p size. If the new index plus the number of elements added |
292 * the current array @p size. If the new index plus the number of elements added |
142 * would extend the array's size, and \p capacity is not \c NULL, the remaining |
293 * would extend the array's size, the remaining @p capacity is used. |
143 * capacity is used. |
294 * |
144 * |
295 * If the @p capacity is also insufficient to hold the new data, a reallocation |
145 * If the capacity is insufficient to hold the new data, a reallocation |
296 * attempt is made with the specified @p reallocator. |
146 * attempt is made, unless the \p reallocator is set to \c NULL, in which case |
297 * You can create your own reallocator by hand, use #cx_array_default_reallocator, |
147 * this function ultimately returns a failure. |
298 * or use the convenience function cx_array_reallocator() to create a custom reallocator. |
|
299 * |
|
300 * The @p width in bytes refers to the size and capacity. |
|
301 * Both must have the same width. |
|
302 * Supported are 0, 1, 2, and 4, as well as 8 if running on a 64 bit |
|
303 * architecture. If set to zero, the native word width is used. |
148 * |
304 * |
149 * @param target a pointer to the target array |
305 * @param target a pointer to the target array |
150 * @param size a pointer to the size of the target array |
306 * @param size a pointer to the size of the target array |
151 * @param capacity a pointer to the target array's capacity - |
307 * @param capacity a pointer to the capacity of the target array |
152 * \c NULL if only the size shall be used to bound the array (reallocations |
308 * @param width the width in bytes for the @p size and @p capacity or zero for default |
153 * will NOT be supported in that case) |
|
154 * @param index the index where the copied elements shall be placed |
309 * @param index the index where the copied elements shall be placed |
155 * @param src the source array |
310 * @param src the source array |
156 * @param elem_size the size of one element |
311 * @param elem_size the size of one element |
157 * @param elem_count the number of elements to copy |
312 * @param elem_count the number of elements to copy |
158 * @param reallocator the array reallocator to use, or \c NULL |
313 * @param reallocator the array reallocator to use |
159 * if reallocation shall not happen |
314 * (@c NULL defaults to #cx_array_default_reallocator) |
160 * @return zero on success, non-zero error code on failure |
315 * @retval zero success |
161 */ |
316 * @retval non-zero failure |
162 __attribute__((__nonnull__(1, 2, 5))) |
317 * @see cx_array_reallocator() |
163 enum cx_array_result cx_array_copy( |
318 */ |
|
319 cx_attr_nonnull_arg(1, 2, 3, 6) |
|
320 int cx_array_copy( |
164 void **target, |
321 void **target, |
165 size_t *size, |
322 void *size, |
166 size_t *capacity, |
323 void *capacity, |
|
324 unsigned width, |
167 size_t index, |
325 size_t index, |
168 const void *src, |
326 const void *src, |
169 size_t elem_size, |
327 size_t elem_size, |
170 size_t elem_count, |
328 size_t elem_count, |
171 struct cx_array_reallocator_s *reallocator |
329 CxArrayReallocator *reallocator |
172 ); |
330 ); |
173 |
331 |
174 /** |
332 /** |
175 * Convenience macro that uses cx_array_copy() with a default layout and the default reallocator. |
333 * Convenience macro that uses cx_array_copy() with a default layout and |
176 * |
334 * the specified reallocator. |
177 * @param array the name of the array (NOT a pointer to the array) |
335 * |
178 * @param index the index where the copied elements shall be placed |
336 * @param reallocator (@c CxArrayReallocator*) the array reallocator to use |
179 * @param src the source array |
337 * @param array the name of the array (NOT a pointer or alias to the array) |
180 * @param count the number of elements to copy |
338 * @param index (@c size_t) the index where the copied elements shall be placed |
181 * @see CX_ARRAY_DECLARE() |
339 * @param src (@c void*) the source array |
|
340 * @param count (@c size_t) the number of elements to copy |
|
341 * @retval zero success |
|
342 * @retval non-zero failure |
|
343 * @see CX_ARRAY_DECLARE() |
|
344 * @see cx_array_simple_copy() |
|
345 */ |
|
346 #define cx_array_simple_copy_a(reallocator, array, index, src, count) \ |
|
347 cx_array_copy((void**)&(array), &(array##_size), &(array##_capacity), \ |
|
348 sizeof(array##_size), index, src, sizeof((array)[0]), count, \ |
|
349 reallocator) |
|
350 |
|
351 /** |
|
352 * Convenience macro that uses cx_array_copy() with a default layout and |
|
353 * the default reallocator. |
|
354 * |
|
355 * @param array the name of the array (NOT a pointer or alias to the array) |
|
356 * @param index (@c size_t) the index where the copied elements shall be placed |
|
357 * @param src (@c void*) the source array |
|
358 * @param count (@c size_t) the number of elements to copy |
|
359 * @retval zero success |
|
360 * @retval non-zero failure |
|
361 * @see CX_ARRAY_DECLARE() |
|
362 * @see cx_array_simple_copy_a() |
182 */ |
363 */ |
183 #define cx_array_simple_copy(array, index, src, count) \ |
364 #define cx_array_simple_copy(array, index, src, count) \ |
184 cx_array_copy((void**)&(array), &(array##_size), &(array##_capacity), \ |
365 cx_array_simple_copy_a(NULL, array, index, src, count) |
185 index, src, sizeof((array)[0]), count, cx_array_default_reallocator) |
366 |
|
367 /** |
|
368 * Convenience macro that uses cx_array_reserve() with a default layout and |
|
369 * the specified reallocator. |
|
370 * |
|
371 * @param reallocator (@c CxArrayReallocator*) the array reallocator to use |
|
372 * @param array the name of the array (NOT a pointer or alias to the array) |
|
373 * @param count (@c size_t) the number of expected @em additional elements |
|
374 * @retval zero success |
|
375 * @retval non-zero failure |
|
376 * @see CX_ARRAY_DECLARE() |
|
377 * @see cx_array_simple_reserve() |
|
378 */ |
|
379 #define cx_array_simple_reserve_a(reallocator, array, count) \ |
|
380 cx_array_reserve((void**)&(array), &(array##_size), &(array##_capacity), \ |
|
381 sizeof(array##_size), sizeof((array)[0]), count, \ |
|
382 reallocator) |
|
383 |
|
384 /** |
|
385 * Convenience macro that uses cx_array_reserve() with a default layout and |
|
386 * the default reallocator. |
|
387 * |
|
388 * @param array the name of the array (NOT a pointer or alias to the array) |
|
389 * @param count (@c size_t) the number of expected additional elements |
|
390 * @retval zero success |
|
391 * @retval non-zero failure |
|
392 * @see CX_ARRAY_DECLARE() |
|
393 * @see cx_array_simple_reserve_a() |
|
394 */ |
|
395 #define cx_array_simple_reserve(array, count) \ |
|
396 cx_array_simple_reserve_a(NULL, array, count) |
186 |
397 |
187 /** |
398 /** |
188 * Adds an element to an array with the possibility of allocating more space. |
399 * Adds an element to an array with the possibility of allocating more space. |
189 * |
400 * |
190 * The element \p elem is added to the end of the \p target array which containing |
401 * The element @p elem is added to the end of the @p target array which contains |
191 * \p size elements, already. The \p capacity must not be \c NULL and point a |
402 * @p size elements, already. The @p capacity must point to a variable denoting |
192 * variable holding the current maximum number of elements the array can hold. |
403 * the current maximum number of elements the array can hold. |
193 * |
404 * |
194 * If the capacity is insufficient to hold the new element, and the optional |
405 * If the capacity is insufficient to hold the new element, an attempt to |
195 * \p reallocator is not \c NULL, an attempt increase the \p capacity is made |
406 * increase the @p capacity is made and the new capacity is written back. |
196 * and the new capacity is written back. |
407 * |
|
408 * The \@ SIZE_TYPE is flexible and can be any unsigned integer type. |
|
409 * It is important, however, that @p size and @p capacity are pointers to |
|
410 * variables of the same type. |
|
411 * |
|
412 * @param target (@c void**) a pointer to the target array |
|
413 * @param size (@c SIZE_TYPE*) a pointer to the size of the target array |
|
414 * @param capacity (@c SIZE_TYPE*) a pointer to the capacity of the target array |
|
415 * @param elem_size (@c size_t) the size of one element |
|
416 * @param elem (@c void*) a pointer to the element to add |
|
417 * @param reallocator (@c CxArrayReallocator*) the array reallocator to use |
|
418 * @retval zero success |
|
419 * @retval non-zero failure |
|
420 */ |
|
421 #define cx_array_add(target, size, capacity, elem_size, elem, reallocator) \ |
|
422 cx_array_copy((void**)(target), size, capacity, sizeof(*(size)), \ |
|
423 *(size), elem, elem_size, 1, reallocator) |
|
424 |
|
425 /** |
|
426 * Convenience macro that uses cx_array_add() with a default layout and |
|
427 * the specified reallocator. |
|
428 * |
|
429 * @param reallocator (@c CxArrayReallocator*) the array reallocator to use |
|
430 * @param array the name of the array (NOT a pointer or alias to the array) |
|
431 * @param elem the element to add (NOT a pointer, address is automatically taken) |
|
432 * @retval zero success |
|
433 * @retval non-zero failure |
|
434 * @see CX_ARRAY_DECLARE() |
|
435 * @see cx_array_simple_add() |
|
436 */ |
|
437 #define cx_array_simple_add_a(reallocator, array, elem) \ |
|
438 cx_array_simple_copy_a(reallocator, array, array##_size, &(elem), 1) |
|
439 |
|
440 /** |
|
441 * Convenience macro that uses cx_array_add() with a default layout and |
|
442 * the default reallocator. |
|
443 * |
|
444 * @param array the name of the array (NOT a pointer or alias to the array) |
|
445 * @param elem the element to add (NOT a pointer, address is automatically taken) |
|
446 * @retval zero success |
|
447 * @retval non-zero failure |
|
448 * @see CX_ARRAY_DECLARE() |
|
449 * @see cx_array_simple_add_a() |
|
450 */ |
|
451 #define cx_array_simple_add(array, elem) \ |
|
452 cx_array_simple_add_a(cx_array_default_reallocator, array, elem) |
|
453 |
|
454 /** |
|
455 * Inserts a sorted array into another sorted array. |
|
456 * |
|
457 * If either the target or the source array is not already sorted with respect |
|
458 * to the specified @p cmp_func, the behavior is undefined. |
|
459 * |
|
460 * If the capacity is insufficient to hold the new data, a reallocation |
|
461 * attempt is made. |
|
462 * You can create your own reallocator by hand, use #cx_array_default_reallocator, |
|
463 * or use the convenience function cx_array_reallocator() to create a custom reallocator. |
197 * |
464 * |
198 * @param target a pointer to the target array |
465 * @param target a pointer to the target array |
199 * @param size a pointer to the size of the target array |
466 * @param size a pointer to the size of the target array |
200 * @param capacity a pointer to the target array's capacity - must not be \c NULL |
467 * @param capacity a pointer to the capacity of the target array |
201 * @param elem_size the size of one element |
|
202 * @param elem a pointer to the element to add |
|
203 * @param reallocator the array reallocator to use, or \c NULL if reallocation shall not happen |
|
204 * @return zero on success, non-zero error code on failure |
|
205 */ |
|
206 #define cx_array_add(target, size, capacity, elem_size, elem, reallocator) \ |
|
207 cx_array_copy((void**)(target), size, capacity, *(size), elem, elem_size, 1, reallocator) |
|
208 |
|
209 /** |
|
210 * Convenience macro that uses cx_array_add() with a default layout and |
|
211 * the default reallocator. |
|
212 * |
|
213 * @param array the name of the array (NOT a pointer to the array) |
|
214 * @param elem the element to add (NOT a pointer, address is automatically taken) |
|
215 * @see CX_ARRAY_DECLARE() |
|
216 */ |
|
217 #define cx_array_simple_add(array, elem) \ |
|
218 cx_array_simple_copy(array, array##_size, &(elem), 1) |
|
219 |
|
220 |
|
221 /** |
|
222 * Inserts a sorted array into another sorted array. |
|
223 * |
|
224 * If either the target or the source array is not already sorted with respect |
|
225 * to the specified \p cmp_func, the behavior is undefined. |
|
226 * |
|
227 * If the capacity is insufficient to hold the new data, a reallocation |
|
228 * attempt is made. |
|
229 * |
|
230 * @param target a pointer to the target array |
|
231 * @param size a pointer to the size of the target array |
|
232 * @param capacity a pointer to the target array's capacity |
|
233 * @param cmp_func the compare function for the elements |
468 * @param cmp_func the compare function for the elements |
234 * @param src the source array |
469 * @param src the source array |
235 * @param elem_size the size of one element |
470 * @param elem_size the size of one element |
236 * @param elem_count the number of elements to insert |
471 * @param elem_count the number of elements to insert |
237 * @param reallocator the array reallocator to use |
472 * @param reallocator the array reallocator to use |
238 * @return zero on success, non-zero error code on failure |
473 * (@c NULL defaults to #cx_array_default_reallocator) |
239 */ |
474 * @retval zero success |
240 __attribute__((__nonnull__)) |
475 * @retval non-zero failure |
241 enum cx_array_result cx_array_insert_sorted( |
476 */ |
|
477 cx_attr_nonnull_arg(1, 2, 3, 5) |
|
478 int cx_array_insert_sorted( |
242 void **target, |
479 void **target, |
243 size_t *size, |
480 size_t *size, |
244 size_t *capacity, |
481 size_t *capacity, |
245 cx_compare_func cmp_func, |
482 cx_compare_func cmp_func, |
246 const void *src, |
483 const void *src, |
247 size_t elem_size, |
484 size_t elem_size, |
248 size_t elem_count, |
485 size_t elem_count, |
249 struct cx_array_reallocator_s *reallocator |
486 CxArrayReallocator *reallocator |
250 ); |
487 ); |
251 |
488 |
252 /** |
489 /** |
253 * Inserts an element into a sorted array. |
490 * Inserts an element into a sorted array. |
254 * |
491 * |
255 * If the target array is not already sorted with respect |
492 * If the target array is not already sorted with respect |
256 * to the specified \p cmp_func, the behavior is undefined. |
493 * to the specified @p cmp_func, the behavior is undefined. |
257 * |
494 * |
258 * If the capacity is insufficient to hold the new data, a reallocation |
495 * If the capacity is insufficient to hold the new data, a reallocation |
259 * attempt is made. |
496 * attempt is made. |
260 * |
497 * |
261 * @param target a pointer to the target array |
498 * The \@ SIZE_TYPE is flexible and can be any unsigned integer type. |
262 * @param size a pointer to the size of the target array |
499 * It is important, however, that @p size and @p capacity are pointers to |
263 * @param capacity a pointer to the target array's capacity |
500 * variables of the same type. |
264 * @param elem_size the size of one element |
501 * |
265 * @param elem a pointer to the element to add |
502 * @param target (@c void**) a pointer to the target array |
266 * @param reallocator the array reallocator to use |
503 * @param size (@c SIZE_TYPE*) a pointer to the size of the target array |
267 * @return zero on success, non-zero error code on failure |
504 * @param capacity (@c SIZE_TYPE*) a pointer to the capacity of the target array |
|
505 * @param elem_size (@c size_t) the size of one element |
|
506 * @param elem (@c void*) a pointer to the element to add |
|
507 * @param cmp_func (@c cx_cmp_func) the compare function for the elements |
|
508 * @param reallocator (@c CxArrayReallocator*) the array reallocator to use |
|
509 * @retval zero success |
|
510 * @retval non-zero failure |
268 */ |
511 */ |
269 #define cx_array_add_sorted(target, size, capacity, elem_size, elem, cmp_func, reallocator) \ |
512 #define cx_array_add_sorted(target, size, capacity, elem_size, elem, cmp_func, reallocator) \ |
270 cx_array_insert_sorted((void**)(target), size, capacity, cmp_func, elem, elem_size, 1, reallocator) |
513 cx_array_insert_sorted((void**)(target), size, capacity, cmp_func, elem, elem_size, 1, reallocator) |
271 |
514 |
272 /** |
515 /** |
273 * Convenience macro for cx_array_add_sorted() with a default |
516 * Convenience macro for cx_array_add_sorted() with a default |
|
517 * layout and the specified reallocator. |
|
518 * |
|
519 * @param reallocator (@c CxArrayReallocator*) the array reallocator to use |
|
520 * @param array the name of the array (NOT a pointer or alias to the array) |
|
521 * @param elem the element to add (NOT a pointer, address is automatically taken) |
|
522 * @param cmp_func (@c cx_cmp_func) the compare function for the elements |
|
523 * @retval zero success |
|
524 * @retval non-zero failure |
|
525 * @see CX_ARRAY_DECLARE() |
|
526 * @see cx_array_simple_add_sorted() |
|
527 */ |
|
528 #define cx_array_simple_add_sorted_a(reallocator, array, elem, cmp_func) \ |
|
529 cx_array_add_sorted(&array, &(array##_size), &(array##_capacity), \ |
|
530 sizeof((array)[0]), &(elem), cmp_func, reallocator) |
|
531 |
|
532 /** |
|
533 * Convenience macro for cx_array_add_sorted() with a default |
274 * layout and the default reallocator. |
534 * layout and the default reallocator. |
275 * |
535 * |
276 * @param array the name of the array (NOT a pointer to the array) |
536 * @param array the name of the array (NOT a pointer or alias to the array) |
277 * @param elem the element to add (NOT a pointer, address is automatically taken) |
537 * @param elem the element to add (NOT a pointer, address is automatically taken) |
278 * @param cmp_func the compare function for the elements |
538 * @param cmp_func (@c cx_cmp_func) the compare function for the elements |
279 * @see CX_ARRAY_DECLARE() |
539 * @retval zero success |
|
540 * @retval non-zero failure |
|
541 * @see CX_ARRAY_DECLARE() |
|
542 * @see cx_array_simple_add_sorted_a() |
280 */ |
543 */ |
281 #define cx_array_simple_add_sorted(array, elem, cmp_func) \ |
544 #define cx_array_simple_add_sorted(array, elem, cmp_func) \ |
282 cx_array_add_sorted(&array, &(array##_size), &(array##_capacity), \ |
545 cx_array_simple_add_sorted_a(NULL, array, elem, cmp_func) |
283 sizeof((array)[0]), &(elem), cmp_func, cx_array_default_reallocator) |
546 |
|
547 /** |
|
548 * Convenience macro for cx_array_insert_sorted() with a default |
|
549 * layout and the specified reallocator. |
|
550 * |
|
551 * @param reallocator (@c CxArrayReallocator*) the array reallocator to use |
|
552 * @param array the name of the array (NOT a pointer or alias to the array) |
|
553 * @param src (@c void*) pointer to the source array |
|
554 * @param n (@c size_t) number of elements in the source array |
|
555 * @param cmp_func (@c cx_cmp_func) the compare function for the elements |
|
556 * @retval zero success |
|
557 * @retval non-zero failure |
|
558 * @see CX_ARRAY_DECLARE() |
|
559 * @see cx_array_simple_insert_sorted() |
|
560 */ |
|
561 #define cx_array_simple_insert_sorted_a(reallocator, array, src, n, cmp_func) \ |
|
562 cx_array_insert_sorted((void**)(&array), &(array##_size), &(array##_capacity), \ |
|
563 cmp_func, src, sizeof((array)[0]), n, reallocator) |
284 |
564 |
285 /** |
565 /** |
286 * Convenience macro for cx_array_insert_sorted() with a default |
566 * Convenience macro for cx_array_insert_sorted() with a default |
287 * layout and the default reallocator. |
567 * layout and the default reallocator. |
288 * |
568 * |
289 * @param array the name of the array (NOT a pointer to the array) |
569 * @param array the name of the array (NOT a pointer or alias to the array) |
290 * @param src pointer to the source array |
570 * @param src (@c void*) pointer to the source array |
291 * @param n number of elements in the source array |
571 * @param n (@c size_t) number of elements in the source array |
292 * @param cmp_func the compare function for the elements |
572 * @param cmp_func (@c cx_cmp_func) the compare function for the elements |
293 * @see CX_ARRAY_DECLARE() |
573 * @retval zero success |
|
574 * @retval non-zero failure |
|
575 * @see CX_ARRAY_DECLARE() |
|
576 * @see cx_array_simple_insert_sorted_a() |
294 */ |
577 */ |
295 #define cx_array_simple_insert_sorted(array, src, n, cmp_func) \ |
578 #define cx_array_simple_insert_sorted(array, src, n, cmp_func) \ |
296 cx_array_insert_sorted((void**)(&array), &(array##_size), &(array##_capacity), \ |
579 cx_array_simple_insert_sorted_a(NULL, array, src, n, cmp_func) |
297 cmp_func, src, sizeof((array)[0]), n, cx_array_default_reallocator) |
|
298 |
|
299 |
580 |
300 /** |
581 /** |
301 * Searches the largest lower bound in a sorted array. |
582 * Searches the largest lower bound in a sorted array. |
302 * |
583 * |
303 * In other words, this function returns the index of the largest element |
584 * In other words, this function returns the index of the largest element |
304 * in \p arr that is less or equal to \p elem with respect to \p cmp_func. |
585 * in @p arr that is less or equal to @p elem with respect to @p cmp_func. |
305 * When no such element exists, \p size is returned. |
586 * When no such element exists, @p size is returned. |
306 * |
587 * |
307 * If \p elem is contained in the array, this is identical to |
588 * If @p elem is contained in the array, this is identical to |
308 * #cx_array_binary_search(). |
589 * #cx_array_binary_search(). |
309 * |
590 * |
310 * If the array is not sorted with respect to the \p cmp_func, the behavior |
591 * If the array is not sorted with respect to the @p cmp_func, the behavior |
311 * is undefined. |
592 * is undefined. |
312 * |
593 * |
313 * @param arr the array to search |
594 * @param arr the array to search |
314 * @param size the size of the array |
595 * @param size the size of the array |
315 * @param elem_size the size of one element |
596 * @param elem_size the size of one element |
316 * @param elem the element to find |
597 * @param elem the element to find |
317 * @param cmp_func the compare function |
598 * @param cmp_func the compare function |
318 * @return the index of the largest lower bound, or \p size |
599 * @return the index of the largest lower bound, or @p size |
319 */ |
600 * @see cx_array_binary_search_sup() |
320 __attribute__((__nonnull__)) |
601 * @see cx_array_binary_search() |
|
602 */ |
|
603 cx_attr_nonnull |
321 size_t cx_array_binary_search_inf( |
604 size_t cx_array_binary_search_inf( |
322 const void *arr, |
605 const void *arr, |
323 size_t size, |
606 size_t size, |
324 size_t elem_size, |
607 size_t elem_size, |
325 const void *elem, |
608 const void *elem, |
327 ); |
610 ); |
328 |
611 |
329 /** |
612 /** |
330 * Searches an item in a sorted array. |
613 * Searches an item in a sorted array. |
331 * |
614 * |
332 * If the array is not sorted with respect to the \p cmp_func, the behavior |
615 * If the array is not sorted with respect to the @p cmp_func, the behavior |
333 * is undefined. |
616 * is undefined. |
334 * |
617 * |
335 * @param arr the array to search |
618 * @param arr the array to search |
336 * @param size the size of the array |
619 * @param size the size of the array |
337 * @param elem_size the size of one element |
620 * @param elem_size the size of one element |
338 * @param elem the element to find |
621 * @param elem the element to find |
339 * @param cmp_func the compare function |
622 * @param cmp_func the compare function |
340 * @return the index of the element in the array, or \p size if the element |
623 * @return the index of the element in the array, or @p size if the element |
341 * cannot be found |
624 * cannot be found |
342 */ |
625 * @see cx_array_binary_search_inf() |
343 __attribute__((__nonnull__)) |
626 * @see cx_array_binary_search_sup() |
344 static inline size_t cx_array_binary_search( |
627 */ |
|
628 cx_attr_nonnull |
|
629 size_t cx_array_binary_search( |
345 const void *arr, |
630 const void *arr, |
346 size_t size, |
631 size_t size, |
347 size_t elem_size, |
632 size_t elem_size, |
348 const void *elem, |
633 const void *elem, |
349 cx_compare_func cmp_func |
634 cx_compare_func cmp_func |
350 ) { |
635 ); |
351 size_t index = cx_array_binary_search_inf( |
|
352 arr, size, elem_size, elem, cmp_func |
|
353 ); |
|
354 if (index < size && cmp_func(((const char *) arr) + index * elem_size, elem) == 0) { |
|
355 return index; |
|
356 } else { |
|
357 return size; |
|
358 } |
|
359 } |
|
360 |
636 |
361 /** |
637 /** |
362 * Searches the smallest upper bound in a sorted array. |
638 * Searches the smallest upper bound in a sorted array. |
363 * |
639 * |
364 * In other words, this function returns the index of the smallest element |
640 * In other words, this function returns the index of the smallest element |
365 * in \p arr that is greater or equal to \p elem with respect to \p cmp_func. |
641 * in @p arr that is greater or equal to @p elem with respect to @p cmp_func. |
366 * When no such element exists, \p size is returned. |
642 * When no such element exists, @p size is returned. |
367 * |
643 * |
368 * If \p elem is contained in the array, this is identical to |
644 * If @p elem is contained in the array, this is identical to |
369 * #cx_array_binary_search(). |
645 * #cx_array_binary_search(). |
370 * |
646 * |
371 * If the array is not sorted with respect to the \p cmp_func, the behavior |
647 * If the array is not sorted with respect to the @p cmp_func, the behavior |
372 * is undefined. |
648 * is undefined. |
373 * |
649 * |
374 * @param arr the array to search |
650 * @param arr the array to search |
375 * @param size the size of the array |
651 * @param size the size of the array |
376 * @param elem_size the size of one element |
652 * @param elem_size the size of one element |
377 * @param elem the element to find |
653 * @param elem the element to find |
378 * @param cmp_func the compare function |
654 * @param cmp_func the compare function |
379 * @return the index of the smallest upper bound, or \p size |
655 * @return the index of the smallest upper bound, or @p size |
380 */ |
656 * @see cx_array_binary_search_inf() |
381 __attribute__((__nonnull__)) |
657 * @see cx_array_binary_search() |
382 static inline size_t cx_array_binary_search_sup( |
658 */ |
|
659 cx_attr_nonnull |
|
660 size_t cx_array_binary_search_sup( |
383 const void *arr, |
661 const void *arr, |
384 size_t size, |
662 size_t size, |
385 size_t elem_size, |
663 size_t elem_size, |
386 const void *elem, |
664 const void *elem, |
387 cx_compare_func cmp_func |
665 cx_compare_func cmp_func |
388 ) { |
666 ); |
389 size_t inf = cx_array_binary_search_inf(arr, size, elem_size, elem, cmp_func); |
|
390 if (inf == size) { |
|
391 // no infimum means, first element is supremum |
|
392 return 0; |
|
393 } else if (cmp_func(((const char *) arr) + inf * elem_size, elem) == 0) { |
|
394 return inf; |
|
395 } else { |
|
396 return inf + 1; |
|
397 } |
|
398 } |
|
399 |
667 |
400 /** |
668 /** |
401 * Swaps two array elements. |
669 * Swaps two array elements. |
402 * |
670 * |
403 * @param arr the array |
671 * @param arr the array |
404 * @param elem_size the element size |
672 * @param elem_size the element size |
405 * @param idx1 index of first element |
673 * @param idx1 index of first element |
406 * @param idx2 index of second element |
674 * @param idx2 index of second element |
407 */ |
675 */ |
408 __attribute__((__nonnull__)) |
676 cx_attr_nonnull |
409 void cx_array_swap( |
677 void cx_array_swap( |
410 void *arr, |
678 void *arr, |
411 size_t elem_size, |
679 size_t elem_size, |
412 size_t idx1, |
680 size_t idx1, |
413 size_t idx2 |
681 size_t idx2 |
414 ); |
682 ); |
415 |
683 |
416 /** |
684 /** |
417 * Allocates an array list for storing elements with \p elem_size bytes each. |
685 * Allocates an array list for storing elements with @p elem_size bytes each. |
418 * |
686 * |
419 * If \p elem_size is CX_STORE_POINTERS, the created list will be created as if |
687 * If @p elem_size is CX_STORE_POINTERS, the created list will be created as if |
420 * cxListStorePointers() was called immediately after creation and the compare |
688 * cxListStorePointers() was called immediately after creation and the compare |
421 * function will be automatically set to cx_cmp_ptr(), if none is given. |
689 * function will be automatically set to cx_cmp_ptr(), if none is given. |
422 * |
690 * |
423 * @param allocator the allocator for allocating the list memory |
691 * @param allocator the allocator for allocating the list memory |
424 * (if \c NULL the cxDefaultAllocator will be used) |
692 * (if @c NULL, a default stdlib allocator will be used) |
425 * @param comparator the comparator for the elements |
693 * @param comparator the comparator for the elements |
426 * (if \c NULL, and the list is not storing pointers, sort and find |
694 * (if @c NULL, and the list is not storing pointers, sort and find |
427 * functions will not work) |
695 * functions will not work) |
428 * @param elem_size the size of each element in bytes |
696 * @param elem_size the size of each element in bytes |
429 * @param initial_capacity the initial number of elements the array can store |
697 * @param initial_capacity the initial number of elements the array can store |
430 * @return the created list |
698 * @return the created list |
431 */ |
699 */ |
|
700 cx_attr_nodiscard |
|
701 cx_attr_malloc |
|
702 cx_attr_dealloc(cxListFree, 1) |
432 CxList *cxArrayListCreate( |
703 CxList *cxArrayListCreate( |
433 const CxAllocator *allocator, |
704 const CxAllocator *allocator, |
434 cx_compare_func comparator, |
705 cx_compare_func comparator, |
435 size_t elem_size, |
706 size_t elem_size, |
436 size_t initial_capacity |
707 size_t initial_capacity |
437 ); |
708 ); |
438 |
709 |
439 /** |
710 /** |
440 * Allocates an array list for storing elements with \p elem_size bytes each. |
711 * Allocates an array list for storing elements with @p elem_size bytes each. |
441 * |
712 * |
442 * The list will use the cxDefaultAllocator and \em NO compare function. |
713 * The list will use the cxDefaultAllocator and @em NO compare function. |
443 * If you want to call functions that need a compare function, you have to |
714 * If you want to call functions that need a compare function, you have to |
444 * set it immediately after creation or use cxArrayListCreate(). |
715 * set it immediately after creation or use cxArrayListCreate(). |
445 * |
716 * |
446 * If \p elem_size is CX_STORE_POINTERS, the created list will be created as if |
717 * If @p elem_size is CX_STORE_POINTERS, the created list will be created as if |
447 * cxListStorePointers() was called immediately after creation and the compare |
718 * cxListStorePointers() was called immediately after creation and the compare |
448 * function will be automatically set to cx_cmp_ptr(). |
719 * function will be automatically set to cx_cmp_ptr(). |
449 * |
720 * |
450 * @param elem_size the size of each element in bytes |
721 * @param elem_size (@c size_t) the size of each element in bytes |
451 * @param initial_capacity the initial number of elements the array can store |
722 * @param initial_capacity (@c size_t) the initial number of elements the array can store |
452 * @return the created list |
723 * @return the created list |
453 */ |
724 */ |
454 #define cxArrayListCreateSimple(elem_size, initial_capacity) \ |
725 #define cxArrayListCreateSimple(elem_size, initial_capacity) \ |
455 cxArrayListCreate(NULL, NULL, elem_size, initial_capacity) |
726 cxArrayListCreate(NULL, NULL, elem_size, initial_capacity) |
456 |
727 |