summaryrefslogtreecommitdiff
path: root/src/std/mem.c
blob: a537330bfc4f832fd2355123e71507ef0ed5af61 (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
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
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "log.h"
#include "mem.h"

#ifndef DEFAULT_ALIGNMENT
#define DEFAULT_ALIGNMENT (2 * sizeof(void*))
#endif

// --- Arena

void* arena_alloc_align(arena* a, size_t size, size_t align) {
  ptrdiff_t padding = -(uintptr_t)a->curr & (align - 1);
  ptrdiff_t available = a->end - a->curr - padding;
  // TRACE("Padding %td available %td", padding, available);
  if (available < 0 || (ptrdiff_t)size > available) {
    ERROR_EXIT("Arena ran out of memory\n");
  }
  void* p = a->curr + padding;
  a->curr += padding + size;
  return memset(p, 0, size);
}
void* arena_alloc(arena* a, size_t size) { return arena_alloc_align(a, size, DEFAULT_ALIGNMENT); }

arena arena_create(void* backing_buffer, size_t capacity) {
  return (arena){ .begin = backing_buffer,
                  .curr = backing_buffer,
                  .end = backing_buffer + (ptrdiff_t)capacity };
}

void arena_free_all(arena* a) {
  a->curr = a->begin;  // pop everything at once and reset to the start.
}

void arena_free_storage(arena* a) { free(a->begin); }

arena_save arena_savepoint(arena* a) {
  arena_save savept = { .arena = a, .savepoint = a->curr };
  return savept;
}

void arena_rewind(arena_save savepoint) { savepoint.arena->curr = savepoint.savepoint; }

// --- Pool

void_pool void_pool_create(arena* a, const char* debug_label, u64 capacity, u64 entry_size) {
  size_t memory_requirements = capacity * entry_size;
  void* backing_buf = arena_alloc(a, memory_requirements);

  assert(entry_size >= sizeof(void_pool_header));  // TODO: create my own assert with error message

  void_pool pool = { .capacity = capacity,
                     .entry_size = entry_size,
                     .count = 0,
                     .backing_buffer = backing_buf,
                     .free_list_head = NULL,
                     .debug_label = debug_label };

  void_pool_free_all(&pool);

  return pool;
}

void void_pool_free_all(void_pool* pool) {
  // set all entries to be free
  for (u64 i = 0; i < pool->capacity; i++) {
    void* ptr = &pool->backing_buffer[i * pool->entry_size];
    void_pool_header* free_node =
        (void_pool_header*)ptr;  // we reuse the actual entry itself to hold the header
    if (i == (pool->capacity - 1)) {
      // if the last one we make its next pointer NULL indicating its full
      free_node->next = NULL;
    }
    free_node->next = pool->free_list_head;
    // now the head points to this entry
    pool->free_list_head = free_node;
  }
}

void* void_pool_get(void_pool* pool, u32 raw_handle) {
  // An handle is an index into the array essentially
  void* ptr = pool->backing_buffer + (raw_handle * pool->entry_size);
  return ptr;
}

void* void_pool_alloc(void_pool* pool, u32* out_raw_handle) {
  // get the next free node
  if (pool->count == pool->capacity) {
    WARN("Pool is full!");
    return NULL;
  }
  if (pool->free_list_head == NULL) {
    ERROR("%s Pool is full (head = null)", pool->debug_label);
    return NULL;
  }
  void_pool_header* free_node = pool->free_list_head;

  // What index does this become?
  uintptr_t start = (uintptr_t)pool->backing_buffer;
  uintptr_t cur = (uintptr_t)free_node;
  TRACE("%ld %ld ", start, cur);
  assert(cur > start);
  u32 index = (u32)((cur - start) / pool->entry_size);
  /* printf("Index %d\n", index); */
  if (out_raw_handle != NULL) {
    *out_raw_handle = index;
  }

  pool->free_list_head = free_node->next;

  memset(free_node, 0, pool->entry_size);
  pool->count++;
  return (void*)free_node;
}

void void_pool_dealloc(void_pool* pool, u32 raw_handle) {
  // push free node back onto the free list
  void* ptr = void_pool_get(pool, raw_handle);
  void_pool_header* freed_node = (void_pool_header*)ptr;

  freed_node->next = pool->free_list_head;
  pool->free_list_head = freed_node;

  pool->count--;
}

u32 void_pool_insert(void_pool* pool, void* item) {
  u32 raw_handle;
  void* item_dest = void_pool_alloc(pool, &raw_handle);
  memcpy(item_dest, item, pool->entry_size);
  return raw_handle;
}