dynarray.h 9.0 KB

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