Compare commits
	
		
			11 Commits
		
	
	
		
			6195b521f5
			...
			b59aedad89
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b59aedad89 | |||
| 3f5e3558b9 | |||
| bb2db0d30d | |||
| e75846a507 | |||
| 05e56d67ea | |||
| 7164156c35 | |||
| e67e1df9a5 | |||
| e206b4f4a6 | |||
| 05bfa73509 | |||
| d4313fb8e4 | |||
| 92db9206cc | 
							
								
								
									
										9
									
								
								compile
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								compile
									
									
									
									
									
								
							| @@ -2,15 +2,10 @@ | ||||
|  | ||||
| CC=clang | ||||
| INCLUDE="\ | ||||
| 	-Ialiases \ | ||||
| 	-Icpath/include \ | ||||
| 	-Idstr/include \ | ||||
| 	$(find mem/include -type d | xargs -I{} echo -n "-I{} ") \ | ||||
| 	$(find src -type d | xargs -I{} echo -n "-I{} ") \ | ||||
| " | ||||
| SRC="\ | ||||
| 	cpath/src/*.c \ | ||||
| 	dstr/src/*.c \ | ||||
| 	mem/src/*/*.c \ | ||||
| 	$(find src -type f -name *.c | xargs -I{} echo -n "{} ") \ | ||||
| " | ||||
| CFLAGS="-O3 -shared -fPIC -Wall -Werror -pedantic" | ||||
| OUT="libwapp.so" | ||||
|   | ||||
| @@ -1,40 +0,0 @@ | ||||
| #ifndef MEM_ALLOCATOR_H | ||||
| #define MEM_ALLOCATOR_H | ||||
|  | ||||
| #include "aliases.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif // __cplusplus | ||||
|  | ||||
| typedef void *(MemAllocFunc)(u64 size, void *alloc_obj); | ||||
| typedef void *(MemAllocAlignedFunc)(u64 size, u64 alignment, void *alloc_obj); | ||||
| typedef void *(MemReallocFunc)(void *ptr, u64 size, void *alloc_obj); | ||||
| typedef void *(MemReallocAlignedFunc)(void *ptr, u64 size, u64 alignment, | ||||
|                                       void *alloc_obj); | ||||
| typedef void(MemFreeFunc)(void **ptr, void *alloc_obj); | ||||
|  | ||||
| typedef struct allocator Allocator; | ||||
| struct allocator { | ||||
|   void *obj; | ||||
|   MemAllocFunc *alloc; | ||||
|   MemAllocAlignedFunc *alloc_aligned; | ||||
|   MemReallocFunc *realloc; | ||||
|   MemReallocAlignedFunc *realloc_aligned; | ||||
|   MemFreeFunc *free; | ||||
| }; | ||||
|  | ||||
| void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size); | ||||
| void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, | ||||
|                                        u64 alignment); | ||||
| void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, | ||||
|                                  u64 size); | ||||
| void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, | ||||
|                                          u64 size, u64 alignment); | ||||
| void wapp_mem_allocator_free(const Allocator *allocator, void **ptr); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif // __cplusplus | ||||
|  | ||||
| #endif // !MEM_ALLOCATOR_H | ||||
| @@ -1,32 +0,0 @@ | ||||
| #ifndef MEM_CTX_H | ||||
| #define MEM_CTX_H | ||||
|  | ||||
| #include "mem_allocator.h" | ||||
| #include "mem_arena.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif // __cplusplus | ||||
|  | ||||
| typedef enum { | ||||
|   CTX_DEST_BUFFER_MAIN, | ||||
|   CTX_DEST_BUFFER_TEMP, | ||||
|  | ||||
|   COUNT_CTX_DEST_BUFFER, | ||||
| } CTXDestBuffer; | ||||
|  | ||||
| Allocator wapp_mem_ctx_allocator(CTXDestBuffer buffer); | ||||
| void wapp_mem_ctx_init(u64 main_buf_capacity, u64 temp_buf_capacity); | ||||
| void *wapp_mem_ctx_alloc(CTXDestBuffer buffer, u64 size); | ||||
| void *wapp_mem_ctx_alloc_aligned(CTXDestBuffer buffer, u64 size, u64 alignment); | ||||
| void *wapp_mem_ctx_realloc(CTXDestBuffer buffer, void *ptr, u64 size); | ||||
| void *wapp_mem_ctx_realloc_aligned(CTXDestBuffer buffer, void *ptr, u64 size, | ||||
|                                    u64 alignment); | ||||
| void wapp_mem_ctx_clear(CTXDestBuffer buffer); | ||||
| void wapp_mem_ctx_free(void); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif // __cplusplus | ||||
|  | ||||
| #endif // !MEM_CTX_H | ||||
| @@ -1,15 +0,0 @@ | ||||
| #ifndef MEM_LIBC_H | ||||
| #define MEM_LIBC_H | ||||
|  | ||||
| #include "mem_allocator.h" | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif // __cplusplus | ||||
|  | ||||
| Allocator wapp_mem_libc_allocator(void); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif // __cplusplus | ||||
|  | ||||
| #endif // !MEM_LIBC_H | ||||
| @@ -1,45 +0,0 @@ | ||||
| #include "mem_allocator.h" | ||||
| #include <stdlib.h> | ||||
|  | ||||
| void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size) { | ||||
|   if (!allocator || !(allocator->alloc)) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   return allocator->alloc(size, allocator->obj); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, | ||||
|                                        u64 alignment) { | ||||
|   if (!allocator || !(allocator->alloc_aligned)) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   return allocator->alloc_aligned(size, alignment, allocator->obj); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, | ||||
|                                  u64 size) { | ||||
|   if (!allocator || !(allocator->realloc)) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   return allocator->realloc(ptr, size, allocator->obj); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, | ||||
|                                          u64 size, u64 alignment) { | ||||
|   if (!allocator || !(allocator->realloc_aligned)) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   return allocator->realloc_aligned(ptr, size, alignment, allocator->obj); | ||||
| } | ||||
|  | ||||
| void wapp_mem_allocator_free(const Allocator *allocator, void **ptr) { | ||||
|   if (!allocator || !(allocator->free)) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   allocator->free(ptr, allocator->obj); | ||||
| } | ||||
| @@ -1,406 +0,0 @@ | ||||
| #include "mem_arena.h" | ||||
| #include "aliases.h" | ||||
| #include "mem_allocator.h" | ||||
| #include "mem_utils.h" | ||||
| #include <math.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #ifndef DEFAULT_ALIGNMENT | ||||
| // Why 2 * sizeof(void *) instead of sizeof(void *) | ||||
| // https://handmade.network/forums/t/6860-alignment_arena_allocator | ||||
| #define DEFAULT_ALIGNMENT (2 * sizeof(void *)) | ||||
| #endif /* ifndef DEFAULT_ALIGNMENT */ | ||||
|  | ||||
| #define HDR_MAGIC_BYTE_COUNT 8 | ||||
| #define HDR_MAGIC                                                              \ | ||||
|   { 0x57, 0x41, 0x41, 0x52, 0x4e, 0x48, 0x44, 0x52 } | ||||
| #define MAX_HDR_SEARCH_LENGTH 256 | ||||
|  | ||||
| #define ARENA_MINIMUM_CAPACITY 1024 | ||||
|  | ||||
| typedef struct arena_alloc_hdr ArenaAllocHDR; | ||||
| struct arena_alloc_hdr { | ||||
|   u8 magic[HDR_MAGIC_BYTE_COUNT]; | ||||
|   u64 alloc_size; | ||||
|   u64 alignment; | ||||
|   u8 *alloc_start; | ||||
| }; | ||||
|  | ||||
| typedef struct base_arena BaseArena; | ||||
| struct base_arena { | ||||
|   u8 *buf; | ||||
|   u8 *offset; | ||||
|   u64 capacity; | ||||
|   BaseArena *prev; | ||||
|   BaseArena *next; | ||||
| }; | ||||
|  | ||||
| struct growing_arena { | ||||
|   BaseArena *active_arena; | ||||
|   u64 count; | ||||
|   u64 initial_capacity; | ||||
| }; | ||||
|  | ||||
| internal BaseArena *find_arena_from_pointer(const Arena *arena, void *ptr); | ||||
|  | ||||
| internal bool base_arena_init(BaseArena *arena, u64 capacity); | ||||
| internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size, | ||||
|                                         u64 alignment); | ||||
| internal void base_arena_clear(BaseArena *arena); | ||||
| internal void base_arena_free(BaseArena *arena); | ||||
| internal ArenaAllocHDR *find_alloc_header(BaseArena *arena, void *alloc_ptr); | ||||
|  | ||||
| internal void *mem_arena_alloc(u64 size, void *alloc_obj); | ||||
| internal void *mem_arena_alloc_aligned(u64 size, u64 alignment, | ||||
|                                        void *alloc_obj); | ||||
| internal void *mem_arena_realloc(void *ptr, u64 size, void *alloc_obj); | ||||
| internal void *mem_arena_realloc_aligned(void *ptr, u64 size, u64 alignment, | ||||
|                                          void *alloc_obj); | ||||
|  | ||||
| // PUBLIC API | ||||
|  | ||||
| Allocator wapp_mem_arena_allocator(const Arena *arena) { | ||||
|   return (Allocator){ | ||||
|       .obj = (void *)arena, | ||||
|       .alloc = mem_arena_alloc, | ||||
|       .alloc_aligned = mem_arena_alloc_aligned, | ||||
|       .realloc = mem_arena_realloc, | ||||
|       .realloc_aligned = mem_arena_realloc_aligned, | ||||
|       .free = NULL, | ||||
|   }; | ||||
| } | ||||
|  | ||||
| bool wapp_mem_arena_init(Arena **arena, u64 base_capacity) { | ||||
|   if (!arena || *arena || base_capacity == 0) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   *arena = (Arena *)calloc(1, sizeof(Arena)); | ||||
|   Arena *arena_ptr = *arena; | ||||
|   if (!arena_ptr) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   arena_ptr->active_arena = (BaseArena *)calloc(1, sizeof(BaseArena)); | ||||
|   if (!(arena_ptr->active_arena)) { | ||||
|     wapp_mem_arena_free(arena); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (!base_arena_init(arena_ptr->active_arena, base_capacity)) { | ||||
|     wapp_mem_arena_free(arena); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   arena_ptr->count = 1; | ||||
|   arena_ptr->initial_capacity = base_capacity; | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| void *wapp_mem_arena_alloc(Arena *arena, u64 size) { | ||||
|   return wapp_mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) { | ||||
|   if (!arena || !(arena->active_arena)) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   void *output = base_arena_alloc_aligned(arena->active_arena, size, alignment); | ||||
|   if (!output) { | ||||
|     if (arena->active_arena->next) { | ||||
|       arena->active_arena = arena->active_arena->next; | ||||
|     } else { | ||||
|       arena->active_arena->next = (BaseArena *)calloc(1, sizeof(BaseArena)); | ||||
|       if (!(arena->active_arena->next)) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       if (!base_arena_init(arena->active_arena->next, | ||||
|                            arena->initial_capacity)) { | ||||
|         free(arena->active_arena->next); | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       arena->active_arena->next->prev = arena->active_arena; | ||||
|       arena->active_arena = arena->active_arena->next; | ||||
|  | ||||
|       ++(arena->count); | ||||
|     } | ||||
|  | ||||
|     output = base_arena_alloc_aligned(arena->active_arena, size, alignment); | ||||
|     if (!output) { | ||||
|       return NULL; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   memset(output, 0, size); | ||||
|  | ||||
|   return output; | ||||
| } | ||||
|  | ||||
| void *wapp_mem_arena_realloc(Arena *arena, void *ptr, u64 size) { | ||||
|   return wapp_mem_arena_realloc_aligned(arena, ptr, size, DEFAULT_ALIGNMENT); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 size, | ||||
|                                      u64 alignment) { | ||||
|   if (!arena) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   BaseArena *base_arena = find_arena_from_pointer(arena, ptr); | ||||
|   if (!base_arena) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   ArenaAllocHDR *header = find_alloc_header(base_arena, ptr); | ||||
|   if (!header) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   if (header->alloc_start + header->alloc_size == base_arena->offset) { | ||||
|     // Avoid allocating new pointer and copying memory if pointer is at the end | ||||
|     // of the arena | ||||
|     i64 diff = size - header->alloc_size; | ||||
|  | ||||
|     u8 *new_offset = base_arena->offset + diff; | ||||
|  | ||||
|     u8 *clear_start = diff < 0 ? new_offset : base_arena->offset; | ||||
|     memset(clear_start, 0, llabs(diff)); | ||||
|  | ||||
|     header->alloc_size = size; | ||||
|     base_arena->offset = new_offset; | ||||
|  | ||||
|     return header->alloc_start; | ||||
|   } | ||||
|  | ||||
|   void *new_alloc = wapp_mem_arena_alloc_aligned(arena, size, alignment); | ||||
|   if (!new_alloc) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   u64 to_copy = size < header->alloc_size ? size : header->alloc_size; | ||||
|  | ||||
|   memcpy(new_alloc, ptr, to_copy); | ||||
|  | ||||
|   return new_alloc; | ||||
| } | ||||
|  | ||||
| void wapp_mem_arena_clear(Arena *arena) { | ||||
|   if (!arena) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   BaseArena *last_active = NULL; | ||||
|   while (arena->active_arena) { | ||||
|     base_arena_clear(arena->active_arena); | ||||
|  | ||||
|     last_active = arena->active_arena; | ||||
|  | ||||
|     arena->active_arena = arena->active_arena->prev; | ||||
|   } | ||||
|  | ||||
|   arena->active_arena = last_active; | ||||
| } | ||||
|  | ||||
| void wapp_mem_arena_free(Arena **arena) { | ||||
|   if (!arena) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   Arena *arena_ptr = *arena; | ||||
|   if (!arena_ptr) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   BaseArena *current; | ||||
|   BaseArena *next; | ||||
|   BaseArena *prev; | ||||
|  | ||||
|   current = arena_ptr->active_arena->next; | ||||
|   while (current) { | ||||
|     next = current->next; | ||||
|  | ||||
|     base_arena_free(current); | ||||
|     free(current); | ||||
|  | ||||
|     current = next; | ||||
|   } | ||||
|  | ||||
|   current = arena_ptr->active_arena->prev; | ||||
|   while (current) { | ||||
|     prev = current->prev; | ||||
|  | ||||
|     base_arena_free(current); | ||||
|     free(current); | ||||
|  | ||||
|     current = prev; | ||||
|   } | ||||
|  | ||||
|   base_arena_free(arena_ptr->active_arena); | ||||
|  | ||||
|   free(arena_ptr->active_arena); | ||||
|   arena_ptr->active_arena = NULL; | ||||
|  | ||||
|   arena_ptr->count = 0; | ||||
|   arena_ptr->initial_capacity = 0; | ||||
|  | ||||
|   free(*arena); | ||||
|   *arena = NULL; | ||||
| } | ||||
|  | ||||
| // INTERNAL FUNCTIONS | ||||
|  | ||||
| internal BaseArena *find_arena_from_pointer(const Arena *arena, void *ptr) { | ||||
|   if (!arena || !ptr) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   // Ensure pointer is not out of bounds | ||||
|   u8 *alloc = (u8 *)ptr; | ||||
|   BaseArena *active = arena->active_arena; | ||||
|  | ||||
|   if (alloc > active->buf + arena->initial_capacity) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   for (u64 i = 0; i < arena->count; ++i) { | ||||
|     if (alloc >= active->buf && alloc < active->buf + arena->initial_capacity) { | ||||
|       return (BaseArena *)active; | ||||
|     } | ||||
|  | ||||
|     active = active->prev; | ||||
|   } | ||||
|  | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| internal bool base_arena_init(BaseArena *arena, u64 capacity) { | ||||
|   if (!arena || arena->buf || capacity == 0) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   u64 arena_capacity = | ||||
|       capacity >= ARENA_MINIMUM_CAPACITY ? capacity : ARENA_MINIMUM_CAPACITY; | ||||
|  | ||||
|   arena->buf = (u8 *)calloc(arena_capacity, sizeof(u8)); | ||||
|   if (!(arena->buf)) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   arena->capacity = arena_capacity; | ||||
|   arena->offset = arena->buf; | ||||
|   arena->prev = arena->next = NULL; | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size, | ||||
|                                         u64 alignment) { | ||||
|   if (!arena) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   u8 *start_offset = arena->offset; | ||||
|   u8 *alloc_start = arena->offset + sizeof(ArenaAllocHDR); | ||||
|  | ||||
|   u8 *output = wapp_mem_util_align_forward((void *)alloc_start, alignment); | ||||
|   if (output + size >= arena->buf + arena->capacity) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   ArenaAllocHDR *header = (ArenaAllocHDR *)start_offset; | ||||
|   *header = (ArenaAllocHDR){ | ||||
|       .magic = HDR_MAGIC, | ||||
|       .alloc_size = size, | ||||
|       .alignment = alignment, | ||||
|       .alloc_start = output, | ||||
|   }; | ||||
|  | ||||
|   arena->offset = output + size; | ||||
|  | ||||
|   return (void *)output; | ||||
| } | ||||
|  | ||||
| internal void base_arena_clear(BaseArena *arena) { | ||||
|   if (!arena) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   memset(arena->buf, 0, arena->offset - arena->buf); | ||||
|   arena->offset = arena->buf; | ||||
| } | ||||
|  | ||||
| internal void base_arena_free(BaseArena *arena) { | ||||
|   if (!arena) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (arena->buf) { | ||||
|     free(arena->buf); | ||||
|   } | ||||
|  | ||||
|   arena->buf = arena->offset = NULL; | ||||
|   arena->capacity = 0; | ||||
|   arena->prev = arena->next = NULL; | ||||
| } | ||||
|  | ||||
| internal ArenaAllocHDR *find_alloc_header(BaseArena *arena, void *alloc_ptr) { | ||||
|   persistent const u8 magic[HDR_MAGIC_BYTE_COUNT] = HDR_MAGIC; | ||||
|  | ||||
|   u8 *current = (u8 *)alloc_ptr; | ||||
|  | ||||
|   u8 *max_search_end = current - MAX_HDR_SEARCH_LENGTH; | ||||
|   u8 *arena_buf_start = arena->buf; | ||||
|  | ||||
|   u8 *search_end = | ||||
|       max_search_end > arena_buf_start ? max_search_end : arena_buf_start; | ||||
|  | ||||
|   bool match; | ||||
|   for (; current >= search_end; --current) { | ||||
|     match = true; | ||||
|  | ||||
|     for (u64 i = 0; i < HDR_MAGIC_BYTE_COUNT; ++i) { | ||||
|       if (current[i] != magic[i]) { | ||||
|         match = false; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (match) { | ||||
|       return (ArenaAllocHDR *)current; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| internal void *mem_arena_alloc(u64 size, void *alloc_obj) { | ||||
|   Arena *arena = (Arena *)alloc_obj; | ||||
|  | ||||
|   return wapp_mem_arena_alloc(arena, size); | ||||
| } | ||||
|  | ||||
| internal void *mem_arena_alloc_aligned(u64 size, u64 alignment, | ||||
|                                        void *alloc_obj) { | ||||
|   Arena *arena = (Arena *)alloc_obj; | ||||
|  | ||||
|   return wapp_mem_arena_alloc_aligned(arena, size, alignment); | ||||
| } | ||||
|  | ||||
| internal void *mem_arena_realloc(void *ptr, u64 size, void *alloc_obj) { | ||||
|   Arena *arena = (Arena *)alloc_obj; | ||||
|  | ||||
|   return wapp_mem_arena_realloc(arena, ptr, size); | ||||
| } | ||||
|  | ||||
| internal void *mem_arena_realloc_aligned(void *ptr, u64 size, u64 alignment, | ||||
|                                          void *alloc_obj) { | ||||
|   Arena *arena = (Arena *)alloc_obj; | ||||
|  | ||||
|   return wapp_mem_arena_realloc_aligned(arena, ptr, size, alignment); | ||||
| } | ||||
| @@ -1,106 +0,0 @@ | ||||
| #include "mem_ctx.h" | ||||
| #include "aliases.h" | ||||
| #include "mem_arena.h" | ||||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| typedef struct mem_ctx MemCTX; | ||||
| struct mem_ctx { | ||||
|   Arena *main; | ||||
|   Arena *temp; | ||||
|   bool main_initialised; | ||||
|   bool temp_initialised; | ||||
| }; | ||||
|  | ||||
| internal MemCTX g_context = {0}; | ||||
|  | ||||
| internal Arena *get_arena(CTXDestBuffer buffer); | ||||
|  | ||||
| Allocator wapp_mem_ctx_allocator(CTXDestBuffer buffer) { | ||||
|   Arena *arena = get_arena(buffer); | ||||
|   return wapp_mem_arena_allocator(arena); | ||||
| } | ||||
|  | ||||
| void wapp_mem_ctx_init(u64 main_buf_capacity, u64 temp_buf_capacity) { | ||||
|   g_context.main_initialised = | ||||
|       wapp_mem_arena_init(&g_context.main, main_buf_capacity); | ||||
|   g_context.temp_initialised = | ||||
|       wapp_mem_arena_init(&g_context.temp, temp_buf_capacity); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_ctx_alloc(CTXDestBuffer buffer, u64 size) { | ||||
|   Arena *arena = get_arena(buffer); | ||||
|   if (!arena) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   return wapp_mem_arena_alloc(arena, size); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_ctx_alloc_aligned(CTXDestBuffer buffer, u64 size, | ||||
|                                  u64 alignment) { | ||||
|   Arena *arena = get_arena(buffer); | ||||
|   if (!arena) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   return wapp_mem_arena_alloc_aligned(arena, size, alignment); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_ctx_realloc(CTXDestBuffer buffer, void *ptr, u64 size) { | ||||
|   Arena *arena = get_arena(buffer); | ||||
|   if (!arena) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   return wapp_mem_arena_realloc(arena, ptr, size); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_ctx_realloc_aligned(CTXDestBuffer buffer, void *ptr, u64 size, | ||||
|                                    u64 alignment) { | ||||
|   Arena *arena = get_arena(buffer); | ||||
|   if (!arena) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   return wapp_mem_arena_realloc_aligned(arena, ptr, size, alignment); | ||||
| } | ||||
|  | ||||
| void wapp_mem_ctx_clear(CTXDestBuffer buffer) { | ||||
|   Arena *arena = get_arena(buffer); | ||||
|   if (!arena) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   wapp_mem_arena_clear(arena); | ||||
| } | ||||
|  | ||||
| void wapp_mem_ctx_free(void) { | ||||
|   wapp_mem_arena_free(&(g_context.main)); | ||||
|   g_context.main_initialised = false; | ||||
|  | ||||
|   wapp_mem_arena_free(&(g_context.temp)); | ||||
|   g_context.temp_initialised = false; | ||||
| } | ||||
|  | ||||
| internal Arena *get_arena(CTXDestBuffer buffer) { | ||||
|   Arena *output = NULL; | ||||
|  | ||||
|   switch (buffer) { | ||||
|   case CTX_DEST_BUFFER_MAIN: | ||||
|     if (g_context.main_initialised) { | ||||
|       output = g_context.main; | ||||
|     } | ||||
|     break; | ||||
|   case CTX_DEST_BUFFER_TEMP: | ||||
|     if (g_context.temp_initialised) { | ||||
|       output = g_context.temp; | ||||
|     } | ||||
|     break; | ||||
|   default: | ||||
|     assert(false && "Not all context destination buffers are handled"); | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   return output; | ||||
| } | ||||
| @@ -1,48 +0,0 @@ | ||||
| #include "mem_libc.h" | ||||
| #include "aliases.h" | ||||
| #include "mem_allocator.h" | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| internal void *mem_libc_alloc(u64 size, void *alloc_obj); | ||||
| internal void *mem_libc_alloc_aligned(u64 size, u64 alignment, void *alloc_obj); | ||||
| internal void *mem_libc_realloc(void *ptr, u64 size, void *alloc_obj); | ||||
| internal void mem_libc_free(void **ptr, void *alloc_obj); | ||||
|  | ||||
| Allocator wapp_mem_libc_allocator(void) { | ||||
|   return (Allocator){ | ||||
|       .obj = NULL, | ||||
|       .alloc = mem_libc_alloc, | ||||
|       .alloc_aligned = mem_libc_alloc_aligned, | ||||
|       .realloc = mem_libc_realloc, | ||||
|       .realloc_aligned = NULL, | ||||
|       .free = mem_libc_free, | ||||
|   }; | ||||
| } | ||||
|  | ||||
| internal void *mem_libc_alloc(u64 size, void *alloc_obj) { | ||||
|   return calloc(1, size); | ||||
| } | ||||
|  | ||||
| internal void *mem_libc_alloc_aligned(u64 size, u64 alignment, | ||||
|                                       void *alloc_obj) { | ||||
|   void *output = aligned_alloc(alignment, size); | ||||
|   if (output) { | ||||
|     memset(output, 0, size); | ||||
|   } | ||||
|  | ||||
|   return output; | ||||
| } | ||||
|  | ||||
| internal void *mem_libc_realloc(void *ptr, u64 size, void *alloc_obj) { | ||||
|   return realloc(ptr, size); | ||||
| } | ||||
|  | ||||
| internal void mem_libc_free(void **ptr, void *alloc_obj) { | ||||
|   if (!ptr || !(*ptr)) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   free(*ptr); | ||||
|   *ptr = NULL; | ||||
| } | ||||
							
								
								
									
										233
									
								
								src/mem/arena/mem_arena.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								src/mem/arena/mem_arena.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,233 @@ | ||||
| #include "mem_arena.h" | ||||
| #include "aliases.h" | ||||
| #include "mem_utils.h" | ||||
| #include <stdbool.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #ifndef DEFAULT_ALIGNMENT | ||||
| // Why 2 * sizeof(void *) instead of sizeof(void *) | ||||
| // https://handmade.network/forums/t/6860-alignment_arena_allocator | ||||
| #define DEFAULT_ALIGNMENT (2 * sizeof(void *)) | ||||
| #endif /* ifndef DEFAULT_ALIGNMENT */ | ||||
|  | ||||
| #define ARENA_MINIMUM_CAPACITY 1024 | ||||
|  | ||||
| typedef struct base_arena BaseArena; | ||||
| struct base_arena { | ||||
|   u8 *buf; | ||||
|   u8 *offset; | ||||
|   u64 capacity; | ||||
|   BaseArena *prev; | ||||
|   BaseArena *next; | ||||
| }; | ||||
|  | ||||
| struct growing_arena { | ||||
|   BaseArena *active_arena; | ||||
|   u64 count; | ||||
|   u64 initial_capacity; | ||||
| }; | ||||
|  | ||||
| internal bool base_arena_init(BaseArena *arena, u64 capacity); | ||||
| internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size, | ||||
|                                         u64 alignment); | ||||
| internal void base_arena_clear(BaseArena *arena); | ||||
| internal void base_arena_destroy(BaseArena *arena); | ||||
|  | ||||
| // PUBLIC API | ||||
|  | ||||
| bool wapp_mem_arena_init(Arena **arena, u64 base_capacity) { | ||||
|   if (!arena || *arena || base_capacity == 0) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   *arena = (Arena *)calloc(1, sizeof(Arena)); | ||||
|   Arena *arena_ptr = *arena; | ||||
|   if (!arena_ptr) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   arena_ptr->active_arena = (BaseArena *)calloc(1, sizeof(BaseArena)); | ||||
|   if (!(arena_ptr->active_arena)) { | ||||
|     wapp_mem_arena_destroy(arena); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (!base_arena_init(arena_ptr->active_arena, base_capacity)) { | ||||
|     wapp_mem_arena_destroy(arena); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   arena_ptr->count = 1; | ||||
|   arena_ptr->initial_capacity = base_capacity; | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| void *wapp_mem_arena_alloc(Arena *arena, u64 size) { | ||||
|   return wapp_mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT); | ||||
| } | ||||
|  | ||||
| void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) { | ||||
|   if (!arena || !(arena->active_arena)) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   void *output = base_arena_alloc_aligned(arena->active_arena, size, alignment); | ||||
|   if (!output) { | ||||
|     if (arena->active_arena->next) { | ||||
|       arena->active_arena = arena->active_arena->next; | ||||
|     } else { | ||||
|       arena->active_arena->next = (BaseArena *)calloc(1, sizeof(BaseArena)); | ||||
|       if (!(arena->active_arena->next)) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       if (!base_arena_init(arena->active_arena->next, | ||||
|                            arena->initial_capacity)) { | ||||
|         free(arena->active_arena->next); | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       arena->active_arena->next->prev = arena->active_arena; | ||||
|       arena->active_arena = arena->active_arena->next; | ||||
|  | ||||
|       ++(arena->count); | ||||
|     } | ||||
|  | ||||
|     output = base_arena_alloc_aligned(arena->active_arena, size, alignment); | ||||
|     if (!output) { | ||||
|       return NULL; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   memset(output, 0, size); | ||||
|  | ||||
|   return output; | ||||
| } | ||||
|  | ||||
| void wapp_mem_arena_clear(Arena *arena) { | ||||
|   if (!arena) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   BaseArena *last_active = NULL; | ||||
|   while (arena->active_arena) { | ||||
|     base_arena_clear(arena->active_arena); | ||||
|  | ||||
|     last_active = arena->active_arena; | ||||
|  | ||||
|     arena->active_arena = arena->active_arena->prev; | ||||
|   } | ||||
|  | ||||
|   arena->active_arena = last_active; | ||||
| } | ||||
|  | ||||
| void wapp_mem_arena_destroy(Arena **arena) { | ||||
|   if (!arena) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   Arena *arena_ptr = *arena; | ||||
|   if (!arena_ptr) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   BaseArena *current; | ||||
|   BaseArena *next; | ||||
|   BaseArena *prev; | ||||
|  | ||||
|   current = arena_ptr->active_arena->next; | ||||
|   while (current) { | ||||
|     next = current->next; | ||||
|  | ||||
|     base_arena_destroy(current); | ||||
|     free(current); | ||||
|  | ||||
|     current = next; | ||||
|   } | ||||
|  | ||||
|   current = arena_ptr->active_arena->prev; | ||||
|   while (current) { | ||||
|     prev = current->prev; | ||||
|  | ||||
|     base_arena_destroy(current); | ||||
|     free(current); | ||||
|  | ||||
|     current = prev; | ||||
|   } | ||||
|  | ||||
|   base_arena_destroy(arena_ptr->active_arena); | ||||
|  | ||||
|   free(arena_ptr->active_arena); | ||||
|   arena_ptr->active_arena = NULL; | ||||
|  | ||||
|   arena_ptr->count = 0; | ||||
|   arena_ptr->initial_capacity = 0; | ||||
|  | ||||
|   free(*arena); | ||||
|   *arena = NULL; | ||||
| } | ||||
|  | ||||
| // INTERNAL FUNCTIONS | ||||
|  | ||||
| internal bool base_arena_init(BaseArena *arena, u64 capacity) { | ||||
|   if (!arena || arena->buf || capacity == 0) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   u64 arena_capacity = | ||||
|       capacity >= ARENA_MINIMUM_CAPACITY ? capacity : ARENA_MINIMUM_CAPACITY; | ||||
|  | ||||
|   arena->buf = (u8 *)calloc(arena_capacity, sizeof(u8)); | ||||
|   if (!(arena->buf)) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   arena->capacity = arena_capacity; | ||||
|   arena->offset = arena->buf; | ||||
|   arena->prev = arena->next = NULL; | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size, | ||||
|                                         u64 alignment) { | ||||
|   if (!arena) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   u8 *alloc_start = arena->offset; | ||||
|  | ||||
|   u8 *output = wapp_mem_util_align_forward((void *)alloc_start, alignment); | ||||
|   if (output + size >= arena->buf + arena->capacity) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   arena->offset = output + size; | ||||
|  | ||||
|   return (void *)output; | ||||
| } | ||||
|  | ||||
| internal void base_arena_clear(BaseArena *arena) { | ||||
|   if (!arena) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   memset(arena->buf, 0, arena->offset - arena->buf); | ||||
|   arena->offset = arena->buf; | ||||
| } | ||||
|  | ||||
| internal void base_arena_destroy(BaseArena *arena) { | ||||
|   if (!arena) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (arena->buf) { | ||||
|     free(arena->buf); | ||||
|   } | ||||
|  | ||||
|   arena->buf = arena->offset = NULL; | ||||
|   arena->capacity = 0; | ||||
|   arena->prev = arena->next = NULL; | ||||
| } | ||||
| @@ -2,7 +2,6 @@ | ||||
| #define MEM_ARENA_H | ||||
| 
 | ||||
| #include "aliases.h" | ||||
| #include "mem_allocator.h" | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| @@ -11,15 +10,11 @@ extern "C" { | ||||
| 
 | ||||
| typedef struct growing_arena Arena; | ||||
| 
 | ||||
| Allocator wapp_mem_arena_allocator(const Arena *arena); | ||||
| bool wapp_mem_arena_init(Arena **arena, u64 base_capacity); | ||||
| void *wapp_mem_arena_alloc(Arena *arena, u64 size); | ||||
| void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment); | ||||
| void *wapp_mem_arena_realloc(Arena *arena, void *ptr, u64 size); | ||||
| void *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 size, | ||||
|                                      u64 alignment); | ||||
| void wapp_mem_arena_clear(Arena *arena); | ||||
| void wapp_mem_arena_free(Arena **arena); | ||||
| void wapp_mem_arena_destroy(Arena **arena); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/strings/basic_strings/basic_strings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/strings/basic_strings/basic_strings.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| #ifndef BASIC_STRING_H | ||||
| #define BASIC_STRING_H | ||||
|  | ||||
| #include "aliases.h" | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif // __cplusplus | ||||
|  | ||||
| typedef struct bstr BasicString; | ||||
| struct bstr { | ||||
|   u64 size; | ||||
|   const char *buf; | ||||
| }; | ||||
|  | ||||
| typedef struct strvw StringView; | ||||
| struct strvw { | ||||
|   const u64 size; | ||||
|   const char *buf; | ||||
| }; | ||||
|  | ||||
| #define new_string(STR)                                                        \ | ||||
|   { .size = strlen(STR), .buf = STR } | ||||
| #define wapp_bstr_new(STR) ((BasicString)new_string(STR)) | ||||
| #define wapp_strvw_new(STR) ((StringView)new_string(STR)) | ||||
| #define wapp_string_print(STR) (printf("%.*s\n", (i32)STR.size, STR.buf)) | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif // __cplusplus | ||||
|  | ||||
| #endif // !BASIC_STRING_H | ||||
| @@ -1,7 +1,6 @@ | ||||
| #include "dstr.h" | ||||
| #include "aliases.h" | ||||
| #include "mem_allocator.h" | ||||
| #include "mem_libc.h" | ||||
| #include "mem_arena.h" | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| @@ -9,45 +8,42 @@ | ||||
| // Use this scalar to allocate extra memory in order to avoid having to
 | ||||
| // constantly reallocate
 | ||||
| #define CAPACITY_SCALAR 8 | ||||
| #define MINIMUM_DSTR_CAPACITY 1024 | ||||
| 
 | ||||
| struct dstr { | ||||
|   Allocator allocator; | ||||
|   u64 capacity; | ||||
|   u64 size; | ||||
|   char buf[]; | ||||
| }; | ||||
| 
 | ||||
| String *wapp_dstr_with_capacity(u64 capacity, const Allocator *allocator) { | ||||
|   Allocator alloc; | ||||
|   if (allocator) { | ||||
|     alloc = *allocator; | ||||
|   } else { | ||||
|     alloc = wapp_mem_libc_allocator(); | ||||
| String *wapp_dstr_with_capacity(u64 capacity, Arena *arena) { | ||||
|   if (!arena) { | ||||
|     return NULL; | ||||
|   } | ||||
| 
 | ||||
|   String *out = | ||||
|       (String *)wapp_mem_allocator_alloc(&alloc, sizeof(String) + capacity + 1); | ||||
|       (String *)wapp_mem_arena_alloc(arena, sizeof(String) + capacity + 1); | ||||
|   if (!out) { | ||||
|     return NULL; | ||||
|   } | ||||
| 
 | ||||
|   out->allocator = alloc; | ||||
|   out->capacity = capacity; | ||||
|   out->size = 0; | ||||
| 
 | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| String *wapp_dstr_from_string(const char *str, const Allocator *allocator) { | ||||
|   if (!str) { | ||||
| String *wapp_dstr_from_string(const char *str, Arena *arena) { | ||||
|   if (!str || !arena) { | ||||
|     return NULL; | ||||
|   } | ||||
| 
 | ||||
|   u64 length = strlen(str); | ||||
| 
 | ||||
|   u64 capacity = length * CAPACITY_SCALAR; | ||||
|   capacity = | ||||
|       capacity >= MINIMUM_DSTR_CAPACITY ? capacity : MINIMUM_DSTR_CAPACITY; | ||||
| 
 | ||||
|   String *out = wapp_dstr_with_capacity(capacity, allocator); | ||||
|   String *out = wapp_dstr_with_capacity(capacity, arena); | ||||
|   if (!out) { | ||||
|     return NULL; | ||||
|   } | ||||
| @@ -58,55 +54,45 @@ String *wapp_dstr_from_string(const char *str, const Allocator *allocator) { | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| void wapp_dstr_update(String **dst, const char *src) { | ||||
| StringUpdate wapp_dstr_update(String **dst, const char *src, Arena *arena) { | ||||
|   if (!dst || !(*dst)) { | ||||
|     return; | ||||
|     return (StringUpdate){.updated = false, .str = *dst}; | ||||
|   } | ||||
| 
 | ||||
|   u64 length = strlen(src); | ||||
| 
 | ||||
|   String *str = *dst; | ||||
| 
 | ||||
|   if (length < str->capacity) { | ||||
|     memset(str->buf, 0, str->capacity); | ||||
| 
 | ||||
|     str->size = length; | ||||
| 
 | ||||
|     strncpy(str->buf, src, length + 1); | ||||
|   } else { | ||||
|     u64 capacity = length * CAPACITY_SCALAR; | ||||
| 
 | ||||
|     String *tmp = (String *)wapp_mem_allocator_realloc( | ||||
|         &(str->allocator), *dst, sizeof(String) + capacity + 1); | ||||
|     if (!tmp) { | ||||
|       return; | ||||
|   if (length >= str->capacity) { | ||||
|     if (!arena) { | ||||
|       return (StringUpdate){.updated = false, .str = *dst}; | ||||
|     } | ||||
| 
 | ||||
|     tmp->capacity = capacity; | ||||
|     tmp->size = length; | ||||
|     strncpy(tmp->buf, src, length + 1); | ||||
|     String *new_str = wapp_dstr_from_string(src, arena); | ||||
|     if (!new_str) { | ||||
|       return (StringUpdate){.updated = false, .str = *dst}; | ||||
|     } | ||||
| 
 | ||||
|     *dst = tmp; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void wapp_dstr_free(String **str) { | ||||
|   if (!str || !(*str)) { | ||||
|     return; | ||||
|     return (StringUpdate){.updated = true, .str = new_str}; | ||||
|   } | ||||
| 
 | ||||
|   String *str_ptr = *str; | ||||
|   wapp_mem_allocator_free(&(str_ptr->allocator), (void **)str); | ||||
|   memset(str->buf, 0, str->capacity); | ||||
| 
 | ||||
|   str->size = length; | ||||
| 
 | ||||
|   strncpy(str->buf, src, length + 1); | ||||
| 
 | ||||
|   return (StringUpdate){.updated = true, .str = *dst}; | ||||
| } | ||||
| 
 | ||||
| void wapp_dstr_concat(String **dst, const char *src) { | ||||
| StringUpdate wapp_dstr_concat(String **dst, const char *src, Arena *arena) { | ||||
|   if (!dst || !(*dst)) { | ||||
|     return; | ||||
|     return (StringUpdate){.updated = false, .str = *dst}; | ||||
|   } | ||||
| 
 | ||||
|   u64 src_length = strlen(src); | ||||
|   if (src_length == 0) { | ||||
|     return; | ||||
|     return (StringUpdate){.updated = false, .str = *dst}; | ||||
|   } | ||||
| 
 | ||||
|   u64 new_length = (*dst)->size + src_length; | ||||
| @@ -117,42 +103,7 @@ void wapp_dstr_concat(String **dst, const char *src) { | ||||
|   strncpy(str, (*dst)->buf, (*dst)->size); | ||||
|   strncat(str, src, new_length + 1 - (*dst)->size); | ||||
| 
 | ||||
|   wapp_dstr_update(dst, str); | ||||
| } | ||||
| 
 | ||||
| void wapp_dstr_append(String **dst, char c) { | ||||
|   if (!dst || !(*dst)) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   u64 new_length = (*dst)->size + 1; | ||||
| 
 | ||||
|   char str[new_length + 1]; | ||||
|   memset(str, 0, new_length + 1); | ||||
| 
 | ||||
|   strncpy(str, (*dst)->buf, (*dst)->size); | ||||
|   str[(*dst)->size] = c; | ||||
| 
 | ||||
|   wapp_dstr_update(dst, str); | ||||
| } | ||||
| 
 | ||||
| void wapp_dstr_resize(String **str) { | ||||
|   if (!str || !(*str)) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   String *str_ptr = *str; | ||||
|   u64 capacity = (*str)->size; | ||||
| 
 | ||||
|   String *tmp = (String *)wapp_mem_allocator_realloc( | ||||
|       &(str_ptr->allocator), *str, sizeof(String) + capacity + 1); | ||||
|   if (!tmp) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   tmp->capacity = capacity; | ||||
| 
 | ||||
|   *str = tmp; | ||||
|   return wapp_dstr_update(dst, str, arena); | ||||
| } | ||||
| 
 | ||||
| void wapp_dstr_clear(String *str) { | ||||
| @@ -2,7 +2,8 @@ | ||||
| #define DSTR_H | ||||
| 
 | ||||
| #include "aliases.h" | ||||
| #include "mem_allocator.h" | ||||
| #include "mem_arena.h" | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| @@ -10,13 +11,16 @@ extern "C" { | ||||
| 
 | ||||
| typedef struct dstr String; | ||||
| 
 | ||||
| String *wapp_dstr_with_capacity(u64 capacity, const Allocator *allocator); | ||||
| String *wapp_dstr_from_string(const char *str, const Allocator *allocator); | ||||
| void wapp_dstr_update(String **dst, const char *src); | ||||
| void wapp_dstr_free(String **str); | ||||
| void wapp_dstr_concat(String **dst, const char *src); | ||||
| void wapp_dstr_append(String **dst, char c); | ||||
| void wapp_dstr_resize(String **str); | ||||
| typedef struct string_update StringUpdate; | ||||
| struct string_update { | ||||
|   bool updated; | ||||
|   String *str; | ||||
| }; | ||||
| 
 | ||||
| String *wapp_dstr_with_capacity(u64 capacity, Arena *arena); | ||||
| String *wapp_dstr_from_string(const char *str, Arena *arena); | ||||
| StringUpdate wapp_dstr_update(String **dst, const char *src, Arena *arena); | ||||
| StringUpdate wapp_dstr_concat(String **dst, const char *src, Arena *arena); | ||||
| void wapp_dstr_clear(String *str); | ||||
| void wapp_dstr_print(const String *str); | ||||
| i64 wapp_dstr_find(const String *str, const char *substr); | ||||
		Reference in New Issue
	
	Block a user