xref: /Universal-ctags/gnulib/dynarray.h (revision 820c1a8d46849a90376d8eb15b319ac05439f656)
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