MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
array.c
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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 as published by
5  the Free Software Foundation; version 2 of the License.
6 
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 General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /* Handling of arrays that can grow dynamicly. */
17 
18 #include "mysys_priv.h"
19 #include "m_string.h"
20 
21 /*
22  Initiate dynamic array
23 
24  SYNOPSIS
25  init_dynamic_array2()
26  array Pointer to an array
27  element_size Size of element
28  init_buffer Initial buffer pointer
29  init_alloc Number of initial elements
30  alloc_increment Increment for adding new elements
31 
32  DESCRIPTION
33  init_dynamic_array() initiates array and allocate space for
34  init_alloc eilements.
35  Array is usable even if space allocation failed, hence, the
36  function never returns TRUE.
37  Static buffers must begin immediately after the array structure.
38 
39  RETURN VALUE
40  FALSE Ok
41 */
42 
43 my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
44  void *init_buffer, uint init_alloc,
45  uint alloc_increment)
46 {
47  DBUG_ENTER("init_dynamic_array");
48  if (!alloc_increment)
49  {
50  alloc_increment=MY_MAX((8192-MALLOC_OVERHEAD)/element_size,16);
51  if (init_alloc > 8 && alloc_increment > init_alloc * 2)
52  alloc_increment=init_alloc*2;
53  }
54 
55  if (!init_alloc)
56  {
57  init_alloc=alloc_increment;
58  init_buffer= 0;
59  }
60  array->elements=0;
61  array->max_element=init_alloc;
62  array->alloc_increment=alloc_increment;
63  array->size_of_element=element_size;
64  if ((array->buffer= init_buffer))
65  DBUG_RETURN(FALSE);
66  /*
67  Since the dynamic array is usable even if allocation fails here malloc
68  should not throw an error
69  */
70  if (!(array->buffer= (uchar*) my_malloc(element_size*init_alloc, MYF(0))))
71  array->max_element=0;
72  DBUG_RETURN(FALSE);
73 }
74 
75 my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
76  uint init_alloc, uint alloc_increment)
77 {
78  /* placeholder to preserve ABI */
79  return my_init_dynamic_array_ci(array, element_size, init_alloc,
80  alloc_increment);
81 }
82 /*
83  Insert element at the end of array. Allocate memory if needed.
84 
85  SYNOPSIS
86  insert_dynamic()
87  array
88  element
89 
90  RETURN VALUE
91  TRUE Insert failed
92  FALSE Ok
93 */
94 
95 my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void *element)
96 {
97  uchar* buffer;
98  if (array->elements == array->max_element)
99  { /* Call only when nessesary */
100  if (!(buffer=alloc_dynamic(array)))
101  return TRUE;
102  }
103  else
104  {
105  buffer=array->buffer+(array->elements * array->size_of_element);
106  array->elements++;
107  }
108  memcpy(buffer,element,(size_t) array->size_of_element);
109  return FALSE;
110 }
111 
112 
113 /*
114  Alloc space for next element(s)
115 
116  SYNOPSIS
117  alloc_dynamic()
118  array
119 
120  DESCRIPTION
121  alloc_dynamic() checks if there is empty space for at least
122  one element if not tries to allocate space for alloc_increment
123  elements at the end of array.
124 
125  RETURN VALUE
126  pointer Pointer to empty space for element
127  0 Error
128 */
129 
130 void *alloc_dynamic(DYNAMIC_ARRAY *array)
131 {
132  if (array->elements == array->max_element)
133  {
134  char *new_ptr;
135  if (array->buffer == (uchar *)(array + 1))
136  {
137  /*
138  In this senerio, the buffer is statically preallocated,
139  so we have to create an all-new malloc since we overflowed
140  */
141  if (!(new_ptr= (char *) my_malloc((array->max_element+
142  array->alloc_increment) *
143  array->size_of_element,
144  MYF(MY_WME))))
145  return 0;
146  memcpy(new_ptr, array->buffer,
147  array->elements * array->size_of_element);
148  }
149  else
150  if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+
151  array->alloc_increment)*
152  array->size_of_element,
153  MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
154  return 0;
155  array->buffer= (uchar*) new_ptr;
156  array->max_element+=array->alloc_increment;
157  }
158  return array->buffer+(array->elements++ * array->size_of_element);
159 }
160 
161 
162 /*
163  Pop last element from array.
164 
165  SYNOPSIS
166  pop_dynamic()
167  array
168 
169  RETURN VALUE
170  pointer Ok
171  0 Array is empty
172 */
173 
174 void *pop_dynamic(DYNAMIC_ARRAY *array)
175 {
176  if (array->elements)
177  return array->buffer+(--array->elements * array->size_of_element);
178  return 0;
179 }
180 
181 /*
182  Replace element in array with given element and index
183 
184  SYNOPSIS
185  set_dynamic()
186  array
187  element Element to be inserted
188  idx Index where element is to be inserted
189 
190  DESCRIPTION
191  set_dynamic() replaces element in array.
192  If idx > max_element insert new element. Allocate memory if needed.
193 
194  RETURN VALUE
195  TRUE Idx was out of range and allocation of new memory failed
196  FALSE Ok
197 */
198 
199 my_bool set_dynamic(DYNAMIC_ARRAY *array, const void *element, uint idx)
200 {
201  if (idx >= array->elements)
202  {
203  if (idx >= array->max_element && allocate_dynamic(array, idx))
204  return TRUE;
205  memset((array->buffer+array->elements*array->size_of_element), 0,
206  (idx - array->elements)*array->size_of_element);
207  array->elements=idx+1;
208  }
209  memcpy(array->buffer+(idx * array->size_of_element),element,
210  (size_t) array->size_of_element);
211  return FALSE;
212 }
213 
214 
215 /*
216  Ensure that dynamic array has enough elements
217 
218  SYNOPSIS
219  allocate_dynamic()
220  array
221  max_elements Numbers of elements that is needed
222 
223  NOTES
224  Any new allocated element are NOT initialized
225 
226  RETURN VALUE
227  FALSE Ok
228  TRUE Allocation of new memory failed
229 */
230 
231 my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements)
232 {
233  if (max_elements >= array->max_element)
234  {
235  uint size;
236  uchar *new_ptr;
237  size= (max_elements + array->alloc_increment)/array->alloc_increment;
238  size*= array->alloc_increment;
239  if (array->buffer == (uchar *)(array + 1))
240  {
241  /*
242  In this senerio, the buffer is statically preallocated,
243  so we have to create an all-new malloc since we overflowed
244  */
245  if (!(new_ptr= (uchar *) my_malloc(size *
246  array->size_of_element,
247  MYF(MY_WME))))
248  return 0;
249  memcpy(new_ptr, array->buffer,
250  array->elements * array->size_of_element);
251  }
252  else
253 
254 
255  if (!(new_ptr= (uchar*) my_realloc(array->buffer,size*
256  array->size_of_element,
257  MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
258  return TRUE;
259  array->buffer= new_ptr;
260  array->max_element= size;
261  }
262  return FALSE;
263 }
264 
265 
266 /*
267  Get an element from array by given index
268 
269  SYNOPSIS
270  get_dynamic()
271  array
272  uchar* Element to be returned. If idx > elements contain zeroes.
273  idx Index of element wanted.
274 */
275 
276 void get_dynamic(DYNAMIC_ARRAY *array, void *element, uint idx)
277 {
278  if (idx >= array->elements)
279  {
280  DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
281  idx,array->elements));
282  memset(element, 0, array->size_of_element);
283  return;
284  }
285  memcpy(element,array->buffer+idx*array->size_of_element,
286  (size_t) array->size_of_element);
287 }
288 
289 
290 /*
291  Empty array by freeing all memory
292 
293  SYNOPSIS
294  delete_dynamic()
295  array Array to be deleted
296 */
297 
298 void delete_dynamic(DYNAMIC_ARRAY *array)
299 {
300  /*
301  Just mark as empty if we are using a static buffer
302  */
303  if (array->buffer == (uchar *)(array + 1))
304  array->elements= 0;
305  else
306  if (array->buffer)
307  {
308  my_free(array->buffer);
309  array->buffer=0;
310  array->elements=array->max_element=0;
311  }
312 }
313 
314 /*
315  Delete element by given index
316 
317  SYNOPSIS
318  delete_dynamic_element()
319  array
320  idx Index of element to be deleted
321 */
322 
323 void delete_dynamic_element(DYNAMIC_ARRAY *array, uint idx)
324 {
325  char *ptr= (char*) array->buffer+array->size_of_element*idx;
326  array->elements--;
327  memmove(ptr,ptr+array->size_of_element,
328  (array->elements-idx)*array->size_of_element);
329 }
330 
331 
332 /*
333  Free unused memory
334 
335  SYNOPSIS
336  freeze_size()
337  array Array to be freed
338 
339 */
340 
341 void freeze_size(DYNAMIC_ARRAY *array)
342 {
343  uint elements=MY_MAX(array->elements,1);
344 
345  /*
346  Do nothing if we are using a static buffer
347  */
348  if (array->buffer == (uchar *)(array + 1))
349  return;
350 
351  if (array->buffer && array->max_element != elements)
352  {
353  array->buffer=(uchar*) my_realloc(array->buffer,
354  elements*array->size_of_element,
355  MYF(MY_WME));
356  array->max_element=elements;
357  }
358 }