aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAryadev Chavali <aryadev@aryadevchavali.com>2025-05-14 21:12:58 +0100
committerAryadev Chavali <aryadev@aryadevchavali.com>2025-05-15 22:25:45 +0100
commit12de1e8db90bccd5a0eefd21075f07c7b7e3dfaa (patch)
tree0434141f2bfd24207a2864f613a1c2e3ee7181fc /lib
parentba5c0a4579ece5d53c009a14d00e683e70b982f4 (diff)
downloadoats-12de1e8db90bccd5a0eefd21075f07c7b7e3dfaa.tar.gz
oats-12de1e8db90bccd5a0eefd21075f07c7b7e3dfaa.tar.bz2
oats-12de1e8db90bccd5a0eefd21075f07c7b7e3dfaa.zip
Refactor for cleanliness
Move files into separate folders for ease of reading, include source directory so we can use angle bracket includes, adjust build system to make directories for objects
Diffstat (limited to 'lib')
-rw-r--r--lib/arena.c203
-rw-r--r--lib/arena.h51
-rw-r--r--lib/sv.c158
-rw-r--r--lib/sv.h70
-rw-r--r--lib/vec.c38
-rw-r--r--lib/vec.h30
6 files changed, 550 insertions, 0 deletions
diff --git a/lib/arena.c b/lib/arena.c
new file mode 100644
index 0000000..aa2d775
--- /dev/null
+++ b/lib/arena.c
@@ -0,0 +1,203 @@
+/* Copyright (C) 2025 Aryadev Chavali
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
+ * details.
+
+ * You may distribute and modify this code under the terms of the GNU General
+ * Public License Version 2, which you should have received a copy of along with
+ * this program. If not, please go to <https://www.gnu.org/licenses/>.
+
+ * Created: 2025-04-05
+ * Description: Implementations for memory models.
+ */
+
+#include <lib/arena.h>
+
+#include <malloc.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+page_t *page_create(u64 size)
+{
+ size = MAX(size, PAGE_DEFAULT_SIZE);
+ page_t *page = calloc(1, sizeof(*page) + size);
+ page->next = NULL;
+ page->size = 0;
+ page->capacity = size;
+ return page;
+}
+
+void page_resize(page_t **page, u64 size)
+{
+ if (!page)
+ return;
+ else if (!(*page))
+ *page = page_create(size);
+ else if (page[0]->capacity < size)
+ {
+ page[0]->capacity = MAX(size, page[0]->capacity * 1.5);
+ page[0] = realloc(page[0], sizeof(*page[0]) + page[0]->capacity);
+ }
+}
+
+i64 page_append(page_t *page, void *data, u64 size)
+{
+ if (!page || page->size + size >= page->capacity)
+ return -1;
+ if (data)
+ memcpy(page->data + page->size, data, size);
+ u64 ptr = page->size;
+ page->size += size;
+ return ptr;
+}
+
+u64 page_rappend(page_t **page, void *data, u64 size)
+{
+ page_resize(page, page[0]->size + size);
+ if (data)
+ memcpy(page[0]->data + page[0]->size, data, size);
+ u64 ptr = page[0]->size;
+ page[0]->size += size;
+ return ptr;
+}
+
+void *arena_alloc(arena_t *arena, u64 size)
+{
+ if (!arena)
+ return NULL;
+ else if (!arena->start)
+ {
+ arena->start = page_create(1);
+ arena->end = arena->start;
+ }
+
+ page_t *best_fit;
+ for (best_fit = arena->start; best_fit; best_fit = best_fit->next)
+ if (best_fit->size + size + MEMORY_ALIGNMENT < best_fit->capacity)
+ break;
+
+ if (!best_fit)
+ {
+ best_fit = page_create(size);
+ arena->end->next = best_fit;
+ arena->end = best_fit;
+ }
+
+ // NOTE: Fsanitize has a hissy fit if we don't align memory "correctly"
+ u64 offset = 0;
+
+ if (size % MEMORY_ALIGNMENT == 0)
+ {
+ u64 div = (((u64)(best_fit->data + best_fit->size)) % MEMORY_ALIGNMENT);
+ if (div != 0)
+ offset = MEMORY_ALIGNMENT - div;
+ }
+
+ void *start = best_fit->data + best_fit->size + offset;
+
+ best_fit->size += size + offset;
+
+ return start;
+}
+
+void *arena_realloc(arena_t *arena, void *ptr, u64 oldsize, u64 newsize)
+{
+ if (!ptr)
+ return arena_alloc(arena, newsize);
+ else if (!arena || !arena->start)
+ return NULL;
+ else if (newsize <= oldsize)
+ // No need to change anything.
+ return ptr;
+
+ bool copy_into_new = true;
+ void *start = NULL;
+ page_t *old_page = NULL, *best_fit = NULL;
+
+ for (page_t *page = arena->start; page; page = page->next)
+ {
+ if (!best_fit && page->size + newsize < page->capacity)
+ best_fit = page;
+ if (page->data <= (u8 *)ptr &&
+ (u8 *)(ptr) + oldsize <= page->data + page->capacity)
+ old_page = page;
+ }
+
+ // If the old page exists, ptr is the latest allocation in it, and it has
+ // enough space to contain the new size, just resize and return.
+ if (old_page && old_page->data + old_page->size - oldsize == ptr &&
+ old_page->size - oldsize + newsize < old_page->capacity)
+ {
+ start = ptr;
+ old_page->size += newsize - oldsize;
+ copy_into_new = false;
+ }
+ else
+ {
+ if (!old_page)
+ copy_into_new = false;
+ if (!best_fit)
+ {
+ best_fit = page_create(newsize);
+ arena->end->next = best_fit;
+ arena->end = best_fit;
+ }
+
+ start = best_fit->data + best_fit->size;
+ best_fit->size += newsize;
+ }
+
+ if (copy_into_new)
+ {
+ memcpy(start, ptr, oldsize);
+ memset(start + oldsize, 0, newsize - oldsize);
+ }
+
+ return start;
+}
+
+void arena_attach(arena_t *arena, page_t *page)
+{
+ if (!arena || !page)
+ return;
+ else if (!arena->start || !arena->end)
+ {
+ arena->start = page;
+ arena->end = page;
+ }
+ else
+ {
+ page->next = arena->start;
+ arena->start = page;
+ }
+}
+
+void arena_reset(arena_t *arena)
+{
+ if (!arena || !arena->start)
+ return;
+
+ for (page_t *cur = arena->start; cur; cur = cur->next)
+ {
+ if (cur->size == 0)
+ continue;
+ cur->size = 0;
+ memset(cur->data, 0, cur->capacity);
+ }
+}
+
+void arena_cleanup(arena_t *arena)
+{
+ if (!arena || !arena->start)
+ return;
+
+ for (page_t *cur = arena->start, *next = NULL; cur;
+ next = cur->next, free(cur), cur = next)
+ continue;
+
+ memset(arena, 0, sizeof(*arena));
+}
diff --git a/lib/arena.h b/lib/arena.h
new file mode 100644
index 0000000..3b0724f
--- /dev/null
+++ b/lib/arena.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2025 Aryadev Chavali
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
+ * details.
+
+ * You may distribute and modify this code under the terms of the GNU General
+ * Public License Version 2, which you should have received a copy of along with
+ * this program. If not, please go to <https://www.gnu.org/licenses/>.
+
+ * Created: 2025-04-05
+ * Description: Arena
+ */
+
+#ifndef ARENA_H
+#define ARENA_H
+
+#include <base.h>
+#include <stdio.h>
+
+#define PAGE_DEFAULT_SIZE 1024
+#define MEMORY_ALIGNMENT 8
+
+typedef struct Page
+{
+ struct Page *next;
+ u64 size, capacity;
+ u8 data[];
+} page_t;
+
+page_t *page_create(u64 size);
+void page_resize(page_t **page, u64 newsize);
+// Append - fail (by returning <0) if not enough space.
+i64 page_append(page_t *page, void *data, u64 size);
+// Append - will resize if necessary
+u64 page_rappend(page_t **page, void *data, u64 size);
+
+typedef struct Aren
+{
+ page_t *start, *end;
+} arena_t;
+
+void *arena_alloc(arena_t *arena, u64 size);
+void *arena_realloc(arena_t *arena, void *ptr, u64 oldsize, u64 newsize);
+void *arena_copy(arena_t *arena, void *ptr, u64 size);
+void arena_attach(arena_t *arena, page_t *page);
+void arena_reset(arena_t *arena);
+void arena_cleanup(arena_t *arena);
+
+#endif
diff --git a/lib/sv.c b/lib/sv.c
new file mode 100644
index 0000000..b2425b8
--- /dev/null
+++ b/lib/sv.c
@@ -0,0 +1,158 @@
+/* Copyright (C) 2025 Aryadev Chavali
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
+ * details.
+
+ * You may distribute and modify this code under the terms of the GNU General
+ * Public License Version 2, which you should have received a copy of along with
+ * this program. If not, please go to <https://www.gnu.org/licenses/>.
+
+ * Created: 2025-04-14
+ * Description: String View implementation
+ */
+
+#include <lib/sv.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+sv_t sv_make(arena_t *allocator, const char *data, u64 size)
+{
+ sv_t s = {0};
+ if (data)
+ s = sv_append(allocator, s, data, size);
+ else
+ {
+ s.data = arena_alloc(allocator, size);
+ s.size = size;
+ }
+ return s;
+}
+
+sv_t sv_copy(arena_t *allocator, sv_t sv)
+{
+ return sv_make(allocator, sv.data, sv.size);
+}
+
+sv_t sv_substr(sv_t sv, u64 index, u64 size)
+{
+ sv_t newsv = {0};
+ if (index + size > sv.size)
+ return newsv;
+ newsv.data = sv.data + index;
+ newsv.size = size;
+ return newsv;
+}
+
+sv_t sv_cut(sv_t sv, u64 index)
+{
+ return sv_substr(sv, index, sv.size < index ? 0 : sv.size - index);
+}
+
+sv_t sv_chop(sv_t sv, u64 size)
+{
+ return sv_substr(sv, 0, size);
+}
+
+sv_t sv_concat(arena_t *allocator, sv_t a, sv_t b)
+{
+ sv_t c = sv_make(allocator, a.data, a.size + b.size);
+ memcpy(c.data + a.size, b.data, b.size);
+ return c;
+}
+
+sv_t sv_append(arena_t *allocator, sv_t sv, const char *data, u64 size)
+{
+ if (!allocator)
+ return (sv_t){0};
+
+ sv_t newsv = {0};
+ newsv.size = sv.size + size;
+ newsv.data = arena_realloc(allocator, sv.data, sv.size, newsv.size);
+ if (data)
+ memcpy(newsv.data + sv.size, data, size);
+ return newsv;
+}
+
+sv_t sv_prepend(arena_t *allocator, sv_t sv, const char *data, u64 size)
+{
+ if (!allocator)
+ return (sv_t){0};
+
+ // TODO: Can we make this cheaper to do?
+ sv_t newsv = sv_make(allocator, NULL, size + sv.size);
+ // Copy over `data` to the left side
+ memcpy(newsv.data, data, size);
+ // Copy old string to the right side
+ if (sv.data)
+ memcpy(newsv.data + size, sv.data, sv.size);
+
+ return newsv;
+}
+
+sv_t sv_fmt(arena_t *allocator, char *fmt, ...)
+{
+ if (!allocator)
+ return (sv_t){0};
+
+ va_list ap_1, ap_2;
+ va_start(ap_1, fmt);
+
+ va_copy(ap_2, ap_1);
+ u64 size = vsnprintf(NULL, 0, fmt, ap_2);
+ va_end(ap_2);
+
+ sv_t sv = sv_make(allocator, NULL, size);
+ vsprintf(sv.data, fmt, ap_1);
+ va_end(ap_1);
+
+ return sv;
+}
+
+i64 sv_find_substr(const sv_t sv, const sv_t substr)
+{
+ if (substr.size == 0)
+ return 0;
+ else if (sv.size < substr.size)
+ return -1;
+ else if (sv.size == substr.size)
+ return strncmp(sv.data, substr.data, sv.size) == 0 ? 0 : -1;
+
+ for (u64 i = 0; i < (sv.size - substr.size); ++i)
+ if (strncmp(sv.data + i, substr.data, substr.size) == 0)
+ return i;
+ return -1;
+}
+
+i64 sv_find_subcstr(const sv_t sv, const char *substr, u64 size)
+{
+ return sv_find_substr(sv, SV((char *)substr, size));
+}
+
+i64 sv_find_any(const sv_t sv, const char *bag)
+{
+ for (u64 i = 0; i < sv.size; ++i)
+ if (strchr(bag, sv.data[i]))
+ return i;
+ return -1;
+}
+
+u64 sv_while(const sv_t sv, bool (*pred)(char))
+{
+ u64 i;
+ for (i = 0; i < sv.size && pred(sv.data[i]); ++i)
+ continue;
+ return i;
+}
+
+u64 sv_till(const sv_t sv, bool (*pred)(char))
+{
+ u64 i;
+ for (i = 0; i < sv.size && !pred(sv.data[i]); ++i)
+ continue;
+ return i;
+}
diff --git a/lib/sv.h b/lib/sv.h
new file mode 100644
index 0000000..3293b1c
--- /dev/null
+++ b/lib/sv.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 2025 Aryadev Chavali
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
+ * details.
+
+ * You may distribute and modify this code under the terms of the GNU General
+ * Public License Version 2, which you should have received a copy of along with
+ * this program. If not, please go to <https://www.gnu.org/licenses/>.
+
+ * Created: 2025-04-14
+ * Description: String Views
+ */
+
+#ifndef SV_H
+#define SV_H
+
+#include <lib/arena.h>
+
+typedef struct SV
+{
+ u64 size;
+ char *data;
+} sv_t;
+
+#define SV(DATA, SIZE) ((const sv_t){.size = (SIZE), .data = (DATA)})
+#define SV_FMT(SV) (int)(SV).size, (SV).data
+#define PR_SV "%.*s"
+
+sv_t sv_make(arena_t *allocator, const char *data, u64 size);
+sv_t sv_copy(arena_t *allocator, sv_t sv);
+sv_t sv_append(arena_t *allocator, sv_t sv, const char *data, u64 size);
+sv_t sv_prepend(arena_t *allocator, sv_t sv, const char *data, u64 size);
+
+/**
+ * @brief Concatenate two string views, returning that concatenation.
+
+ * Allocates memory.
+ */
+sv_t sv_concat(arena_t *allocator, sv_t a, sv_t b);
+
+/**
+ * @brief Allocates a string view with the given `printf` format.
+ */
+sv_t sv_fmt(arena_t *allocator, char *fmt, ...);
+
+/**
+ * @brief Constructs a new string view at a different offset. Does not allocate
+ * new memory.
+ */
+sv_t sv_substr(sv_t sv, u64 index, u64 size);
+/**
+ * @brief Return a string view INDEX characters ahead (i.e. cut the string from
+ * the left).
+ */
+sv_t sv_cut(sv_t sv, u64 index);
+/**
+ * @brief Return a string view with SIZE (i.e. chopping the string from the
+ * right)
+ */
+sv_t sv_chop(sv_t sv, u64 size);
+
+i64 sv_find_substr(const sv_t sv, const sv_t substr);
+i64 sv_find_subcstr(const sv_t sv, const char *substr, u64 size);
+i64 sv_find_any(const sv_t sv, const char *bag);
+u64 sv_while(const sv_t sv, bool (*pred)(char));
+u64 sv_till(const sv_t sv, bool (*pred)(char));
+
+#endif
diff --git a/lib/vec.c b/lib/vec.c
new file mode 100644
index 0000000..551f679
--- /dev/null
+++ b/lib/vec.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2025 Aryadev Chavali
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
+ * details.
+
+ * You may distribute and modify this code under the terms of the GNU General
+ * Public License Version 2, which you should have received a copy of along with
+ * this program. If not, please go to <https://www.gnu.org/licenses/>.
+
+ * Created: 2025-04-15
+ * Description: Vector implementation
+ */
+
+#include <lib/vec.h>
+
+#include <malloc.h>
+#include <string.h>
+
+void vec_reserve(arena_t *allocator, vec_t *vec, u32 size)
+{
+ if (vec->cap - vec->size < size)
+ {
+ u32 old_cap = vec->cap;
+ vec->cap = MAX(vec->cap * 1.5, vec->size + size);
+ vec->data = arena_realloc(allocator, vec->data, old_cap, vec->cap);
+ }
+}
+
+u32 vec_append(arena_t *allocator, vec_t *vec, const void *data, u32 size)
+{
+ vec_reserve(allocator, vec, size);
+ memcpy(vec->data + vec->size, data, size);
+ u32 ptr = vec->size;
+ vec->size += size;
+ return ptr;
+}
diff --git a/lib/vec.h b/lib/vec.h
new file mode 100644
index 0000000..20a3523
--- /dev/null
+++ b/lib/vec.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2025 Aryadev Chavali
+
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
+ * details.
+
+ * You may distribute and modify this code under the terms of the GNU General
+ * Public License Version 2, which you should have received a copy of along with
+ * this program. If not, please go to <https://www.gnu.org/licenses/>.
+
+ * Created: 2025-04-15
+ * Description: Vectors (dynamic sized arrays)
+ */
+
+#ifndef VEC_H
+#define VEC_H
+
+#include <lib/arena.h>
+
+typedef struct
+{
+ u32 size, cap;
+ u8 *data;
+} vec_t;
+
+void vec_reserve(arena_t *alloactor, vec_t *vec, u32 size);
+u32 vec_append(arena_t *allocator, vec_t *vec, const void *data, u32 size);
+
+#endif