xref: /src/contrib/libdiff/include/arraylist.h (revision 59c8e88e72633afbc47a4ace0d2170d00d51f7dc)
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