dynarray.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /* Type-safe arrays which grow dynamically. Shared definitions.
  2. Copyright (C) 2017-2023 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. /* To use the dynarray facility, you need to include
  16. <malloc/dynarray-skeleton.c> and define the parameter macros
  17. documented in that file.
  18. A minimal example which provides a growing list of integers can be
  19. defined like this:
  20. struct int_array
  21. {
  22. // Pointer to result array followed by its length,
  23. // as required by DYNARRAY_FINAL_TYPE.
  24. int *array;
  25. size_t length;
  26. };
  27. #define DYNARRAY_STRUCT dynarray_int
  28. #define DYNARRAY_ELEMENT int
  29. #define DYNARRAY_PREFIX dynarray_int_
  30. #define DYNARRAY_FINAL_TYPE struct int_array
  31. #include <malloc/dynarray-skeleton.c>
  32. To create a three-element array with elements 1, 2, 3, use this
  33. code:
  34. struct dynarray_int dyn;
  35. dynarray_int_init (&dyn);
  36. for (int i = 1; i <= 3; ++i)
  37. {
  38. int *place = dynarray_int_emplace (&dyn);
  39. assert (place != NULL);
  40. *place = i;
  41. }
  42. struct int_array result;
  43. bool ok = dynarray_int_finalize (&dyn, &result);
  44. assert (ok);
  45. assert (result.length == 3);
  46. assert (result.array[0] == 1);
  47. assert (result.array[1] == 2);
  48. assert (result.array[2] == 3);
  49. free (result.array);
  50. If the elements contain resources which must be freed, define
  51. DYNARRAY_ELEMENT_FREE appropriately, like this:
  52. struct str_array
  53. {
  54. char **array;
  55. size_t length;
  56. };
  57. #define DYNARRAY_STRUCT dynarray_str
  58. #define DYNARRAY_ELEMENT char *
  59. #define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr)
  60. #define DYNARRAY_PREFIX dynarray_str_
  61. #define DYNARRAY_FINAL_TYPE struct str_array
  62. #include <malloc/dynarray-skeleton.c>
  63. Compared to scratch buffers, dynamic arrays have the following
  64. features:
  65. - They have an element type, and are not just an untyped buffer of
  66. bytes.
  67. - When growing, previously stored elements are preserved. (It is
  68. expected that scratch_buffer_grow_preserve and
  69. scratch_buffer_set_array_size eventually go away because all
  70. current users are moved to dynamic arrays.)
  71. - Scratch buffers have a more aggressive growth policy because
  72. growing them typically means a retry of an operation (across an
  73. NSS service module boundary), which is expensive.
  74. - For the same reason, scratch buffers have a much larger initial
  75. stack allocation. */
  76. #ifndef _DYNARRAY_H
  77. #define _DYNARRAY_H
  78. #include <stddef.h>
  79. #include <string.h>
  80. struct dynarray_header
  81. {
  82. size_t used;
  83. size_t allocated;
  84. void *array;
  85. };
  86. /* Marker used in the allocated member to indicate that an error was
  87. encountered. */
  88. static inline size_t
  89. __dynarray_error_marker (void)
  90. {
  91. return -1;
  92. }
  93. /* Internal function. See the has_failed function in
  94. dynarray-skeleton.c. */
  95. static inline bool
  96. __dynarray_error (struct dynarray_header *list)
  97. {
  98. return list->allocated == __dynarray_error_marker ();
  99. }
  100. /* Internal function. Enlarge the dynamically allocated area of the
  101. array to make room for one more element. SCRATCH is a pointer to
  102. the scratch area (which is not heap-allocated and must not be
  103. freed). ELEMENT_SIZE is the size, in bytes, of one element.
  104. Return false on failure, true on success. */
  105. bool __libc_dynarray_emplace_enlarge (struct dynarray_header *,
  106. void *scratch, size_t element_size);
  107. /* Internal function. Enlarge the dynamically allocated area of the
  108. array to make room for at least SIZE elements (which must be larger
  109. than the existing used part of the dynamic array). SCRATCH is a
  110. pointer to the scratch area (which is not heap-allocated and must
  111. not be freed). ELEMENT_SIZE is the size, in bytes, of one element.
  112. Return false on failure, true on success. */
  113. bool __libc_dynarray_resize (struct dynarray_header *, size_t size,
  114. void *scratch, size_t element_size);
  115. /* Internal function. Like __libc_dynarray_resize, but clear the new
  116. part of the dynamic array. */
  117. bool __libc_dynarray_resize_clear (struct dynarray_header *, size_t size,
  118. void *scratch, size_t element_size);
  119. /* Internal type. */
  120. struct dynarray_finalize_result
  121. {
  122. void *array;
  123. size_t length;
  124. };
  125. /* Internal function. Copy the dynamically-allocated area to an
  126. explicitly-sized heap allocation. SCRATCH is a pointer to the
  127. embedded scratch space. ELEMENT_SIZE is the size, in bytes, of the
  128. element type. On success, true is returned, and pointer and length
  129. are written to *RESULT. On failure, false is returned. The caller
  130. has to take care of some of the memory management; this function is
  131. expected to be called from dynarray-skeleton.c. */
  132. bool __libc_dynarray_finalize (struct dynarray_header *list, void *scratch,
  133. size_t element_size,
  134. struct dynarray_finalize_result *result);
  135. /* Internal function. Terminate the process after an index error.
  136. SIZE is the number of elements of the dynamic array. INDEX is the
  137. lookup index which triggered the failure. */
  138. _Noreturn void __libc_dynarray_at_failure (size_t size, size_t index);
  139. #ifndef _ISOMAC
  140. libc_hidden_proto (__libc_dynarray_emplace_enlarge)
  141. libc_hidden_proto (__libc_dynarray_resize)
  142. libc_hidden_proto (__libc_dynarray_resize_clear)
  143. libc_hidden_proto (__libc_dynarray_finalize)
  144. libc_hidden_proto (__libc_dynarray_at_failure)
  145. #endif
  146. #endif /* _DYNARRAY_H */