Coverage Report

Created: 2024-06-18 07:03

/src/server/mysys/array.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2000, 2010, 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-1335  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
      ps_key            Key to register instrumented memory
27
      array   Pointer to an array
28
      element_size  Size of element
29
      init_buffer       Initial buffer pointer
30
      init_alloc  Number of initial elements
31
      alloc_increment Increment for adding new elements
32
      my_flags    Flags to my_malloc
33
34
  DESCRIPTION
35
    init_dynamic_array() initiates array and allocate space for
36
    init_alloc eilements.
37
    Array is usable even if space allocation failed, hence, the
38
    function never returns TRUE.
39
40
  RETURN VALUE
41
    FALSE Ok
42
*/
43
44
my_bool init_dynamic_array2(PSI_memory_key psi_key, DYNAMIC_ARRAY *array,
45
                            size_t element_size, void *init_buffer,
46
                            size_t init_alloc, size_t alloc_increment,
47
                            myf my_flags)
48
0
{
49
0
  DBUG_ENTER("init_dynamic_array2");
50
0
  if (!alloc_increment)
51
0
  {
52
0
    alloc_increment=MY_MAX((8192-MALLOC_OVERHEAD)/element_size,16);
53
0
    if (init_alloc > 8 && alloc_increment > init_alloc * 2)
54
0
      alloc_increment=init_alloc*2;
55
0
  }
56
0
  array->elements=0;
57
0
  array->max_element=init_alloc;
58
0
  array->alloc_increment=alloc_increment;
59
0
  array->size_of_element=element_size;
60
0
  array->m_psi_key= psi_key;
61
0
  array->malloc_flags= my_flags;
62
0
  DBUG_ASSERT((my_flags & MY_INIT_BUFFER_USED) == 0);
63
0
  if ((array->buffer= init_buffer))
64
0
  {
65
0
    array->malloc_flags|= MY_INIT_BUFFER_USED; 
66
0
    DBUG_RETURN(FALSE);
67
0
  }
68
  /* 
69
    Since the dynamic array is usable even if allocation fails here malloc
70
    should not throw an error
71
  */
72
0
  if (init_alloc &&
73
0
      !(array->buffer= (uchar*) my_malloc(psi_key, element_size*init_alloc,
74
0
                                          MYF(my_flags))))
75
0
    array->max_element=0;
76
0
  DBUG_RETURN(FALSE);
77
0
}
78
79
/*
80
  Insert element at the end of array. Allocate memory if needed.
81
82
  SYNOPSIS
83
    insert_dynamic()
84
      array
85
      element
86
87
  RETURN VALUE
88
    TRUE  Insert failed
89
    FALSE Ok
90
*/
91
92
my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void * element)
93
0
{
94
0
  void *buffer;
95
0
  if (unlikely(array->elements == array->max_element))
96
0
  {           /* Call only when necessary */
97
0
    if (!(buffer=alloc_dynamic(array)))
98
0
      return TRUE;
99
0
  }
100
0
  else
101
0
  {
102
0
    buffer=array->buffer+(array->elements * array->size_of_element);
103
0
    array->elements++;
104
0
  }
105
0
  memcpy(buffer, element, array->size_of_element);
106
0
  return FALSE;
107
0
}
108
109
110
/* Fast version of appending to dynamic array */
111
112
void init_append_dynamic(DYNAMIC_ARRAY_APPEND *append,
113
                         DYNAMIC_ARRAY *array)
114
0
{
115
0
  append->array= array;
116
0
  append->pos= array->buffer + array->elements * array->size_of_element;
117
0
  append->end= array->buffer + array->max_element * array->size_of_element;
118
0
}
119
120
121
my_bool append_dynamic(DYNAMIC_ARRAY_APPEND *append,
122
                       const void *element)
123
0
{
124
0
  DYNAMIC_ARRAY *array= append->array;
125
0
  size_t size_of_element= array->size_of_element;
126
0
  if (unlikely(append->pos == append->end))
127
0
  {
128
0
    void *buffer;
129
0
    if (!(buffer=alloc_dynamic(array)))
130
0
      return TRUE;
131
0
    append->pos= (uchar*)buffer + size_of_element;
132
0
    append->end= array->buffer + array->max_element * size_of_element;
133
0
    memcpy(buffer, element, size_of_element);
134
0
  }
135
0
  else
136
0
  {
137
0
    array->elements++;
138
0
    memcpy(append->pos, element, size_of_element);
139
0
    append->pos+= size_of_element;
140
0
  }
141
0
  return FALSE;
142
0
}
143
144
145
/*
146
  Alloc space for next element(s)
147
148
  SYNOPSIS
149
    alloc_dynamic()
150
      array
151
152
  DESCRIPTION
153
    alloc_dynamic() checks if there is empty space for at least
154
    one element if not tries to allocate space for alloc_increment
155
    elements at the end of array.
156
157
  RETURN VALUE
158
    pointer Pointer to empty space for element
159
    0   Error
160
*/
161
162
void *alloc_dynamic(DYNAMIC_ARRAY *array)
163
0
{
164
0
  DBUG_ENTER("alloc_dynamic");
165
166
0
  DBUG_ASSERT(array->size_of_element);          /* Ensure init() is called */
167
0
  if (array->elements == array->max_element)
168
0
  {
169
0
    char *new_ptr;
170
0
    if (array->malloc_flags & MY_INIT_BUFFER_USED)
171
0
    {
172
      /*
173
        In this scenario, the buffer is statically preallocated,
174
        so we have to create an all-new malloc since we overflowed
175
      */
176
0
      if (!(new_ptr= (char *) my_malloc(array->m_psi_key,
177
0
                                        (array->max_element+
178
0
                                         array->alloc_increment) *
179
0
                                        array->size_of_element,
180
0
                                        MYF(array->malloc_flags | MY_WME))))
181
0
        DBUG_RETURN(0);
182
0
      if (array->elements)
183
0
        memcpy(new_ptr, array->buffer,
184
0
               array->elements * array->size_of_element);
185
0
      array->malloc_flags&= ~MY_INIT_BUFFER_USED;
186
0
    }
187
0
    else if (!(new_ptr=(char*)
188
0
               my_realloc(array->m_psi_key, array->buffer,
189
0
                          (array->max_element+ array->alloc_increment) *
190
0
                          array->size_of_element,
191
0
                          MYF(MY_WME | MY_ALLOW_ZERO_PTR |
192
0
                              array->malloc_flags))))
193
0
      DBUG_RETURN(0);
194
0
    array->buffer= (uchar*) new_ptr;
195
0
    array->max_element+=array->alloc_increment;
196
0
  }
197
0
  DBUG_RETURN(array->buffer+(array->elements++ * array->size_of_element));
198
0
}
199
200
201
/*
202
  Pop last element from array.
203
204
  SYNOPSIS
205
    pop_dynamic()
206
      array
207
208
  RETURN VALUE
209
    pointer Ok
210
    0   Array is empty
211
*/
212
213
void *pop_dynamic(DYNAMIC_ARRAY *array)
214
0
{
215
0
  if (array->elements)
216
0
    return array->buffer+(--array->elements * array->size_of_element);
217
0
  return 0;
218
0
}
219
220
/*
221
  Replace element in array with given element and index
222
223
  SYNOPSIS
224
    set_dynamic()
225
      array
226
      element Element to be inserted
227
      idx Index where element is to be inserted
228
229
  DESCRIPTION
230
    set_dynamic() replaces element in array.
231
    If idx > max_element insert new element. Allocate memory if needed.
232
233
  RETURN VALUE
234
    TRUE  Idx was out of range and allocation of new memory failed
235
    FALSE Ok
236
*/
237
238
my_bool set_dynamic(DYNAMIC_ARRAY *array, const void *element, size_t idx)
239
0
{
240
0
  if (idx >= array->elements)
241
0
  {
242
0
    if (idx >= array->max_element && allocate_dynamic(array, idx))
243
0
      return TRUE;
244
0
    bzero((uchar*) (array->buffer+array->elements*array->size_of_element),
245
0
    (idx - array->elements)*array->size_of_element);
246
0
    array->elements=idx+1;
247
0
  }
248
0
  memcpy(array->buffer+(idx * array->size_of_element),element,
249
0
         array->size_of_element);
250
0
  return FALSE;
251
0
}
252
253
254
/*
255
  Ensure that dynamic array has enough elements
256
257
  SYNOPSIS
258
    allocate_dynamic()
259
    array
260
    max_elements        Numbers of elements that is needed
261
262
  NOTES
263
   Any new allocated element are NOT initialized
264
265
  RETURN VALUE
266
    FALSE Ok
267
    TRUE  Allocation of new memory failed
268
*/
269
270
my_bool allocate_dynamic(DYNAMIC_ARRAY *array, size_t max_elements)
271
0
{
272
0
  DBUG_ENTER("allocate_dynamic");
273
274
0
  if (max_elements >= array->max_element)
275
0
  {
276
0
    size_t size;
277
0
    uchar *new_ptr;
278
0
    size= (max_elements + array->alloc_increment)/array->alloc_increment;
279
0
    size*= array->alloc_increment;
280
0
    if (array->malloc_flags & MY_INIT_BUFFER_USED)
281
0
    {
282
       /*
283
         In this senerio, the buffer is statically preallocated,
284
         so we have to create an all-new malloc since we overflowed
285
       */
286
0
       if (!(new_ptr= (uchar *) my_malloc(array->m_psi_key, size *
287
0
                                          array->size_of_element,
288
0
                                          MYF(array->malloc_flags | MY_WME))))
289
0
         DBUG_RETURN(0);
290
0
       memcpy(new_ptr, array->buffer,
291
0
              array->elements * array->size_of_element);
292
0
       array->malloc_flags&= ~MY_INIT_BUFFER_USED;
293
0
    }
294
0
    else if (!(new_ptr= (uchar*) my_realloc(array->m_psi_key,
295
0
                                            array->buffer,size *
296
0
                                            array->size_of_element,
297
0
                                            MYF(MY_WME | MY_ALLOW_ZERO_PTR |
298
0
                                                array->malloc_flags))))
299
0
      DBUG_RETURN(TRUE);
300
0
    array->buffer= new_ptr;
301
0
    array->max_element= size;
302
0
  }
303
0
  DBUG_RETURN(FALSE);
304
0
}
305
306
307
/*
308
  Get an element from array by given index
309
310
  SYNOPSIS
311
    get_dynamic()
312
      array
313
      uchar*  Element to be returned. If idx > elements contain zeroes.
314
      idx Index of element wanted.
315
*/
316
317
void get_dynamic(DYNAMIC_ARRAY *array, void *element, size_t idx)
318
0
{
319
0
  if (unlikely(idx >= array->elements))
320
0
  {
321
0
    DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
322
0
                          idx,array->elements));
323
0
    bzero(element,array->size_of_element);
324
0
    return;
325
0
  }
326
0
  memcpy(element,array->buffer+idx*array->size_of_element,
327
0
         (size_t) array->size_of_element);
328
0
}
329
330
331
/*
332
  Empty array by freeing all memory
333
334
  SYNOPSIS
335
    delete_dynamic()
336
      array Array to be deleted
337
*/
338
339
void delete_dynamic(DYNAMIC_ARRAY *array)
340
0
{
341
  /*
342
    Just mark as empty if we are using a static buffer
343
  */
344
0
  if (array->buffer && !(array->malloc_flags & MY_INIT_BUFFER_USED))
345
0
    my_free(array->buffer);
346
347
0
  array->buffer= 0;
348
0
  array->elements= array->max_element= 0;
349
0
}
350
351
/*
352
  Delete element by given index
353
354
  SYNOPSIS
355
    delete_dynamic_element()
356
      array
357
      idx        Index of element to be deleted
358
*/
359
360
void delete_dynamic_element(DYNAMIC_ARRAY *array, size_t idx)
361
0
{
362
0
  char *ptr= (char*) array->buffer+array->size_of_element*idx;
363
0
  array->elements--;
364
0
  memmove(ptr,ptr+array->size_of_element,
365
0
          (array->elements-idx)*array->size_of_element);
366
0
}
367
368
/*
369
  Wrapper around delete_dynamic, calling a FREE function on every
370
  element, before releasing the memory
371
372
  SYNOPSIS
373
    delete_dynamic_with_callback()
374
      array
375
      f          The function to be called on every element before
376
                 deleting the array;
377
*/
378
0
void delete_dynamic_with_callback(DYNAMIC_ARRAY *array, FREE_FUNC f) {
379
0
  size_t i;
380
0
  char *ptr= (char*) array->buffer;
381
0
  for (i= 0; i < array->elements; i++, ptr+= array->size_of_element) {
382
0
    f(ptr);
383
0
  }
384
0
  delete_dynamic(array);
385
0
}
386
/*
387
  Free unused memory
388
389
  SYNOPSIS
390
    freeze_size()
391
      array Array to be freed
392
393
*/
394
395
void freeze_size(DYNAMIC_ARRAY *array)
396
0
{
397
0
  size_t elements;
398
399
  /*
400
    Do nothing if we are using a static buffer
401
  */
402
0
  if (array->malloc_flags & MY_INIT_BUFFER_USED)
403
0
    return;
404
405
0
  elements= MY_MAX(array->elements, 1);
406
0
  if (array->buffer && array->max_element > elements)
407
0
  {
408
0
    array->buffer=(uchar*) my_realloc(array->m_psi_key, array->buffer,
409
0
                                      elements * array->size_of_element,
410
0
                                      MYF(MY_WME | array->malloc_flags));
411
0
    array->max_element= elements;
412
0
  }
413
0
}