|
@@ -75,7 +75,6 @@ free :: proc[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
|
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, loc := #caller_location) -> rawptr {
|
|
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, loc := #caller_location) -> rawptr {
|
|
|
if old_memory == nil do return alloc(new_size, alignment, loc);
|
|
if old_memory == nil do return alloc(new_size, alignment, loc);
|
|
|
|
|
|
|
@@ -108,3 +107,162 @@ nil_allocator :: proc() -> Allocator {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+Pool :: struct {
|
|
|
|
|
+ block_size: int,
|
|
|
|
|
+ out_band_size: int,
|
|
|
|
|
+ alignment: int,
|
|
|
|
|
+
|
|
|
|
|
+ unused_blocks: [dynamic]rawptr,
|
|
|
|
|
+ used_blocks: [dynamic]rawptr,
|
|
|
|
|
+ out_band_allocations: [dynamic]rawptr,
|
|
|
|
|
+
|
|
|
|
|
+ current_block: rawptr,
|
|
|
|
|
+ current_pos: rawptr,
|
|
|
|
|
+ bytes_left: int,
|
|
|
|
|
+
|
|
|
|
|
+ block_allocator: Allocator,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+POOL_BLOCK_SIZE_DEFAULT :: 65536;
|
|
|
|
|
+POOL_OUT_OF_BAND_SIZE_DEFAULT :: 6554;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|
|
|
|
+ size, alignment: int,
|
|
|
|
|
+ old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
|
|
|
|
+ pool := (^Pool)(allocator_data);
|
|
|
|
|
+
|
|
|
|
|
+ switch mode {
|
|
|
|
|
+ case Allocator_Mode.Alloc:
|
|
|
|
|
+ return pool_alloc(pool, size);
|
|
|
|
|
+ case Allocator_Mode.Free:
|
|
|
|
|
+ panic("Allocator_Mode.Free is not supported for a pool");
|
|
|
|
|
+ case Allocator_Mode.Free_All:
|
|
|
|
|
+ pool_free_all(pool);
|
|
|
|
|
+ case Allocator_Mode.Resize:
|
|
|
|
|
+ panic("Allocator_Mode.Resize is not supported for a pool");
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+pool_allocator :: proc(pool: ^Pool) -> Allocator {
|
|
|
|
|
+ return Allocator{
|
|
|
|
|
+ procedure = pool_allocator_proc,
|
|
|
|
|
+ data = pool,
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+pool_init :: proc(pool: ^Pool,
|
|
|
|
|
+ block_allocator := Allocator{} , array_allocator := Allocator{},
|
|
|
|
|
+ block_size := POOL_BLOCK_SIZE_DEFAULT, out_band_size := POOL_OUT_OF_BAND_SIZE_DEFAULT,
|
|
|
|
|
+ alignment := 8) {
|
|
|
|
|
+ pool.block_size = block_size;
|
|
|
|
|
+ pool.out_band_size = out_band_size;
|
|
|
|
|
+ pool.alignment = alignment;
|
|
|
|
|
+
|
|
|
|
|
+ if block_allocator.procedure == nil {
|
|
|
|
|
+ block_allocator = context.allocator;
|
|
|
|
|
+ }
|
|
|
|
|
+ if array_allocator.procedure == nil {
|
|
|
|
|
+ array_allocator = context.allocator;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pool.block_allocator = block_allocator;
|
|
|
|
|
+
|
|
|
|
|
+ pool.out_band_allocations.allocator = array_allocator;
|
|
|
|
|
+ pool. unused_blocks.allocator = array_allocator;
|
|
|
|
|
+ pool. used_blocks.allocator = array_allocator;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+pool_destroy :: proc(using pool: ^Pool) {
|
|
|
|
|
+ pool_free_all(pool);
|
|
|
|
|
+ free(unused_blocks);
|
|
|
|
|
+ free(used_blocks);
|
|
|
|
|
+
|
|
|
|
|
+ zero(pool, size_of(pool^));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+pool_alloc :: proc(using pool: ^Pool, bytes: int) -> rawptr {
|
|
|
|
|
+ cycle_new_block :: proc(using pool: ^Pool) {
|
|
|
|
|
+ if block_allocator.procedure == nil {
|
|
|
|
|
+ panic("You must call pool_init on a Pool before using it");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if current_block != nil {
|
|
|
|
|
+ append(&used_blocks, current_block);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ new_block: rawptr;
|
|
|
|
|
+ if len(unused_blocks) > 0 {
|
|
|
|
|
+ new_block = pop(&unused_blocks);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ new_block = block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc,
|
|
|
|
|
+ block_size, alignment,
|
|
|
|
|
+ nil, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bytes_left = block_size;
|
|
|
|
|
+ current_pos = new_block;
|
|
|
|
|
+ current_block = new_block;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ extra := alignment - (bytes % alignment);
|
|
|
|
|
+ bytes += extra;
|
|
|
|
|
+ if bytes >= out_band_size {
|
|
|
|
|
+ assert(block_allocator.procedure != nil);
|
|
|
|
|
+ memory := block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc,
|
|
|
|
|
+ block_size, alignment,
|
|
|
|
|
+ nil, 0);
|
|
|
|
|
+ if memory != nil {
|
|
|
|
|
+ append(&out_band_allocations, (^byte)(memory));
|
|
|
|
|
+ }
|
|
|
|
|
+ return memory;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if bytes_left < bytes {
|
|
|
|
|
+ cycle_new_block(pool);
|
|
|
|
|
+ if current_block == nil {
|
|
|
|
|
+ return nil;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ memory := current_pos;
|
|
|
|
|
+ current_pos = ptr_offset((^byte)(current_pos), uintptr(bytes));
|
|
|
|
|
+ bytes_left -= bytes;
|
|
|
|
|
+ return memory;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+pool_reset :: proc(using pool: ^Pool) {
|
|
|
|
|
+ if current_block != nil {
|
|
|
|
|
+ append(&unused_blocks, current_block);
|
|
|
|
|
+ current_block = nil;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for block in used_blocks {
|
|
|
|
|
+ append(&unused_blocks, block);
|
|
|
|
|
+ }
|
|
|
|
|
+ clear(&used_blocks);
|
|
|
|
|
+
|
|
|
|
|
+ for a in out_band_allocations {
|
|
|
|
|
+ free_ptr_with_allocator(block_allocator, a);
|
|
|
|
|
+ }
|
|
|
|
|
+ clear(&out_band_allocations);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+pool_free_all :: proc(using pool: ^Pool) {
|
|
|
|
|
+ pool_reset(pool);
|
|
|
|
|
+
|
|
|
|
|
+ for block in unused_blocks {
|
|
|
|
|
+ free_ptr_with_allocator(block_allocator, block);
|
|
|
|
|
+ }
|
|
|
|
|
+ clear(&unused_blocks);
|
|
|
|
|
+}
|