aboutsummaryrefslogtreecommitdiff
path: root/src/mempool.h
blob: 6c25ac9547724871ba4bde53a3dcae80b00244ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#ifndef MEMPOOL_H
#define MEMPOOL_H

#ifndef MEMPOOL_OBJ_TYPE
#define MEMPOOL_OBJ_TYPE int
#endif

#ifndef MEMPOOL_CAP
#define MEMPOOL_CAP (1 << 16)
#endif

#define for_each_block(id, b, head)                     \
    for(struct id##_block *b = (head), *next = NULL;    \
        b && (next = b->next, 1); b = next)
#define get_last_block(b)                       \
    while((b)->next != NULL) (b) = (b)->next

#define MEMPOOL_GENERATE(id)                                             \
                                                                         \
    struct id##_block {                                                  \
        union id##_chunk {                                               \
            MEMPOOL_OBJ_TYPE obj;                                        \
            union id##_chunk *next;                                      \
        } chunks[MEMPOOL_CAP];                                           \
                                                                         \
        struct id##_block *next;                                         \
    };                                                                   \
                                                                         \
    static union  id##_chunk *id##_ap = NULL;                            \
    static struct id##_block id##_block;                                 \
    static size_t id##_allocations = 0;                                  \
                                                                         \
    static inline void *_##id##_mempool_init_block(struct id##_block *b) \
    {                                                                    \
        b->next = NULL;                                                  \
        for(size_t i = 0; i < MEMPOOL_CAP; i++)                          \
            b->chunks[i].next = &b->chunks[i+1];                         \
        b->chunks[MEMPOOL_CAP-1].next = NULL;                            \
                                                                         \
        return b->chunks;                                                \
    }                                                                    \
                                                                         \
    static inline void *id##_mempool_allocate(void)                      \
    {                                                                    \
        if(!id##_ap) {                                                   \
            struct id##_block *new_block = &(id##_block);                \
            if((id##_allocations) > 0) {                                 \
                new_block = malloc(sizeof(*new_block));                  \
                struct id##_block *last_block = &(id##_block);           \
                get_last_block(last_block);                              \
                last_block->next = new_block;                            \
            }                                                            \
            id##_ap = _##id##_mempool_init_block(new_block);             \
        }                                                                \
                                                                         \
        id##_allocations++;                                              \
                                                                         \
        void *ptr = &(id##_ap)->obj;                                     \
        id##_ap = (id##_ap)->next;                                       \
        return ptr;                                                      \
    }                                                                    \
                                                                         \
    static inline void id##_mempool_free(void *ptr)                      \
    {                                                                    \
        ((union id##_chunk *)ptr)->next = id##_ap;                       \
        id##_ap = (union id##_chunk *)ptr;                               \
                                                                         \
        if(--id##_allocations == 0) {                                    \
            for_each_block(id, b, (id##_block).next)                     \
                free(b);                                                 \
            id##_ap = id##_block.chunks;                                 \
        }                                                                \
    }                                                                    \

#endif