| |
1 /* |
| |
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
| |
3 * |
| |
4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. |
| |
5 * |
| |
6 * Redistribution and use in source and binary forms, with or without |
| |
7 * modification, are permitted provided that the following conditions are met: |
| |
8 * |
| |
9 * 1. Redistributions of source code must retain the above copyright |
| |
10 * notice, this list of conditions and the following disclaimer. |
| |
11 * |
| |
12 * 2. Redistributions in binary form must reproduce the above copyright |
| |
13 * notice, this list of conditions and the following disclaimer in the |
| |
14 * documentation and/or other materials provided with the distribution. |
| |
15 * |
| |
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| |
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| |
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| |
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| |
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| |
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| |
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| |
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| |
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| |
26 * POSSIBILITY OF SUCH DAMAGE. |
| |
27 */ |
| |
28 |
| |
29 #include "cx/mempool.h" |
| |
30 #include "cx/utils.h" |
| |
31 #include <string.h> |
| |
32 |
| |
33 struct cx_mempool_memory_s { |
| |
34 /** The destructor. */ |
| |
35 cx_destructor_func destructor; |
| |
36 /** The actual memory. */ |
| |
37 char c[]; |
| |
38 }; |
| |
39 |
| |
40 static void *cx_mempool_malloc( |
| |
41 void *p, |
| |
42 size_t n |
| |
43 ) { |
| |
44 struct cx_mempool_s *pool = p; |
| |
45 |
| |
46 if (pool->size >= pool->capacity) { |
| |
47 size_t newcap = pool->capacity - (pool->capacity % 16) + 16; |
| |
48 struct cx_mempool_memory_s **newdata = realloc(pool->data, newcap*sizeof(struct cx_mempool_memory_s*)); |
| |
49 if (newdata == NULL) { |
| |
50 return NULL; |
| |
51 } |
| |
52 pool->data = newdata; |
| |
53 pool->capacity = newcap; |
| |
54 } |
| |
55 |
| |
56 struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n); |
| |
57 if (mem == NULL) { |
| |
58 return NULL; |
| |
59 } |
| |
60 |
| |
61 mem->destructor = pool->auto_destr; |
| |
62 pool->data[pool->size] = mem; |
| |
63 pool->size++; |
| |
64 |
| |
65 return mem->c; |
| |
66 } |
| |
67 |
| |
68 static void *cx_mempool_calloc( |
| |
69 void *p, |
| |
70 size_t nelem, |
| |
71 size_t elsize |
| |
72 ) { |
| |
73 size_t msz; |
| |
74 if (cx_szmul(nelem, elsize, &msz)) { |
| |
75 return NULL; |
| |
76 } |
| |
77 void *ptr = cx_mempool_malloc(p, msz); |
| |
78 if (ptr == NULL) { |
| |
79 return NULL; |
| |
80 } |
| |
81 memset(ptr, 0, nelem * elsize); |
| |
82 return ptr; |
| |
83 } |
| |
84 |
| |
85 static void *cx_mempool_realloc( |
| |
86 void *p, |
| |
87 void *ptr, |
| |
88 size_t n |
| |
89 ) { |
| |
90 struct cx_mempool_s *pool = p; |
| |
91 |
| |
92 struct cx_mempool_memory_s *mem, *newm; |
| |
93 mem = (struct cx_mempool_memory_s*)(((char *) ptr) - sizeof(cx_destructor_func)); |
| |
94 newm = realloc(mem, n + sizeof(cx_destructor_func)); |
| |
95 |
| |
96 if (newm == NULL) { |
| |
97 return NULL; |
| |
98 } |
| |
99 if (mem != newm) { |
| |
100 cx_for_n(i, pool->size) { |
| |
101 if (pool->data[i] == mem) { |
| |
102 pool->data[i] = newm; |
| |
103 return ((char*)newm) + sizeof(cx_destructor_func); |
| |
104 } |
| |
105 } |
| |
106 abort(); |
| |
107 } else { |
| |
108 return ptr; |
| |
109 } |
| |
110 } |
| |
111 |
| |
112 static void cx_mempool_free( |
| |
113 void *p, |
| |
114 void *ptr |
| |
115 ) { |
| |
116 if(!ptr) return; |
| |
117 struct cx_mempool_s *pool = p; |
| |
118 |
| |
119 struct cx_mempool_memory_s *mem = (struct cx_mempool_memory_s *) |
| |
120 ((char *) ptr - sizeof(cx_destructor_func)); |
| |
121 |
| |
122 cx_for_n(i, pool->size) { |
| |
123 if (mem == pool->data[i]) { |
| |
124 if (mem->destructor) { |
| |
125 mem->destructor(mem->c); |
| |
126 } |
| |
127 free(mem); |
| |
128 size_t last_index = pool->size - 1; |
| |
129 if (i != last_index) { |
| |
130 pool->data[i] = pool->data[last_index]; |
| |
131 pool->data[last_index] = NULL; |
| |
132 } |
| |
133 pool->size--; |
| |
134 return; |
| |
135 } |
| |
136 } |
| |
137 abort(); |
| |
138 } |
| |
139 |
| |
140 void cxMempoolDestroy(CxMempool *pool) { |
| |
141 struct cx_mempool_memory_s *mem; |
| |
142 cx_for_n(i, pool->size) { |
| |
143 mem = pool->data[i]; |
| |
144 if (mem->destructor) { |
| |
145 mem->destructor(mem->c); |
| |
146 } |
| |
147 free(mem); |
| |
148 } |
| |
149 free(pool->data); |
| |
150 free((void*) pool->allocator); |
| |
151 free(pool); |
| |
152 } |
| |
153 |
| |
154 void cxMempoolSetDestructor( |
| |
155 void *ptr, |
| |
156 cx_destructor_func func |
| |
157 ) { |
| |
158 *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func; |
| |
159 } |
| |
160 |
| |
161 struct cx_mempool_foreign_mem_s { |
| |
162 cx_destructor_func destr; |
| |
163 void* mem; |
| |
164 }; |
| |
165 |
| |
166 static void cx_mempool_destr_foreign_mem(void* ptr) { |
| |
167 struct cx_mempool_foreign_mem_s *fm = ptr; |
| |
168 fm->destr(fm->mem); |
| |
169 } |
| |
170 |
| |
171 int cxMempoolRegister( |
| |
172 CxMempool *pool, |
| |
173 void *memory, |
| |
174 cx_destructor_func destr |
| |
175 ) { |
| |
176 struct cx_mempool_foreign_mem_s *fm = cx_mempool_malloc( |
| |
177 pool, |
| |
178 sizeof(struct cx_mempool_foreign_mem_s) |
| |
179 ); |
| |
180 if (fm == NULL) return 1; |
| |
181 |
| |
182 fm->mem = memory; |
| |
183 fm->destr = destr; |
| |
184 *(cx_destructor_func *) ((char *) fm - sizeof(cx_destructor_func)) = cx_mempool_destr_foreign_mem; |
| |
185 |
| |
186 return 0; |
| |
187 } |
| |
188 |
| |
189 static cx_allocator_class cx_mempool_allocator_class = { |
| |
190 cx_mempool_malloc, |
| |
191 cx_mempool_realloc, |
| |
192 cx_mempool_calloc, |
| |
193 cx_mempool_free |
| |
194 }; |
| |
195 |
| |
196 CxMempool *cxMempoolCreate( |
| |
197 size_t capacity, |
| |
198 cx_destructor_func destr |
| |
199 ) { |
| |
200 size_t poolsize; |
| |
201 if (cx_szmul(capacity, sizeof(struct cx_mempool_memory_s*), &poolsize)) { |
| |
202 return NULL; |
| |
203 } |
| |
204 |
| |
205 struct cx_mempool_s *pool = |
| |
206 malloc(sizeof(struct cx_mempool_s)); |
| |
207 if (pool == NULL) { |
| |
208 return NULL; |
| |
209 } |
| |
210 |
| |
211 CxAllocator *provided_allocator = malloc(sizeof(CxAllocator)); |
| |
212 if (provided_allocator == NULL) { |
| |
213 free(pool); |
| |
214 return NULL; |
| |
215 } |
| |
216 provided_allocator->cl = &cx_mempool_allocator_class; |
| |
217 provided_allocator->data = pool; |
| |
218 |
| |
219 pool->allocator = provided_allocator; |
| |
220 |
| |
221 pool->data = malloc(poolsize); |
| |
222 if (pool->data == NULL) { |
| |
223 free(provided_allocator); |
| |
224 free(pool); |
| |
225 return NULL; |
| |
226 } |
| |
227 |
| |
228 pool->size = 0; |
| |
229 pool->capacity = capacity; |
| |
230 pool->auto_destr = destr; |
| |
231 |
| |
232 return (CxMempool *) pool; |
| |
233 } |