aboutsummaryrefslogtreecommitdiff
path: root/BumpAlloc.c
blob: 09af8fa273612b61c559517187d13ad1fb7e7c7d (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "BumpAlloc.h"
#include "Types.h"
#include <stdio.h>
#include <stdlib.h>

struct BumpAlloc {
    void* memory;
    usize size;
    usize top;
};

static inline usize*
top_size(struct BumpAlloc* b) {
    return (usize*)(b->memory + b->top);
}

static int
bump_resizeable(struct BumpAlloc *b, void *ptr) {
    if (NULL == b)
        return 0;

    return b->memory + b->top - *top_size(b) <= ptr &&
           ptr < b->memory + b->top;
}

Result
bump_free(MemoryManager mm, void **ptr) {
    if (NULL == mm.priv)
        return R_Uninitialized;

    struct BumpAlloc *b = (struct BumpAlloc*)mm.priv;

    if (NULL != ptr) {
        if (bump_resizeable(b, *ptr))
            *ptr = NULL;
        else
            return R_InvalidArgument;
    }

    if (b->top > 0) {
        b->top -= *top_size(b);
        if (b->top > 0)
            b->top -= sizeof(usize);
    }

    return R_Ok;
}

Result
bump_destroy(MemoryManager *mm) {
    if (NULL == mm->priv)
        return R_Uninitialized;

    struct BumpAlloc b = *(struct BumpAlloc*)mm->priv;

    if (NULL == b.memory) {
        free(mm->priv);
        mm->priv = NULL;
        return R_Uninitialized;
    }

    free(b.memory);
    free(mm->priv);
    mm->priv = NULL;

    return R_Ok;
}

Result
bump_alloc(MemoryManager mm, void** ptr, usize size) {
    if (NULL == mm.priv)
        return R_Uninitialized;

    if (0 == size || NULL == ptr)
        return R_NullArgument;

    struct BumpAlloc *b = (struct BumpAlloc*)mm.priv;

    if (size + b->top + sizeof(usize) > b->size)
        return R_OutOfMemory;

    if (b->top > 0)
        b->top += sizeof(usize);
    usize start = b->top;

    b->top += size;
    // Keep allocated memory size at the end of every allocation
    *top_size(b) = size;

    *ptr = b->memory + start;
    return R_Ok;
}

Result
bump_resize(MemoryManager mm, void **ptr, usize size) {
    if (NULL == mm.priv)
        return R_Uninitialized;

    if (size == 0)
        return bump_free(mm, ptr);

    if (NULL == ptr)
        return R_NullArgument;

    struct BumpAlloc *b = (struct BumpAlloc*)mm.priv;

    if (NULL == ptr || !bump_resizeable(b, *ptr))
        return R_InvalidArgument;

    usize last_size = *top_size(b);
    usize start = b->top - last_size;

    if (start + size + sizeof(usize) > b->size)
        return R_OutOfMemory;

    *top_size(b) = 0;
    b->top = start + size;
    *top_size(b) = size;

    return R_Ok;
}

MemoryManager
M_bump(usize size) {
    struct BumpAlloc *b = malloc(sizeof(struct BumpAlloc));
    b->memory = malloc(size);
    b->size = size;
    b->top = 0;

    return (MemoryManager){
        .alloc = &bump_alloc,
        .realloc = &bump_resize,
        .free = &bump_free,
        .destroy = &bump_destroy,
        .priv = b,
    };
}