~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/my_alloc.c

  • Committer: Andy Lester
  • Date: 2008-08-09 05:23:39 UTC
  • mto: (266.1.29 use-replace-funcs)
  • mto: This revision was merged to the branch mainline in revision 287.
  • Revision ID: andy@petdance.com-20080809052339-iafoesszmesweq6b
use NULL, not 0

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
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
 
/**
17
 
 * @file
18
 
 * Routines to handle mallocing of results which will be freed the same time 
19
 
 */
20
 
 
21
 
#include "config.h"
22
 
 
23
 
#include "drizzled/internal/my_sys.h"
24
 
#include "drizzled/internal/m_string.h"
25
 
 
26
 
#include <algorithm>
27
 
 
28
 
using namespace std;
29
 
 
30
 
namespace drizzled
31
 
{
32
 
 
33
 
static const unsigned int MAX_BLOCK_TO_DROP= 4096;
34
 
static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
35
 
 
36
 
/**
37
 
 * @brief
38
 
 * Initialize memory root
39
 
 *
40
 
 * @details
41
 
 * This function prepares memory root for further use, sets initial size of
42
 
 * chunk for memory allocation and pre-allocates first block if specified.
43
 
 * Altough error can happen during execution of this function if
44
 
 * pre_alloc_size is non-0 it won't be reported. Instead it will be
45
 
 * reported as error in first alloc_root() on this memory root.
46
 
 *
47
 
 * @param  mem_root       memory root to initialize
48
 
 * @param  block_size     size of chunks (blocks) used for memory allocation
49
 
 *                       (It is external size of chunk i.e. it should include
50
 
 *                      memory required for internal structures, thus it
51
 
 *                      should be no less than memory::ROOT_MIN_BLOCK_SIZE)
52
 
 *
53
 
 */
54
 
void memory::Root::init_alloc_root(size_t block_size_arg)
55
 
{
56
 
  free= used= pre_alloc= 0;
57
 
  min_malloc= 32;
58
 
  block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
59
 
  error_handler= 0;
60
 
  block_num= 4;                 /* We shift this with >>2 */
61
 
  first_block_usage= 0;
62
 
}
63
 
 
64
 
memory::Root::~Root()
65
 
{
66
 
}
67
 
 
68
 
 
69
 
/**
70
 
 * @details
71
 
 * Function aligns and assigns new value to block size; then it tries to
72
 
 * reuse one of existing blocks as prealloc block, or malloc new one of
73
 
 * requested size. If no blocks can be reused, all unused blocks are freed
74
 
 * before allocation.
75
 
 *
76
 
 * @param  mem_root        memory root to change defaults of
77
 
 * @param  block_size      new value of block size. Must be greater or equal
78
 
 *                         than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
79
 
 *                         68 bytes and depends on platform and compilation flags)
80
 
 * @param pre_alloc_size  new size of preallocated block. If not zero,
81
 
 *                        must be equal to or greater than block size,
82
 
 *                        otherwise means 'no prealloc'.
83
 
 */
84
 
void memory::Root::reset_root_defaults(size_t block_size_arg, size_t pre_alloc_size)
85
 
{
86
 
  block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
87
 
  if (pre_alloc_size)
88
 
  {
89
 
    size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
90
 
    if (not pre_alloc || pre_alloc->size != size)
91
 
    {
92
 
      memory::internal::UsedMemory *mem, **prev= &this->free;
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
/* Routines to handle mallocing of results which will be freed the same time */
 
17
 
 
18
#include <mystrings/m_string.h>
 
19
#include <my_sys.h>
 
20
#undef EXTRA_DEBUG
 
21
#define EXTRA_DEBUG
 
22
 
 
23
 
 
24
/*
 
25
  Initialize memory root
 
26
 
 
27
  SYNOPSIS
 
28
    init_alloc_root()
 
29
      mem_root       - memory root to initialize
 
30
      block_size     - size of chunks (blocks) used for memory allocation
 
31
                       (It is external size of chunk i.e. it should include
 
32
                        memory required for internal structures, thus it
 
33
                        should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
 
34
      pre_alloc_size - if non-0, then size of block that should be
 
35
                       pre-allocated during memory root initialization.
 
36
 
 
37
  DESCRIPTION
 
38
    This function prepares memory root for further use, sets initial size of
 
39
    chunk for memory allocation and pre-allocates first block if specified.
 
40
    Altough error can happen during execution of this function if
 
41
    pre_alloc_size is non-0 it won't be reported. Instead it will be
 
42
    reported as error in first alloc_root() on this memory root.
 
43
*/
 
44
 
 
45
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
 
46
                     size_t pre_alloc_size __attribute__((unused)))
 
47
{
 
48
  mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
 
49
  mem_root->min_malloc= 32;
 
50
  mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
 
51
  mem_root->error_handler= 0;
 
52
  mem_root->block_num= 4;                       /* We shift this with >>2 */
 
53
  mem_root->first_block_usage= 0;
 
54
 
 
55
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
 
56
  if (pre_alloc_size)
 
57
  {
 
58
    if ((mem_root->free= mem_root->pre_alloc=
 
59
         (USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
 
60
                               MYF(0))))
 
61
    {
 
62
      mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
 
63
      mem_root->free->left= pre_alloc_size;
 
64
      mem_root->free->next= 0;
 
65
    }
 
66
  }
 
67
#endif
 
68
  return;
 
69
}
 
70
 
 
71
 
 
72
/*
 
73
  SYNOPSIS
 
74
    reset_root_defaults()
 
75
    mem_root        memory root to change defaults of
 
76
    block_size      new value of block size. Must be greater or equal
 
77
                    than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
 
78
                    68 bytes and depends on platform and compilation flags)
 
79
    pre_alloc_size  new size of preallocated block. If not zero,
 
80
                    must be equal to or greater than block size,
 
81
                    otherwise means 'no prealloc'.
 
82
  DESCRIPTION
 
83
    Function aligns and assigns new value to block size; then it tries to
 
84
    reuse one of existing blocks as prealloc block, or malloc new one of
 
85
    requested size. If no blocks can be reused, all unused blocks are freed
 
86
    before allocation.
 
87
*/
 
88
 
 
89
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
 
90
                         size_t pre_alloc_size __attribute__((unused)))
 
91
{
 
92
  assert(alloc_root_inited(mem_root));
 
93
 
 
94
  mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
 
95
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
 
96
  if (pre_alloc_size)
 
97
  {
 
98
    size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
 
99
    if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
 
100
    {
 
101
      USED_MEM *mem, **prev= &mem_root->free;
93
102
      /*
94
103
        Free unused blocks, so that consequent calls
95
104
        to reset_root_defaults won't eat away memory.
100
109
        if (mem->size == size)
101
110
        {
102
111
          /* We found a suitable block, no need to do anything else */
103
 
          pre_alloc= mem;
 
112
          mem_root->pre_alloc= mem;
104
113
          return;
105
114
        }
106
 
        if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
 
115
        if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
107
116
        {
108
117
          /* remove block from the list and free it */
109
118
          *prev= mem->next;
110
 
          std::free(mem);
 
119
          my_free(mem, MYF(0));
111
120
        }
112
121
        else
113
122
          prev= &mem->next;
114
123
      }
115
124
      /* Allocate new prealloc block and add it to the end of free list */
116
 
      if ((mem= static_cast<memory::internal::UsedMemory *>(malloc(size))))
 
125
      if ((mem= (USED_MEM *) my_malloc(size, MYF(0))))
117
126
      {
118
 
        mem->size= size;
 
127
        mem->size= size; 
119
128
        mem->left= pre_alloc_size;
120
129
        mem->next= *prev;
121
 
        *prev= pre_alloc= mem;
 
130
        *prev= mem_root->pre_alloc= mem; 
122
131
      }
123
132
      else
124
133
      {
125
 
        pre_alloc= 0;
 
134
        mem_root->pre_alloc= 0;
126
135
      }
127
136
    }
128
137
  }
129
138
  else
 
139
#endif
 
140
    mem_root->pre_alloc= 0;
 
141
}
 
142
 
 
143
 
 
144
void *alloc_root(MEM_ROOT *mem_root, size_t length)
 
145
{
 
146
#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
 
147
  register USED_MEM *next;
 
148
 
 
149
  assert(alloc_root_inited(mem_root));
 
150
 
 
151
  length+=ALIGN_SIZE(sizeof(USED_MEM));
 
152
  if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME | ME_FATALERROR))))
130
153
  {
131
 
    pre_alloc= 0;
 
154
    if (mem_root->error_handler)
 
155
      (*mem_root->error_handler)();
 
156
    return((uchar*) 0);                 /* purecov: inspected */
132
157
  }
133
 
}
134
 
 
135
 
/**
136
 
 * @brief 
137
 
 * Allocate a chunk of memory from the Root structure provided, 
138
 
 * obtaining more memory from the heap if necessary
139
 
 *
140
 
 * @pre
141
 
 * mem_root must have been initialised via init_alloc_root()
142
 
 *
143
 
 * @param  mem_root  The memory Root to allocate from
144
 
 * @param  length    The size of the block to allocate
145
 
 *
146
 
 * @todo Would this be more suitable as a member function on the
147
 
 * Root class?
148
 
 */
149
 
void *memory::Root::alloc_root(size_t length)
150
 
{
151
 
  unsigned char* point;
152
 
  memory::internal::UsedMemory *next= NULL;
153
 
  memory::internal::UsedMemory **prev;
154
 
  assert(alloc_root_inited());
 
158
  next->next= mem_root->used;
 
159
  next->size= length;
 
160
  mem_root->used= next;
 
161
  return((uchar*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
 
162
#else
 
163
  size_t get_size, block_size;
 
164
  uchar* point;
 
165
  register USED_MEM *next= 0;
 
166
  register USED_MEM **prev;
 
167
  assert(alloc_root_inited(mem_root));
155
168
 
156
169
  length= ALIGN_SIZE(length);
157
 
  if ((*(prev= &this->free)) != NULL)
 
170
  if ((*(prev= &mem_root->free)) != NULL)
158
171
  {
159
172
    if ((*prev)->left < length &&
160
 
        this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
161
 
        (*prev)->left < MAX_BLOCK_TO_DROP)
 
173
        mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
 
174
        (*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
162
175
    {
163
176
      next= *prev;
164
177
      *prev= next->next;                        /* Remove block from list */
165
 
      next->next= this->used;
166
 
      this->used= next;
167
 
      this->first_block_usage= 0;
 
178
      next->next= mem_root->used;
 
179
      mem_root->used= next;
 
180
      mem_root->first_block_usage= 0;
168
181
    }
169
182
    for (next= *prev ; next && next->left < length ; next= next->next)
170
183
      prev= &next->next;
171
184
  }
172
185
  if (! next)
173
186
  {                                             /* Time to alloc new block */
174
 
    size_t get_size, tmp_block_size;
175
 
 
176
 
    tmp_block_size= this->block_size * (this->block_num >> 2);
177
 
    get_size= length+ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
178
 
    get_size= max(get_size, tmp_block_size);
179
 
 
180
 
    if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
 
187
    block_size= mem_root->block_size * (mem_root->block_num >> 2);
 
188
    get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
 
189
    get_size= max(get_size, block_size);
 
190
 
 
191
    if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR))))
181
192
    {
182
 
      if (this->error_handler)
183
 
        (*this->error_handler)();
184
 
      return NULL;
 
193
      if (mem_root->error_handler)
 
194
        (*mem_root->error_handler)();
 
195
      return((void*) 0);                      /* purecov: inspected */
185
196
    }
186
 
    this->block_num++;
 
197
    mem_root->block_num++;
187
198
    next->next= *prev;
188
199
    next->size= get_size;
189
 
    next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
 
200
    next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
190
201
    *prev=next;
191
202
  }
192
203
 
193
 
  point= (unsigned char*) ((char*) next+ (next->size-next->left));
194
 
  /** @todo next part may be unneeded due to this->first_block_usage counter*/
195
 
  if ((next->left-= length) < this->min_malloc)
 
204
  point= (uchar*) ((char*) next+ (next->size-next->left));
 
205
  /*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
 
206
  if ((next->left-= length) < mem_root->min_malloc)
196
207
  {                                             /* Full block */
197
208
    *prev= next->next;                          /* Remove block from list */
198
 
    next->next= this->used;
199
 
    this->used= next;
200
 
    this->first_block_usage= 0;
 
209
    next->next= mem_root->used;
 
210
    mem_root->used= next;
 
211
    mem_root->first_block_usage= 0;
201
212
  }
202
 
 
203
 
  return point;
 
213
  return((void*) point);
 
214
#endif
204
215
}
205
216
 
206
217
 
207
 
/**
208
 
 * @brief
209
 
 * Allocate many pointers at the same time.
210
 
 *
211
 
 * @details
212
 
 * The variable arguments are a list of alternating pointers and lengths,
213
 
 * terminated by a null pointer:
214
 
 * @li <tt>char ** pointer1</tt>
215
 
 * @li <tt>uint length1</tt>
216
 
 * @li <tt>char ** pointer2</tt>
217
 
 * @li <tt>uint length2</tt>
218
 
 * @li <tt>...</tt>
219
 
 * @li <tt>NULL</tt>
220
 
 *
221
 
 * @c pointer1, @c pointer2 etc. all point into big allocated memory area
222
 
 *
223
 
 * @param root  Memory root
224
 
 *
225
 
 * @return
226
 
 * A pointer to the beginning of the allocated memory block in case of 
227
 
 * success or NULL if out of memory
228
 
 */
229
 
void *memory::Root::multi_alloc_root(int unused, ...)
 
218
/*
 
219
  Allocate many pointers at the same time.
 
220
 
 
221
  DESCRIPTION
 
222
    ptr1, ptr2, etc all point into big allocated memory area.
 
223
 
 
224
  SYNOPSIS
 
225
    multi_alloc_root()
 
226
      root               Memory root
 
227
      ptr1, length1      Multiple arguments terminated by a NULL pointer
 
228
      ptr2, length2      ...
 
229
      ...
 
230
      NULL
 
231
 
 
232
  RETURN VALUE
 
233
    A pointer to the beginning of the allocated memory block
 
234
    in case of success or NULL if out of memory.
 
235
*/
 
236
 
 
237
void *multi_alloc_root(MEM_ROOT *root, ...)
230
238
{
231
239
  va_list args;
232
240
  char **ptr, *start, *res;
233
241
  size_t tot_length, length;
234
242
 
235
 
  (void)unused; // For some reason Sun Studio registers unused as not used.
236
 
  va_start(args, unused);
 
243
  va_start(args, root);
237
244
  tot_length= 0;
238
245
  while ((ptr= va_arg(args, char **)))
239
246
  {
242
249
  }
243
250
  va_end(args);
244
251
 
245
 
  if (!(start= (char*) this->alloc_root(tot_length)))
246
 
    return(0);
 
252
  if (!(start= (char*) alloc_root(root, tot_length)))
 
253
    return(0);                            /* purecov: inspected */
247
254
 
248
 
  va_start(args, unused);
 
255
  va_start(args, root);
249
256
  res= start;
250
257
  while ((ptr= va_arg(args, char **)))
251
258
  {
257
264
  return((void*) start);
258
265
}
259
266
 
260
 
static void trash_mem(memory::internal::UsedMemory *)
261
 
{
262
 
  TRASH(((char*)(x) + (x->size - x->left)), x->left);
263
 
}
264
 
 
265
 
/**
266
 
 * @brief
267
 
 * Mark all data in blocks free for reusage 
268
 
 */
269
 
void memory::Root::mark_blocks_free()
270
 
{
271
 
  memory::internal::UsedMemory *next;
272
 
  memory::internal::UsedMemory **last;
 
267
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
 
268
 
 
269
/* Mark all data in blocks free for reusage */
 
270
 
 
271
static inline void mark_blocks_free(MEM_ROOT* root)
 
272
{
 
273
  register USED_MEM *next;
 
274
  register USED_MEM **last;
273
275
 
274
276
  /* iterate through (partially) free blocks, mark them free */
275
 
  last= &free;
276
 
  for (next= free; next; next= *(last= &next->next))
 
277
  last= &root->free;
 
278
  for (next= root->free; next; next= *(last= &next->next))
277
279
  {
278
 
    next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
279
 
    trash_mem(next);
 
280
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
 
281
    TRASH_MEM(next);
280
282
  }
281
283
 
282
284
  /* Combine the free and the used list */
283
 
  *last= next= used;
 
285
  *last= next=root->used;
284
286
 
285
287
  /* now go through the used blocks and mark them free */
286
288
  for (; next; next= next->next)
287
289
  {
288
 
    next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
289
 
    trash_mem(next);
 
290
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
 
291
    TRASH_MEM(next);
290
292
  }
291
293
 
292
294
  /* Now everything is set; Indicate that nothing is used anymore */
293
 
  used= 0;
294
 
  first_block_usage= 0;
 
295
  root->used= 0;
 
296
  root->first_block_usage= 0;
295
297
}
296
298
 
297
 
/**
298
 
 * @brief
299
 
 * Deallocate everything used by memory::alloc_root or just move
300
 
 * used blocks to free list if called with MY_USED_TO_FREE
301
 
 *
302
 
 * @note
303
 
 * One can call this function either with root block initialised with
304
 
 * init_alloc_root() or with a zero:ed block.
305
 
 * It's also safe to call this multiple times with the same mem_root.
306
 
 *
307
 
 * @param   root     Memory root
308
 
 * @param   MyFlags  Flags for what should be freed:
309
 
 *   @li   MARK_BLOCKS_FREED    Don't free blocks, just mark them free
310
 
 *   @li   KEEP_PREALLOC        If this is not set, then free also the
311
 
 *                              preallocated block
312
 
 */
313
 
void memory::Root::free_root(myf MyFlags)
 
299
 
 
300
/*
 
301
  Deallocate everything used by alloc_root or just move
 
302
  used blocks to free list if called with MY_USED_TO_FREE
 
303
 
 
304
  SYNOPSIS
 
305
    free_root()
 
306
      root              Memory root
 
307
      MyFlags           Flags for what should be freed:
 
308
 
 
309
        MY_MARK_BLOCKS_FREED    Don't free blocks, just mark them free
 
310
        MY_KEEP_PREALLOC        If this is not set, then free also the
 
311
                                preallocated block
 
312
 
 
313
  NOTES
 
314
    One can call this function either with root block initialised with
 
315
    init_alloc_root() or with a zero:ed block.
 
316
    It's also safe to call this multiple times with the same mem_root.
 
317
*/
 
318
 
 
319
void free_root(MEM_ROOT *root, myf MyFlags)
314
320
{
315
 
  memory::internal::UsedMemory *next,*old;
 
321
  register USED_MEM *next,*old;
316
322
 
317
 
  if (MyFlags & memory::MARK_BLOCKS_FREE)
 
323
  if (MyFlags & MY_MARK_BLOCKS_FREE)
318
324
  {
319
 
    this->mark_blocks_free();
 
325
    mark_blocks_free(root);
320
326
    return;
321
327
  }
322
 
  if (!(MyFlags & memory::KEEP_PREALLOC))
323
 
    this->pre_alloc=0;
 
328
  if (!(MyFlags & MY_KEEP_PREALLOC))
 
329
    root->pre_alloc=0;
324
330
 
325
 
  for (next=this->used; next ;)
 
331
  for (next=root->used; next ;)
326
332
  {
327
333
    old=next; next= next->next ;
328
 
    if (old != this->pre_alloc)
329
 
      std::free(old);
 
334
    if (old != root->pre_alloc)
 
335
      my_free(old,MYF(0));
330
336
  }
331
 
  for (next=this->free ; next ;)
 
337
  for (next=root->free ; next ;)
332
338
  {
333
339
    old=next; next= next->next;
334
 
    if (old != this->pre_alloc)
335
 
      std::free(old);
336
 
  }
337
 
  this->used=this->free=0;
338
 
  if (this->pre_alloc)
339
 
  {
340
 
    this->free=this->pre_alloc;
341
 
    this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
342
 
    trash_mem(this->pre_alloc);
343
 
    this->free->next=0;
344
 
  }
345
 
  this->block_num= 4;
346
 
  this->first_block_usage= 0;
347
 
}
348
 
 
349
 
/**
350
 
 * @brief
351
 
 * Duplicate a null-terminated string into memory allocated from within the
352
 
 * specified Root
353
 
 */
354
 
char *memory::Root::strdup_root(const char *str)
355
 
{
356
 
  return strmake_root(str, strlen(str));
357
 
}
358
 
 
359
 
/**
360
 
 * @brief
361
 
 * Copy the (not necessarily null-terminated) string into memory allocated
362
 
 * from within the specified Root
363
 
 *
364
 
 * @details
365
 
 * Note that the string is copied according to the length specified, so
366
 
 * null-termination is ignored. The duplicated string will be null-terminated,
367
 
 * even if the original string wasn't (one additional byte is allocated for
368
 
 * this purpose).
369
 
 */
370
 
char *memory::Root::strmake_root(const char *str, size_t len)
 
340
    if (old != root->pre_alloc)
 
341
      my_free(old,MYF(0));
 
342
  }
 
343
  root->used=root->free=0;
 
344
  if (root->pre_alloc)
 
345
  {
 
346
    root->free=root->pre_alloc;
 
347
    root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
 
348
    TRASH_MEM(root->pre_alloc);
 
349
    root->free->next=0;
 
350
  }
 
351
  root->block_num= 4;
 
352
  root->first_block_usage= 0;
 
353
  return;
 
354
}
 
355
 
 
356
/*
 
357
  Find block that contains an object and set the pre_alloc to it
 
358
*/
 
359
 
 
360
void set_prealloc_root(MEM_ROOT *root, char *ptr)
 
361
{
 
362
  USED_MEM *next;
 
363
  for (next=root->used; next ; next=next->next)
 
364
  {
 
365
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
 
366
    {
 
367
      root->pre_alloc=next;
 
368
      return;
 
369
    }
 
370
  }
 
371
  for (next=root->free ; next ; next=next->next)
 
372
  {
 
373
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
 
374
    {
 
375
      root->pre_alloc=next;
 
376
      return;
 
377
    }
 
378
  }
 
379
}
 
380
 
 
381
 
 
382
char *strdup_root(MEM_ROOT *root, const char *str)
 
383
{
 
384
  return strmake_root(root, str, strlen(str));
 
385
}
 
386
 
 
387
 
 
388
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
371
389
{
372
390
  char *pos;
373
 
  if ((pos= (char *)alloc_root(len+1)))
 
391
  if ((pos=alloc_root(root,len+1)))
374
392
  {
375
393
    memcpy(pos,str,len);
376
394
    pos[len]=0;
378
396
  return pos;
379
397
}
380
398
 
381
 
/**
382
 
 * @brief
383
 
 * Duplicate the provided block into memory allocated from within the specified
384
 
 * Root
385
 
 *
386
 
 * @return
387
 
 * non-NULL pointer to a copy of the data if memory could be allocated, otherwise
388
 
 * NULL
389
 
 */
390
 
void *memory::Root::memdup_root(const void *str, size_t len)
 
399
 
 
400
void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
391
401
{
392
 
  void *pos;
393
 
 
394
 
  if ((pos= this->alloc_root(len)))
 
402
  char *pos;
 
403
  if ((pos=alloc_root(root,len)))
395
404
    memcpy(pos,str,len);
396
 
 
397
405
  return pos;
398
406
}
399
 
 
400
 
} /* namespace drizzled */