now thats a lot of damage!
[vg.git] / src / vg / vg_mem.h
diff --git a/src/vg/vg_mem.h b/src/vg/vg_mem.h
new file mode 100644 (file)
index 0000000..1ef1e77
--- /dev/null
@@ -0,0 +1,196 @@
+#ifndef VG_MEM_H
+#define VG_MEM_H
+
+#include "vg_stdint.h"
+#include "vg_platform.h"
+
+#include <stdlib.h>
+
+typedef struct vg_linear_allocator vg_linear_allocator;
+
+struct
+{
+   void *rtmemory,
+        *scratch;
+}
+static vg_mem;
+
+#pragma pack(push,1)
+struct vg_linear_allocator
+{
+   u32 size, cur;
+
+   /* allows temporarily extendable buffers */
+   void *last_alloc;
+   u32 last_alloc_size;
+};
+#pragma pack(pop)
+
+/* 
+ * TODO: Fallback on libc
+ * TODO: 8 byte alignment
+ */
+
+VG_STATIC void vg_error(const char *fmt, ...);
+
+/* allocate something from a linear allocator */
+__attribute__((warn_unused_result))
+VG_STATIC void *vg_linear_alloc( void *allocator, u32 size )
+{
+   if( allocator == NULL )
+      vg_fatal_exit_loop( "Null allocator" );
+
+   vg_linear_allocator *allocptr = allocator;
+   allocptr --;
+
+   if( allocptr->cur + size > allocptr->size )
+   {
+      vg_error( "%u(current) + %u(alloc) > %u(max)\n",
+                  allocptr->cur, size, allocptr->size );
+
+      vg_fatal_exit_loop( "Linear allocator out of memory" );
+   }
+
+   void *data = allocator + allocptr->cur;
+   allocptr->cur += size;
+   allocptr->last_alloc = data;
+   allocptr->last_alloc_size = size;
+
+   return data;
+}
+
+/* resize latest block of memory from linear */
+__attribute__((warn_unused_result))
+VG_STATIC void *vg_linear_resize( void *allocator, void *data, u32 newsize )
+{
+   vg_linear_allocator *allocptr = allocator;
+   allocptr --;
+
+   if( allocptr->last_alloc == data )
+   {
+      allocptr->cur -= allocptr->last_alloc_size;
+      return vg_linear_alloc( allocator, newsize );
+   }
+   else
+   {
+      vg_fatal_exit_loop( "Cannot resize this buffer anymore" );
+   }
+
+   return NULL;
+}
+
+VG_STATIC void vg_linear_del( void *allocator, void *data )
+{
+   void *ignore = vg_linear_resize( allocator, data, 0 );
+
+   vg_linear_allocator *allocptr = allocator;
+   allocptr --;
+
+   allocptr->last_alloc = NULL;
+   allocptr->last_alloc_size = 0;
+}
+
+/* extend latest block of memory from linear */
+__attribute__((warn_unused_result))
+VG_STATIC void *vg_linear_extend( void *allocator, void *data, u32 extra )
+{
+   vg_linear_allocator *allocptr = allocator;
+   allocptr --;
+
+   return vg_linear_resize( allocator, data, allocptr->last_alloc_size+extra );
+}
+
+/* get the current usage of allocator */
+VG_STATIC u32 vg_linear_get_cur( void *allocator )
+{
+   vg_linear_allocator *allocptr = allocator;
+   allocptr --;
+   
+   return allocptr->cur;
+}
+
+/* get the capacity of allocator */
+VG_STATIC u32 vg_linear_get_capacity( void *allocator )
+{
+   vg_linear_allocator *allocptr = allocator;
+   allocptr --;
+   
+   return allocptr->size;
+}
+
+/* get the size of the last allocated thing */
+VG_STATIC u32 vg_linear_last_size( void *allocator )
+{
+   vg_linear_allocator *allocptr = allocator;
+   allocptr --;
+   
+   return allocptr->last_alloc_size;
+}
+
+/* yeet all memory from linear allocator */
+VG_STATIC void vg_linear_clear( void *allocator )
+{
+   vg_linear_allocator *allocptr = allocator;
+   allocptr --;
+
+   allocptr->last_alloc = NULL;
+   allocptr->last_alloc_size = 0;
+   allocptr->cur = 0;
+}
+
+/* allocate a FIXED SIZE linear allocator */
+VG_STATIC void *vg_create_linear_allocator( void *lin_alloc, u32 size )
+{
+   u32 total = size + sizeof(vg_linear_allocator);
+   vg_linear_allocator *allocptr;
+
+   if( lin_alloc == NULL )
+   {
+      static int allow_once = 1;
+
+      if( allow_once )
+      {
+         allocptr = malloc( total );
+
+         if( allocptr == NULL )
+            vg_fatal_exit_loop( "Create linear: Malloc failed" );
+
+         allow_once = 0;
+      }
+      else
+         vg_fatal_exit_loop( "Shouldnt call this twice!" );
+   }
+   else
+   {
+      vg_linear_allocator *parent = lin_alloc;
+      parent --;
+
+      allocptr = vg_linear_alloc( lin_alloc, total );
+
+#if 0
+      parent->last_alloc = allocptr+1;
+      parent->last_alloc_size = total;
+#else
+      parent->last_alloc = NULL;
+      parent->last_alloc_size = total;
+#endif
+   }
+   
+   allocptr->size = size;
+   allocptr->cur  = 0;
+   allocptr->last_alloc = NULL;
+   allocptr->last_alloc_size = 0;
+   
+   void *data = allocptr+1;
+   return data;
+}
+
+/* request all the memory we need in advance */
+VG_STATIC void vg_prealloc_quota( u32 size )
+{
+   size = VG_MAX( size, 20*1024*1024 );
+   vg_mem.rtmemory = vg_create_linear_allocator( NULL, size );
+   vg_mem.scratch = vg_create_linear_allocator( vg_mem.rtmemory, 10*1024*1024 );
+}
+
+#endif /* VG_MEM_H */