1 : /* Copyright (c) 2007 James Antill -- See LICENSE file for terms. */
2 :
3 : #ifndef USTR_POOL_H
4 : #error " You should have already included ustr-pool.h, or just include ustr.h."
5 : #endif
6 :
7 : struct Ustr__pool_ll_node
8 : {
9 : struct Ustr__pool_ll_node *next;
10 : void *ptr;
11 : };
12 :
13 : struct Ustr__pool_ll_base
14 : { /* "simple" pool implementation */
15 : struct Ustr_pool cbs;
16 : struct Ustr__pool_ll_node *beg;
17 :
18 : struct Ustr__pool_ll_base *sbeg; /* wasting a lot of space for sub pools */
19 : struct Ustr__pool_ll_base *base;
20 : struct Ustr__pool_ll_base *next;
21 : struct Ustr__pool_ll_base *prev;
22 :
23 : unsigned int free_num : 30; /* how many nodes we search to free */
24 :
25 : unsigned int call_realloc : 1;
26 : };
27 :
28 : #define USTR__POOL_LL_SIB_NULL ((struct Ustr__pool_ll_base *) 0)
29 :
30 : USTR_CONF_e_PROTO void *ustr__pool_ll_sys_malloc(struct Ustr_pool *, size_t)
31 : USTR__COMPILE_ATTR_WARN_UNUSED_RET() USTR__COMPILE_ATTR_NONNULL_A()
32 : USTR__COMPILE_ATTR_MALLOC();
33 : USTR_CONF_e_PROTO
34 : void *ustr__pool_ll_sys_realloc(struct Ustr_pool *, void *, size_t, size_t)
35 : USTR__COMPILE_ATTR_WARN_UNUSED_RET() USTR__COMPILE_ATTR_NONNULL_L((1))
36 : USTR__COMPILE_ATTR_MALLOC();
37 : USTR_CONF_e_PROTO void ustr__pool_ll_sys_free(struct Ustr_pool *, void *)
38 : USTR__COMPILE_ATTR_NONNULL_L((1));
39 :
40 : USTR_CONF_e_PROTO
41 : struct Ustr_pool *ustr__pool_ll_make_subpool(struct Ustr_pool *)
42 : USTR__COMPILE_ATTR_WARN_UNUSED_RET() USTR__COMPILE_ATTR_MALLOC();
43 : USTR_CONF_e_PROTO void ustr__pool_ll__clear(struct Ustr__pool_ll_base *, int);
44 : USTR_CONF_e_PROTO void ustr__pool_ll_clear(struct Ustr_pool *)
45 : USTR__COMPILE_ATTR_NONNULL_A();
46 : USTR_CONF_e_PROTO void ustr__pool_ll__free(struct Ustr__pool_ll_base *, int);
47 : USTR_CONF_e_PROTO void ustr__pool_ll_free(struct Ustr_pool *);
48 :
49 : USTR_CONF_i_PROTO void *ustr__pool_ll_sys_malloc(struct Ustr_pool *p,size_t len)
50 868 : {
51 868 : struct Ustr__pool_ll_base *sip = (struct Ustr__pool_ll_base *)p;
52 : struct Ustr__pool_ll_node *np;
53 868 : void *ret = USTR_CONF_MALLOC(len);
54 :
55 225 : ustr_assert(USTR_CNTL_MALLOC_CHECK_MEM_SZ(p,
56 : sizeof(struct Ustr__pool_ll_base)));
57 :
58 868 : if (!ret)
59 96 : return (ret);
60 :
61 772 : if (!(np = USTR_CONF_MALLOC(sizeof(struct Ustr__pool_ll_node))))
62 : {
63 4 : USTR_CONF_FREE(ret);
64 4 : return (0);
65 : }
66 :
67 768 : np->next = sip->beg;
68 768 : sip->beg = np;
69 768 : np->ptr = ret;
70 :
71 768 : return (ret);
72 : }
73 :
74 : USTR_CONF_i_PROTO
75 : void *ustr__pool_ll_sys_realloc(struct Ustr_pool *p, void *old,
76 : size_t olen, size_t nlen)
77 250 : {
78 250 : struct Ustr__pool_ll_base *sip = (struct Ustr__pool_ll_base *)p;
79 250 : void *ret = 0;
80 :
81 53 : ustr_assert(USTR_CNTL_MALLOC_CHECK_MEM_SZ(p,
82 : sizeof(struct Ustr__pool_ll_base)));
83 119 : USTR_ASSERT((old && sip->beg && sip->beg->ptr) || !olen);
84 53 : ustr_assert(olen ? USTR_CNTL_MALLOC_CHECK_MEM_MINSZ(old, olen) :
85 : (!old || USTR_CNTL_MALLOC_CHECK_MEM(old)));
86 :
87 250 : if (!nlen)
88 4 : ++nlen;
89 :
90 369 : if (olen && (sip->beg->ptr == old) && sip->call_realloc)
91 : { /* let the last allocated Ustrp grow/shrink */
92 226 : if ((ret = USTR_CONF_REALLOC(old, nlen)))
93 192 : sip->beg->ptr = ret;
94 : }
95 24 : else if (olen >= nlen) /* always allow reductions/nothing */
96 : {
97 2 : USTR__CNTL_MALLOC_CHECK_FIXUP_REALLOC(old, nlen);
98 4 : return (old);
99 : }
100 20 : else if ((ret = ustr__pool_ll_sys_malloc(p, nlen)))
101 16 : memcpy(ret, old, olen);
102 :
103 246 : return (ret);
104 : }
105 :
106 : USTR_CONF_i_PROTO
107 : void ustr__pool_ll_sys_free(struct Ustr_pool *p, void *old)
108 116 : {
109 116 : struct Ustr__pool_ll_base *sip = (struct Ustr__pool_ll_base *)p;
110 116 : struct Ustr__pool_ll_node **op = &sip->beg;
111 116 : unsigned int num = sip->free_num;
112 :
113 30 : ustr_assert(USTR_CNTL_MALLOC_CHECK_MEM_SZ(p,
114 : sizeof(struct Ustr__pool_ll_base)));
115 30 : ustr_assert(USTR_CNTL_MALLOC_CHECK_MEM(old));
116 :
117 242 : while (*op && num--)
118 : {
119 152 : if ((*op)->ptr == old)
120 : {
121 112 : struct Ustr__pool_ll_node *rm = *op;
122 :
123 112 : *op = rm->next;
124 :
125 112 : USTR_CONF_FREE(rm->ptr);
126 112 : USTR_CONF_FREE(rm);
127 112 : return;
128 : }
129 :
130 40 : op = &(*op)->next;
131 : }
132 : }
133 :
134 : USTR_CONF_i_PROTO void ustr__pool_ll__clear(struct Ustr__pool_ll_base *base,
135 : int siblings)
136 384 : {
137 : struct Ustr__pool_ll_node *scan;
138 :
139 384 : if (!base)
140 192 : return;
141 :
142 192 : scan = base->beg;
143 1040 : while (scan)
144 : {
145 656 : struct Ustr__pool_ll_node *scan_next = scan->next;
146 :
147 656 : USTR_CONF_FREE(scan->ptr);
148 656 : USTR_CONF_FREE(scan);
149 :
150 656 : scan = scan_next;
151 : }
152 192 : base->beg = 0;
153 :
154 192 : if (siblings)
155 64 : ustr__pool_ll__clear(base->next, USTR_TRUE);
156 :
157 192 : ustr__pool_ll__clear(base->sbeg, USTR_TRUE);
158 : }
159 : USTR_CONF_i_PROTO void ustr__pool_ll_clear(struct Ustr_pool *base)
160 40 : {
161 10 : ustr_assert(USTR_CNTL_MALLOC_CHECK_MEM_SZ(base,
162 : sizeof(struct Ustr__pool_ll_base)));
163 40 : ustr__pool_ll__clear((struct Ustr__pool_ll_base *)base, USTR_FALSE);
164 40 : }
165 :
166 : USTR_CONF_i_PROTO void ustr__pool_ll__free(struct Ustr__pool_ll_base *base,
167 : int siblings)
168 176 : {
169 176 : if (!base)
170 88 : return;
171 :
172 88 : if (siblings)
173 32 : ustr__pool_ll__free(base->next, USTR_TRUE);
174 88 : ustr__pool_ll__free(base->sbeg, USTR_TRUE);
175 88 : base->sbeg = 0;
176 :
177 88 : ustr__pool_ll__clear(base, USTR_FALSE);
178 88 : USTR_CONF_FREE(base);
179 : }
180 : USTR_CONF_i_PROTO void ustr__pool_ll_free(struct Ustr_pool *p)
181 56 : {
182 56 : struct Ustr__pool_ll_base *sip = (struct Ustr__pool_ll_base *)p;
183 :
184 14 : ustr_assert(USTR_CNTL_MALLOC_CHECK_MEM_SZ(p,
185 : sizeof(struct Ustr__pool_ll_base)));
186 :
187 56 : if (sip->prev)
188 4 : sip->prev->next = sip->next;
189 52 : else if (sip->base)
190 4 : sip->base->sbeg = sip->next;
191 :
192 56 : if (sip->next)
193 8 : sip->next->prev = sip->prev;
194 :
195 56 : ustr__pool_ll__free(sip, USTR_FALSE);
196 56 : }
197 :
198 : USTR_CONF_i_PROTO
199 : struct Ustr_pool *ustr__pool_ll_make_subpool(struct Ustr_pool *p)
200 96 : {
201 96 : struct Ustr__pool_ll_base *sip = (struct Ustr__pool_ll_base *)p;
202 : struct Ustr__pool_ll_base *tmp;
203 :
204 96 : if (!(tmp = USTR_CONF_MALLOC(sizeof(struct Ustr__pool_ll_base))))
205 :
206 8 : return (USTR_POOL_NULL);
207 :
208 88 : tmp->cbs.pool_sys_malloc = ustr__pool_ll_sys_malloc;
209 88 : tmp->cbs.pool_sys_realloc = ustr__pool_ll_sys_realloc;
210 88 : tmp->cbs.pool_sys_free = ustr__pool_ll_sys_free;
211 :
212 88 : tmp->cbs.pool_make_subpool = ustr__pool_ll_make_subpool;
213 88 : tmp->cbs.pool_clear = ustr__pool_ll_clear;
214 88 : tmp->cbs.pool_free = ustr__pool_ll_free;
215 :
216 88 : tmp->beg = 0;
217 88 : tmp->sbeg = USTR__POOL_LL_SIB_NULL;
218 88 : tmp->prev = USTR__POOL_LL_SIB_NULL;
219 :
220 88 : tmp->next = USTR__POOL_LL_SIB_NULL;
221 88 : tmp->base = USTR__POOL_LL_SIB_NULL;
222 :
223 88 : tmp->free_num = 2; /* magic number, allows dupx + copy + free */
224 :
225 88 : tmp->call_realloc = USTR_TRUE;
226 :
227 88 : if (!p)
228 48 : return (&tmp->cbs);
229 :
230 10 : ustr_assert(USTR_CNTL_MALLOC_CHECK_MEM_SZ(p,
231 : sizeof(struct Ustr__pool_ll_base)));
232 :
233 40 : if ((tmp->next = sip->sbeg))
234 24 : tmp->next->prev = tmp;
235 40 : sip->sbeg = tmp;
236 :
237 40 : tmp->base = sip;
238 :
239 40 : return (&tmp->cbs);
240 : }
241 :
242 : /* linked list pool API */
243 : USTR_CONF_I_PROTO struct Ustr_pool *ustr_pool_ll_make(void)
244 48 : { return (ustr__pool_ll_make_subpool(USTR_POOL_NULL)); }
245 :
246 : #include <stdarg.h> /* va_list for va_arg() functionality */
247 :
248 : USTR_CONF_I_PROTO
249 : int ustr_pool_ll_cntl(struct Ustr_pool *p, int option, ...)
250 24 : {
251 24 : struct Ustr__pool_ll_base *sip = (struct Ustr__pool_ll_base *)p;
252 24 : int ret = USTR_FALSE;
253 : va_list ap;
254 :
255 24 : va_start(ap, option);
256 :
257 24 : switch (option)
258 : {
259 : case USTR_POOL_LL_CNTL_GET_FREE_CMP:
260 : {
261 8 : unsigned int *num = va_arg(ap, unsigned int *);
262 :
263 8 : *num = sip->free_num;
264 :
265 8 : ret = USTR_TRUE;
266 : }
267 8 : break;
268 : case USTR_POOL_LL_CNTL_SET_FREE_CMP:
269 : {
270 4 : unsigned int num = va_arg(ap, unsigned int);
271 :
272 4 : USTR_ASSERT_RET((num <= 65535), USTR_FALSE); /* 2 ** 16 */
273 :
274 4 : sip->free_num = num;
275 :
276 4 : ret = USTR_TRUE;
277 : }
278 4 : break;
279 :
280 : case USTR_POOL_LL_CNTL_GET_REALLOC:
281 : {
282 8 : int *toggle = va_arg(ap, int *);
283 :
284 8 : *toggle = sip->call_realloc;
285 :
286 8 : ret = USTR_TRUE;
287 : }
288 8 : break;
289 : case USTR_POOL_LL_CNTL_SET_REALLOC:
290 : {
291 4 : int toggle = va_arg(ap, int);
292 :
293 4 : USTR_ASSERT_RET((toggle == !!toggle), USTR_FALSE);
294 :
295 4 : sip->call_realloc = toggle;
296 :
297 4 : ret = USTR_TRUE;
298 : }
299 : break;
300 : }
301 :
302 12 : USTR_ASSERT(ret);
303 :
304 24 : va_end(ap);
305 :
306 24 : return (ret);
307 : }
308 :
309 : /* "block" pool API */
310 : /* USTR_CONF_I_PROTO struct Ustr_pool *ustr_pool_blk_make(void)
311 : { return (ustr__pool_blk_make_subpool(USTR_POOL_NULL)); } */
312 :
313 : /* choose one of the above -- linked list */
314 : USTR_CONF_I_PROTO struct Ustr_pool *ustr_pool_make_pool(void)
315 4 : { return (ustr__pool_ll_make_subpool(USTR_POOL_NULL)); }
316 :
|