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