• 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_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