aboutsummaryrefslogtreecommitdiff
path: root/src_c/pool.c
blob: 619a97d4162fe1e2b0a699679e2ec951fd2516aa (plain) (blame)
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
76
77
78
79
80
81
82
83
84
85
#include <stdlib.h>
#include "pool.h"


#define PAGE_SIZE 4096


typedef struct header_t {
    struct header_t *next;
} header_t;


struct opcut_pool_t {
    size_t item_size;
    header_t *blocks;
    header_t *items;
};


static void allocate_block(opcut_pool_t *pool) {
    size_t items_per_block =
        (PAGE_SIZE - sizeof(header_t)) / (sizeof(header_t) + pool->item_size);
    if (items_per_block < 1)
        items_per_block = 1;

    header_t *block =
        malloc(sizeof(header_t) +
               items_per_block * (sizeof(header_t) + pool->item_size));
    if (!block)
        return;
    block->next = pool->blocks;
    pool->blocks = block;

    for (size_t i = 0; i < items_per_block; ++i) {
        header_t *header = (void *)block + sizeof(header_t) +
                           i * (sizeof(header_t) + pool->item_size);
        header->next = pool->items;
        pool->items = header;
    }
}


opcut_pool_t *opcut_pool_create(size_t item_size) {
    opcut_pool_t *pool = malloc(sizeof(opcut_pool_t));
    if (!pool)
        return NULL;

    if (item_size % sizeof(void *) != 0)
        item_size += sizeof(void *) - (item_size % sizeof(void *));

    pool->item_size = item_size;
    pool->blocks = NULL;
    pool->items = NULL;

    return pool;
}


void opcut_pool_destroy(opcut_pool_t *pool) {
    while (pool->blocks) {
        header_t *block = pool->blocks;
        pool->blocks = block->next;
        free(block);
    }
    free(pool);
}


void *opcut_pool_get(opcut_pool_t *pool) {
    if (!pool->items)
        allocate_block(pool);

    if (!pool->items)
        return NULL;

    header_t *header = pool->items;
    pool->items = header->next;
    return header + 1;
}

void opcut_pool_return(opcut_pool_t *pool, void *item) {
    header_t *header = (header_t *)item - 1;
    header->next = pool->items;
    pool->items = header;
}