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_strdup2(IWPOOL * pool,const char * str)134 char* iwpool_strdup2(IWPOOL *pool, const char *str) {
135 iwrc rc;
136 return iwpool_strndup(pool, str, strlen(str), &rc);
137 }
138
iwpool_strndup2(IWPOOL * pool,const char * str,size_t len)139 char* iwpool_strndup2(IWPOOL *pool, const char *str, size_t len) {
140 iwrc rc;
141 return iwpool_strndup(pool, str, len, &rc);
142 }
143
_iwpool_printf_estimate_size(const char * format,va_list ap)144 IW_INLINE int _iwpool_printf_estimate_size(const char *format, va_list ap) {
145 char buf[1];
146 return vsnprintf(buf, sizeof(buf), format, ap) + 1;
147 }
148
_iwpool_printf_va(IWPOOL * pool,int size,const char * format,va_list ap)149 static char* _iwpool_printf_va(IWPOOL *pool, int size, const char *format, va_list ap) {
150 char *wbuf = iwpool_alloc(size, pool);
151 if (!wbuf) {
152 return 0;
153 }
154 vsnprintf(wbuf, size, format, ap);
155 return wbuf;
156 }
157
iwpool_printf(IWPOOL * pool,const char * format,...)158 char* iwpool_printf(IWPOOL *pool, const char *format, ...) {
159 va_list ap;
160 va_start(ap, format);
161 int size = _iwpool_printf_estimate_size(format, ap);
162 va_end(ap);
163 va_start(ap, format);
164 char *res = _iwpool_printf_va(pool, size, format, ap);
165 va_end(ap);
166 return res;
167 }
168
iwpool_split_string(IWPOOL * pool,const char * haystack,const char * split_chars,bool ignore_whitespace)169 const char** iwpool_split_string(
170 IWPOOL *pool, const char *haystack, const char *split_chars,
171 bool ignore_whitespace
172 ) {
173 size_t hsz = strlen(haystack);
174 const char **ret = iwpool_alloc((hsz + 1) * sizeof(char*), pool);
175 if (!ret) {
176 return 0;
177 }
178 const char *sp = haystack;
179 const char *ep = sp;
180 int j = 0;
181 for (int i = 0; *ep; ++i, ++ep) {
182 const char ch = haystack[i];
183 const char *sch = strchr(split_chars, ch);
184 if ((ep >= sp) && (sch || (*(ep + 1) == '\0'))) {
185 if (!sch && (*(ep + 1) == '\0')) {
186 ++ep;
187 }
188 if (ignore_whitespace) {
189 while (isspace(*sp)) ++sp;
190 while (isspace(*(ep - 1))) --ep;
191 }
192 if (ep >= sp) {
193 char *s = iwpool_alloc(ep - sp + 1, pool);
194 if (!s) {
195 return 0;
196 }
197 memcpy(s, sp, ep - sp);
198 s[ep - sp] = '\0';
199 ret[j++] = s;
200 ep = haystack + i;
201 }
202 sp = haystack + i + 1;
203 }
204 }
205 ret[j] = 0;
206 return ret;
207 }
208
iwpool_printf_split(IWPOOL * pool,const char * split_chars,bool ignore_whitespace,const char * format,...)209 const char** iwpool_printf_split(
210 IWPOOL *pool,
211 const char *split_chars, bool ignore_whitespace,
212 const char *format, ...
213 ) {
214 va_list ap;
215 va_start(ap, format);
216 int size = _iwpool_printf_estimate_size(format, ap);
217 va_end(ap);
218 char *buf = malloc(size);
219 if (!buf) {
220 return 0;
221 }
222 va_start(ap, format);
223 vsnprintf(buf, size, format, ap);
224 va_end(ap);
225 const char **ret = iwpool_split_string(pool, buf, split_chars, ignore_whitespace);
226 free(buf);
227 return ret;
228 }
229
iwpool_free_fn(void * pool)230 void iwpool_free_fn(void *pool) {
231 iwpool_destroy(pool);
232 }
233
iwpool_user_data_set(IWPOOL * pool,void * data,void (* free_fn)(void *))234 void iwpool_user_data_set(IWPOOL *pool, void *data, void (*free_fn)(void*)) {
235 if (pool->user_data_free_fn) {
236 pool->user_data_free_fn(pool->user_data);
237 }
238 pool->user_data_free_fn = free_fn;
239 pool->user_data = data;
240 }
241
iwpool_user_data_detach(IWPOOL * pool)242 void* iwpool_user_data_detach(IWPOOL *pool) {
243 pool->user_data_free_fn = 0;
244 return pool->user_data;
245 }
246
iwpool_user_data_get(IWPOOL * pool)247 void* iwpool_user_data_get(IWPOOL *pool) {
248 return pool->user_data;
249 }
250
iwpool_allocated_size(IWPOOL * pool)251 size_t iwpool_allocated_size(IWPOOL *pool) {
252 return pool->asiz;
253 }
254
iwpool_used_size(IWPOOL * pool)255 size_t iwpool_used_size(IWPOOL *pool) {
256 return pool->usiz;
257 }
258
iwpool_destroy(IWPOOL * pool)259 void iwpool_destroy(IWPOOL *pool) {
260 if (!pool) {
261 return;
262 }
263 for (IWPOOL_UNIT *u = pool->unit, *next; u; u = next) {
264 next = u->next;
265 free(u->heap);
266 free(u);
267 }
268 if (pool->user_data_free_fn) {
269 pool->user_data_free_fn(pool->user_data);
270 }
271 free(pool);
272 }
273