comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/tkArray.h @ 69:33d812a61356

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
comparison
equal deleted inserted replaced
67:0e9998148a16 69:33d812a61356
1 /*
2 * tkArray.h --
3 *
4 * An array is a sequence of items, stored in a contiguous memory region.
5 * Random access to any item is very fast. New items can be either appended
6 * or prepended. An array may be traversed in the forward or backward direction.
7 *
8 * Copyright (c) 2018-2019 by Gregor Cramer.
9 *
10 * See the file "license.terms" for information on usage and redistribution of
11 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 */
13
14 /*
15 * Note that this file will not be included in header files, it is the purpose
16 * of this file to be included in source files only. Thus we are not using the
17 * prefix "Tk_" here for functions, because all the functions have private scope.
18 */
19
20 /*
21 * -------------------------------------------------------------------------------
22 * Use the array in the following way:
23 * -------------------------------------------------------------------------------
24 * typedef struct { int key, value; } Pair;
25 * TK_PTR_ARRAY_DEFINE(MyArray, Pair);
26 * MyArray *arr = NULL;
27 * if (MyArray_IsEmpty(arr)) {
28 * MyArray_Append(&arr, MakePair(1, 2));
29 * MyArray_Append(&arr, MakePair(2, 3));
30 * for (i = 0; i < MyArray_Size(arr); ++i) {
31 * Pair *p = MyArray_Get(arr, i);
32 * printf("%d -> %d\n", p->key, p->value);
33 * ckfree(p);
34 * }
35 * MyArray_Free(&arr);
36 * assert(arr == NULL);
37 * }
38 * -------------------------------------------------------------------------------
39 * Or with aggregated elements:
40 * -------------------------------------------------------------------------------
41 * typedef struct { int key, value; } Pair;
42 * TK_ARRAY_DEFINE(MyArray, Pair);
43 * Pair p1 = { 1, 2 };
44 * Pair p2 = { 2, 3 };
45 * MyArray *arr = NULL;
46 * if (MyArray_IsEmpty(arr)) {
47 * MyArray_Append(&arr, p1);
48 * MyArray_Append(&arr, p2);
49 * for (i = 0; i < MyArray_Size(arr); ++i) {
50 * const Pair *p = MyArray_Get(arr, i);
51 * printf("%d -> %d\n", p->key, p->value);
52 * }
53 * MyArray_Free(&arr);
54 * assert(arr == NULL);
55 * }
56 * -------------------------------------------------------------------------------
57 */
58
59 /*************************************************************************/
60 /*
61 * Two array types will be provided:
62 * Use TK_ARRAY_DEFINE if your array is aggregating the elements. Use
63 * TK_PTR_ARRAY_DEFINE if your array contains pointers to elements. But
64 * in latter case the array is not responsible for the lifetime of the
65 * elements.
66 */
67 /*************************************************************************/
68 /*
69 * Array_ElemSize: Returns the memory size for one array element.
70 */
71 /*************************************************************************/
72 /*
73 * Array_BufferSize: Returns the memory size for given number of elements.
74 */
75 /*************************************************************************/
76 /*
77 * Array_IsEmpty: Array is empty?
78 */
79 /*************************************************************************/
80 /*
81 * Array_Size: Number of elements in array.
82 */
83 /*************************************************************************/
84 /*
85 * Array_Capacity: Capacity of given array. This is the maximal number of
86 * elements fitting into current array memory without resizing the buffer.
87 */
88 /*************************************************************************/
89 /*
90 * Array_SetSize: Set array size, new size must not exceed the capacity of
91 * the array. This function has to be used with care when increasing the
92 * array size.
93 */
94 /*************************************************************************/
95 /*
96 * Array_First: Returns position of first element in array. Given array
97 * may be NULL.
98 */
99 /*************************************************************************/
100 /*
101 * Array_Last: Returns position after last element in array. Given array
102 * may be empty.
103 */
104 /*************************************************************************/
105 /*
106 * Array_Front: Returns first element in array. Given array must not be
107 * empty.
108 */
109 /*************************************************************************/
110 /*
111 * Array_Back: Returns last element in array. Given array must not be
112 * empty.
113 */
114 /*************************************************************************/
115 /*
116 * Array_Resize: Resize buffer of array for given number of elements. The
117 * array may grow or shrink. Note that this function is not initializing
118 * the increased buffer.
119 */
120 /*************************************************************************/
121 /*
122 * Array_ResizeAndClear: Resize buffer of array for given number of
123 * elements. The array may grow or shrink. The increased memory will be
124 * filled with zeroes.
125 */
126 /*************************************************************************/
127 /*
128 * Array_Clear: Fill specified range with zeroes.
129 */
130 /*************************************************************************/
131 /*
132 * Array_Free: Resize array to size zero. This function will release the
133 * array buffer.
134 */
135 /*************************************************************************/
136 /*
137 * Array_Append: Insert given element after end of array.
138 */
139 /*************************************************************************/
140 /*
141 * Array_PopBack: Shrink array by one element. Given array must not be
142 * empty.
143 */
144 /*************************************************************************/
145 /*
146 * Array_Get: Random access to array element at given position. The given
147 * index must not exceed current array size.
148 */
149 /*************************************************************************/
150 /*
151 * Array_Set: Replace array element at given position with new value. The
152 * given index must not exceed current array size.
153 */
154 /*************************************************************************/
155 /*
156 * Array_Find: Return index position of element which matches given
157 * argument. If not found then -1 will be returned.
158 */
159 /*************************************************************************/
160
161 #ifndef TK_ARRAY_DEFINED
162 #define TK_ARRAY_DEFINED
163
164 #include "tkInt.h"
165
166 #if defined(__GNUC__) || defined(__clang__)
167 # define __TK_ARRAY_UNUSED __attribute__((unused))
168 #else
169 # define __TK_ARRAY_UNUSED
170 #endif
171
172 #define TK_ARRAY_DEFINE(AT, ElemType) /* AT = type of array */ \
173 /* ------------------------------------------------------------------------- */ \
174 typedef struct AT { \
175 size_t size; \
176 size_t capacity; \
177 ElemType buf[1]; \
178 } AT; \
179 \
180 __TK_ARRAY_UNUSED \
181 static void \
182 AT##_Init(AT *arr) \
183 { \
184 assert(arr); \
185 arr->size = 0; \
186 arr->capacity = 0; \
187 } \
188 \
189 __TK_ARRAY_UNUSED \
190 static size_t \
191 AT##_ElemSize() \
192 { \
193 return sizeof(ElemType); \
194 } \
195 \
196 __TK_ARRAY_UNUSED \
197 static size_t \
198 AT##_BufferSize(size_t numElems) \
199 { \
200 return numElems*sizeof(ElemType); \
201 } \
202 \
203 __TK_ARRAY_UNUSED \
204 static int \
205 AT##_IsEmpty(const AT *arr) \
206 { \
207 assert(!arr || arr->size != 0xdeadbeef); \
208 return !arr || arr->size == 0u; \
209 } \
210 \
211 __TK_ARRAY_UNUSED \
212 static size_t \
213 AT##_Size(const AT *arr) \
214 { \
215 assert(!arr || arr->size != 0xdeadbeef); \
216 return arr ? arr->size : 0u; \
217 } \
218 \
219 __TK_ARRAY_UNUSED \
220 static size_t \
221 AT##_Capacity(const AT *arr) \
222 { \
223 assert(!arr || arr->size != 0xdeadbeef); \
224 return arr ? arr->capacity : 0u; \
225 } \
226 \
227 __TK_ARRAY_UNUSED \
228 static ElemType * \
229 AT##_First(AT *arr) \
230 { \
231 assert(!arr || arr->size != 0xdeadbeef); \
232 return arr ? arr->buf : NULL; \
233 } \
234 \
235 __TK_ARRAY_UNUSED \
236 static ElemType * \
237 AT##_Last(AT *arr) \
238 { \
239 assert(!arr || arr->size != 0xdeadbeef); \
240 return arr ? arr->buf + arr->size : NULL; \
241 } \
242 \
243 __TK_ARRAY_UNUSED \
244 static ElemType * \
245 AT##_Front(AT *arr) \
246 { \
247 assert(arr); \
248 assert(arr->size != 0xdeadbeef); \
249 assert(!AT##_IsEmpty(arr)); \
250 return &arr->buf[0]; \
251 } \
252 \
253 __TK_ARRAY_UNUSED \
254 static ElemType * \
255 AT##_Back(AT *arr) \
256 { \
257 assert(arr); \
258 assert(arr->size != 0xdeadbeef); \
259 assert(!AT##_IsEmpty(arr)); \
260 return &arr->buf[arr->size - 1]; \
261 } \
262 \
263 __TK_ARRAY_UNUSED \
264 static void \
265 AT##_Resize(AT **arrp, size_t newSize) \
266 { \
267 assert(arrp); \
268 assert(!*arrp || (*arrp)->size != 0xdeadbeef); \
269 if (newSize == 0) { \
270 assert(!*arrp || ((*arrp)->size = 0xdeadbeef)); \
271 ckfree(*arrp); \
272 *arrp = NULL; \
273 } else { \
274 int init = *arrp == NULL; \
275 size_t memSize = AT##_BufferSize(newSize - 1) + sizeof(AT); \
276 *arrp = ckrealloc(*arrp, memSize); \
277 if (init) { \
278 (*arrp)->size = 0; \
279 } else if (newSize < (*arrp)->size) { \
280 (*arrp)->size = newSize; \
281 } \
282 (*arrp)->capacity = newSize; \
283 } \
284 } \
285 \
286 __TK_ARRAY_UNUSED \
287 static void \
288 AT##_Clear(AT *arr, size_t from, size_t to) \
289 { \
290 assert(arr); \
291 assert(arr->size != 0xdeadbeef); \
292 assert(to <= AT##_Capacity(arr)); \
293 assert(from <= to); \
294 memset(arr->buf + from, 0, AT##_BufferSize(to - from)); \
295 } \
296 \
297 __TK_ARRAY_UNUSED \
298 static void \
299 AT##_ResizeAndClear(AT **arrp, size_t newSize) \
300 { \
301 size_t oldCapacity; \
302 assert(arrp); \
303 oldCapacity = *arrp ? (*arrp)->capacity : 0; \
304 AT##_Resize(arrp, newSize); \
305 if (newSize > oldCapacity) { \
306 AT##_Clear(*arrp, oldCapacity, newSize); \
307 } \
308 } \
309 \
310 __TK_ARRAY_UNUSED \
311 static void \
312 AT##_SetSize(AT *arr, size_t newSize) \
313 { \
314 assert(newSize <= AT##_Capacity(arr)); \
315 assert(!arr || arr->size != 0xdeadbeef); \
316 if (arr) { \
317 arr->size = newSize; \
318 } \
319 } \
320 \
321 __TK_ARRAY_UNUSED \
322 static void \
323 AT##_Append(AT **arrp, ElemType *elem) \
324 { \
325 assert(arrp); \
326 if (!*arrp) { \
327 AT##_Resize(arrp, 1); \
328 } else if ((*arrp)->size == (*arrp)->capacity) { \
329 AT##_Resize(arrp, (*arrp)->capacity + ((*arrp)->capacity + 1)/2); \
330 } \
331 (*arrp)->buf[(*arrp)->size++] = *elem; \
332 } \
333 \
334 __TK_ARRAY_UNUSED \
335 static size_t \
336 AT##_PopBack(AT *arr) \
337 { \
338 assert(!AT##_IsEmpty(arr)); \
339 return arr->size -= 1; \
340 } \
341 \
342 __TK_ARRAY_UNUSED \
343 static ElemType * \
344 AT##_Get(const AT *arr, size_t at) \
345 { \
346 assert(arr); \
347 assert(at < AT##_Size(arr)); \
348 return (ElemType *) &arr->buf[at]; \
349 } \
350 \
351 __TK_ARRAY_UNUSED \
352 static void \
353 AT##_Set(AT *arr, size_t at, ElemType *elem) \
354 { \
355 assert(arr); \
356 assert(at < AT##_Size(arr)); \
357 arr->buf[at] = *elem; \
358 } \
359 \
360 __TK_ARRAY_UNUSED \
361 static void \
362 AT##_Free(AT **arrp) \
363 { \
364 AT##_Resize(arrp, 0); \
365 } \
366 \
367 __TK_ARRAY_UNUSED \
368 static int \
369 AT##_Find(const AT *arr, const ElemType *elem) \
370 { \
371 assert(!arr || arr->size != 0xdeadbeef); \
372 if (arr) { \
373 const ElemType *buf = arr->buf; \
374 size_t i; \
375 for (i = 0; i < arr->size; ++i) { \
376 if (memcmp(&buf[i], elem, sizeof(ElemType)) == 0) { \
377 return (int) i; \
378 } \
379 } \
380 } \
381 return -1; \
382 } \
383 \
384 __TK_ARRAY_UNUSED \
385 static int \
386 AT##_Contains(const AT *arr, const ElemType *elem) \
387 { \
388 return AT##_Find(arr, elem) != -1; \
389 } \
390 /* ------------------------------------------------------------------------- */
391
392 #define TK_PTR_ARRAY_DEFINE(AT, ElemType) /* AT = type of array */ \
393 /* ------------------------------------------------------------------------- */ \
394 typedef struct AT { \
395 size_t size; \
396 size_t capacity; \
397 ElemType *buf[1]; \
398 } AT; \
399 \
400 __TK_ARRAY_UNUSED \
401 static size_t \
402 AT##_ElemSize() \
403 { \
404 return sizeof(ElemType); \
405 } \
406 \
407 __TK_ARRAY_UNUSED \
408 static size_t \
409 AT##_BufferSize(size_t numElems) \
410 { \
411 return numElems*sizeof(ElemType *); \
412 } \
413 \
414 __TK_ARRAY_UNUSED \
415 static int \
416 AT##_IsEmpty(const AT *arr) \
417 { \
418 assert(!arr || arr->size != 0xdeadbeef); \
419 return !arr || arr->size == 0; \
420 } \
421 \
422 __TK_ARRAY_UNUSED \
423 static ElemType ** \
424 AT##_First(AT *arr) \
425 { \
426 assert(!arr || arr->size != 0xdeadbeef); \
427 return arr ? arr->buf : NULL; \
428 } \
429 \
430 __TK_ARRAY_UNUSED \
431 static ElemType ** \
432 AT##_Last(AT *arr) \
433 { \
434 assert(!arr || arr->size != 0xdeadbeef); \
435 return arr ? arr->buf + arr->size : NULL; \
436 } \
437 \
438 __TK_ARRAY_UNUSED \
439 static ElemType * \
440 AT##_Front(AT *arr) \
441 { \
442 assert(arr); \
443 assert(arr->size != 0xdeadbeef); \
444 assert(!AT##_IsEmpty(arr)); \
445 return arr->buf[0]; \
446 } \
447 \
448 __TK_ARRAY_UNUSED \
449 static ElemType * \
450 AT##_Back(AT *arr) \
451 { \
452 assert(arr); \
453 assert(arr->size != 0xdeadbeef); \
454 assert(!AT##_IsEmpty(arr)); \
455 return arr->buf[arr->size - 1]; \
456 } \
457 \
458 __TK_ARRAY_UNUSED \
459 static size_t \
460 AT##_Size(const AT *arr) \
461 { \
462 assert(!arr || arr->size != 0xdeadbeef); \
463 return arr ? arr->size : 0; \
464 } \
465 \
466 __TK_ARRAY_UNUSED \
467 static size_t \
468 AT##_Capacity(const AT *arr) \
469 { \
470 assert(!arr || arr->size != 0xdeadbeef); \
471 return arr ? arr->capacity : 0; \
472 } \
473 \
474 __TK_ARRAY_UNUSED \
475 static void \
476 AT##_Resize(AT **arrp, size_t newCapacity) \
477 { \
478 assert(arrp); \
479 assert(!*arrp || (*arrp)->size != 0xdeadbeef); \
480 if (newCapacity == 0) { \
481 assert(!*arrp || ((*arrp)->size = 0xdeadbeef)); \
482 ckfree(*arrp); \
483 *arrp = NULL; \
484 } else { \
485 int init = *arrp == NULL; \
486 size_t memSize = AT##_BufferSize(newCapacity - 1) + sizeof(AT); \
487 *arrp = ckrealloc(*arrp, memSize); \
488 if (init) { \
489 (*arrp)->size = 0; \
490 } else if (newCapacity < (*arrp)->size) { \
491 (*arrp)->size = newCapacity; \
492 } \
493 (*arrp)->capacity = newCapacity; \
494 } \
495 } \
496 \
497 __TK_ARRAY_UNUSED \
498 static void \
499 AT##_Clear(AT *arr, size_t from, size_t to) \
500 { \
501 assert(arr); \
502 assert(arr->size != 0xdeadbeef); \
503 assert(to <= AT##_Capacity(arr)); \
504 assert(from <= to); \
505 memset(arr->buf + from, 0, AT##_BufferSize(to - from)); \
506 } \
507 \
508 __TK_ARRAY_UNUSED \
509 static void \
510 AT##_ResizeAndClear(AT **arrp, size_t newCapacity) \
511 { \
512 size_t oldCapacity; \
513 assert(arrp); \
514 oldCapacity = *arrp ? (*arrp)->capacity : 0; \
515 AT##_Resize(arrp, newCapacity); \
516 if (newCapacity > oldCapacity) { \
517 AT##_Clear(*arrp, oldCapacity, newCapacity); \
518 } \
519 } \
520 \
521 __TK_ARRAY_UNUSED \
522 static void \
523 AT##_SetSize(AT *arr, size_t newSize) \
524 { \
525 assert(arr); \
526 assert(newSize <= AT##_Capacity(arr)); \
527 arr->size = newSize; \
528 } \
529 \
530 __TK_ARRAY_UNUSED \
531 static void \
532 AT##_Append(AT **arrp, ElemType *elem) \
533 { \
534 assert(arrp); \
535 if (!*arrp) { \
536 AT##_Resize(arrp, 1); \
537 } else if ((*arrp)->size == (*arrp)->capacity) { \
538 AT##_Resize(arrp, (*arrp)->capacity + ((*arrp)->capacity + 1)/2); \
539 } \
540 (*arrp)->buf[(*arrp)->size++] = elem; \
541 } \
542 \
543 __TK_ARRAY_UNUSED \
544 static size_t \
545 AT##_PopBack(AT *arr) \
546 { \
547 assert(!AT##_IsEmpty(arr)); \
548 return arr->size -= 1; \
549 } \
550 \
551 __TK_ARRAY_UNUSED \
552 static ElemType * \
553 AT##_Get(const AT *arr, size_t at) \
554 { \
555 assert(arr); \
556 assert(at < AT##_Size(arr)); \
557 return arr->buf[at]; \
558 } \
559 \
560 __TK_ARRAY_UNUSED \
561 static void \
562 AT##_Set(AT *arr, size_t at, ElemType *elem) \
563 { \
564 assert(arr); \
565 assert(at < AT##_Size(arr)); \
566 arr->buf[at] = elem; \
567 } \
568 \
569 __TK_ARRAY_UNUSED \
570 static void \
571 AT##_Free(AT **arrp) \
572 { \
573 AT##_Resize(arrp, 0); \
574 } \
575 \
576 __TK_ARRAY_UNUSED \
577 static int \
578 AT##_Find(const AT *arr, const ElemType *elem) \
579 { \
580 assert(!arr || arr->size != 0xdeadbeef); \
581 if (arr) { \
582 ElemType *const *buf = arr->buf; \
583 size_t i; \
584 for (i = 0; i < arr->size; ++i) { \
585 if (buf[i] == elem) { \
586 return (int) i; \
587 } \
588 } \
589 } \
590 return -1; \
591 } \
592 \
593 __TK_ARRAY_UNUSED \
594 static int \
595 AT##_Contains(const AT *arr, const ElemType *elem) \
596 { \
597 return AT##_Find(arr, elem) != -1; \
598 } \
599 /* ------------------------------------------------------------------------- */
600
601 #endif /* TK_ARRAY_DEFINED */
602
603 /*
604 * Local Variables:
605 * mode: c
606 * c-basic-offset: 4
607 * fill-column: 105
608 * End:
609 * vi:set ts=8 sw=4:
610 */