1*820c1a8dSHiroo HAYASHI /* Type-safe arrays which grow dynamically. 2*820c1a8dSHiroo HAYASHI Copyright 2021 Free Software Foundation, Inc. 3*820c1a8dSHiroo HAYASHI 4*820c1a8dSHiroo HAYASHI This file is free software: you can redistribute it and/or modify 5*820c1a8dSHiroo HAYASHI it under the terms of the GNU Lesser General Public License as 6*820c1a8dSHiroo HAYASHI published by the Free Software Foundation; either version 2.1 of the 7*820c1a8dSHiroo HAYASHI License, or (at your option) any later version. 8*820c1a8dSHiroo HAYASHI 9*820c1a8dSHiroo HAYASHI This file is distributed in the hope that it will be useful, 10*820c1a8dSHiroo HAYASHI but WITHOUT ANY WARRANTY; without even the implied warranty of 11*820c1a8dSHiroo HAYASHI MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*820c1a8dSHiroo HAYASHI GNU Lesser General Public License for more details. 13*820c1a8dSHiroo HAYASHI 14*820c1a8dSHiroo HAYASHI You should have received a copy of the GNU Lesser General Public License 15*820c1a8dSHiroo HAYASHI along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16*820c1a8dSHiroo HAYASHI 17*820c1a8dSHiroo HAYASHI /* Written by Paul Eggert and Bruno Haible, 2021. */ 18*820c1a8dSHiroo HAYASHI 19*820c1a8dSHiroo HAYASHI #ifndef _GL_DYNARRAY_H 20*820c1a8dSHiroo HAYASHI #define _GL_DYNARRAY_H 21*820c1a8dSHiroo HAYASHI 22*820c1a8dSHiroo HAYASHI /* Before including this file, you need to define: 23*820c1a8dSHiroo HAYASHI 24*820c1a8dSHiroo HAYASHI DYNARRAY_STRUCT 25*820c1a8dSHiroo HAYASHI The struct tag of dynamic array to be defined. 26*820c1a8dSHiroo HAYASHI 27*820c1a8dSHiroo HAYASHI DYNARRAY_ELEMENT 28*820c1a8dSHiroo HAYASHI The type name of the element type. Elements are copied 29*820c1a8dSHiroo HAYASHI as if by memcpy, and can change address as the dynamic 30*820c1a8dSHiroo HAYASHI array grows. 31*820c1a8dSHiroo HAYASHI 32*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX 33*820c1a8dSHiroo HAYASHI The prefix of the functions which are defined. 34*820c1a8dSHiroo HAYASHI 35*820c1a8dSHiroo HAYASHI The following parameters are optional: 36*820c1a8dSHiroo HAYASHI 37*820c1a8dSHiroo HAYASHI DYNARRAY_ELEMENT_FREE 38*820c1a8dSHiroo HAYASHI DYNARRAY_ELEMENT_FREE (E) is evaluated to deallocate the 39*820c1a8dSHiroo HAYASHI contents of elements. E is of type DYNARRAY_ELEMENT *. 40*820c1a8dSHiroo HAYASHI 41*820c1a8dSHiroo HAYASHI DYNARRAY_ELEMENT_INIT 42*820c1a8dSHiroo HAYASHI DYNARRAY_ELEMENT_INIT (E) is evaluated to initialize a new 43*820c1a8dSHiroo HAYASHI element. E is of type DYNARRAY_ELEMENT *. 44*820c1a8dSHiroo HAYASHI If DYNARRAY_ELEMENT_FREE but not DYNARRAY_ELEMENT_INIT is 45*820c1a8dSHiroo HAYASHI defined, new elements are automatically zero-initialized. 46*820c1a8dSHiroo HAYASHI Otherwise, new elements have undefined contents. 47*820c1a8dSHiroo HAYASHI 48*820c1a8dSHiroo HAYASHI DYNARRAY_INITIAL_SIZE 49*820c1a8dSHiroo HAYASHI The size of the statically allocated array (default: 50*820c1a8dSHiroo HAYASHI at least 2, more elements if they fit into 128 bytes). 51*820c1a8dSHiroo HAYASHI Must be a preprocessor constant. If DYNARRAY_INITIAL_SIZE is 0, 52*820c1a8dSHiroo HAYASHI there is no statically allocated array at, and all non-empty 53*820c1a8dSHiroo HAYASHI arrays are heap-allocated. 54*820c1a8dSHiroo HAYASHI 55*820c1a8dSHiroo HAYASHI DYNARRAY_FINAL_TYPE 56*820c1a8dSHiroo HAYASHI The name of the type which holds the final array. If not 57*820c1a8dSHiroo HAYASHI defined, is PREFIX##finalize not provided. DYNARRAY_FINAL_TYPE 58*820c1a8dSHiroo HAYASHI must be a struct type, with members of type DYNARRAY_ELEMENT and 59*820c1a8dSHiroo HAYASHI size_t at the start (in this order). 60*820c1a8dSHiroo HAYASHI 61*820c1a8dSHiroo HAYASHI These macros are undefined after this header file has been 62*820c1a8dSHiroo HAYASHI included. 63*820c1a8dSHiroo HAYASHI 64*820c1a8dSHiroo HAYASHI The following types are provided (their members are private to the 65*820c1a8dSHiroo HAYASHI dynarray implementation): 66*820c1a8dSHiroo HAYASHI 67*820c1a8dSHiroo HAYASHI struct DYNARRAY_STRUCT 68*820c1a8dSHiroo HAYASHI 69*820c1a8dSHiroo HAYASHI The following functions are provided: 70*820c1a8dSHiroo HAYASHI */ 71*820c1a8dSHiroo HAYASHI 72*820c1a8dSHiroo HAYASHI /* Initialize a dynamic array object. This must be called before any 73*820c1a8dSHiroo HAYASHI use of the object. */ 74*820c1a8dSHiroo HAYASHI #if 0 75*820c1a8dSHiroo HAYASHI static void 76*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##init (struct DYNARRAY_STRUCT *list); 77*820c1a8dSHiroo HAYASHI #endif 78*820c1a8dSHiroo HAYASHI 79*820c1a8dSHiroo HAYASHI /* Deallocate the dynamic array and its elements. */ 80*820c1a8dSHiroo HAYASHI #if 0 81*820c1a8dSHiroo HAYASHI static void 82*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##free (struct DYNARRAY_STRUCT *list); 83*820c1a8dSHiroo HAYASHI #endif 84*820c1a8dSHiroo HAYASHI 85*820c1a8dSHiroo HAYASHI /* Return true if the dynamic array is in an error state. */ 86*820c1a8dSHiroo HAYASHI #if 0 87*820c1a8dSHiroo HAYASHI static bool 88*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##has_failed (const struct DYNARRAY_STRUCT *list); 89*820c1a8dSHiroo HAYASHI #endif 90*820c1a8dSHiroo HAYASHI 91*820c1a8dSHiroo HAYASHI /* Mark the dynamic array as failed. All elements are deallocated as 92*820c1a8dSHiroo HAYASHI a side effect. */ 93*820c1a8dSHiroo HAYASHI #if 0 94*820c1a8dSHiroo HAYASHI static void 95*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##mark_failed (struct DYNARRAY_STRUCT *list); 96*820c1a8dSHiroo HAYASHI #endif 97*820c1a8dSHiroo HAYASHI 98*820c1a8dSHiroo HAYASHI /* Return the number of elements which have been added to the dynamic 99*820c1a8dSHiroo HAYASHI array. */ 100*820c1a8dSHiroo HAYASHI #if 0 101*820c1a8dSHiroo HAYASHI static size_t 102*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##size (const struct DYNARRAY_STRUCT *list); 103*820c1a8dSHiroo HAYASHI #endif 104*820c1a8dSHiroo HAYASHI 105*820c1a8dSHiroo HAYASHI /* Return a pointer to the first array element, if any. For a 106*820c1a8dSHiroo HAYASHI zero-length array, the pointer can be NULL even though the dynamic 107*820c1a8dSHiroo HAYASHI array has not entered the failure state. */ 108*820c1a8dSHiroo HAYASHI #if 0 109*820c1a8dSHiroo HAYASHI static DYNARRAY_ELEMENT * 110*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##begin (const struct DYNARRAY_STRUCT *list); 111*820c1a8dSHiroo HAYASHI #endif 112*820c1a8dSHiroo HAYASHI 113*820c1a8dSHiroo HAYASHI /* Return a pointer one element past the last array element. For a 114*820c1a8dSHiroo HAYASHI zero-length array, the pointer can be NULL even though the dynamic 115*820c1a8dSHiroo HAYASHI array has not entered the failure state. */ 116*820c1a8dSHiroo HAYASHI #if 0 117*820c1a8dSHiroo HAYASHI static DYNARRAY_ELEMENT * 118*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##end (const struct DYNARRAY_STRUCT *list); 119*820c1a8dSHiroo HAYASHI #endif 120*820c1a8dSHiroo HAYASHI 121*820c1a8dSHiroo HAYASHI /* Return a pointer to the array element at INDEX. Terminate the 122*820c1a8dSHiroo HAYASHI process if INDEX is out of bounds. */ 123*820c1a8dSHiroo HAYASHI #if 0 124*820c1a8dSHiroo HAYASHI static DYNARRAY_ELEMENT * 125*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##at (struct DYNARRAY_STRUCT *list, size_t index); 126*820c1a8dSHiroo HAYASHI #endif 127*820c1a8dSHiroo HAYASHI 128*820c1a8dSHiroo HAYASHI /* Add ITEM at the end of the array, enlarging it by one element. 129*820c1a8dSHiroo HAYASHI Mark *LIST as failed if the dynamic array allocation size cannot be 130*820c1a8dSHiroo HAYASHI increased. */ 131*820c1a8dSHiroo HAYASHI #if 0 132*820c1a8dSHiroo HAYASHI static void 133*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##add (struct DYNARRAY_STRUCT *list, 134*820c1a8dSHiroo HAYASHI DYNARRAY_ELEMENT item); 135*820c1a8dSHiroo HAYASHI #endif 136*820c1a8dSHiroo HAYASHI 137*820c1a8dSHiroo HAYASHI /* Allocate a place for a new element in *LIST and return a pointer to 138*820c1a8dSHiroo HAYASHI it. The pointer can be NULL if the dynamic array cannot be 139*820c1a8dSHiroo HAYASHI enlarged due to a memory allocation failure. */ 140*820c1a8dSHiroo HAYASHI #if 0 141*820c1a8dSHiroo HAYASHI static DYNARRAY_ELEMENT * 142*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##emplace (struct DYNARRAY_STRUCT *list); 143*820c1a8dSHiroo HAYASHI #endif 144*820c1a8dSHiroo HAYASHI 145*820c1a8dSHiroo HAYASHI /* Change the size of *LIST to SIZE. If SIZE is larger than the 146*820c1a8dSHiroo HAYASHI existing size, new elements are added (which can be initialized). 147*820c1a8dSHiroo HAYASHI Otherwise, the list is truncated, and elements are freed. Return 148*820c1a8dSHiroo HAYASHI false on memory allocation failure (and mark *LIST as failed). */ 149*820c1a8dSHiroo HAYASHI #if 0 150*820c1a8dSHiroo HAYASHI static bool 151*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##resize (struct DYNARRAY_STRUCT *list, size_t size); 152*820c1a8dSHiroo HAYASHI #endif 153*820c1a8dSHiroo HAYASHI 154*820c1a8dSHiroo HAYASHI /* Remove the last element of LIST if it is present. */ 155*820c1a8dSHiroo HAYASHI #if 0 156*820c1a8dSHiroo HAYASHI static void 157*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##remove_last (struct DYNARRAY_STRUCT *list); 158*820c1a8dSHiroo HAYASHI #endif 159*820c1a8dSHiroo HAYASHI 160*820c1a8dSHiroo HAYASHI /* Remove all elements from the list. The elements are freed, but the 161*820c1a8dSHiroo HAYASHI list itself is not. */ 162*820c1a8dSHiroo HAYASHI #if 0 163*820c1a8dSHiroo HAYASHI static void 164*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##clear (struct DYNARRAY_STRUCT *list); 165*820c1a8dSHiroo HAYASHI #endif 166*820c1a8dSHiroo HAYASHI 167*820c1a8dSHiroo HAYASHI #if defined DYNARRAY_FINAL_TYPE 168*820c1a8dSHiroo HAYASHI /* Transfer the dynamic array to a permanent location at *RESULT. 169*820c1a8dSHiroo HAYASHI Returns true on success on false on allocation failure. In either 170*820c1a8dSHiroo HAYASHI case, *LIST is re-initialized and can be reused. A NULL pointer is 171*820c1a8dSHiroo HAYASHI stored in *RESULT if LIST refers to an empty list. On success, the 172*820c1a8dSHiroo HAYASHI pointer in *RESULT is heap-allocated and must be deallocated using 173*820c1a8dSHiroo HAYASHI free. */ 174*820c1a8dSHiroo HAYASHI #if 0 175*820c1a8dSHiroo HAYASHI static bool 176*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *list, 177*820c1a8dSHiroo HAYASHI DYNARRAY_FINAL_TYPE *result); 178*820c1a8dSHiroo HAYASHI #endif 179*820c1a8dSHiroo HAYASHI #else /* !defined DYNARRAY_FINAL_TYPE */ 180*820c1a8dSHiroo HAYASHI /* Transfer the dynamic array to a heap-allocated array and return a 181*820c1a8dSHiroo HAYASHI pointer to it. The pointer is NULL if memory allocation fails, or 182*820c1a8dSHiroo HAYASHI if the array is empty, so this function should be used only for 183*820c1a8dSHiroo HAYASHI arrays which are known not be empty (usually because they always 184*820c1a8dSHiroo HAYASHI have a sentinel at the end). If LENGTHP is not NULL, the array 185*820c1a8dSHiroo HAYASHI length is written to *LENGTHP. *LIST is re-initialized and can be 186*820c1a8dSHiroo HAYASHI reused. */ 187*820c1a8dSHiroo HAYASHI #if 0 188*820c1a8dSHiroo HAYASHI static DYNARRAY_ELEMENT * 189*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *list, 190*820c1a8dSHiroo HAYASHI size_t *lengthp); 191*820c1a8dSHiroo HAYASHI #endif 192*820c1a8dSHiroo HAYASHI #endif 193*820c1a8dSHiroo HAYASHI 194*820c1a8dSHiroo HAYASHI /* A minimal example which provides a growing list of integers can be 195*820c1a8dSHiroo HAYASHI defined like this: 196*820c1a8dSHiroo HAYASHI 197*820c1a8dSHiroo HAYASHI struct int_array 198*820c1a8dSHiroo HAYASHI { 199*820c1a8dSHiroo HAYASHI // Pointer to result array followed by its length, 200*820c1a8dSHiroo HAYASHI // as required by DYNARRAY_FINAL_TYPE. 201*820c1a8dSHiroo HAYASHI int *array; 202*820c1a8dSHiroo HAYASHI size_t length; 203*820c1a8dSHiroo HAYASHI }; 204*820c1a8dSHiroo HAYASHI 205*820c1a8dSHiroo HAYASHI #define DYNARRAY_STRUCT dynarray_int 206*820c1a8dSHiroo HAYASHI #define DYNARRAY_ELEMENT int 207*820c1a8dSHiroo HAYASHI #define DYNARRAY_PREFIX dynarray_int_ 208*820c1a8dSHiroo HAYASHI #define DYNARRAY_FINAL_TYPE struct int_array 209*820c1a8dSHiroo HAYASHI #include <malloc/dynarray-skeleton.c> 210*820c1a8dSHiroo HAYASHI 211*820c1a8dSHiroo HAYASHI To create a three-element array with elements 1, 2, 3, use this 212*820c1a8dSHiroo HAYASHI code: 213*820c1a8dSHiroo HAYASHI 214*820c1a8dSHiroo HAYASHI struct dynarray_int dyn; 215*820c1a8dSHiroo HAYASHI dynarray_int_init (&dyn); 216*820c1a8dSHiroo HAYASHI for (int i = 1; i <= 3; ++i) 217*820c1a8dSHiroo HAYASHI { 218*820c1a8dSHiroo HAYASHI int *place = dynarray_int_emplace (&dyn); 219*820c1a8dSHiroo HAYASHI assert (place != NULL); 220*820c1a8dSHiroo HAYASHI *place = i; 221*820c1a8dSHiroo HAYASHI } 222*820c1a8dSHiroo HAYASHI struct int_array result; 223*820c1a8dSHiroo HAYASHI bool ok = dynarray_int_finalize (&dyn, &result); 224*820c1a8dSHiroo HAYASHI assert (ok); 225*820c1a8dSHiroo HAYASHI assert (result.length == 3); 226*820c1a8dSHiroo HAYASHI assert (result.array[0] == 1); 227*820c1a8dSHiroo HAYASHI assert (result.array[1] == 2); 228*820c1a8dSHiroo HAYASHI assert (result.array[2] == 3); 229*820c1a8dSHiroo HAYASHI free (result.array); 230*820c1a8dSHiroo HAYASHI 231*820c1a8dSHiroo HAYASHI If the elements contain resources which must be freed, define 232*820c1a8dSHiroo HAYASHI DYNARRAY_ELEMENT_FREE appropriately, like this: 233*820c1a8dSHiroo HAYASHI 234*820c1a8dSHiroo HAYASHI struct str_array 235*820c1a8dSHiroo HAYASHI { 236*820c1a8dSHiroo HAYASHI char **array; 237*820c1a8dSHiroo HAYASHI size_t length; 238*820c1a8dSHiroo HAYASHI }; 239*820c1a8dSHiroo HAYASHI 240*820c1a8dSHiroo HAYASHI #define DYNARRAY_STRUCT dynarray_str 241*820c1a8dSHiroo HAYASHI #define DYNARRAY_ELEMENT char * 242*820c1a8dSHiroo HAYASHI #define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr) 243*820c1a8dSHiroo HAYASHI #define DYNARRAY_PREFIX dynarray_str_ 244*820c1a8dSHiroo HAYASHI #define DYNARRAY_FINAL_TYPE struct str_array 245*820c1a8dSHiroo HAYASHI #include <malloc/dynarray-skeleton.c> 246*820c1a8dSHiroo HAYASHI */ 247*820c1a8dSHiroo HAYASHI 248*820c1a8dSHiroo HAYASHI 249*820c1a8dSHiroo HAYASHI /* The implementation is imported from glibc. */ 250*820c1a8dSHiroo HAYASHI 251*820c1a8dSHiroo HAYASHI /* Avoid possible conflicts with symbols exported by the GNU libc. */ 252*820c1a8dSHiroo HAYASHI #define __libc_dynarray_at_failure gl_dynarray_at_failure 253*820c1a8dSHiroo HAYASHI #define __libc_dynarray_emplace_enlarge gl_dynarray_emplace_enlarge 254*820c1a8dSHiroo HAYASHI #define __libc_dynarray_finalize gl_dynarray_finalize 255*820c1a8dSHiroo HAYASHI #define __libc_dynarray_resize_clear gl_dynarray_resize_clear 256*820c1a8dSHiroo HAYASHI #define __libc_dynarray_resize gl_dynarray_resize 257*820c1a8dSHiroo HAYASHI 258*820c1a8dSHiroo HAYASHI #if defined DYNARRAY_STRUCT || defined DYNARRAY_ELEMENT || defined DYNARRAY_PREFIX 259*820c1a8dSHiroo HAYASHI 260*820c1a8dSHiroo HAYASHI # ifndef _GL_LIKELY 261*820c1a8dSHiroo HAYASHI /* Rely on __builtin_expect, as provided by the module 'builtin-expect'. */ 262*820c1a8dSHiroo HAYASHI # define _GL_LIKELY(cond) __builtin_expect ((cond), 1) 263*820c1a8dSHiroo HAYASHI # define _GL_UNLIKELY(cond) __builtin_expect ((cond), 0) 264*820c1a8dSHiroo HAYASHI # endif 265*820c1a8dSHiroo HAYASHI 266*820c1a8dSHiroo HAYASHI /* Define auxiliary structs and declare auxiliary functions, common to all 267*820c1a8dSHiroo HAYASHI instantiations of dynarray. */ 268*820c1a8dSHiroo HAYASHI # include <malloc/dynarray.gl.h> 269*820c1a8dSHiroo HAYASHI 270*820c1a8dSHiroo HAYASHI /* Define the instantiation, specified through 271*820c1a8dSHiroo HAYASHI DYNARRAY_STRUCT 272*820c1a8dSHiroo HAYASHI DYNARRAY_ELEMENT 273*820c1a8dSHiroo HAYASHI DYNARRAY_PREFIX 274*820c1a8dSHiroo HAYASHI etc. */ 275*820c1a8dSHiroo HAYASHI # include <malloc/dynarray-skeleton.gl.h> 276*820c1a8dSHiroo HAYASHI 277*820c1a8dSHiroo HAYASHI #else 278*820c1a8dSHiroo HAYASHI 279*820c1a8dSHiroo HAYASHI /* This file is being included from one of the malloc/dynarray_*.c files. */ 280*820c1a8dSHiroo HAYASHI # include <malloc/dynarray.h> 281*820c1a8dSHiroo HAYASHI 282*820c1a8dSHiroo HAYASHI #endif 283*820c1a8dSHiroo HAYASHI 284*820c1a8dSHiroo HAYASHI #endif /* _GL_DYNARRAY_H */ 285