1 #include "iwpool.h"
2 #include "iwutils.h"
3 #include "iwlog.h"
4 #include <stdlib.h>
5 #include <string.h>
6 #include <stdarg.h>
7 #include <errno.h>
8 #include <ctype.h>
9
10 #define IWPOOL_UNIT_ALIGN_SIZE 8
11
12 /** Atomic heap unit */
13 typedef struct IWPOOL_UNIT {
14 void *heap;
15 struct IWPOOL_UNIT *next;
16 } IWPOOL_UNIT;
17
18 /** Memory pool */
19 struct _IWPOOL {
20 size_t usiz; /**< Used size */
21 size_t asiz; /**< Allocated size */
22 char *heap; /**< Current pool heap ptr */
23 IWPOOL_UNIT *unit; /**< Current heap unit */
24 void *user_data; /**< Associated user data */
25 void (*user_data_free_fn)(void *); /**< User data dispose function */
26 };
27
iwpool_create(size_t siz)28 IWPOOL *iwpool_create(size_t siz) {
29 IWPOOL *pool;
30 siz = siz < 1 ? IWPOOL_POOL_SIZ : siz;
31 siz = IW_ROUNDUP(siz, IWPOOL_UNIT_ALIGN_SIZE);
32 pool = malloc(sizeof(*pool));
33 if (!pool) {
34 goto error;
35 }
36 pool->unit = malloc(sizeof(*pool->unit));
37 if (!pool->unit) {
38 goto error;
39 }
40 pool->unit->heap = malloc(siz);
41 if (!pool->unit->heap) {
42 goto error;
43 }
44 pool->asiz = siz;
45 pool->heap = pool->unit->heap;
46 pool->usiz = 0;
47 pool->unit->next = 0;
48 pool->user_data = 0;
49 pool->user_data_free_fn = 0;
50 return pool;
51
52 error:
53 if (pool) {
54 if (pool->unit && pool->unit->heap) {
55 free(pool->unit->heap);
56 }
57 free(pool->unit);
58 free(pool);
59 }
60 return 0;
61 }
62
iwpool_create_empty(void)63 IWPOOL *iwpool_create_empty(void) {
64 return calloc(1, sizeof(struct _IWPOOL));
65 }
66
iwpool_extend(IWPOOL * pool,size_t siz)67 IW_INLINE int iwpool_extend(IWPOOL *pool, size_t siz) {
68 IWPOOL_UNIT *nunit = malloc(sizeof(*nunit));
69 if (!nunit) {
70 return 0;
71 }
72 siz = IW_ROUNDUP(siz, IWPOOL_UNIT_ALIGN_SIZE);
73 nunit->heap = malloc(siz);
74 if (!nunit->heap) {
75 free(nunit);
76 return 0;
77 }
78 nunit->next = pool->unit;
79 pool->heap = nunit->heap;
80 pool->unit = nunit;
81 pool->usiz = 0;
82 pool->asiz = siz;
83 return 1;
84 }
85
iwpool_alloc(size_t siz,IWPOOL * pool)86 void *iwpool_alloc(size_t siz, IWPOOL *pool) {
87 siz = IW_ROUNDUP(siz, IWPOOL_UNIT_ALIGN_SIZE);
88 size_t usiz = pool->usiz + siz;
89 if (SIZE_T_MAX - pool->usiz < siz) {
90 return 0;
91 }
92 void *h = pool->heap;
93 if (usiz > pool->asiz) {
94 if (SIZE_T_MAX - pool->asiz < usiz) {
95 return 0;
96 }
97 usiz = usiz + pool->asiz;
98 if (!iwpool_extend(pool, usiz)) {
99 return 0;
100 }
101 h = pool->heap;
102 }
103 pool->usiz += siz;
104 pool->heap += siz;
105 return h;
106 }
107
iwpool_calloc(size_t siz,IWPOOL * pool)108 void *iwpool_calloc(size_t siz, IWPOOL *pool) {
109 void *res = iwpool_alloc(siz, pool);
110 if (!res) {
111 return 0;
112 }
113 memset(res, 0, siz);
114 return res;
115 }
116
iwpool_strndup(IWPOOL * pool,const char * str,size_t len,iwrc * rcp)117 char *iwpool_strndup(IWPOOL *pool, const char *str, size_t len, iwrc *rcp) {
118 char *ret = iwpool_alloc(len + 1, pool);
119 if (!ret) {
120 *rcp = iwrc_set_errno(IW_ERROR_ALLOC, errno);
121 return 0;
122 } else {
123 *rcp = 0;
124 }
125 memcpy(ret, str, len);
126 ret[len] = '\0';
127 return ret;
128 }
129
iwpool_strdup(IWPOOL * pool,const char * str,iwrc * rcp)130 char *iwpool_strdup(IWPOOL *pool, const char *str, iwrc *rcp) {
131 return iwpool_strndup(pool, str, strlen(str), rcp);
132 }
133
_iwpool_printf_estimate_size(const char * format,va_list ap)134 IW_INLINE int _iwpool_printf_estimate_size(const char *format, va_list ap) {
135 char buf[1];
136 return vsnprintf(buf, sizeof(buf), format, ap) + 1;
137 }
138
_iwpool_printf_va(IWPOOL * pool,int size,const char * format,va_list ap)139 static char *_iwpool_printf_va(IWPOOL *pool, int size, const char *format, va_list ap) {
140 char *wbuf = iwpool_alloc(size, pool);
141 if (!wbuf) {
142 return 0;
143 }
144 vsnprintf(wbuf, size, format, ap);
145 return wbuf;
146 }
147
iwpool_printf(IWPOOL * pool,const char * format,...)148 char *iwpool_printf(IWPOOL *pool, const char *format, ...) {
149 va_list ap;
150 va_start(ap, format);
151 int size = _iwpool_printf_estimate_size(format, ap);
152 va_end(ap);
153 va_start(ap, format);
154 char *res = _iwpool_printf_va(pool, size, format, ap);
155 va_end(ap);
156 return res;
157 }
158
iwpool_split_string(IWPOOL * pool,const char * haystack,const char * split_chars,bool ignore_whitespace)159 char **iwpool_split_string(IWPOOL *pool, const char *haystack, const char *split_chars,
160 bool ignore_whitespace) {
161
162 size_t hsz = strlen(haystack);
163 char **ret = iwpool_alloc((hsz + 1) * sizeof(char *), pool);
164 if (!ret) return 0;
165 const char *sp = haystack;
166 const char *ep = sp;
167 int j = 0;
168 for (int i = 0; *ep; ++i, ++ep) {
169 const char ch = haystack[i];
170 const char *sch = strchr(split_chars, ch);
171 if (ep >= sp && (sch || *(ep + 1) == '\0')) {
172 if (!sch && *(ep + 1) == '\0') ++ep;
173 if (ignore_whitespace) {
174 while (isspace(*sp)) ++sp;
175 while (isspace(*(ep - 1))) --ep;
176 }
177 if (ep >= sp) {
178 char *s = iwpool_alloc(ep - sp + 1, pool);
179 if (!s) return 0;
180 memcpy(s, sp, ep - sp);
181 s[ep - sp] = '\0';
182 ret[j++] = s;
183 ep = haystack + i;
184 }
185 sp = haystack + i + 1;
186 }
187 }
188 ret[j] = 0;
189 return ret;
190 }
191
iwpool_printf_split(IWPOOL * pool,const char * split_chars,bool ignore_whitespace,const char * format,...)192 char **iwpool_printf_split(IWPOOL *pool,
193 const char *split_chars, bool ignore_whitespace,
194 const char *format, ...) {
195
196 va_list ap;
197 va_start(ap, format);
198 int size = _iwpool_printf_estimate_size(format, ap);
199 va_end(ap);
200 char *buf = malloc(size);
201 if (!buf) {
202 return 0;
203 }
204 va_start(ap, format);
205 vsnprintf(buf, size, format, ap);
206 va_end(ap);
207 char **ret = iwpool_split_string(pool, buf, split_chars, ignore_whitespace);
208 free(buf);
209 return ret;
210 }
211
iwpool_free_fn(void * pool)212 void iwpool_free_fn(void *pool) {
213 iwpool_destroy(pool);
214 }
215
iwpool_user_data_set(IWPOOL * pool,void * data,void (* free_fn)(void *))216 void iwpool_user_data_set(IWPOOL *pool, void *data, void (*free_fn)(void *)) {
217 if (pool->user_data_free_fn) {
218 pool->user_data_free_fn(pool->user_data);
219 }
220 pool->user_data_free_fn = free_fn;
221 pool->user_data = data;
222 }
223
iwpool_user_data_detach(IWPOOL * pool)224 void *iwpool_user_data_detach(IWPOOL *pool) {
225 pool->user_data_free_fn = 0;
226 return pool->user_data;
227 }
228
iwpool_user_data_get(IWPOOL * pool)229 void *iwpool_user_data_get(IWPOOL *pool) {
230 return pool->user_data;
231 }
232
iwpool_allocated_size(IWPOOL * pool)233 size_t iwpool_allocated_size(IWPOOL *pool) {
234 return pool->asiz;
235 }
236
iwpool_used_size(IWPOOL * pool)237 size_t iwpool_used_size(IWPOOL *pool) {
238 return pool->usiz;
239 }
240
iwpool_destroy(IWPOOL * pool)241 void iwpool_destroy(IWPOOL *pool) {
242 if (!pool) {
243 return;
244 }
245 for (IWPOOL_UNIT *u = pool->unit, *next; u; u = next) {
246 next = u->next;
247 free(u->heap);
248 free(u);
249 }
250 if (pool->user_data_free_fn) {
251 pool->user_data_free_fn(pool->user_data);
252 }
253 free(pool);
254 }
255