19eb461aaSDag-Erling Smørgrav /* Auto-reallocating array for arbitrary member types. */ 29eb461aaSDag-Erling Smørgrav /* 39eb461aaSDag-Erling Smørgrav * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de> 49eb461aaSDag-Erling Smørgrav * 59eb461aaSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 69eb461aaSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 79eb461aaSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 89eb461aaSDag-Erling Smørgrav * 99eb461aaSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 109eb461aaSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 119eb461aaSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 129eb461aaSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 139eb461aaSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 149eb461aaSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 159eb461aaSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 169eb461aaSDag-Erling Smørgrav */ 179eb461aaSDag-Erling Smørgrav 189eb461aaSDag-Erling Smørgrav /* Usage: 199eb461aaSDag-Erling Smørgrav * 209eb461aaSDag-Erling Smørgrav * ARRAYLIST(any_type_t) list; 219eb461aaSDag-Erling Smørgrav * // OR 229eb461aaSDag-Erling Smørgrav * typedef ARRAYLIST(any_type_t) any_type_list_t; 239eb461aaSDag-Erling Smørgrav * any_type_list_t list; 249eb461aaSDag-Erling Smørgrav * 259eb461aaSDag-Erling Smørgrav * // pass the number of (at first unused) members to add on each realloc: 269eb461aaSDag-Erling Smørgrav * ARRAYLIST_INIT(list, 128); 279eb461aaSDag-Erling Smørgrav * any_type_t *x; 289eb461aaSDag-Erling Smørgrav * while (bar) { 299eb461aaSDag-Erling Smørgrav * // This enlarges the allocated array as needed; 309eb461aaSDag-Erling Smørgrav * // list.head may change due to realloc: 319eb461aaSDag-Erling Smørgrav * ARRAYLIST_ADD(x, list); 329eb461aaSDag-Erling Smørgrav * if (!x) 339eb461aaSDag-Erling Smørgrav * return ENOMEM; 349eb461aaSDag-Erling Smørgrav * *x = random_foo_value; 359eb461aaSDag-Erling Smørgrav * } 369eb461aaSDag-Erling Smørgrav * for (i = 0; i < list.len; i++) 379eb461aaSDag-Erling Smørgrav * printf("%s", foo_to_str(list.head[i])); 389eb461aaSDag-Erling Smørgrav * ARRAYLIST_FREE(list); 399eb461aaSDag-Erling Smørgrav */ 409eb461aaSDag-Erling Smørgrav #define ARRAYLIST(MEMBER_TYPE) \ 419eb461aaSDag-Erling Smørgrav struct { \ 429eb461aaSDag-Erling Smørgrav MEMBER_TYPE *head; \ 439eb461aaSDag-Erling Smørgrav MEMBER_TYPE *p; \ 449eb461aaSDag-Erling Smørgrav unsigned int len; \ 459eb461aaSDag-Erling Smørgrav unsigned int allocated; \ 469eb461aaSDag-Erling Smørgrav unsigned int alloc_blocksize; \ 479eb461aaSDag-Erling Smørgrav } 489eb461aaSDag-Erling Smørgrav 499eb461aaSDag-Erling Smørgrav #define ARRAYLIST_INIT(ARRAY_LIST, ALLOC_BLOCKSIZE) do { \ 509eb461aaSDag-Erling Smørgrav (ARRAY_LIST).head = NULL; \ 519eb461aaSDag-Erling Smørgrav (ARRAY_LIST).len = 0; \ 529eb461aaSDag-Erling Smørgrav (ARRAY_LIST).allocated = 0; \ 539eb461aaSDag-Erling Smørgrav (ARRAY_LIST).alloc_blocksize = ALLOC_BLOCKSIZE; \ 549eb461aaSDag-Erling Smørgrav } while(0) 559eb461aaSDag-Erling Smørgrav 569eb461aaSDag-Erling Smørgrav #define ARRAYLIST_ADD(NEW_ITEM_P, ARRAY_LIST) do { \ 579eb461aaSDag-Erling Smørgrav if ((ARRAY_LIST).len && !(ARRAY_LIST).allocated) { \ 589eb461aaSDag-Erling Smørgrav NEW_ITEM_P = NULL; \ 599eb461aaSDag-Erling Smørgrav break; \ 609eb461aaSDag-Erling Smørgrav } \ 619eb461aaSDag-Erling Smørgrav if ((ARRAY_LIST).head == NULL \ 629eb461aaSDag-Erling Smørgrav || (ARRAY_LIST).allocated < (ARRAY_LIST).len + 1) { \ 639eb461aaSDag-Erling Smørgrav (ARRAY_LIST).p = recallocarray((ARRAY_LIST).head, \ 649eb461aaSDag-Erling Smørgrav (ARRAY_LIST).len, \ 659eb461aaSDag-Erling Smørgrav (ARRAY_LIST).allocated + \ 669eb461aaSDag-Erling Smørgrav ((ARRAY_LIST).allocated ? \ 679eb461aaSDag-Erling Smørgrav (ARRAY_LIST).allocated / 2 : \ 689eb461aaSDag-Erling Smørgrav (ARRAY_LIST).alloc_blocksize ? \ 699eb461aaSDag-Erling Smørgrav (ARRAY_LIST).alloc_blocksize : 8), \ 709eb461aaSDag-Erling Smørgrav sizeof(*(ARRAY_LIST).head)); \ 719eb461aaSDag-Erling Smørgrav if ((ARRAY_LIST).p == NULL) { \ 729eb461aaSDag-Erling Smørgrav NEW_ITEM_P = NULL; \ 739eb461aaSDag-Erling Smørgrav break; \ 749eb461aaSDag-Erling Smørgrav } \ 759eb461aaSDag-Erling Smørgrav (ARRAY_LIST).allocated += \ 769eb461aaSDag-Erling Smørgrav (ARRAY_LIST).allocated ? \ 779eb461aaSDag-Erling Smørgrav (ARRAY_LIST).allocated / 2 : \ 789eb461aaSDag-Erling Smørgrav (ARRAY_LIST).alloc_blocksize ? \ 799eb461aaSDag-Erling Smørgrav (ARRAY_LIST).alloc_blocksize : 8, \ 809eb461aaSDag-Erling Smørgrav (ARRAY_LIST).head = (ARRAY_LIST).p; \ 819eb461aaSDag-Erling Smørgrav (ARRAY_LIST).p = NULL; \ 829eb461aaSDag-Erling Smørgrav }; \ 839eb461aaSDag-Erling Smørgrav if ((ARRAY_LIST).head == NULL \ 849eb461aaSDag-Erling Smørgrav || (ARRAY_LIST).allocated < (ARRAY_LIST).len + 1) { \ 859eb461aaSDag-Erling Smørgrav NEW_ITEM_P = NULL; \ 869eb461aaSDag-Erling Smørgrav break; \ 879eb461aaSDag-Erling Smørgrav } \ 889eb461aaSDag-Erling Smørgrav (NEW_ITEM_P) = &(ARRAY_LIST).head[(ARRAY_LIST).len]; \ 899eb461aaSDag-Erling Smørgrav (ARRAY_LIST).len++; \ 909eb461aaSDag-Erling Smørgrav } while (0) 919eb461aaSDag-Erling Smørgrav 929eb461aaSDag-Erling Smørgrav #define ARRAYLIST_INSERT(NEW_ITEM_P, ARRAY_LIST, AT_IDX) do { \ 939eb461aaSDag-Erling Smørgrav int _at_idx = (AT_IDX); \ 949eb461aaSDag-Erling Smørgrav ARRAYLIST_ADD(NEW_ITEM_P, ARRAY_LIST); \ 959eb461aaSDag-Erling Smørgrav if ((NEW_ITEM_P) \ 969eb461aaSDag-Erling Smørgrav && _at_idx >= 0 \ 979eb461aaSDag-Erling Smørgrav && _at_idx < (ARRAY_LIST).len) { \ 989eb461aaSDag-Erling Smørgrav memmove(&(ARRAY_LIST).head[_at_idx + 1], \ 999eb461aaSDag-Erling Smørgrav &(ARRAY_LIST).head[_at_idx], \ 1009eb461aaSDag-Erling Smørgrav ((ARRAY_LIST).len - 1 - _at_idx) \ 1019eb461aaSDag-Erling Smørgrav * sizeof(*(ARRAY_LIST).head)); \ 1029eb461aaSDag-Erling Smørgrav (NEW_ITEM_P) = &(ARRAY_LIST).head[_at_idx]; \ 1039eb461aaSDag-Erling Smørgrav }; \ 1049eb461aaSDag-Erling Smørgrav } while (0) 1059eb461aaSDag-Erling Smørgrav 1069eb461aaSDag-Erling Smørgrav #define ARRAYLIST_CLEAR(ARRAY_LIST) \ 1079eb461aaSDag-Erling Smørgrav (ARRAY_LIST).len = 0 1089eb461aaSDag-Erling Smørgrav 1099eb461aaSDag-Erling Smørgrav #define ARRAYLIST_FREE(ARRAY_LIST) \ 1109eb461aaSDag-Erling Smørgrav do { \ 1119eb461aaSDag-Erling Smørgrav if ((ARRAY_LIST).head && (ARRAY_LIST).allocated) \ 1129eb461aaSDag-Erling Smørgrav free((ARRAY_LIST).head); \ 1139eb461aaSDag-Erling Smørgrav ARRAYLIST_INIT(ARRAY_LIST, (ARRAY_LIST).alloc_blocksize); \ 1149eb461aaSDag-Erling Smørgrav } while(0) 1159eb461aaSDag-Erling Smørgrav 1169eb461aaSDag-Erling Smørgrav #define ARRAYLIST_FOREACH(ITEM_P, ARRAY_LIST) \ 1179eb461aaSDag-Erling Smørgrav for ((ITEM_P) = (ARRAY_LIST).head; \ 1189eb461aaSDag-Erling Smørgrav (ITEM_P) - (ARRAY_LIST).head < (ARRAY_LIST).len; \ 1199eb461aaSDag-Erling Smørgrav (ITEM_P)++) 1209eb461aaSDag-Erling Smørgrav 1219eb461aaSDag-Erling Smørgrav #define ARRAYLIST_IDX(ITEM_P, ARRAY_LIST) ((ITEM_P) - (ARRAY_LIST).head) 122