diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 73f69e0..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
-# Editor-based HTTP Client requests
-/httpRequests/
diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index 5934ec5..0000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-flint
\ No newline at end of file
diff --git a/.idea/editor.xml b/.idea/editor.xml
deleted file mode 100644
index a4fac68..0000000
--- a/.idea/editor.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-  
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-  
-
\ No newline at end of file
diff --git a/.idea/libfputs.iml b/.idea/libfputs.iml
deleted file mode 100644
index f08604b..0000000
--- a/.idea/libfputs.iml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 0b76fe5..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-  
-    
-  
-  
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 2ff26f1..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-  
-    
-      
-    
-  
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-  
-    
-  
-
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fa09448..2fd17e0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,6 +22,7 @@ set(SOURCES
         src/crypto.c
         src/parsing.c
         src/network.c
+        src/memory.c
 )
 
 if ((${CMAKE_SYSTEM_NAME} STREQUAL "Darwin"))
diff --git a/docs/math.md b/docs/math.md
index 48f1146..4c5917c 100644
--- a/docs/math.md
+++ b/docs/math.md
@@ -57,3 +57,11 @@ Works the same as `bresenham()` but uses the `Point` struct instead of `int`
 ```c
 Point *bresenham_p(Point p1, Point p2, size_t *sz);
 ```
+
+## is_power_of_two
+
+Returns `1` if `i` is a power of two, otherwise returns `1`.
+
+```c
+int is_power_of_two(int i);
+```
diff --git a/docs/memory.md b/docs/memory.md
new file mode 100644
index 0000000..95e4709
--- /dev/null
+++ b/docs/memory.md
@@ -0,0 +1,99 @@
+# memory
+
+Custom allocators and memory functions
+
+# Arena Allocator
+
+A simple arena-style allocator
+
+## Structs
+
+### ArenaAllocator
+
+Represents an arena allocator. `ArenaAllocator` holds its own buffer, but managing its size is left to the user. Like
+most structs in `libflint`, it must be malloced first before being passed to `arena_init()`.
+
+```c
+typedef struct {
+    unsigned char* buf;
+    size_t buf_sz;
+    size_t offset_cur;
+    size_t offset_prev;
+} ArenaAllocator;
+```
+
+## Functions
+
+### arena_init
+
+Initializes the `ArenaAllocator`. The struct must first be created by the user using `malloc()`, see the example below.
+`buf_sz` is the size of the underlying buffer in bytes.
+
+```c
+void arena_init(ArenaAllocator *allocator, size_t buf_sz);
+
+/* Usage */
+ArenaAllocator *a = malloc(sizeof(ArenaAllocator));
+arena_init(a, 1024);
+```
+
+### arena_free
+Frees `allocator` and its underlying buffer. Users should set `allocator` to `NULL` after calling `arena_free()`.
+```c
+void arena_free(ArenaAllocator *allocator);
+
+/* Usage */
+arena_free(allocator);
+allocator = NULL;
+```
+
+### arena_clear
+
+Resets the offset markers of the arena to `0`, but does not wipe the underlying buffer. Technically, any assigned pointers
+will still work and
+
+```c
+void arena_clear(ArenaAllocator *allocator);
+```
+
+
+### *arena_malloc
+
+Request memory of `size` bytes in length from the arena. Returns `NULL` if the assignment failed.
+
+```c
+void *arena_malloc(ArenaAllocator* allocator, size_t size);
+```
+
+### arena_resize_buf
+
+Reallocates the underlying buffer in the arena to `new_sz`. You can grow or shrink the arena using this function. Any
+pointers allocated out of the arena are invalid after using this function.
+
+```c
+void arena_resize_buf(ArenaAllocator *allocator, size_t new_sz);
+```
+
+### *arena_resize
+
+Resize an allocated pointer from the arena. See the example below for a simple use case
+
+```c
+void *arena_resize(ArenaAllocator *allocator, void *mem, size_t old_sz, size_t new_sz);
+
+/* Usage */
+int *i = arena_malloc(a, sizeof(int));
+*i = 1;
+long *l = arena_resize(a, i1, sizeof(int), sizeof(long));
+assert(*l == 1);
+```
+
+## Macros
+
+### arena_sz
+
+Convenience macro for getting the size of the arena's buffer
+
+```c
+#define arena_sz(a) (a)->buf_sz
+```
\ No newline at end of file
diff --git a/include/lfmath.h b/include/lfmath.h
index 34542bb..09f75a4 100644
--- a/include/lfmath.h
+++ b/include/lfmath.h
@@ -1,6 +1,8 @@
 #ifndef LIBFLINT_H_MATH
 #define LIBFLINT_H_MATH
 
+#include 
+
 #include "lfutility.h"
 
 int max_int(int a, int b);
@@ -11,6 +13,8 @@ int clamp_int(int i, int low, int high);
 
 int binstr_to_int(const char *s);
 
+int is_power_of_two(int i);
+
 Point *bresenham(int x0, int y0, int x1, int y1, size_t *sz);
 
 Point *bresenham_p(Point p1, Point p2, size_t *sz);
diff --git a/include/lfmemory.h b/include/lfmemory.h
new file mode 100644
index 0000000..0aac0c3
--- /dev/null
+++ b/include/lfmemory.h
@@ -0,0 +1,20 @@
+#ifndef LIBFLINT_H_MEMORY
+#define LIBFLINT_H_MEMORY
+
+#include 
+
+typedef struct {
+    unsigned char* buf;
+    size_t buf_sz;
+    size_t offset_cur;
+    size_t offset_prev;
+} ArenaAllocator;
+
+void arena_init(ArenaAllocator *allocator, size_t buf_sz);
+void arena_free(ArenaAllocator *allocator);
+void *arena_malloc(ArenaAllocator* allocator, size_t size);
+void arena_resize_buf(ArenaAllocator *allocator, size_t new_sz);
+void *arena_resize(ArenaAllocator *allocator, void *mem, size_t old_sz, size_t new_sz);
+void arena_clear(ArenaAllocator *allocator);
+
+#endif // LIBFLINT_H_MEMORY
diff --git a/src/math.c b/src/math.c
index 53efd33..14e275b 100644
--- a/src/math.c
+++ b/src/math.c
@@ -77,3 +77,6 @@ Point *bresenham_p(Point p1, Point p2, size_t *sz) {
     return bresenham(p1.x, p1.y, p2.x, p2.y, sz);
 }
 
+int is_power_of_two(int i) {
+    return (i & (i - 1)) == 0;
+}
diff --git a/src/memory.c b/src/memory.c
new file mode 100644
index 0000000..f49db3b
--- /dev/null
+++ b/src/memory.c
@@ -0,0 +1,109 @@
+#include 
+#include 
+#include 
+#include 
+
+#include "lfmemory.h"
+
+#define arena_sz(a) (a)->buf_sz
+
+void arena_init(ArenaAllocator *allocator, size_t buf_sz) {
+    if (allocator == NULL) {
+        return;
+    }
+
+    allocator->buf = malloc(sizeof(unsigned char) * buf_sz);
+    allocator->buf_sz = buf_sz;
+    allocator->offset_cur = 0;
+    allocator->offset_prev = 0;
+}
+
+void arena_free(ArenaAllocator *allocator) {
+    free(allocator->buf);
+    free(allocator);
+}
+
+void arena_clear(ArenaAllocator *allocator) {
+    allocator->offset_cur = 0;
+    allocator->offset_prev = 0;
+}
+
+static uintptr_t align_forward(uintptr_t ptr, size_t align) {
+    uintptr_t p, a, m;
+    if (!is_power_of_two(align)) {
+        // TODO: Error
+    }
+    p = ptr;
+    a = (uintptr_t)align;
+    m = p & (a - 1);
+
+    if (m != 0) {
+        p += a - m;
+    }
+    return p;
+}
+
+static void *arena_malloc_align(ArenaAllocator *allocator, size_t size, size_t align) {
+    uintptr_t cur_ptr = (uintptr_t)allocator->buf + (uintptr_t)allocator->offset_cur;
+
+    // Push forward to align, then change to relative offset
+    uintptr_t offset = align_forward(cur_ptr, align);
+    offset -= (uintptr_t)allocator->buf;
+
+    if (offset + size <= allocator->buf_sz) {
+        void *ptr = &allocator->buf[offset];
+        allocator->offset_prev = offset;
+        allocator->offset_cur = offset + size;
+        memset(ptr, 0, size);
+        return ptr;
+    }
+
+    // Arena is full
+    return NULL;
+}
+
+static void *arena_resize_align(ArenaAllocator *allocator, void *mem, size_t old_sz, size_t new_sz, size_t align) {
+    unsigned char *old_mem = (unsigned char *)mem;
+    if (!is_power_of_two(align)) {
+        // TODO: Error handling
+    }
+
+    if (old_mem == NULL || old_sz == 0) {
+        return arena_malloc_align(allocator, new_sz, align);
+    }
+
+    if (allocator->buf <= mem && mem < allocator->buf + allocator->buf_sz) {
+        if (allocator->buf + allocator->offset_prev == old_mem) {
+            allocator->offset_cur = allocator->offset_prev + new_sz;
+            if (new_sz > old_sz) {
+                // Zero out memory
+                memset(&allocator->buf[allocator->offset_cur], 0, new_sz - old_sz);
+            }
+            return old_mem;
+        }
+
+        void *new_mem = arena_malloc_align(allocator, new_sz, align);
+        size_t copy_size = old_sz < new_sz ? old_sz : new_sz;
+        memmove(new_mem, old_mem, copy_size);
+        return new_mem;
+    }
+
+    return NULL;
+}
+
+void arena_resize_buf(ArenaAllocator *allocator, size_t new_sz) {
+    allocator->buf = realloc(allocator->buf, sizeof(unsigned char) * new_sz);
+}
+
+#ifndef DEFAULT_ALIGNMENT
+#define DEFAULT_ALIGNMENT (2*sizeof(void*))
+#endif // DEFAULT_ALIGNMENT
+
+void *arena_malloc(ArenaAllocator *allocator, size_t size) {
+    return arena_malloc_align(allocator, size, DEFAULT_ALIGNMENT);
+}
+
+void *arena_resize(ArenaAllocator *allocator, void *mem, size_t old_sz, size_t new_sz) {
+    return arena_resize_align(allocator, mem, old_sz, new_sz, DEFAULT_ALIGNMENT);
+}
+
diff --git a/tests/tests.c b/tests/tests.c
index 663631f..7258357 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -16,6 +16,7 @@
 #include "lfcrypto.h"
 #include "lfparsing.h"
 #include "lfinput.h"
+#include "lfmemory.h"
 
 #if defined(__APPLE__) || defined(__MACH__)
 #include "lfmacos.h"
@@ -468,6 +469,30 @@ void test_macos() {
 }
 #endif
 
+void test_memory() {
+    printf("\n--- MEMORY TEST ---\n");
+    ArenaAllocator *a = malloc(sizeof(ArenaAllocator));
+    arena_init(a, 1024);
+
+    int *i1 = arena_malloc(a, sizeof(int));
+    int *i2 = arena_malloc(a, sizeof(int));
+
+    *i1 = 1;
+    *i2 = 2;
+
+    assert(i1 < i2);
+    assert(*i1 < *i2);
+
+    long *l = arena_resize(a, i1, sizeof(int), sizeof(long));
+    assert(*l == 1);
+
+    unsigned char *c = arena_resize(a, i2, sizeof(int), sizeof(unsigned char));
+    assert(*c == 2);
+
+    arena_free(a);
+    printf("Passes all memory tests\n");
+}
+
 int main() {
     test_ll();
     test_set();
@@ -479,6 +504,7 @@ int main() {
     test_crypto();
     test_parsing();
     test_network();
+    test_memory();
 
 #if defined(__APPLE__) || defined(__MACH__)
     test_macos();