123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- /* Type-safe arrays which grow dynamically.
- Copyright 2021 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>. */
- /* Written by Paul Eggert and Bruno Haible, 2021. */
- #ifndef _GL_DYNARRAY_H
- #define _GL_DYNARRAY_H
- /* Before including this file, you need to define:
- DYNARRAY_STRUCT
- The struct tag of dynamic array to be defined.
- DYNARRAY_ELEMENT
- The type name of the element type. Elements are copied
- as if by memcpy, and can change address as the dynamic
- array grows.
- DYNARRAY_PREFIX
- The prefix of the functions which are defined.
- The following parameters are optional:
- DYNARRAY_ELEMENT_FREE
- DYNARRAY_ELEMENT_FREE (E) is evaluated to deallocate the
- contents of elements. E is of type DYNARRAY_ELEMENT *.
- DYNARRAY_ELEMENT_INIT
- DYNARRAY_ELEMENT_INIT (E) is evaluated to initialize a new
- element. E is of type DYNARRAY_ELEMENT *.
- If DYNARRAY_ELEMENT_FREE but not DYNARRAY_ELEMENT_INIT is
- defined, new elements are automatically zero-initialized.
- Otherwise, new elements have undefined contents.
- DYNARRAY_INITIAL_SIZE
- The size of the statically allocated array (default:
- at least 2, more elements if they fit into 128 bytes).
- Must be a preprocessor constant. If DYNARRAY_INITIAL_SIZE is 0,
- there is no statically allocated array at, and all non-empty
- arrays are heap-allocated.
- DYNARRAY_FINAL_TYPE
- The name of the type which holds the final array. If not
- defined, is PREFIX##finalize not provided. DYNARRAY_FINAL_TYPE
- must be a struct type, with members of type DYNARRAY_ELEMENT and
- size_t at the start (in this order).
- These macros are undefined after this header file has been
- included.
- The following types are provided (their members are private to the
- dynarray implementation):
- struct DYNARRAY_STRUCT
- The following functions are provided:
- */
- /* Initialize a dynamic array object. This must be called before any
- use of the object. */
- #if 0
- static void
- DYNARRAY_PREFIX##init (struct DYNARRAY_STRUCT *list);
- #endif
- /* Deallocate the dynamic array and its elements. */
- #if 0
- static void
- DYNARRAY_PREFIX##free (struct DYNARRAY_STRUCT *list);
- #endif
- /* Return true if the dynamic array is in an error state. */
- #if 0
- static bool
- DYNARRAY_PREFIX##has_failed (const struct DYNARRAY_STRUCT *list);
- #endif
- /* Mark the dynamic array as failed. All elements are deallocated as
- a side effect. */
- #if 0
- static void
- DYNARRAY_PREFIX##mark_failed (struct DYNARRAY_STRUCT *list);
- #endif
- /* Return the number of elements which have been added to the dynamic
- array. */
- #if 0
- static size_t
- DYNARRAY_PREFIX##size (const struct DYNARRAY_STRUCT *list);
- #endif
- /* Return a pointer to the first array element, if any. For a
- zero-length array, the pointer can be NULL even though the dynamic
- array has not entered the failure state. */
- #if 0
- static DYNARRAY_ELEMENT *
- DYNARRAY_PREFIX##begin (const struct DYNARRAY_STRUCT *list);
- #endif
- /* Return a pointer one element past the last array element. For a
- zero-length array, the pointer can be NULL even though the dynamic
- array has not entered the failure state. */
- #if 0
- static DYNARRAY_ELEMENT *
- DYNARRAY_PREFIX##end (const struct DYNARRAY_STRUCT *list);
- #endif
- /* Return a pointer to the array element at INDEX. Terminate the
- process if INDEX is out of bounds. */
- #if 0
- static DYNARRAY_ELEMENT *
- DYNARRAY_PREFIX##at (struct DYNARRAY_STRUCT *list, size_t index);
- #endif
- /* Add ITEM at the end of the array, enlarging it by one element.
- Mark *LIST as failed if the dynamic array allocation size cannot be
- increased. */
- #if 0
- static void
- DYNARRAY_PREFIX##add (struct DYNARRAY_STRUCT *list,
- DYNARRAY_ELEMENT item);
- #endif
- /* Allocate a place for a new element in *LIST and return a pointer to
- it. The pointer can be NULL if the dynamic array cannot be
- enlarged due to a memory allocation failure. */
- #if 0
- static DYNARRAY_ELEMENT *
- DYNARRAY_PREFIX##emplace (struct DYNARRAY_STRUCT *list);
- #endif
- /* Change the size of *LIST to SIZE. If SIZE is larger than the
- existing size, new elements are added (which can be initialized).
- Otherwise, the list is truncated, and elements are freed. Return
- false on memory allocation failure (and mark *LIST as failed). */
- #if 0
- static bool
- DYNARRAY_PREFIX##resize (struct DYNARRAY_STRUCT *list, size_t size);
- #endif
- /* Remove the last element of LIST if it is present. */
- #if 0
- static void
- DYNARRAY_PREFIX##remove_last (struct DYNARRAY_STRUCT *list);
- #endif
- /* Remove all elements from the list. The elements are freed, but the
- list itself is not. */
- #if 0
- static void
- DYNARRAY_PREFIX##clear (struct DYNARRAY_STRUCT *list);
- #endif
- #if defined DYNARRAY_FINAL_TYPE
- /* Transfer the dynamic array to a permanent location at *RESULT.
- Returns true on success on false on allocation failure. In either
- case, *LIST is re-initialized and can be reused. A NULL pointer is
- stored in *RESULT if LIST refers to an empty list. On success, the
- pointer in *RESULT is heap-allocated and must be deallocated using
- free. */
- #if 0
- static bool
- DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *list,
- DYNARRAY_FINAL_TYPE *result);
- #endif
- #else /* !defined DYNARRAY_FINAL_TYPE */
- /* Transfer the dynamic array to a heap-allocated array and return a
- pointer to it. The pointer is NULL if memory allocation fails, or
- if the array is empty, so this function should be used only for
- arrays which are known not be empty (usually because they always
- have a sentinel at the end). If LENGTHP is not NULL, the array
- length is written to *LENGTHP. *LIST is re-initialized and can be
- reused. */
- #if 0
- static DYNARRAY_ELEMENT *
- DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *list,
- size_t *lengthp);
- #endif
- #endif
- /* A minimal example which provides a growing list of integers can be
- defined like this:
- struct int_array
- {
- // Pointer to result array followed by its length,
- // as required by DYNARRAY_FINAL_TYPE.
- int *array;
- size_t length;
- };
- #define DYNARRAY_STRUCT dynarray_int
- #define DYNARRAY_ELEMENT int
- #define DYNARRAY_PREFIX dynarray_int_
- #define DYNARRAY_FINAL_TYPE struct int_array
- #include <malloc/dynarray-skeleton.c>
- To create a three-element array with elements 1, 2, 3, use this
- code:
- struct dynarray_int dyn;
- dynarray_int_init (&dyn);
- for (int i = 1; i <= 3; ++i)
- {
- int *place = dynarray_int_emplace (&dyn);
- assert (place != NULL);
- *place = i;
- }
- struct int_array result;
- bool ok = dynarray_int_finalize (&dyn, &result);
- assert (ok);
- assert (result.length == 3);
- assert (result.array[0] == 1);
- assert (result.array[1] == 2);
- assert (result.array[2] == 3);
- free (result.array);
- If the elements contain resources which must be freed, define
- DYNARRAY_ELEMENT_FREE appropriately, like this:
- struct str_array
- {
- char **array;
- size_t length;
- };
- #define DYNARRAY_STRUCT dynarray_str
- #define DYNARRAY_ELEMENT char *
- #define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr)
- #define DYNARRAY_PREFIX dynarray_str_
- #define DYNARRAY_FINAL_TYPE struct str_array
- #include <malloc/dynarray-skeleton.c>
- */
- /* The implementation is imported from glibc. */
- /* Avoid possible conflicts with symbols exported by the GNU libc. */
- #define __libc_dynarray_at_failure gl_dynarray_at_failure
- #define __libc_dynarray_emplace_enlarge gl_dynarray_emplace_enlarge
- #define __libc_dynarray_finalize gl_dynarray_finalize
- #define __libc_dynarray_resize_clear gl_dynarray_resize_clear
- #define __libc_dynarray_resize gl_dynarray_resize
- #if defined DYNARRAY_STRUCT || defined DYNARRAY_ELEMENT || defined DYNARRAY_PREFIX
- # include <libc-config.h>
- /* Define auxiliary structs and declare auxiliary functions, common to all
- instantiations of dynarray. */
- # include <malloc/dynarray.h>
- /* Define the instantiation, specified through
- DYNARRAY_STRUCT
- DYNARRAY_ELEMENT
- DYNARRAY_PREFIX
- etc. */
- # include <malloc/dynarray-skeleton.c>
- #else
- /* This file is being included from one of the malloc/dynarray_*.c files. */
- # include <malloc/dynarray.h>
- #endif
- #endif /* _GL_DYNARRAY_H */
|