• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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