| /* | |
| * MessagePack for C memory pool implementation | |
| * | |
| * Copyright (C) 2008-2009 FURUHASHI Sadayuki | |
| * | |
| * Distributed under the Boost Software License, Version 1.0. | |
| * (See accompanying file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| */ | |
| #include "msgpack/zone.h" | |
| #include <stdlib.h> | |
| #include <string.h> | |
| struct msgpack_zone_chunk { | |
| struct msgpack_zone_chunk* next; | |
| /* data ... */ | |
| }; | |
| static inline bool init_chunk_list(msgpack_zone_chunk_list* cl, size_t chunk_size) | |
| { | |
| msgpack_zone_chunk* chunk = (msgpack_zone_chunk*)malloc( | |
| sizeof(msgpack_zone_chunk) + chunk_size); | |
| if(chunk == NULL) { | |
| return false; | |
| } | |
| cl->head = chunk; | |
| cl->free = chunk_size; | |
| cl->ptr = ((char*)chunk) + sizeof(msgpack_zone_chunk); | |
| chunk->next = NULL; | |
| return true; | |
| } | |
| static inline void destroy_chunk_list(msgpack_zone_chunk_list* cl) | |
| { | |
| msgpack_zone_chunk* c = cl->head; | |
| while(true) { | |
| msgpack_zone_chunk* n = c->next; | |
| free(c); | |
| if(n != NULL) { | |
| c = n; | |
| } else { | |
| break; | |
| } | |
| } | |
| } | |
| static inline void clear_chunk_list(msgpack_zone_chunk_list* cl, size_t chunk_size) | |
| { | |
| msgpack_zone_chunk* c = cl->head; | |
| while(true) { | |
| msgpack_zone_chunk* n = c->next; | |
| if(n != NULL) { | |
| free(c); | |
| c = n; | |
| } else { | |
| cl->head = c; | |
| break; | |
| } | |
| } | |
| cl->head->next = NULL; | |
| cl->free = chunk_size; | |
| cl->ptr = ((char*)cl->head) + sizeof(msgpack_zone_chunk); | |
| } | |
| void* msgpack_zone_malloc_expand(msgpack_zone* zone, size_t size) | |
| { | |
| msgpack_zone_chunk_list* const cl = &zone->chunk_list; | |
| msgpack_zone_chunk* chunk; | |
| size_t sz = zone->chunk_size; | |
| while(sz < size) { | |
| size_t tmp_sz = sz * 2; | |
| if (tmp_sz <= sz) { | |
| sz = size; | |
| break; | |
| } | |
| sz = tmp_sz; | |
| } | |
| chunk = (msgpack_zone_chunk*)malloc( | |
| sizeof(msgpack_zone_chunk) + sz); | |
| if (chunk == NULL) { | |
| return NULL; | |
| } | |
| else { | |
| char* ptr = ((char*)chunk) + sizeof(msgpack_zone_chunk); | |
| chunk->next = cl->head; | |
| cl->head = chunk; | |
| cl->free = sz - size; | |
| cl->ptr = ptr + size; | |
| return ptr; | |
| } | |
| } | |
| static inline void init_finalizer_array(msgpack_zone_finalizer_array* fa) | |
| { | |
| fa->tail = NULL; | |
| fa->end = NULL; | |
| fa->array = NULL; | |
| } | |
| static inline void call_finalizer_array(msgpack_zone_finalizer_array* fa) | |
| { | |
| msgpack_zone_finalizer* fin = fa->tail; | |
| for(; fin != fa->array; --fin) { | |
| (*(fin-1)->func)((fin-1)->data); | |
| } | |
| } | |
| static inline void destroy_finalizer_array(msgpack_zone_finalizer_array* fa) | |
| { | |
| call_finalizer_array(fa); | |
| free(fa->array); | |
| } | |
| static inline void clear_finalizer_array(msgpack_zone_finalizer_array* fa) | |
| { | |
| call_finalizer_array(fa); | |
| fa->tail = fa->array; | |
| } | |
| bool msgpack_zone_push_finalizer_expand(msgpack_zone* zone, | |
| void (*func)(void* data), void* data) | |
| { | |
| msgpack_zone_finalizer_array* const fa = &zone->finalizer_array; | |
| msgpack_zone_finalizer* tmp; | |
| const size_t nused = (size_t)(fa->end - fa->array); | |
| size_t nnext; | |
| if(nused == 0) { | |
| nnext = (sizeof(msgpack_zone_finalizer) < 72/2) ? | |
| 72 / sizeof(msgpack_zone_finalizer) : 8; | |
| } else { | |
| nnext = nused * 2; | |
| } | |
| tmp = (msgpack_zone_finalizer*)realloc(fa->array, | |
| sizeof(msgpack_zone_finalizer) * nnext); | |
| if(tmp == NULL) { | |
| return false; | |
| } | |
| fa->array = tmp; | |
| fa->end = tmp + nnext; | |
| fa->tail = tmp + nused; | |
| fa->tail->func = func; | |
| fa->tail->data = data; | |
| ++fa->tail; | |
| return true; | |
| } | |
| bool msgpack_zone_is_empty(msgpack_zone* zone) | |
| { | |
| msgpack_zone_chunk_list* const cl = &zone->chunk_list; | |
| msgpack_zone_finalizer_array* const fa = &zone->finalizer_array; | |
| return cl->free == zone->chunk_size && cl->head->next == NULL && | |
| fa->tail == fa->array; | |
| } | |
| void msgpack_zone_destroy(msgpack_zone* zone) | |
| { | |
| destroy_finalizer_array(&zone->finalizer_array); | |
| destroy_chunk_list(&zone->chunk_list); | |
| } | |
| void msgpack_zone_clear(msgpack_zone* zone) | |
| { | |
| clear_finalizer_array(&zone->finalizer_array); | |
| clear_chunk_list(&zone->chunk_list, zone->chunk_size); | |
| } | |
| bool msgpack_zone_init(msgpack_zone* zone, size_t chunk_size) | |
| { | |
| zone->chunk_size = chunk_size; | |
| if(!init_chunk_list(&zone->chunk_list, chunk_size)) { | |
| return false; | |
| } | |
| init_finalizer_array(&zone->finalizer_array); | |
| return true; | |
| } | |
| msgpack_zone* msgpack_zone_new(size_t chunk_size) | |
| { | |
| msgpack_zone* zone = (msgpack_zone*)malloc( | |
| sizeof(msgpack_zone)); | |
| if(zone == NULL) { | |
| return NULL; | |
| } | |
| zone->chunk_size = chunk_size; | |
| if(!init_chunk_list(&zone->chunk_list, chunk_size)) { | |
| free(zone); | |
| return NULL; | |
| } | |
| init_finalizer_array(&zone->finalizer_array); | |
| return zone; | |
| } | |
| void msgpack_zone_free(msgpack_zone* zone) | |
| { | |
| if(zone == NULL) { return; } | |
| msgpack_zone_destroy(zone); | |
| free(zone); | |
| } |