Coverage Report

Created: 2023-09-25 06:13

/src/msgpack-c/include/msgpack/v1/detail/cpp11_zone.hpp
Line
Count
Source (jump to first uncovered line)
1
//
2
// MessagePack for C++ memory pool
3
//
4
// Copyright (C) 2008-2013 FURUHASHI Sadayuki and KONDO Takatoshi
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_CPP11_ZONE_HPP
11
#define MSGPACK_CPP11_ZONE_HPP
12
13
#include "msgpack/versioning.hpp"
14
#include "msgpack/cpp_config.hpp"
15
#include "msgpack/zone_decl.hpp"
16
#include "msgpack/assert.hpp"
17
18
#include <cstdint>
19
#include <cstdlib>
20
#include <memory>
21
#include <vector>
22
23
namespace msgpack {
24
25
/// @cond
26
MSGPACK_API_VERSION_NAMESPACE(v1) {
27
/// @endcond
28
29
class zone {
30
private:
31
    struct finalizer {
32
0
        finalizer(void (*func)(void*), void* data):m_func(func), m_data(data) {}
33
0
        void operator()() { m_func(m_data); }
34
        void (*m_func)(void*);
35
        void* m_data;
36
    };
37
    struct finalizer_array {
38
2.25k
        finalizer_array():m_tail(MSGPACK_NULLPTR), m_end(MSGPACK_NULLPTR), m_array(MSGPACK_NULLPTR) {}
39
2.25k
        void call() {
40
2.25k
            finalizer* fin = m_tail;
41
2.25k
            for(; fin != m_array; --fin) (*(fin-1))();
42
2.25k
        }
43
2.25k
        ~finalizer_array() {
44
2.25k
            call();
45
2.25k
            ::free(m_array);
46
2.25k
        }
47
0
        void clear() {
48
0
            call();
49
0
            m_tail = m_array;
50
0
        }
51
        void push(void (*func)(void* data), void* data)
52
0
        {
53
0
            finalizer* fin = m_tail;
54
0
55
0
            if(fin == m_end) {
56
0
                push_expand(func, data);
57
0
                return;
58
0
            }
59
0
60
0
            fin->m_func = func;
61
0
            fin->m_data = data;
62
0
63
0
            ++m_tail;
64
0
        }
65
0
        void push_expand(void (*func)(void*), void* data) {
66
0
            const size_t nused = static_cast<size_t>(m_end - m_array);
67
0
            size_t nnext;
68
0
            if(nused == 0) {
69
0
                nnext = (sizeof(finalizer) < 72/2) ?
70
0
                    72 / sizeof(finalizer) : 8;
71
0
            } else {
72
0
                nnext = nused * 2;
73
0
            }
74
0
            finalizer* tmp =
75
0
                static_cast<finalizer*>(::realloc(m_array, sizeof(finalizer) * nnext));
76
0
            if(!tmp) {
77
0
                throw std::bad_alloc();
78
0
            }
79
0
            m_array     = tmp;
80
0
            m_end   = tmp + nnext;
81
0
            m_tail  = tmp + nused;
82
0
            new (m_tail) finalizer(func, data);
83
0
84
0
            ++m_tail;
85
0
        }
86
        finalizer_array(finalizer_array&& other) noexcept
87
            :m_tail(other.m_tail), m_end(other.m_end), m_array(other.m_array)
88
0
        {
89
0
            other.m_tail = MSGPACK_NULLPTR;
90
0
            other.m_end = MSGPACK_NULLPTR;
91
0
            other.m_array = MSGPACK_NULLPTR;
92
0
        }
93
        finalizer_array& operator=(finalizer_array&& other) noexcept
94
0
        {
95
0
            this->~finalizer_array();
96
0
            new (this) finalizer_array(std::move(other));
97
0
            return *this;
98
0
        }
99
100
        finalizer* m_tail;
101
        finalizer* m_end;
102
        finalizer* m_array;
103
104
    private:
105
        finalizer_array(const finalizer_array&);
106
        finalizer_array& operator=(const finalizer_array&);
107
    };
108
    struct chunk {
109
        chunk* m_next;
110
    };
111
    struct chunk_list {
112
        chunk_list(size_t chunk_size)
113
2.25k
        {
114
2.25k
            chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + chunk_size));
115
2.25k
            if(!c) {
116
0
                throw std::bad_alloc();
117
0
            }
118
119
2.25k
            m_head = c;
120
2.25k
            m_free = chunk_size;
121
2.25k
            m_ptr  = reinterpret_cast<char*>(c) + sizeof(chunk);
122
2.25k
            c->m_next = MSGPACK_NULLPTR;
123
2.25k
        }
124
        ~chunk_list()
125
2.25k
        {
126
2.25k
            chunk* c = m_head;
127
13.6k
            while(c) {
128
11.3k
                chunk* n = c->m_next;
129
11.3k
                ::free(c);
130
11.3k
                c = n;
131
11.3k
            }
132
2.25k
        }
133
        void clear(size_t chunk_size)
134
0
        {
135
0
            chunk* c = m_head;
136
0
            while(true) {
137
0
                chunk* n = c->m_next;
138
0
                if(n) {
139
0
                    ::free(c);
140
0
                    c = n;
141
0
                } else {
142
0
                    m_head = c;
143
0
                    break;
144
0
                }
145
0
            }
146
0
            m_head->m_next = MSGPACK_NULLPTR;
147
0
            m_free = chunk_size;
148
0
            m_ptr  = reinterpret_cast<char*>(m_head) + sizeof(chunk);
149
0
        }
150
        chunk_list(chunk_list&& other) noexcept
151
            :m_free(other.m_free), m_ptr(other.m_ptr), m_head(other.m_head)
152
0
        {
153
0
            other.m_head = MSGPACK_NULLPTR;
154
0
        }
155
        chunk_list& operator=(chunk_list&& other) noexcept
156
0
        {
157
0
            this->~chunk_list();
158
0
            new (this) chunk_list(std::move(other));
159
0
            return *this;
160
0
        }
161
162
        size_t m_free;
163
        char* m_ptr;
164
        chunk* m_head;
165
    private:
166
        chunk_list(const chunk_list&);
167
        chunk_list& operator=(const chunk_list&);
168
    };
169
    size_t m_chunk_size;
170
    chunk_list m_chunk_list;
171
    finalizer_array m_finalizer_array;
172
173
public:
174
    zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE);
175
176
public:
177
    void* allocate_align(size_t size, size_t align = MSGPACK_ZONE_ALIGN);
178
    void* allocate_no_align(size_t size);
179
180
    void push_finalizer(void (*func)(void*), void* data);
181
182
    template <typename T>
183
    void push_finalizer(msgpack::unique_ptr<T> obj);
184
185
    void clear();
186
187
    void swap(zone& o);
188
189
    static void* operator new(std::size_t size)
190
2.25k
    {
191
2.25k
        void* p = ::malloc(size);
192
2.25k
        if (!p) throw std::bad_alloc();
193
2.25k
        return p;
194
2.25k
    }
195
    static void operator delete(void *p) noexcept
196
2.25k
    {
197
2.25k
        ::free(p);
198
2.25k
    }
199
    static void* operator new(std::size_t /*size*/, void* mem) noexcept
200
0
    {
201
0
        return mem;
202
0
    }
203
    static void operator delete(void * /*p*/, void* /*mem*/) noexcept
204
0
    {
205
0
    }
206
207
    template <typename T, typename... Args>
208
    T* allocate(Args... args);
209
210
    zone(zone&&) = default;
211
    zone& operator=(zone&&) = default;
212
    zone(const zone&) = delete;
213
    zone& operator=(const zone&) = delete;
214
215
private:
216
    void undo_allocate(size_t size);
217
218
    template <typename T>
219
    static void object_destruct(void* obj);
220
221
    template <typename T>
222
    static void object_delete(void* obj);
223
224
    static char* get_aligned(char* ptr, size_t align);
225
226
    char* allocate_expand(size_t size);
227
};
228
229
inline zone::zone(size_t chunk_size):m_chunk_size(chunk_size), m_chunk_list(m_chunk_size)
230
2.25k
{
231
2.25k
}
232
233
inline char* zone::get_aligned(char* ptr, size_t align)
234
442k
{
235
442k
    MSGPACK_ASSERT(align != 0 && (align & (align - 1)) == 0); // align must be 2^n (n >= 0)
236
0
    return
237
442k
        reinterpret_cast<char*>(
238
442k
            reinterpret_cast<uintptr_t>(ptr + (align - 1)) & ~static_cast<uintptr_t>(align - 1)
239
442k
        );
240
442k
}
241
242
inline void* zone::allocate_align(size_t size, size_t align)
243
432k
{
244
432k
    char* aligned = get_aligned(m_chunk_list.m_ptr, align);
245
432k
    size_t adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr);
246
432k
    if (m_chunk_list.m_free < adjusted_size) {
247
9.11k
        size_t enough_size = size + align - 1;
248
9.11k
        char* ptr = allocate_expand(enough_size);
249
9.11k
        aligned = get_aligned(ptr, align);
250
9.11k
        adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr);
251
9.11k
    }
252
432k
    m_chunk_list.m_free -= adjusted_size;
253
432k
    m_chunk_list.m_ptr  += adjusted_size;
254
432k
    return aligned;
255
432k
}
256
257
inline void* zone::allocate_no_align(size_t size)
258
0
{
259
0
    char* ptr = m_chunk_list.m_ptr;
260
0
    if(m_chunk_list.m_free < size) {
261
0
        ptr = allocate_expand(size);
262
0
    }
263
0
    m_chunk_list.m_free -= size;
264
0
    m_chunk_list.m_ptr  += size;
265
0
266
0
    return ptr;
267
0
}
268
269
inline char* zone::allocate_expand(size_t size)
270
9.11k
{
271
9.11k
    chunk_list* const cl = &m_chunk_list;
272
273
9.11k
    size_t sz = m_chunk_size;
274
275
12.3k
    while(sz < size) {
276
3.19k
        size_t tmp_sz = sz * 2;
277
3.19k
        if (tmp_sz <= sz) {
278
0
            sz = size;
279
0
            break;
280
0
        }
281
3.19k
        sz = tmp_sz;
282
3.19k
    }
283
284
9.11k
    chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
285
9.11k
    if (!c) throw std::bad_alloc();
286
287
9.11k
    char* ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
288
289
9.11k
    c->m_next  = cl->m_head;
290
9.11k
    cl->m_head = c;
291
9.11k
    cl->m_free = sz;
292
9.11k
    cl->m_ptr  = ptr;
293
294
9.11k
    return ptr;
295
9.11k
}
296
297
inline void zone::push_finalizer(void (*func)(void*), void* data)
298
0
{
299
0
    m_finalizer_array.push(func, data);
300
0
}
301
302
template <typename T>
303
inline void zone::push_finalizer(msgpack::unique_ptr<T> obj)
304
{
305
    m_finalizer_array.push(&zone::object_delete<T>, obj.release());
306
}
307
308
inline void zone::clear()
309
0
{
310
0
    m_finalizer_array.clear();
311
0
    m_chunk_list.clear(m_chunk_size);
312
0
}
313
314
inline void zone::swap(zone& o)
315
0
{
316
0
    std::swap(*this, o);
317
0
}
318
319
template <typename T>
320
void zone::object_delete(void* obj)
321
{
322
    delete static_cast<T*>(obj);
323
}
324
325
template <typename T>
326
void zone::object_destruct(void* obj)
327
{
328
    static_cast<T*>(obj)->~T();
329
}
330
331
inline void zone::undo_allocate(size_t size)
332
0
{
333
0
    m_chunk_list.m_ptr  -= size;
334
0
    m_chunk_list.m_free += size;
335
0
}
336
337
338
template <typename T, typename... Args>
339
T* zone::allocate(Args... args)
340
{
341
    void* x = allocate_align(sizeof(T), MSGPACK_ZONE_ALIGNOF(T));
342
    try {
343
        m_finalizer_array.push(&zone::object_destruct<T>, x);
344
    } catch (...) {
345
        undo_allocate(sizeof(T));
346
        throw;
347
    }
348
    try {
349
        return new (x) T(args...);
350
    } catch (...) {
351
        --m_finalizer_array.m_tail;
352
        undo_allocate(sizeof(T));
353
        throw;
354
    }
355
}
356
357
inline std::size_t aligned_size(
358
    std::size_t size,
359
0
    std::size_t align) {
360
0
    return (size + align - 1) / align * align;
361
0
}
362
363
/// @cond
364
}  // MSGPACK_API_VERSION_NAMESPACE(v1)
365
/// @endcond
366
367
}  // namespace msgpack
368
369
#endif // MSGPACK_CPP11_ZONE_HPP