Upgrade to 1.46.0
[platform/upstream/nghttp2.git] / third-party / mruby / src / pool.c
1 /*
2 ** pool.c - memory pool
3 **
4 ** See Copyright Notice in mruby.h
5 */
6
7 #include <string.h>
8 #include <mruby.h>
9
10 /* configuration section */
11 /* allocated memory address should be multiple of POOL_ALIGNMENT */
12 /* or undef it if alignment does not matter */
13 #ifndef POOL_ALIGNMENT
14 #if INTPTR_MAX == INT64_MAX
15 #define POOL_ALIGNMENT 8
16 #else
17 #define POOL_ALIGNMENT 4
18 #endif
19 #endif
20 /* page size of memory pool */
21 #ifndef POOL_PAGE_SIZE
22 #define POOL_PAGE_SIZE 16000
23 #endif
24 /* end of configuration section */
25
26 /* Disable MSVC warning "C4200: nonstandard extension used: zero-sized array
27  * in struct/union" when in C++ mode */
28 #ifdef _MSC_VER
29 #pragma warning(push)
30 #pragma warning(disable : 4200)
31 #endif
32
33 struct mrb_pool_page {
34   struct mrb_pool_page *next;
35   size_t offset;
36   size_t len;
37   void *last;
38   char page[];
39 };
40
41 #ifdef _MSC_VER
42 #pragma warning(pop)
43 #endif
44
45 struct mrb_pool {
46   mrb_state *mrb;
47   struct mrb_pool_page *pages;
48 };
49
50 #undef TEST_POOL
51 #ifdef TEST_POOL
52
53 #define mrb_malloc_simple(m,s) malloc(s)
54 #define mrb_free(m,p) free(p)
55 #endif
56
57 #ifdef POOL_ALIGNMENT
58 #  define ALIGN_PADDING(x) ((SIZE_MAX - (x) + 1) & (POOL_ALIGNMENT - 1))
59 #else
60 #  define ALIGN_PADDING(x) (0)
61 #endif
62
63 MRB_API mrb_pool*
64 mrb_pool_open(mrb_state *mrb)
65 {
66   mrb_pool *pool = (mrb_pool *)mrb_malloc_simple(mrb, sizeof(mrb_pool));
67
68   if (pool) {
69     pool->mrb = mrb;
70     pool->pages = NULL;
71   }
72
73   return pool;
74 }
75
76 MRB_API void
77 mrb_pool_close(mrb_pool *pool)
78 {
79   struct mrb_pool_page *page, *tmp;
80
81   if (!pool) return;
82   page = pool->pages;
83   while (page) {
84     tmp = page;
85     page = page->next;
86     mrb_free(pool->mrb, tmp);
87   }
88   mrb_free(pool->mrb, pool);
89 }
90
91 static struct mrb_pool_page*
92 page_alloc(mrb_pool *pool, size_t len)
93 {
94   struct mrb_pool_page *page;
95
96   if (len < POOL_PAGE_SIZE)
97     len = POOL_PAGE_SIZE;
98   page = (struct mrb_pool_page *)mrb_malloc_simple(pool->mrb, sizeof(struct mrb_pool_page)+len);
99   if (page) {
100     page->offset = 0;
101     page->len = len;
102   }
103
104   return page;
105 }
106
107 MRB_API void*
108 mrb_pool_alloc(mrb_pool *pool, size_t len)
109 {
110   struct mrb_pool_page *page;
111   size_t n;
112
113   if (!pool) return NULL;
114   len += ALIGN_PADDING(len);
115   page = pool->pages;
116   while (page) {
117     if (page->offset + len <= page->len) {
118       n = page->offset;
119       page->offset += len;
120       page->last = (char*)page->page+n;
121       return page->last;
122     }
123     page = page->next;
124   }
125   page = page_alloc(pool, len);
126   if (!page) return NULL;
127   page->offset = len;
128   page->next = pool->pages;
129   pool->pages = page;
130
131   page->last = (void*)page->page;
132   return page->last;
133 }
134
135 MRB_API mrb_bool
136 mrb_pool_can_realloc(mrb_pool *pool, void *p, size_t len)
137 {
138   struct mrb_pool_page *page;
139
140   if (!pool) return FALSE;
141   len += ALIGN_PADDING(len);
142   page = pool->pages;
143   while (page) {
144     if (page->last == p) {
145       size_t beg;
146
147       beg = (char*)p - page->page;
148       if (beg + len > page->len) return FALSE;
149       return TRUE;
150     }
151     page = page->next;
152   }
153   return FALSE;
154 }
155
156 MRB_API void*
157 mrb_pool_realloc(mrb_pool *pool, void *p, size_t oldlen, size_t newlen)
158 {
159   struct mrb_pool_page *page;
160   void *np;
161
162   if (!pool) return NULL;
163   oldlen += ALIGN_PADDING(oldlen);
164   newlen += ALIGN_PADDING(newlen);
165   page = pool->pages;
166   while (page) {
167     if (page->last == p) {
168       size_t beg;
169
170       beg = (char*)p - page->page;
171       if (beg + oldlen != page->offset) break;
172       if (beg + newlen > page->len) {
173         page->offset = beg;
174         break;
175       }
176       page->offset = beg + newlen;
177       return p;
178     }
179     page = page->next;
180   }
181   np = mrb_pool_alloc(pool, newlen);
182   if (np == NULL) {
183     return NULL;
184   }
185   memcpy(np, p, oldlen);
186   return np;
187 }
188
189 #ifdef TEST_POOL
190 int
191 main(void)
192 {
193   int i, len = 250;
194   mrb_pool *pool;
195   void *p;
196
197   pool = mrb_pool_open(NULL);
198   p = mrb_pool_alloc(pool, len);
199   for (i=1; i<20; i++) {
200     printf("%p (len=%d) %ud\n", p, len, mrb_pool_can_realloc(pool, p, len*2));
201     p = mrb_pool_realloc(pool, p, len, len*2);
202     len *= 2;
203   }
204   mrb_pool_close(pool);
205   return 0;
206 }
207 #endif