6 #include "vg_platform.h"
11 #define VG_MAX_ALLOCATIONS 64
12 #define VG_FUZZ_ALLOCATIONS
14 typedef struct vg_linear_allocator vg_linear_allocator
;
15 typedef struct vg_allocation_meta vg_allocation_meta
;
27 struct vg_allocation_meta
32 k_allocation_type_block
= 0,
33 k_allocation_type_linear
= 1
38 #define VG_MEMORY_SYSTEM 0x1 /* systems memory, slow and low counts */
39 #define VG_MEMORY_REALTIME 0x2 /* per-frame. no max allocs, only size. fast */
41 /* systems memory cannot be declared inside realtime memory regions */
44 * Stored just behind the array. 32 bytes.
47 struct vg_linear_allocator
73 vg_allocation_meta
*alloc_table
;
83 /* 32 bit pointers! */
89 VG_STATIC
void vg_fatal_exit_loop( const char *error
);
90 VG_STATIC
void vg_error(const char *fmt
, ...);
91 VG_STATIC
void vg_info(const char *fmt
, ...);
93 /* Returns allocator structure from data pointer */
94 static vg_linear_allocator
*vg_linear_header( void *data
)
96 vg_linear_allocator
*ptr
= data
;
102 /* allocate something from a linear allocator */
103 __attribute__((warn_unused_result
))
104 VG_STATIC
void *vg_linear_alloc( void *buffer
, u32 size
)
106 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
108 if( (alloc
->cur
+ size
) > alloc
->size
)
110 vg_error( "%u + %u > %u\n", alloc
->cur
, size
, alloc
->size
);
111 vg_fatal_exit_loop( "linear allocator overflow" );
114 if( alloc
->flags
& VG_MEMORY_SYSTEM
)
115 if( (alloc
->allocation_count
+ 1) > VG_MAX_ALLOCATIONS
)
116 vg_fatal_exit_loop( "Max linear allocations reached" );
120 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) )
122 data
= malloc( size
);
124 vg_allocation_meta
*meta
= &alloc
->alloc_table
[ alloc
->allocation_count
];
125 meta
->type
= k_allocation_type_block
;
130 data
= buffer
+ alloc
->cur
;
133 alloc
->allocation_count
++;
134 alloc
->last_alloc
= data
;
135 alloc
->last_alloc_size
= size
;
142 /* resize latest block of memory from linear */
143 __attribute__((warn_unused_result
))
144 VG_STATIC
void *vg_linear_resize( void *buffer
, void *data
, u32 newsize
)
146 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
148 if( alloc
->last_alloc
!= data
)
149 vg_fatal_exit_loop( "This block has been fixed!" );
151 if( (alloc
->cur
- alloc
->last_alloc_size
+ newsize
) > alloc
->size
)
152 vg_fatal_exit_loop( "Cannot resize, overflow" );
154 alloc
->cur
-= alloc
->last_alloc_size
;
155 alloc
->cur
+= newsize
;
156 alloc
->last_alloc_size
= newsize
;
158 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) )
160 data
= realloc( data
, newsize
);
162 vg_fatal_exit_loop( "realloc failed" );
164 alloc
->alloc_table
[ alloc
->allocation_count
-1 ].data
= data
;
165 alloc
->last_alloc
= data
;
174 /* its possible to delete just the last item */
175 VG_STATIC
void vg_linear_del( void *buffer
, void *data
)
177 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
179 if( alloc
->last_alloc
!= data
)
180 vg_fatal_exit_loop( "This block has been fixed!" );
182 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) )
184 vg_allocation_meta
*meta
= &alloc
->alloc_table
[alloc
->allocation_count
-1];
185 if( meta
->type
== k_allocation_type_linear
)
186 vg_fatal_exit_loop( "Cannot free a linear allocator in this conext" );
191 alloc
->allocation_count
--;
192 alloc
->cur
-= alloc
->last_alloc_size
;
193 alloc
->last_alloc
= NULL
;
194 alloc
->last_alloc_size
= 0;
197 /* extend latest block of memory from linear */
198 __attribute__((warn_unused_result
))
199 VG_STATIC
void *vg_linear_extend( void *buffer
, void *data
, u32 extra
)
201 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
203 if( alloc
->last_alloc
!= data
)
204 vg_fatal_exit_loop( "This block has been fixed!" );
206 u32 new_size
= alloc
->last_alloc_size
+ extra
;
207 return vg_linear_resize( buffer
, data
, new_size
);
210 /* get the current usage of allocator */
211 VG_STATIC u32
vg_linear_get_cur( void *buffer
)
213 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
217 /* get the capacity of allocator. */
218 VG_STATIC u32
vg_linear_get_capacity( void *buffer
)
220 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
224 /* get the remaining size of the allocator */
225 VG_STATIC u32
vg_linear_remaining( void *buffer
)
227 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
228 return alloc
->size
- alloc
->cur
;
231 /* yeet all memory from linear allocator */
232 VG_STATIC
void vg_linear_clear( void *buffer
)
234 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
236 /* libc mode we recursively free any allocations made */
237 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) )
239 for( u32 i
=0; i
<alloc
->allocation_count
; i
++ )
241 vg_allocation_meta
*meta
= &alloc
->alloc_table
[i
];
243 if( meta
->type
== k_allocation_type_block
)
249 vg_linear_clear( meta
->data
);
250 vg_linear_allocator
*sub
= vg_linear_header( meta
->data
);
252 free( sub
->alloc_table
);
258 alloc
->last_alloc
= NULL
;
259 alloc
->last_alloc_size
= 0;
260 alloc
->allocation_count
= 0;
264 /* allocate a FIXED SIZE linear allocator */
265 VG_STATIC
void *vg_create_linear_allocator( void *lin_alloc
, u32 size
,
268 assert( sizeof( vg_linear_allocator
) == 32 );
270 vg_linear_allocator
*header
;
271 u32 block_size
= size
+ sizeof(vg_linear_allocator
);
273 /* Creating it inside an existing one */
276 vg_linear_allocator
*alloc
= vg_linear_header( lin_alloc
);
278 if( alloc
->cur
+ block_size
> alloc
->size
)
279 vg_fatal_exit_loop( "Out of memory" );
281 if( alloc
->allocation_count
+ 1 > VG_MAX_ALLOCATIONS
)
282 vg_fatal_exit_loop( "Max allocations in linear allocator" );
284 if( (flags
&& VG_MEMORY_SYSTEM
) && (alloc
->flags
& VG_MEMORY_REALTIME
) )
285 vg_fatal_exit_loop( "Cannot declare realtime allocator inside systems"
288 if( vg_mem
.use_libc_malloc
)
290 vg_allocation_meta
*meta
=
291 &alloc
->alloc_table
[ alloc
->allocation_count
];
293 if( flags
& VG_MEMORY_REALTIME
)
294 header
= malloc( block_size
);
296 header
= malloc( sizeof(vg_linear_allocator
) );
298 meta
->data
= header
+1;
299 meta
->type
= k_allocation_type_linear
;
303 header
= lin_alloc
+ alloc
->cur
;
306 alloc
->cur
+= block_size
;
307 alloc
->last_alloc
= NULL
; /* cant resize this block! */
308 alloc
->last_alloc_size
= block_size
;
310 alloc
->allocation_count
++;
314 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) )
315 header
= malloc( sizeof(vg_linear_allocator
) );
317 header
= malloc( block_size
);
320 header
->allocation_count
= 0;
322 header
->last_alloc
= NULL
;
323 header
->last_alloc_size
= 0;
325 header
->flags
= flags
;
327 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) )
329 u32 table_size
= sizeof(vg_allocation_meta
)*VG_MAX_ALLOCATIONS
;
330 header
->alloc_table
= malloc( table_size
);
333 header
->alloc_table
= NULL
;
338 /* request all the memory we need in advance */
339 VG_STATIC
void vg_set_mem_quota( u32 size
)
344 VG_STATIC
void vg_alloc_quota(void)
346 u32 size_scratch
= 10*1024*1024;
347 u32 size
= VG_MAX( vg_mem
.quota
, size_scratch
);
349 vg_mem
.rtmemory
= vg_create_linear_allocator( NULL
, size
, VG_MEMORY_SYSTEM
);
350 vg_mem
.scratch
= vg_create_linear_allocator( vg_mem
.rtmemory
,
355 #endif /* VG_MEM_H */