Commit | Line | Data |
---|---|---|
116a02e3 JG |
1 | /* |
2 | * MessagePack for C memory pool implementation | |
3 | * | |
4 | * Copyright (C) 2008-2009 FURUHASHI Sadayuki | |
5 | * | |
6 | * Distributed under the Boost Software License, Version 1.0. | |
7 | * (See accompanying file LICENSE_1_0.txt or copy at | |
8 | * http://www.boost.org/LICENSE_1_0.txt) | |
9 | */ | |
10 | #include "vendor/msgpack/zone.h" | |
11 | #include <stdlib.h> | |
12 | #include <string.h> | |
13 | ||
14 | struct msgpack_zone_chunk { | |
15 | struct msgpack_zone_chunk* next; | |
16 | /* data ... */ | |
17 | }; | |
18 | ||
19 | static inline bool init_chunk_list(msgpack_zone_chunk_list* cl, size_t chunk_size) | |
20 | { | |
21 | msgpack_zone_chunk* chunk = (msgpack_zone_chunk*)malloc( | |
22 | sizeof(msgpack_zone_chunk) + chunk_size); | |
23 | if(chunk == NULL) { | |
24 | return false; | |
25 | } | |
26 | ||
27 | cl->head = chunk; | |
28 | cl->free = chunk_size; | |
29 | cl->ptr = ((char*)chunk) + sizeof(msgpack_zone_chunk); | |
30 | chunk->next = NULL; | |
31 | ||
32 | return true; | |
33 | } | |
34 | ||
35 | static inline void destroy_chunk_list(msgpack_zone_chunk_list* cl) | |
36 | { | |
37 | msgpack_zone_chunk* c = cl->head; | |
38 | while(true) { | |
39 | msgpack_zone_chunk* n = c->next; | |
40 | free(c); | |
41 | if(n != NULL) { | |
42 | c = n; | |
43 | } else { | |
44 | break; | |
45 | } | |
46 | } | |
47 | } | |
48 | ||
49 | static inline void clear_chunk_list(msgpack_zone_chunk_list* cl, size_t chunk_size) | |
50 | { | |
51 | msgpack_zone_chunk* c = cl->head; | |
52 | while(true) { | |
53 | msgpack_zone_chunk* n = c->next; | |
54 | if(n != NULL) { | |
55 | free(c); | |
56 | c = n; | |
57 | } else { | |
58 | cl->head = c; | |
59 | break; | |
60 | } | |
61 | } | |
62 | cl->head->next = NULL; | |
63 | cl->free = chunk_size; | |
64 | cl->ptr = ((char*)cl->head) + sizeof(msgpack_zone_chunk); | |
65 | } | |
66 | ||
67 | void* msgpack_zone_malloc_expand(msgpack_zone* zone, size_t size) | |
68 | { | |
69 | msgpack_zone_chunk_list* const cl = &zone->chunk_list; | |
70 | msgpack_zone_chunk* chunk; | |
71 | ||
72 | size_t sz = zone->chunk_size; | |
73 | ||
74 | while(sz < size) { | |
75 | size_t tmp_sz = sz * 2; | |
76 | if (tmp_sz <= sz) { | |
77 | sz = size; | |
78 | break; | |
79 | } | |
80 | sz = tmp_sz; | |
81 | } | |
82 | ||
83 | chunk = (msgpack_zone_chunk*)malloc( | |
84 | sizeof(msgpack_zone_chunk) + sz); | |
85 | if (chunk == NULL) { | |
86 | return NULL; | |
87 | } | |
88 | else { | |
89 | char* ptr = ((char*)chunk) + sizeof(msgpack_zone_chunk); | |
90 | chunk->next = cl->head; | |
91 | cl->head = chunk; | |
92 | cl->free = sz - size; | |
93 | cl->ptr = ptr + size; | |
94 | ||
95 | return ptr; | |
96 | } | |
97 | } | |
98 | ||
99 | ||
100 | static inline void init_finalizer_array(msgpack_zone_finalizer_array* fa) | |
101 | { | |
102 | fa->tail = NULL; | |
103 | fa->end = NULL; | |
104 | fa->array = NULL; | |
105 | } | |
106 | ||
107 | static inline void call_finalizer_array(msgpack_zone_finalizer_array* fa) | |
108 | { | |
109 | msgpack_zone_finalizer* fin = fa->tail; | |
110 | for(; fin != fa->array; --fin) { | |
111 | (*(fin-1)->func)((fin-1)->data); | |
112 | } | |
113 | } | |
114 | ||
115 | static inline void destroy_finalizer_array(msgpack_zone_finalizer_array* fa) | |
116 | { | |
117 | call_finalizer_array(fa); | |
118 | free(fa->array); | |
119 | } | |
120 | ||
121 | static inline void clear_finalizer_array(msgpack_zone_finalizer_array* fa) | |
122 | { | |
123 | call_finalizer_array(fa); | |
124 | fa->tail = fa->array; | |
125 | } | |
126 | ||
127 | bool msgpack_zone_push_finalizer_expand(msgpack_zone* zone, | |
128 | void (*func)(void* data), void* data) | |
129 | { | |
130 | msgpack_zone_finalizer_array* const fa = &zone->finalizer_array; | |
131 | msgpack_zone_finalizer* tmp; | |
132 | ||
133 | const size_t nused = (size_t)(fa->end - fa->array); | |
134 | ||
135 | size_t nnext; | |
136 | if(nused == 0) { | |
137 | nnext = (sizeof(msgpack_zone_finalizer) < 72/2) ? | |
138 | 72 / sizeof(msgpack_zone_finalizer) : 8; | |
139 | ||
140 | } else { | |
141 | nnext = nused * 2; | |
142 | } | |
143 | ||
144 | tmp = (msgpack_zone_finalizer*)realloc(fa->array, | |
145 | sizeof(msgpack_zone_finalizer) * nnext); | |
146 | if(tmp == NULL) { | |
147 | return false; | |
148 | } | |
149 | ||
150 | fa->array = tmp; | |
151 | fa->end = tmp + nnext; | |
152 | fa->tail = tmp + nused; | |
153 | ||
154 | fa->tail->func = func; | |
155 | fa->tail->data = data; | |
156 | ||
157 | ++fa->tail; | |
158 | ||
159 | return true; | |
160 | } | |
161 | ||
162 | ||
163 | bool msgpack_zone_is_empty(msgpack_zone* zone) | |
164 | { | |
165 | msgpack_zone_chunk_list* const cl = &zone->chunk_list; | |
166 | msgpack_zone_finalizer_array* const fa = &zone->finalizer_array; | |
167 | return cl->free == zone->chunk_size && cl->head->next == NULL && | |
168 | fa->tail == fa->array; | |
169 | } | |
170 | ||
171 | ||
172 | void msgpack_zone_destroy(msgpack_zone* zone) | |
173 | { | |
174 | destroy_finalizer_array(&zone->finalizer_array); | |
175 | destroy_chunk_list(&zone->chunk_list); | |
176 | } | |
177 | ||
178 | void msgpack_zone_clear(msgpack_zone* zone) | |
179 | { | |
180 | clear_finalizer_array(&zone->finalizer_array); | |
181 | clear_chunk_list(&zone->chunk_list, zone->chunk_size); | |
182 | } | |
183 | ||
184 | bool msgpack_zone_init(msgpack_zone* zone, size_t chunk_size) | |
185 | { | |
186 | zone->chunk_size = chunk_size; | |
187 | ||
188 | if(!init_chunk_list(&zone->chunk_list, chunk_size)) { | |
189 | return false; | |
190 | } | |
191 | ||
192 | init_finalizer_array(&zone->finalizer_array); | |
193 | ||
194 | return true; | |
195 | } | |
196 | ||
197 | msgpack_zone* msgpack_zone_new(size_t chunk_size) | |
198 | { | |
199 | msgpack_zone* zone = (msgpack_zone*)malloc( | |
200 | sizeof(msgpack_zone)); | |
201 | if(zone == NULL) { | |
202 | return NULL; | |
203 | } | |
204 | ||
205 | zone->chunk_size = chunk_size; | |
206 | ||
207 | if(!init_chunk_list(&zone->chunk_list, chunk_size)) { | |
208 | free(zone); | |
209 | return NULL; | |
210 | } | |
211 | ||
212 | init_finalizer_array(&zone->finalizer_array); | |
213 | ||
214 | return zone; | |
215 | } | |
216 | ||
217 | void msgpack_zone_free(msgpack_zone* zone) | |
218 | { | |
219 | if(zone == NULL) { return; } | |
220 | msgpack_zone_destroy(zone); | |
221 | free(zone); | |
222 | } |