|
@@ -795,93 +795,35 @@ DYNAMIC_POOL_OUT_OF_BAND_SIZE_DEFAULT :: DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT
|
|
|
dynamic_pool_allocator_proc :: dynamic_arena_allocator_proc
|
|
|
dynamic_pool_free_all :: dynamic_arena_free_all
|
|
|
dynamic_pool_reset :: dynamic_arena_reset
|
|
|
-dynamic_pool_alloc_bytes :: dynamic_arena_alloc_bytes
|
|
|
-dynamic_pool_alloc :: dynamic_arena_alloc
|
|
|
+dynamic_pool_alloc_bytes :: dynamic_arena_alloc
|
|
|
+dynamic_pool_alloc :: _dynamic_arena_alloc_ptr
|
|
|
dynamic_pool_init :: dynamic_arena_init
|
|
|
dynamic_pool_allocator :: dynamic_arena_allocator
|
|
|
+dynamic_pool_destroy :: dynamic_arena_destroy
|
|
|
+
|
|
|
+DYNAMIC_ARENA_BLOCK_SIZE_DEFAULT :: 65536
|
|
|
+DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT :: 6554
|
|
|
|
|
|
Dynamic_Arena :: struct {
|
|
|
- block_size: int,
|
|
|
+ block_size: int,
|
|
|
out_band_size: int,
|
|
|
- alignment: int,
|
|
|
-
|
|
|
- unused_blocks: [dynamic]rawptr,
|
|
|
- used_blocks: [dynamic]rawptr,
|
|
|
+ alignment: int,
|
|
|
+ unused_blocks: [dynamic]rawptr,
|
|
|
+ used_blocks: [dynamic]rawptr,
|
|
|
out_band_allocations: [dynamic]rawptr,
|
|
|
-
|
|
|
current_block: rawptr,
|
|
|
- current_pos: rawptr,
|
|
|
- bytes_left: int,
|
|
|
-
|
|
|
+ current_pos: rawptr,
|
|
|
+ bytes_left: int,
|
|
|
block_allocator: Allocator,
|
|
|
}
|
|
|
|
|
|
-DYNAMIC_ARENA_BLOCK_SIZE_DEFAULT :: 65536
|
|
|
-DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT :: 6554
|
|
|
-
|
|
|
-dynamic_arena_allocator_proc :: proc(
|
|
|
- allocator_data: rawptr,
|
|
|
- mode: Allocator_Mode,
|
|
|
- size: int,
|
|
|
- alignment: int,
|
|
|
- old_memory: rawptr,
|
|
|
- old_size: int,
|
|
|
- loc := #caller_location,
|
|
|
-) -> ([]byte, Allocator_Error) {
|
|
|
- pool := (^Dynamic_Arena)(allocator_data)
|
|
|
-
|
|
|
- switch mode {
|
|
|
- case .Alloc, .Alloc_Non_Zeroed:
|
|
|
- return dynamic_arena_alloc_bytes(pool, size)
|
|
|
- case .Free:
|
|
|
- return nil, .Mode_Not_Implemented
|
|
|
- case .Free_All:
|
|
|
- dynamic_arena_free_all(pool)
|
|
|
- return nil, nil
|
|
|
- case .Resize, .Resize_Non_Zeroed:
|
|
|
- if old_size >= size {
|
|
|
- return byte_slice(old_memory, size), nil
|
|
|
- }
|
|
|
- data, err := dynamic_arena_alloc_bytes(pool, size)
|
|
|
- if err == nil {
|
|
|
- runtime.copy(data, byte_slice(old_memory, old_size))
|
|
|
- }
|
|
|
- return data, err
|
|
|
-
|
|
|
- case .Query_Features:
|
|
|
- set := (^Allocator_Mode_Set)(old_memory)
|
|
|
- if set != nil {
|
|
|
- set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features, .Query_Info}
|
|
|
- }
|
|
|
- return nil, nil
|
|
|
-
|
|
|
- case .Query_Info:
|
|
|
- info := (^Allocator_Query_Info)(old_memory)
|
|
|
- if info != nil && info.pointer != nil {
|
|
|
- info.size = pool.block_size
|
|
|
- info.alignment = pool.alignment
|
|
|
- return byte_slice(info, size_of(info^)), nil
|
|
|
- }
|
|
|
- return nil, nil
|
|
|
- }
|
|
|
- return nil, nil
|
|
|
-}
|
|
|
-
|
|
|
-@(require_results)
|
|
|
-dynamic_arena_allocator :: proc(pool: ^Dynamic_Arena) -> Allocator {
|
|
|
- return Allocator{
|
|
|
- procedure = dynamic_arena_allocator_proc,
|
|
|
- data = pool,
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
dynamic_arena_init :: proc(
|
|
|
pool: ^Dynamic_Arena,
|
|
|
block_allocator := context.allocator,
|
|
|
array_allocator := context.allocator,
|
|
|
block_size := DYNAMIC_ARENA_BLOCK_SIZE_DEFAULT,
|
|
|
out_band_size := DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT,
|
|
|
- alignment := 8,
|
|
|
+ alignment := DEFAULT_ALIGNMENT,
|
|
|
) {
|
|
|
pool.block_size = block_size
|
|
|
pool.out_band_size = out_band_size
|
|
@@ -892,6 +834,14 @@ dynamic_arena_init :: proc(
|
|
|
pool.used_blocks.allocator = array_allocator
|
|
|
}
|
|
|
|
|
|
+@(require_results)
|
|
|
+dynamic_arena_allocator :: proc(pool: ^Dynamic_Arena) -> Allocator {
|
|
|
+ return Allocator{
|
|
|
+ procedure = dynamic_arena_allocator_proc,
|
|
|
+ data = pool,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
dynamic_arena_destroy :: proc(pool: ^Dynamic_Arena) {
|
|
|
dynamic_arena_free_all(pool)
|
|
|
delete(pool.unused_blocks)
|
|
@@ -900,62 +850,66 @@ dynamic_arena_destroy :: proc(pool: ^Dynamic_Arena) {
|
|
|
zero(pool, size_of(pool^))
|
|
|
}
|
|
|
|
|
|
-@(require_results)
|
|
|
-dynamic_arena_alloc :: proc(pool: ^Dynamic_Arena, bytes: int) -> (rawptr, Allocator_Error) {
|
|
|
- data, err := dynamic_arena_alloc_bytes(pool, bytes)
|
|
|
+@(private="file")
|
|
|
+_dynamic_arena_cycle_new_block :: proc(p: ^Dynamic_Arena, loc := #caller_location) -> (err: Allocator_Error) {
|
|
|
+ if p.block_allocator.procedure == nil {
|
|
|
+ panic("You must call pool_init on a Pool before using it", loc)
|
|
|
+ }
|
|
|
+ if p.current_block != nil {
|
|
|
+ append(&p.used_blocks, p.current_block, loc=loc)
|
|
|
+ }
|
|
|
+ new_block: rawptr
|
|
|
+ if len(p.unused_blocks) > 0 {
|
|
|
+ new_block = pop(&p.unused_blocks)
|
|
|
+ } else {
|
|
|
+ data: []byte
|
|
|
+ data, err = p.block_allocator.procedure(
|
|
|
+ p.block_allocator.data,
|
|
|
+ Allocator_Mode.Alloc,
|
|
|
+ p.block_size,
|
|
|
+ p.alignment,
|
|
|
+ nil,
|
|
|
+ 0,
|
|
|
+ )
|
|
|
+ new_block = raw_data(data)
|
|
|
+ }
|
|
|
+ p.bytes_left = p.block_size
|
|
|
+ p.current_pos = new_block
|
|
|
+ p.current_block = new_block
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+@(private, require_results)
|
|
|
+_dynamic_arena_alloc_ptr :: proc(pool: ^Dynamic_Arena, size: int, loc := #caller_location) -> (rawptr, Allocator_Error) {
|
|
|
+ data, err := dynamic_arena_alloc(pool, size, loc)
|
|
|
return raw_data(data), err
|
|
|
}
|
|
|
|
|
|
@(require_results)
|
|
|
-dynamic_arena_alloc_bytes :: proc(p: ^Dynamic_Arena, bytes: int) -> ([]byte, Allocator_Error) {
|
|
|
- cycle_new_block :: proc(p: ^Dynamic_Arena) -> (err: Allocator_Error) {
|
|
|
- if p.block_allocator.procedure == nil {
|
|
|
- panic("You must call pool_init on a Pool before using it")
|
|
|
- }
|
|
|
-
|
|
|
- if p.current_block != nil {
|
|
|
- append(&p.used_blocks, p.current_block)
|
|
|
- }
|
|
|
-
|
|
|
- new_block: rawptr
|
|
|
- if len(p.unused_blocks) > 0 {
|
|
|
- new_block = pop(&p.unused_blocks)
|
|
|
- } else {
|
|
|
- data: []byte
|
|
|
- data, err = p.block_allocator.procedure(
|
|
|
- p.block_allocator.data,
|
|
|
- Allocator_Mode.Alloc,
|
|
|
- p.block_size,
|
|
|
- p.alignment,
|
|
|
- nil,
|
|
|
- 0,
|
|
|
- )
|
|
|
- new_block = raw_data(data)
|
|
|
- }
|
|
|
-
|
|
|
- p.bytes_left = p.block_size
|
|
|
- p.current_pos = new_block
|
|
|
- p.current_block = new_block
|
|
|
- return
|
|
|
+dynamic_arena_alloc :: proc(p: ^Dynamic_Arena, size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
|
|
+ bytes, err := dynamic_arena_alloc_non_zeroed(p, size, loc)
|
|
|
+ if bytes != nil {
|
|
|
+ zero_slice(bytes)
|
|
|
}
|
|
|
+ return bytes, err
|
|
|
+}
|
|
|
|
|
|
- n := align_formula(bytes, p.alignment)
|
|
|
+@(require_results)
|
|
|
+dynamic_arena_alloc_non_zeroed :: proc(p: ^Dynamic_Arena, size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
|
|
+ n := align_formula(size, p.alignment)
|
|
|
if n > p.block_size {
|
|
|
return nil, .Invalid_Argument
|
|
|
}
|
|
|
if n >= p.out_band_size {
|
|
|
- assert(p.block_allocator.procedure != nil)
|
|
|
- memory, err := p.block_allocator.procedure(p.block_allocator.data, Allocator_Mode.Alloc,
|
|
|
- p.block_size, p.alignment,
|
|
|
- nil, 0)
|
|
|
+ assert(p.block_allocator.procedure != nil, "Backing block allocator must be initialized", loc=loc)
|
|
|
+ memory, err := alloc_bytes_non_zeroed(p.block_size, p.alignment, p.block_allocator, loc)
|
|
|
if memory != nil {
|
|
|
- append(&p.out_band_allocations, raw_data(memory))
|
|
|
+ append(&p.out_band_allocations, raw_data(memory), loc = loc)
|
|
|
}
|
|
|
return memory, err
|
|
|
}
|
|
|
-
|
|
|
if p.bytes_left < n {
|
|
|
- err := cycle_new_block(p)
|
|
|
+ err := _dynamic_arena_cycle_new_block(p, loc)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
@@ -963,41 +917,86 @@ dynamic_arena_alloc_bytes :: proc(p: ^Dynamic_Arena, bytes: int) -> ([]byte, All
|
|
|
return nil, .Out_Of_Memory
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
memory := p.current_pos
|
|
|
p.current_pos = ([^]byte)(p.current_pos)[n:]
|
|
|
p.bytes_left -= n
|
|
|
- return ([^]byte)(memory)[:bytes], nil
|
|
|
+ return ([^]byte)(memory)[:size], nil
|
|
|
}
|
|
|
|
|
|
-dynamic_arena_reset :: proc(p: ^Dynamic_Arena) {
|
|
|
+dynamic_arena_reset :: proc(p: ^Dynamic_Arena, loc := #caller_location) {
|
|
|
if p.current_block != nil {
|
|
|
- append(&p.unused_blocks, p.current_block)
|
|
|
+ append(&p.unused_blocks, p.current_block, loc=loc)
|
|
|
p.current_block = nil
|
|
|
}
|
|
|
-
|
|
|
for block in p.used_blocks {
|
|
|
- append(&p.unused_blocks, block)
|
|
|
+ append(&p.unused_blocks, block, loc=loc)
|
|
|
}
|
|
|
clear(&p.used_blocks)
|
|
|
-
|
|
|
for a in p.out_band_allocations {
|
|
|
- free(a, p.block_allocator)
|
|
|
+ free(a, p.block_allocator, loc=loc)
|
|
|
}
|
|
|
clear(&p.out_band_allocations)
|
|
|
-
|
|
|
- p.bytes_left = 0 // Make new allocations call `cycle_new_block` again.
|
|
|
+ p.bytes_left = 0 // Make new allocations call `_dynamic_arena_cycle_new_block` again.
|
|
|
}
|
|
|
|
|
|
dynamic_arena_free_all :: proc(p: ^Dynamic_Arena) {
|
|
|
dynamic_arena_reset(p)
|
|
|
-
|
|
|
for block in p.unused_blocks {
|
|
|
free(block, p.block_allocator)
|
|
|
}
|
|
|
clear(&p.unused_blocks)
|
|
|
}
|
|
|
|
|
|
+dynamic_arena_allocator_proc :: proc(
|
|
|
+ allocator_data: rawptr,
|
|
|
+ mode: Allocator_Mode,
|
|
|
+ size: int,
|
|
|
+ alignment: int,
|
|
|
+ old_memory: rawptr,
|
|
|
+ old_size: int,
|
|
|
+ loc := #caller_location,
|
|
|
+) -> ([]byte, Allocator_Error) {
|
|
|
+ pool := (^Dynamic_Arena)(allocator_data)
|
|
|
+
|
|
|
+ switch mode {
|
|
|
+ case .Alloc:
|
|
|
+ return dynamic_arena_alloc(pool, size, loc)
|
|
|
+ case .Alloc_Non_Zeroed:
|
|
|
+ return dynamic_arena_alloc_non_zeroed(pool, size, loc)
|
|
|
+ case .Free:
|
|
|
+ return nil, .Mode_Not_Implemented
|
|
|
+ case .Free_All:
|
|
|
+ dynamic_arena_free_all(pool)
|
|
|
+ return nil, nil
|
|
|
+ case .Resize, .Resize_Non_Zeroed:
|
|
|
+ if old_size >= size {
|
|
|
+ return byte_slice(old_memory, size), nil
|
|
|
+ }
|
|
|
+ data, err := dynamic_arena_alloc(pool, size)
|
|
|
+ if err == nil {
|
|
|
+ runtime.copy(data, byte_slice(old_memory, old_size))
|
|
|
+ }
|
|
|
+ return data, err
|
|
|
+
|
|
|
+ case .Query_Features:
|
|
|
+ set := (^Allocator_Mode_Set)(old_memory)
|
|
|
+ if set != nil {
|
|
|
+ set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features, .Query_Info}
|
|
|
+ }
|
|
|
+ return nil, nil
|
|
|
+
|
|
|
+ case .Query_Info:
|
|
|
+ info := (^Allocator_Query_Info)(old_memory)
|
|
|
+ if info != nil && info.pointer != nil {
|
|
|
+ info.size = pool.block_size
|
|
|
+ info.alignment = pool.alignment
|
|
|
+ return byte_slice(info, size_of(info^)), nil
|
|
|
+ }
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+ return nil, nil
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
|
|
|
panic_allocator_proc :: proc(
|