1 /* Copyright (c) 2000, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27
28 /* Handling of arrays that can grow dynamicly. */
29
30 #include "mysys_priv.h"
31 #include "m_string.h"
32 #include "my_sys.h"
33
34 /*
35 Initiate dynamic array
36
37 SYNOPSIS
38 my_init_dynamic_array()
39 array Pointer to an array
40 element_size Size of element
41 init_buffer Initial buffer pointer
42 init_alloc Number of initial elements
43 alloc_increment Increment for adding new elements
44
45 DESCRIPTION
46 init_dynamic_array() initiates array and allocate space for
47 init_alloc eilements.
48 Array is usable even if space allocation failed, hence, the
49 function never returns TRUE.
50 Static buffers must begin immediately after the array structure.
51
52 RETURN VALUE
53 FALSE Ok
54 */
55
my_init_dynamic_array(DYNAMIC_ARRAY * array,PSI_memory_key psi_key,uint element_size,void * init_buffer,uint init_alloc,uint alloc_increment)56 my_bool my_init_dynamic_array(DYNAMIC_ARRAY *array,
57 PSI_memory_key psi_key,
58 uint element_size,
59 void *init_buffer,
60 uint init_alloc,
61 uint alloc_increment)
62 {
63 DBUG_ENTER("init_dynamic_array");
64 if (!alloc_increment)
65 {
66 alloc_increment=MY_MAX((8192-MALLOC_OVERHEAD)/element_size,16);
67 if (init_alloc > 8 && alloc_increment > init_alloc * 2)
68 alloc_increment=init_alloc*2;
69 }
70
71 if (!init_alloc)
72 {
73 init_alloc=alloc_increment;
74 init_buffer= 0;
75 }
76 array->elements=0;
77 array->max_element=init_alloc;
78 array->alloc_increment=alloc_increment;
79 array->size_of_element=element_size;
80 array->m_psi_key= psi_key;
81 if ((array->buffer= init_buffer))
82 DBUG_RETURN(FALSE);
83 /*
84 Since the dynamic array is usable even if allocation fails here malloc
85 should not throw an error
86 */
87 if (!(array->buffer= (uchar*) my_malloc(psi_key,
88 element_size*init_alloc, MYF(0))))
89 array->max_element=0;
90 DBUG_RETURN(FALSE);
91 }
92
init_dynamic_array(DYNAMIC_ARRAY * array,uint element_size,uint init_alloc,uint alloc_increment)93 my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
94 uint init_alloc, uint alloc_increment)
95 {
96 /* placeholder to preserve ABI */
97 return my_init_dynamic_array(array,
98 PSI_INSTRUMENT_ME,
99 element_size,
100 NULL, /* init_buffer */
101 init_alloc,
102 alloc_increment);
103 }
104 /*
105 Insert element at the end of array. Allocate memory if needed.
106
107 SYNOPSIS
108 insert_dynamic()
109 array
110 element
111
112 RETURN VALUE
113 TRUE Insert failed
114 FALSE Ok
115 */
116
insert_dynamic(DYNAMIC_ARRAY * array,const void * element)117 my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void *element)
118 {
119 uchar* buffer;
120 if (array->elements == array->max_element)
121 { /* Call only when nessesary */
122 if (!(buffer=alloc_dynamic(array)))
123 return TRUE;
124 }
125 else
126 {
127 buffer=array->buffer+(array->elements * array->size_of_element);
128 array->elements++;
129 }
130 memcpy(buffer,element,(size_t) array->size_of_element);
131 return FALSE;
132 }
133
134
135 /*
136 Alloc space for next element(s)
137
138 SYNOPSIS
139 alloc_dynamic()
140 array
141
142 DESCRIPTION
143 alloc_dynamic() checks if there is empty space for at least
144 one element if not tries to allocate space for alloc_increment
145 elements at the end of array.
146
147 RETURN VALUE
148 pointer Pointer to empty space for element
149 0 Error
150 */
151
alloc_dynamic(DYNAMIC_ARRAY * array)152 void *alloc_dynamic(DYNAMIC_ARRAY *array)
153 {
154 if (array->elements == array->max_element)
155 {
156 char *new_ptr;
157 if (array->buffer == (uchar *)(array + 1))
158 {
159 /*
160 In this senerio, the buffer is statically preallocated,
161 so we have to create an all-new malloc since we overflowed
162 */
163 if (!(new_ptr= (char *) my_malloc(array->m_psi_key,
164 (array->max_element+
165 array->alloc_increment) *
166 array->size_of_element,
167 MYF(MY_WME))))
168 return 0;
169 memcpy(new_ptr, array->buffer,
170 array->elements * array->size_of_element);
171 }
172 else
173 if (!(new_ptr=(char*) my_realloc(array->m_psi_key,
174 array->buffer,(array->max_element+
175 array->alloc_increment)*
176 array->size_of_element,
177 MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
178 return 0;
179 array->buffer= (uchar*) new_ptr;
180 array->max_element+=array->alloc_increment;
181 }
182 return array->buffer+(array->elements++ * array->size_of_element);
183 }
184
185
186 /*
187 Pop last element from array.
188
189 SYNOPSIS
190 pop_dynamic()
191 array
192
193 RETURN VALUE
194 pointer Ok
195 0 Array is empty
196 */
197
pop_dynamic(DYNAMIC_ARRAY * array)198 void *pop_dynamic(DYNAMIC_ARRAY *array)
199 {
200 if (array->elements)
201 return array->buffer+(--array->elements * array->size_of_element);
202 return 0;
203 }
204
205
206 /*
207 Get an element from array by given index
208
209 SYNOPSIS
210 get_dynamic()
211 array
212 uchar* Element to be returned. If idx > elements contain zeroes.
213 idx Index of element wanted.
214 */
215
get_dynamic(DYNAMIC_ARRAY * array,void * element,uint idx)216 void get_dynamic(DYNAMIC_ARRAY *array, void *element, uint idx)
217 {
218 if (idx >= array->elements)
219 {
220 DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
221 idx,array->elements));
222 memset(element, 0, array->size_of_element);
223 return;
224 }
225 memcpy(element,array->buffer+idx*array->size_of_element,
226 (size_t) array->size_of_element);
227 }
228
claim_dynamic(DYNAMIC_ARRAY * array)229 void claim_dynamic(DYNAMIC_ARRAY *array)
230 {
231 /*
232 Check for a static buffer
233 */
234 if (array->buffer == (uchar *)(array + 1))
235 return;
236
237 my_claim(array->buffer);
238 }
239
240
241 /*
242 Empty array by freeing all memory
243
244 SYNOPSIS
245 delete_dynamic()
246 array Array to be deleted
247 */
248
delete_dynamic(DYNAMIC_ARRAY * array)249 void delete_dynamic(DYNAMIC_ARRAY *array)
250 {
251 /*
252 Just mark as empty if we are using a static buffer
253 */
254 if (array->buffer == (uchar *)(array + 1))
255 array->elements= 0;
256 else
257 if (array->buffer)
258 {
259 my_free(array->buffer);
260 array->buffer=0;
261 array->elements=array->max_element=0;
262 }
263 }
264
265
266 /*
267 Free unused memory
268
269 SYNOPSIS
270 freeze_size()
271 array Array to be freed
272
273 */
274
freeze_size(DYNAMIC_ARRAY * array)275 void freeze_size(DYNAMIC_ARRAY *array)
276 {
277 uint elements=MY_MAX(array->elements,1);
278
279 /*
280 Do nothing if we are using a static buffer
281 */
282 if (array->buffer == (uchar *)(array + 1))
283 return;
284
285 if (array->buffer && array->max_element != elements)
286 {
287 array->buffer=(uchar*) my_realloc(array->m_psi_key,
288 array->buffer,
289 elements*array->size_of_element,
290 MYF(MY_WME));
291 array->max_element=elements;
292 }
293 }
294