1 // Copyright (c) 2015 Sergio Gonzalez. All rights reserved.
2 // License: https://github.com/serge-rgb/milton#license
3 
4 #pragma once
5 
6 #include "common.h"
7 
8 // TODO: out of memory handler.
9 
10 #define mlt_malloc(sz) INVALID_CODE_PATH
11 #if DEBUG_MEMORY_USAGE
12     #define mlt_calloc(n, sz, category) calloc_with_debug(n, sz, category, __FILE__, __LINE__)
13     #define mlt_free(ptr, category) free_with_debug(ptr, category); ptr=NULL
14     #define mlt_realloc(ptr, sz, category) realloc_with_debug(ptr, sz, category, __FILE__, __LINE__)
15 #else
16     #define mlt_calloc(n, sz, category) calloc(n, sz)
17     #define mlt_free(ptr, category) do { if (ptr) { free(ptr); ptr = NULL; } else { mlt_assert(!"Freeing null"); } } while(0)
18     #define mlt_realloc(ptr, sz, category) realloc(ptr, sz)
19 #endif
20 
21 
22 struct Arena
23 {
24     // Memory:
25     size_t  size;
26     size_t  count;
27     size_t  min_block_size;
28     u8*     ptr;
29 
30     // For pushing/popping
31     Arena*  parent;
32     int     id;
33     int     num_children;
34 };
35 
36 // Stored at the end of the arena.
37 // If the arena expands, its memory block will point to previous memory blocks.
38 struct ArenaFooter
39 {
40     u8*     previous_block;
41     size_t  previous_size;
42 };
43 
44 // Create a root arena from a memory block.
45 Arena arena_init(size_t min_block_size = 0, void* base = NULL);
46 Arena arena_spawn(Arena* parent, size_t size);
47 void  arena_reset(Arena* arena);
48 void  arena_reset_noclear(Arena* arena);
49 void  arena_free(Arena* arena);
50 
51 // ==== Temporary arenas.
52 // Usage:
53 //      child = arena_push(my_arena, some_size);
54 //      use_temporary_arena(&child.arena);
55 //      arena_pop(child);
56 Arena  arena_push(Arena* parent, size_t size = 0);
57 void   arena_pop(Arena* child);
58 void   arena_pop_noclear(Arena* child);
59 
60 #define     arena_alloc_elem_(arena, T, flags)          (T *)arena_alloc_bytes((arena), sizeof(T), flags)
61 #define     arena_alloc_array_(arena, count, T, flags)  (T *)arena_alloc_bytes((arena), (count) * sizeof(T), flags)
62 #define     arena_alloc_elem(arena, T)                  arena_alloc_elem_(arena, T, Arena_NONE)
63 #define     arena_alloc_array(arena, count, T)          arena_alloc_array_(arena, count, T, Arena_NONE)
64 #define     ARENA_VALIDATE(arena)                       mlt_assert ((arena)->num_children == 0)
65 #define     arena_bootstrap(Type, member, size)         (Type*)arena_bootstrap_(size, sizeof(Type), offsetof(Type, member))
66 
67 enum ArenaAllocOpts
68 {
69     Arena_NONE = 0,
70 
71     Arena_NOFAIL = 1<<0,
72 };
73 
74 u8* arena_alloc_bytes(Arena* arena, size_t num_bytes, int alloc_flags=Arena_NONE);
75 
76 void* arena_bootstrap_(size_t size, size_t obj_size, size_t offset);
77 
78 void* calloc_with_debug(size_t n, size_t sz, char* category, char* file, i64 line);
79 void  free_with_debug(void* ptr, char* category);
80 void* realloc_with_debug(void* ptr, size_t sz, char* category, char* file, i64 line);
81 void debug_memory_dump_allocations();
82