5 #include "vg_platform.h"
10 #define VG_MAX_ALLOCATIONS 64
11 #define VG_FUZZ_ALLOCATIONS
12 #define VG_DEBUG_ALLOCATIONS
14 typedef struct vg_linear_allocator vg_linear_allocator
;
15 typedef struct vg_allocation_meta vg_allocation_meta
;
26 struct vg_allocation_meta
31 k_allocation_type_block
= 0,
32 k_allocation_type_linear
= 1
37 #define VG_MEMORY_SYSTEM 0x1 /* systems memory, slow and low counts */
38 #define VG_MEMORY_REALTIME 0x2 /* per-frame. no max allocs, only size. fast */
40 /* systems memory cannot be declared inside realtime memory regions */
43 * Stored just behind the array. 32 bytes.
46 struct vg_linear_allocator
72 vg_allocation_meta
*alloc_table
;
83 VG_STATIC
void vg_error(const char *fmt
, ...);
84 VG_STATIC
void vg_info(const char *fmt
, ...);
86 /* Returns allocator structure from data pointer */
87 static vg_linear_allocator
*vg_linear_header( void *data
)
89 vg_linear_allocator
*ptr
= data
;
95 /* allocate something from a linear allocator */
96 __attribute__((warn_unused_result
))
97 VG_STATIC
void *vg_linear_alloc( void *buffer
, u32 size
)
99 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
101 if( (alloc
->cur
+ size
) > alloc
->size
)
103 vg_error( "%u + %u > %u\n", alloc
->cur
, size
, alloc
->size
);
104 vg_fatal_exit_loop( "linear allocator overflow" );
107 if( alloc
->flags
& VG_MEMORY_SYSTEM
)
108 if( (alloc
->allocation_count
+ 1) > VG_MAX_ALLOCATIONS
)
109 vg_fatal_exit_loop( "Max linear allocations reached" );
113 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) )
115 data
= malloc( size
);
117 #ifdef VG_DEBUG_ALLOCATIONS
118 vg_info( "malloc: %p[%u]\n", data
, size
);
121 vg_allocation_meta
*meta
= &alloc
->alloc_table
[ alloc
->allocation_count
];
122 meta
->type
= k_allocation_type_block
;
127 data
= buffer
+ alloc
->cur
;
130 alloc
->allocation_count
++;
131 alloc
->last_alloc
= data
;
132 alloc
->last_alloc_size
= size
;
139 /* resize latest block of memory from linear */
140 __attribute__((warn_unused_result
))
141 VG_STATIC
void *vg_linear_resize( void *buffer
, void *data
, u32 newsize
)
143 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
145 if( alloc
->last_alloc
!= data
)
146 vg_fatal_exit_loop( "This block has been fixed!" );
148 if( (alloc
->cur
- alloc
->last_alloc_size
+ newsize
) > alloc
->size
)
149 vg_fatal_exit_loop( "Cannot resize, overflow" );
151 alloc
->cur
-= alloc
->last_alloc_size
;
152 alloc
->cur
+= newsize
;
153 alloc
->last_alloc_size
= newsize
;
155 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) )
157 data
= realloc( data
, newsize
);
159 vg_fatal_exit_loop( "realloc failed" );
161 alloc
->alloc_table
[ alloc
->allocation_count
-1 ].data
= data
;
162 alloc
->last_alloc
= data
;
164 #ifdef VG_DEBUG_ALLOCATIONS
165 vg_info( "realloc: %p (->%u)\n", data
, newsize
);
175 /* its possible to delete just the last item */
176 VG_STATIC
void vg_linear_del( void *buffer
, void *data
)
178 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
180 if( alloc
->last_alloc
!= data
)
181 vg_fatal_exit_loop( "This block has been fixed!" );
183 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) )
185 vg_allocation_meta
*meta
= &alloc
->alloc_table
[alloc
->allocation_count
-1];
186 if( meta
->type
== k_allocation_type_linear
)
187 vg_fatal_exit_loop( "Cannot free a linear allocator in this conext" );
192 alloc
->allocation_count
--;
193 alloc
->cur
-= alloc
->last_alloc_size
;
194 alloc
->last_alloc
= NULL
;
195 alloc
->last_alloc_size
= 0;
198 /* extend latest block of memory from linear */
199 __attribute__((warn_unused_result
))
200 VG_STATIC
void *vg_linear_extend( void *buffer
, void *data
, u32 extra
)
202 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
204 if( alloc
->last_alloc
!= data
)
205 vg_fatal_exit_loop( "This block has been fixed!" );
207 u32 new_size
= alloc
->last_alloc_size
+ extra
;
208 return vg_linear_resize( buffer
, data
, new_size
);
211 /* get the current usage of allocator */
212 VG_STATIC u32
vg_linear_get_cur( void *buffer
)
214 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
218 /* get the capacity of allocator. TODO, should return free space? */
219 VG_STATIC u32
vg_linear_get_capacity( void *buffer
)
221 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
225 /* yeet all memory from linear allocator */
226 VG_STATIC
void vg_linear_clear( void *buffer
)
228 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
230 #ifdef VG_DEBUG_ALLOCATIONS
231 if( alloc
->flags
& VG_MEMORY_SYSTEM
)
232 vg_info( "linear_clear on %p\n", alloc
);
235 /* libc mode we recursively free any allocations made */
236 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) )
238 for( u32 i
=0; i
<alloc
->allocation_count
; i
++ )
240 vg_allocation_meta
*meta
= &alloc
->alloc_table
[i
];
242 if( meta
->type
== k_allocation_type_block
)
246 #ifdef VG_DEBUG_ALLOCATIONS
247 vg_info( "free(%p) [%d]\n", meta
->data
, meta
->type
);
252 vg_linear_clear( meta
->data
);
253 vg_linear_allocator
*sub
= vg_linear_header( meta
->data
);
255 #ifdef VG_DEBUG_ALLOCATIONS
256 vg_info( "free(%p) [alloc_table]\n", sub
->alloc_table
);
257 vg_info( "free(%p) [%d]\n", sub
, meta
->type
);
260 free( sub
->alloc_table
);
266 alloc
->last_alloc
= NULL
;
267 alloc
->last_alloc_size
= 0;
268 alloc
->allocation_count
= 0;
272 /* allocate a FIXED SIZE linear allocator */
273 VG_STATIC
void *vg_create_linear_allocator( void *lin_alloc
, u32 size
,
276 assert( sizeof( vg_linear_allocator
) == 32 );
278 vg_linear_allocator
*header
;
279 u32 block_size
= size
+ sizeof(vg_linear_allocator
);
281 /* Creating it inside an existing one */
284 vg_linear_allocator
*alloc
= vg_linear_header( lin_alloc
);
286 if( alloc
->cur
+ block_size
> alloc
->size
)
287 vg_fatal_exit_loop( "Out of memory" );
289 if( alloc
->allocation_count
+ 1 > VG_MAX_ALLOCATIONS
)
290 vg_fatal_exit_loop( "Max allocations in linear allocator" );
292 if( (flags
&& VG_MEMORY_SYSTEM
) && (alloc
->flags
& VG_MEMORY_REALTIME
) )
293 vg_fatal_exit_loop( "Cannot declare realtime allocator inside systems"
296 if( vg_mem
.use_libc_malloc
)
298 vg_allocation_meta
*meta
=
299 &alloc
->alloc_table
[ alloc
->allocation_count
];
301 if( flags
& VG_MEMORY_REALTIME
)
302 header
= malloc( block_size
);
304 header
= malloc( sizeof(vg_linear_allocator
) );
306 #ifdef VG_DEBUG_ALLOCATIONS
307 vg_info( "linear_create(sub) malloc(%p)\n", header
);
310 meta
->data
= header
+1;
311 meta
->type
= k_allocation_type_linear
;
315 header
= lin_alloc
+ alloc
->cur
;
318 alloc
->cur
+= block_size
;
319 alloc
->last_alloc
= NULL
; /* cant resize this block! */
320 alloc
->last_alloc_size
= block_size
;
322 alloc
->allocation_count
++;
326 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) )
327 header
= malloc( sizeof(vg_linear_allocator
) );
329 header
= malloc( block_size
);
331 #ifdef VG_DEBUG_ALLOCATIONS
332 vg_info( "linear_create malloc(%p)\n", header
);
336 header
->allocation_count
= 0;
338 header
->last_alloc
= NULL
;
339 header
->last_alloc_size
= 0;
341 header
->flags
= flags
;
343 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) )
345 u32 table_size
= sizeof(vg_allocation_meta
)*VG_MAX_ALLOCATIONS
;
346 header
->alloc_table
= malloc( table_size
);
347 #ifdef VG_DEBUG_ALLOCATIONS
348 vg_info( "linear_create(%p) [alloc_table]\n", header
->alloc_table
);
352 header
->alloc_table
= NULL
;
357 /* request all the memory we need in advance */
358 VG_STATIC
void vg_prealloc_quota( u32 size
)
360 u32 size_scratch
= 10*1024*1024;
361 size
= VG_MAX( size
, size_scratch
);
363 vg_mem
.rtmemory
= vg_create_linear_allocator( NULL
, size
, VG_MEMORY_SYSTEM
);
364 vg_mem
.scratch
= vg_create_linear_allocator( vg_mem
.rtmemory
,
369 #endif /* VG_MEM_H */