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