From d0127ded519d709e9fa55bccc18a3bb8f236f536 Mon Sep 17 00:00:00 2001 From: Byron Hodel Date: Fri, 21 Feb 2025 21:34:29 -0500 Subject: [PATCH 1/3] Added arena resize procedures and modified arena allocator proc to utilize new resize procs --- core/mem/allocators.odin | 152 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 2 deletions(-) diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 028be58e3ea..667c16a7900 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -234,6 +234,154 @@ arena_free_all :: proc(a: ^Arena) { a.offset = 0 } +/* +Resize an allocation. + +This procedure resizes a memory region, specified by `old_data`, to have a size +`size` and alignment `alignment`. The newly allocated memory, if any +is not explicityly zero-initialized. + +If `old_memory` is `nil`, this procedure acts just like `arena_alloc_bytes_non_zeroed()`, +allocating a memory region `size` bytes in size, aligned on a boundary specified +by `alignment`. + +If `size` is 0 and there is no memory allocated after the `old_data`, this procedure +will free the memory. + +This procedure returns the slice of the resized memory region. +*/ +arena_resize_bytes_non_zeroed :: proc( + a: ^Arena, + old_data: []byte, + size: int, + alignment := DEFAULT_ALIGNMENT, + loc := #caller_location, +) -> ([]byte, Allocator_Error) { + if old_data == nil { + return arena_alloc_bytes_non_zeroed(a, size, loc=loc) + } + if size == len(old_data) { + return old_data, nil + } + + old_data_offset := cast(int)(cast(uintptr)raw_data(old_data) - cast(uintptr)raw_data(a.data)) + if a.offset - len(old_data) == old_data_offset { + if size == 0 { + a.offset = old_data_offset + return nil, nil + } + + new_offset := old_data_offset + size + if new_offset > len(a.data) { + return old_data, .Out_Of_Memory + } + + a.offset = new_offset + return a.data[old_data_offset:][:size], nil + } else { + if size == 0 { + return nil, nil + } + new_data, err := arena_alloc_bytes_non_zeroed(a, size, alignment, loc) + if err != nil { + return old_data, nil + } + copy_non_overlapping(raw_data(new_data), raw_data(old_data), len(old_data)) + return new_data, nil + } +} + +/* +Resize an allocation. + +This procedure resizes a memory region, specified by `old_data` and `old_size`, +to have a size `size` and alignment `alignment`. The newly allocated memory, +if any is not explicityly zero-initialized. + +If `old_memory` is `nil`, this procedure acts just like `arena_alloc_non_zeroed()`, +allocating a memory region `size` bytes in size, aligned on a boundary specified +by `alignment`. + +If `size` is 0 and there is no memory allocated after the `old_data`, this procedure +will free the memory. + +This procedure returns a raw pointer of the resized memory region. +*/ +arena_resize_non_zeroed :: proc( + a: ^Arena, + old_data: rawptr, + old_size: int, + size: int, + alignment := DEFAULT_ALIGNMENT, + loc := #caller_location, +) -> (rawptr, Allocator_Error) { + bytes, err := arena_resize_bytes(a, byte_slice(old_data, old_size), size, alignment, loc) + return raw_data(bytes), err +} + +/* +Resize an allocation. + +This procedure resizes a memory region, specified by `old_data`, to have a size +`size` and alignment `alignment`. The newly allocated memory, if any +is zero-initialized. + +If `old_memory` is `nil`, this procedure acts just like `arena_alloc_bytes()`, +allocating a memory region `size` bytes in size, aligned on a boundary specified +by `alignment`. + +If `size` is 0 and there is no memory allocated after the `old_data`, this procedure +will free the memory. + +This procedure returns the slice of the resized memory region. +*/ +@(require_results) +arena_resize_bytes :: proc( + a: ^Arena, + old_data: []byte, + size: int, + alignment := DEFAULT_ALIGNMENT, + loc := #caller_location, +) -> ([]byte, Allocator_Error) { + bytes, err := arena_resize_bytes_non_zeroed(a, old_data, size, alignment, loc) + if bytes != nil { + if old_data == nil { + zero_slice(bytes) + } else if size > len(old_data) { + zero_slice(bytes[len(old_data):]) + } + } + return bytes, err +} + +/* +Resize an allocation. + +This procedure resizes a memory region, specified by `old_data` and `old_size`, +to have a size `size` and alignment `alignment`. The newly allocated memory, +if any is zero-initialized. + +If `old_memory` is `nil`, this procedure acts just like `arena_alloc()`, +allocating a memory region `size` bytes in size, aligned on a boundary specified +by `alignment`. + +If `size` is 0 and there is no memory allocated after the `old_data`, this procedure +will free the memory. + +This procedure returns a raw pointer of the resized memory region. +*/ +arena_resize :: proc( + a: ^Arena, + old_data: rawptr, + old_size: int, + size: int, + alignment := DEFAULT_ALIGNMENT, + loc := #caller_location, +) -> (rawptr, Allocator_Error) { + bytes, err := arena_resize_bytes(a, byte_slice(old_data, old_size), size, alignment, loc) + return raw_data(bytes), err +} + arena_allocator_proc :: proc( allocator_data: rawptr, mode: Allocator_Mode, @@ -254,9 +402,9 @@ arena_allocator_proc :: proc( case .Free_All: arena_free_all(arena) case .Resize: - return default_resize_bytes_align(byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena), loc) + return arena_resize_bytes(arena, byte_slice(old_memory, old_size), size, alignment, loc) case .Resize_Non_Zeroed: - return default_resize_bytes_align_non_zeroed(byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena), loc) + return arena_resize_bytes_non_zeroed(arena, byte_slice(old_memory, old_size), size, alignment, loc) case .Query_Features: set := (^Allocator_Mode_Set)(old_memory) if set != nil { From 20e076cdbbfcb13fdb6d3c601ad5dd3011768c3e Mon Sep 17 00:00:00 2001 From: Byron Hodel Date: Sun, 23 Feb 2025 12:48:22 -0500 Subject: [PATCH 2/3] added line to update peak memory usage when allocation grows in place --- core/mem/allocators.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 667c16a7900..18b3bd8e6bb 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -277,6 +277,7 @@ arena_resize_bytes_non_zeroed :: proc( } a.offset = new_offset + a.peak_used = max(a.peak_used, a.offset) return a.data[old_data_offset:][:size], nil } else { if size == 0 { From 02aeab71a0504cd82a9bd53b3a31beb312e60c0a Mon Sep 17 00:00:00 2001 From: Byron Hodel Date: Sun, 23 Feb 2025 12:56:47 -0500 Subject: [PATCH 3/3] fixed returning nil error when arena alloc fails --- core/mem/allocators.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 18b3bd8e6bb..487f276729d 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -285,7 +285,7 @@ arena_resize_bytes_non_zeroed :: proc( } new_data, err := arena_alloc_bytes_non_zeroed(a, size, alignment, loc) if err != nil { - return old_data, nil + return old_data, err } copy_non_overlapping(raw_data(new_data), raw_data(old_data), len(old_data)) return new_data, nil