1 /* Auto-reallocating array for arbitrary member types. */ 2 /* 3 * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* Usage: 19 * 20 * ARRAYLIST(any_type_t) list; 21 * // OR 22 * typedef ARRAYLIST(any_type_t) any_type_list_t; 23 * any_type_list_t list; 24 * 25 * // pass the number of (at first unused) members to add on each realloc: 26 * ARRAYLIST_INIT(list, 128); 27 * any_type_t *x; 28 * while (bar) { 29 * // This enlarges the allocated array as needed; 30 * // list.head may change due to realloc: 31 * ARRAYLIST_ADD(x, list); 32 * if (!x) 33 * return ENOMEM; 34 * *x = random_foo_value; 35 * } 36 * for (i = 0; i < list.len; i++) 37 * printf("%s", foo_to_str(list.head[i])); 38 * ARRAYLIST_FREE(list); 39 */ 40 #define ARRAYLIST(MEMBER_TYPE) \ 41 struct { \ 42 MEMBER_TYPE *head; \ 43 MEMBER_TYPE *p; \ 44 unsigned int len; \ 45 unsigned int allocated; \ 46 unsigned int alloc_blocksize; \ 47 } 48 49 #define ARRAYLIST_INIT(ARRAY_LIST, ALLOC_BLOCKSIZE) do { \ 50 (ARRAY_LIST).head = NULL; \ 51 (ARRAY_LIST).len = 0; \ 52 (ARRAY_LIST).allocated = 0; \ 53 (ARRAY_LIST).alloc_blocksize = ALLOC_BLOCKSIZE; \ 54 } while(0) 55 56 #define ARRAYLIST_ADD(NEW_ITEM_P, ARRAY_LIST) do { \ 57 if ((ARRAY_LIST).len && !(ARRAY_LIST).allocated) { \ 58 NEW_ITEM_P = NULL; \ 59 break; \ 60 } \ 61 if ((ARRAY_LIST).head == NULL \ 62 || (ARRAY_LIST).allocated < (ARRAY_LIST).len + 1) { \ 63 (ARRAY_LIST).p = recallocarray((ARRAY_LIST).head, \ 64 (ARRAY_LIST).len, \ 65 (ARRAY_LIST).allocated + \ 66 ((ARRAY_LIST).allocated ? \ 67 (ARRAY_LIST).allocated / 2 : \ 68 (ARRAY_LIST).alloc_blocksize ? \ 69 (ARRAY_LIST).alloc_blocksize : 8), \ 70 sizeof(*(ARRAY_LIST).head)); \ 71 if ((ARRAY_LIST).p == NULL) { \ 72 NEW_ITEM_P = NULL; \ 73 break; \ 74 } \ 75 (ARRAY_LIST).allocated += \ 76 (ARRAY_LIST).allocated ? \ 77 (ARRAY_LIST).allocated / 2 : \ 78 (ARRAY_LIST).alloc_blocksize ? \ 79 (ARRAY_LIST).alloc_blocksize : 8, \ 80 (ARRAY_LIST).head = (ARRAY_LIST).p; \ 81 (ARRAY_LIST).p = NULL; \ 82 }; \ 83 if ((ARRAY_LIST).head == NULL \ 84 || (ARRAY_LIST).allocated < (ARRAY_LIST).len + 1) { \ 85 NEW_ITEM_P = NULL; \ 86 break; \ 87 } \ 88 (NEW_ITEM_P) = &(ARRAY_LIST).head[(ARRAY_LIST).len]; \ 89 (ARRAY_LIST).len++; \ 90 } while (0) 91 92 #define ARRAYLIST_INSERT(NEW_ITEM_P, ARRAY_LIST, AT_IDX) do { \ 93 int _at_idx = (AT_IDX); \ 94 ARRAYLIST_ADD(NEW_ITEM_P, ARRAY_LIST); \ 95 if ((NEW_ITEM_P) \ 96 && _at_idx >= 0 \ 97 && _at_idx < (ARRAY_LIST).len) { \ 98 memmove(&(ARRAY_LIST).head[_at_idx + 1], \ 99 &(ARRAY_LIST).head[_at_idx], \ 100 ((ARRAY_LIST).len - 1 - _at_idx) \ 101 * sizeof(*(ARRAY_LIST).head)); \ 102 (NEW_ITEM_P) = &(ARRAY_LIST).head[_at_idx]; \ 103 }; \ 104 } while (0) 105 106 #define ARRAYLIST_CLEAR(ARRAY_LIST) \ 107 (ARRAY_LIST).len = 0 108 109 #define ARRAYLIST_FREE(ARRAY_LIST) \ 110 do { \ 111 if ((ARRAY_LIST).head && (ARRAY_LIST).allocated) \ 112 free((ARRAY_LIST).head); \ 113 ARRAYLIST_INIT(ARRAY_LIST, (ARRAY_LIST).alloc_blocksize); \ 114 } while(0) 115 116 #define ARRAYLIST_FOREACH(ITEM_P, ARRAY_LIST) \ 117 for ((ITEM_P) = (ARRAY_LIST).head; \ 118 (ITEM_P) - (ARRAY_LIST).head < (ARRAY_LIST).len; \ 119 (ITEM_P)++) 120 121 #define ARRAYLIST_IDX(ITEM_P, ARRAY_LIST) ((ITEM_P) - (ARRAY_LIST).head) 122