1/*
2 * MessagePack for C memory pool implementation
3 *
4 * Copyright (C) 2008-2010 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#ifndef MSGPACK_ZONE_H
11#define MSGPACK_ZONE_H
12
13#include "sysdep.h"
14
15#ifdef __cplusplus
16extern "C" {
17#endif
18
19
20/**
21 * @defgroup msgpack_zone Memory zone
22 * @ingroup msgpack
23 * @{
24 */
25
26typedef struct msgpack_zone_finalizer {
27    void (*func)(void* data);
28    void* data;
29} msgpack_zone_finalizer;
30
31typedef struct msgpack_zone_finalizer_array {
32    msgpack_zone_finalizer* tail;
33    msgpack_zone_finalizer* end;
34    msgpack_zone_finalizer* array;
35} msgpack_zone_finalizer_array;
36
37struct msgpack_zone_chunk;
38typedef struct msgpack_zone_chunk msgpack_zone_chunk;
39
40typedef struct msgpack_zone_chunk_list {
41    size_t free;
42    char* ptr;
43    msgpack_zone_chunk* head;
44} msgpack_zone_chunk_list;
45
46typedef struct msgpack_zone {
47    msgpack_zone_chunk_list chunk_list;
48    msgpack_zone_finalizer_array finalizer_array;
49    size_t chunk_size;
50} msgpack_zone;
51
52#ifndef MSGPACK_ZONE_CHUNK_SIZE
53#define MSGPACK_ZONE_CHUNK_SIZE 8192
54#endif
55
56MSGPACK_DLLEXPORT
57bool msgpack_zone_init(msgpack_zone* zone, size_t chunk_size);
58MSGPACK_DLLEXPORT
59void msgpack_zone_destroy(msgpack_zone* zone);
60
61MSGPACK_DLLEXPORT
62msgpack_zone* msgpack_zone_new(size_t chunk_size);
63MSGPACK_DLLEXPORT
64void msgpack_zone_free(msgpack_zone* zone);
65
66static inline void* msgpack_zone_malloc(msgpack_zone* zone, size_t size);
67static inline void* msgpack_zone_malloc_no_align(msgpack_zone* zone, size_t size);
68
69static inline bool msgpack_zone_push_finalizer(msgpack_zone* zone,
70        void (*func)(void* data), void* data);
71
72static inline void msgpack_zone_swap(msgpack_zone* a, msgpack_zone* b);
73
74MSGPACK_DLLEXPORT
75bool msgpack_zone_is_empty(msgpack_zone* zone);
76
77MSGPACK_DLLEXPORT
78void msgpack_zone_clear(msgpack_zone* zone);
79
80/** @} */
81
82
83#ifndef MSGPACK_ZONE_ALIGN
84#define MSGPACK_ZONE_ALIGN sizeof(void*)
85#endif
86
87MSGPACK_DLLEXPORT
88void* msgpack_zone_malloc_expand(msgpack_zone* zone, size_t size);
89
90static inline void* msgpack_zone_malloc_no_align(msgpack_zone* zone, size_t size)
91{
92    char* ptr;
93    msgpack_zone_chunk_list* cl = &zone->chunk_list;
94
95    if(zone->chunk_list.free < size) {
96        return msgpack_zone_malloc_expand(zone, size);
97    }
98
99    ptr = cl->ptr;
100    cl->free -= size;
101    cl->ptr  += size;
102
103    return ptr;
104}
105
106static inline void* msgpack_zone_malloc(msgpack_zone* zone, size_t size)
107{
108    char* aligned =
109        (char*)(
110            (size_t)(
111                zone->chunk_list.ptr + (MSGPACK_ZONE_ALIGN - 1)
112            ) / MSGPACK_ZONE_ALIGN * MSGPACK_ZONE_ALIGN
113        );
114    size_t adjusted_size = size + (aligned - zone->chunk_list.ptr);
115    if(zone->chunk_list.free >= adjusted_size) {
116        zone->chunk_list.free -= adjusted_size;
117        zone->chunk_list.ptr  += adjusted_size;
118        return aligned;
119    }
120    {
121        void* ptr = msgpack_zone_malloc_expand(zone, size + (MSGPACK_ZONE_ALIGN - 1));
122        if (ptr) {
123            return (char*)((size_t)(ptr) / MSGPACK_ZONE_ALIGN * MSGPACK_ZONE_ALIGN);
124        }
125    }
126    return NULL;
127}
128
129
130bool msgpack_zone_push_finalizer_expand(msgpack_zone* zone,
131        void (*func)(void* data), void* data);
132
133static inline bool msgpack_zone_push_finalizer(msgpack_zone* zone,
134        void (*func)(void* data), void* data)
135{
136    msgpack_zone_finalizer_array* const fa = &zone->finalizer_array;
137    msgpack_zone_finalizer* fin = fa->tail;
138
139    if(fin == fa->end) {
140        return msgpack_zone_push_finalizer_expand(zone, func, data);
141    }
142
143    fin->func = func;
144    fin->data = data;
145
146    ++fa->tail;
147
148    return true;
149}
150
151static inline void msgpack_zone_swap(msgpack_zone* a, msgpack_zone* b)
152{
153    msgpack_zone tmp = *a;
154    *a = *b;
155    *b = tmp;
156}
157
158
159#ifdef __cplusplus
160}
161#endif
162
163#endif /* msgpack/zone.h */
164