aboutsummaryrefslogtreecommitdiff
path: root/src/scoped_allocator.c
blob: 4d4074095fe85ea9b4417611226dcd5b7fd1cca1 (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
76
77
78
79
80
81
82
#include "../include/scoped_allocator.h"
#include "../include/alloc.h"
#include <assert.h>

#define ALLOC_NODE_SIZE 4096

int scoped_allocator_node_init(ScopedAllocatorNode *self) {
    self->data = NULL;
    self->size = 0;
    self->next = NULL;
    return am_malloc(ALLOC_NODE_SIZE, (void**)&self->data);
}

void scoped_allocator_node_deinit(ScopedAllocatorNode *self) {
    am_free(self->data);
    self->data = NULL;
    self->size = 0;
    if(self->next) {
        scoped_allocator_node_deinit(self->next);
        am_free(self->next);
        self->next = NULL;
    }
}

int scoped_allocator_init(ScopedAllocator *self) {
    return_if_error(scoped_allocator_node_init(&self->head));
    self->current = &self->head;
    return buffer_init(&self->buffers, NULL);
}

static void buffer_deinit(Buffer *self) {
    am_free(self->data);
    self->data = NULL;
    self->size = 0;
    self->capacity = 0;
}

void scoped_allocator_deinit(ScopedAllocator *self) {
    Buffer *buffer;
    Buffer *buffer_end;

    scoped_allocator_node_deinit(&self->head);
    self->current = NULL;
    buffer = (Buffer*)&self->buffers.data[0];
    buffer_end = buffer + self->buffers.size / sizeof(Buffer);
    while(buffer != buffer_end) {
        buffer_deinit(buffer);
        ++buffer;
    }
    buffer_deinit(&self->buffers);
}

static CHECK_RESULT int scoped_allocator_ensure_capacity_for(ScopedAllocator *self, usize size) {
    void *new_node;
    new_node = NULL;
    
    if(self->current->size + size > ALLOC_NODE_SIZE) {
        return_if_error(am_malloc(sizeof(ScopedAllocatorNode), &new_node));
        cleanup_if_error(scoped_allocator_node_init(new_node));
        self->current->next = new_node;
        self->current = new_node;
    }
    return 0;

    cleanup:
    if(new_node)
        am_free(new_node);
    return -1;
}

int scoped_allocator_alloc(ScopedAllocator *self, usize size, void **mem) {
    assert(self->current);
    assert(size <= ALLOC_NODE_SIZE);
    return_if_error(scoped_allocator_ensure_capacity_for(self, size));
    *mem = &self->current->data[self->current->size];
    self->current->size += size;
    return 0;
}

int scoped_allocator_add_buffer(ScopedAllocator *self, Buffer *buffer) {
    return buffer_append(&self->buffers, buffer, sizeof(buffer));
}