d7bdd3dbccb2c87b9008706b113defb8911ac06a
[musl] / src / regex / tre-mem.c
1 /*
2   tre-mem.c - TRE memory allocator
3
4   Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi>
5
6   This library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public
8   License as published by the Free Software Foundation; either
9   version 2.1 of the License, or (at your option) any later version.
10
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with this library; if not, write to the Free Software
18   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
20 */
21
22 /*
23   This memory allocator is for allocating small memory blocks efficiently
24   in terms of memory overhead and execution speed.  The allocated blocks
25   cannot be freed individually, only all at once.  There can be multiple
26   allocators, though.
27 */
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "tre.h"
33
34
35 /* Returns a new memory allocator or NULL if out of memory. */
36 tre_mem_t
37 tre_mem_new_impl(int provided, void *provided_block)
38 {
39   tre_mem_t mem;
40   if (provided)
41     {
42       mem = provided_block;
43       memset(mem, 0, sizeof(*mem));
44     }
45   else
46     mem = xcalloc(1, sizeof(*mem));
47   if (mem == NULL)
48     return NULL;
49   return mem;
50 }
51
52
53 /* Frees the memory allocator and all memory allocated with it. */
54 void
55 tre_mem_destroy(tre_mem_t mem)
56 {
57   tre_list_t *tmp, *l = mem->blocks;
58
59   while (l != NULL)
60     {
61       xfree(l->data);
62       tmp = l->next;
63       xfree(l);
64       l = tmp;
65     }
66   xfree(mem);
67 }
68
69
70 /* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the
71    allocated block or NULL if an underlying malloc() failed. */
72 void *
73 tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
74                    int zero, size_t size)
75 {
76   void *ptr;
77
78   if (mem->failed)
79     {
80       DPRINT(("tre_mem_alloc: oops, called after failure?!\n"));
81       return NULL;
82     }
83
84 #ifdef MALLOC_DEBUGGING
85   if (!provided)
86     {
87       ptr = xmalloc(1);
88       if (ptr == NULL)
89         {
90           DPRINT(("tre_mem_alloc: xmalloc forced failure\n"));
91           mem->failed = 1;
92           return NULL;
93         }
94       xfree(ptr);
95     }
96 #endif /* MALLOC_DEBUGGING */
97
98   if (mem->n < size)
99     {
100       /* We need more memory than is available in the current block.
101          Allocate a new block. */
102       tre_list_t *l;
103       if (provided)
104         {
105           DPRINT(("tre_mem_alloc: using provided block\n"));
106           if (provided_block == NULL)
107             {
108               DPRINT(("tre_mem_alloc: provided block was NULL\n"));
109               mem->failed = 1;
110               return NULL;
111             }
112           mem->ptr = provided_block;
113           mem->n = TRE_MEM_BLOCK_SIZE;
114         }
115       else
116         {
117           int block_size;
118           if (size * 8 > TRE_MEM_BLOCK_SIZE)
119             block_size = size * 8;
120           else
121             block_size = TRE_MEM_BLOCK_SIZE;
122           DPRINT(("tre_mem_alloc: allocating new %d byte block\n",
123                   block_size));
124           l = xmalloc(sizeof(*l));
125           if (l == NULL)
126             {
127               mem->failed = 1;
128               return NULL;
129             }
130           l->data = xmalloc(block_size);
131           if (l->data == NULL)
132             {
133               xfree(l);
134               mem->failed = 1;
135               return NULL;
136             }
137           l->next = NULL;
138           if (mem->current != NULL)
139             mem->current->next = l;
140           if (mem->blocks == NULL)
141             mem->blocks = l;
142           mem->current = l;
143           mem->ptr = l->data;
144           mem->n = block_size;
145         }
146     }
147
148   /* Make sure the next pointer will be aligned. */
149   size += ALIGN(mem->ptr + size, long);
150
151   /* Allocate from current block. */
152   ptr = mem->ptr;
153   mem->ptr += size;
154   mem->n -= size;
155
156   /* Set to zero if needed. */
157   if (zero)
158     memset(ptr, 0, size);
159
160   return ptr;
161 }
162
163 /* EOF */