From e84ec719b3bbe5f9d66d1349d23e71585a585797 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Fri, 31 May 2024 19:31:27 -0400 Subject: [PATCH] Progress on lifting the 'grime' module to its own package --- code/grime/array.odin | 43 +++++++++------------ code/{sectr => }/grime/hashmap_chained.odin | 6 +-- code/grime/mappings.odin | 9 +++++ code/grime/math.odin | 7 ++++ code/{sectr => }/grime/pool_allocator.odin | 6 +-- code/{sectr => }/grime/slab_allocator.odin | 8 ++-- code/sectr/font/provider.odin | 2 +- code/sectr/grime/mappings.odin | 21 ++++++++++ code/sectr/ui/floating.odin | 4 +- 9 files changed, 68 insertions(+), 38 deletions(-) rename code/{sectr => }/grime/hashmap_chained.odin (98%) rename code/{sectr => }/grime/pool_allocator.odin (99%) rename code/{sectr => }/grime/slab_allocator.odin (98%) diff --git a/code/grime/array.odin b/code/grime/array.odin index 4e5d1ae..f00c53a 100644 --- a/code/grime/array.odin +++ b/code/grime/array.odin @@ -37,13 +37,8 @@ array_underlying_slice :: proc(slice: []($ Type)) -> Array(Type) return array_ptr ^ } -array_to_slice :: proc( using self : Array($ Type) ) -> []Type { - return slice_ptr( data, int(num) ) -} - -array_to_slice_capacity :: proc( using self : Array($ Type) ) -> []Type { - return slice_ptr( data, int(capacity)) -} +array_to_slice :: #force_inline proc( using self : Array($ Type) ) -> []Type { return slice_ptr( data, int(num)) } +array_to_slice_capacity :: #force_inline proc( using self : Array($ Type) ) -> []Type { return slice_ptr( data, int(capacity)) } array_grow_formula :: proc( value : u64 ) -> u64 { result := (2 * value) + 8 @@ -71,22 +66,6 @@ array_init :: proc( $Array_Type : typeid/Array($Type), capacity : u64, return } -array_append_value :: proc( self : ^Array( $ Type), value : Type ) -> AllocatorError -{ - // profile(#procedure) - if self.header.num == self.header.capacity - { - grow_result := array_grow( self, self.header.capacity ) - if grow_result != AllocatorError.None { - return grow_result - } - } - - self.header.data[ self.header.num ] = value - self.header.num += 1 - return AllocatorError.None -} - array_append_array :: proc( using self: ^Array( $ Type), other : Array(Type)) -> AllocatorError { if num + other.num > capacity @@ -127,7 +106,23 @@ array_append_slice :: proc( using self : ^Array( $ Type ), items : []Type ) -> A return AllocatorError.None } -array_append_at :: proc( using self : ^Array( $ Type ), item : Type, id : u64 ) -> AllocatorError +array_append_value :: proc( self : ^Array( $ Type), value : Type ) -> AllocatorError +{ + // profile(#procedure) + if self.header.num == self.header.capacity + { + grow_result := array_grow( self, self.header.capacity ) + if grow_result != AllocatorError.None { + return grow_result + } + } + + self.header.data[ self.header.num ] = value + self.header.num += 1 + return AllocatorError.None +} + +array_append_at_value :: proc( using self : ^Array( $ Type ), item : Type, id : u64 ) -> AllocatorError { id := id if id >= num { diff --git a/code/sectr/grime/hashmap_chained.odin b/code/grime/hashmap_chained.odin similarity index 98% rename from code/sectr/grime/hashmap_chained.odin rename to code/grime/hashmap_chained.odin index f2dace6..c2a6c3d 100644 --- a/code/sectr/grime/hashmap_chained.odin +++ b/code/grime/hashmap_chained.odin @@ -11,7 +11,7 @@ If its occupied a new slot is chained using the fixed bucket-size pool allocator This is ideal for tables have an indeterminate scope for how entires are added, and direct pointers are kept across the codebase instead of a key to the slot. */ -package sectr +package grime import "core:mem" @@ -55,7 +55,7 @@ hmap_chained_init :: proc( $HMapChainedType : typeid/HMapChained($Type), lookup_ pool_bucket_cap : uint = 1 * Kilo, pool_bucket_reserve_num : uint = 0, pool_alignment : uint = mem.DEFAULT_ALIGNMENT, - dbg_name : string = "" + // dbg_name : string = "" ) -> (table : HMapChained(Type), error : AllocatorError) { header_size := size_of(HMapChainedHeader(Type)) @@ -73,7 +73,7 @@ hmap_chained_init :: proc( $HMapChainedType : typeid/HMapChained($Type), lookup_ bucket_reserve_num = pool_bucket_reserve_num, alignment = pool_alignment, allocator = allocator, - dbg_name = str_intern(str_fmt("%v: pool", dbg_name)).str + // dbg_name = str_intern(str_fmt("%v: pool", dbg_name)).str ) data := transmute([^] ^HMapChainedSlot(Type)) (transmute( [^]HMapChainedHeader(Type)) table.header)[1:] table.lookup = slice_ptr( data, int(lookup_capacity) ) diff --git a/code/grime/mappings.odin b/code/grime/mappings.odin index 413882f..3bb02ef 100644 --- a/code/grime/mappings.odin +++ b/code/grime/mappings.odin @@ -133,6 +133,11 @@ array_append :: proc { array_append_slice, } +array_append_at :: proc { + array_append_at_slice, + array_append_at_value, +} + is_power_of_two :: proc { is_power_of_two_u32, is_power_of_two_uintptr, @@ -152,6 +157,10 @@ make :: proc { make_multi_pointer, } +push :: proc { + stack_push, +} + to_string :: proc { runes_to_string, str_builder_to_string, diff --git a/code/grime/math.odin b/code/grime/math.odin index 4e187d6..ebc8ffe 100644 --- a/code/grime/math.odin +++ b/code/grime/math.odin @@ -1,5 +1,12 @@ package grime +Kilo :: Kilobyte +Mega :: Megabyte +Giga :: Gigabyte +Tera :: Terabyte +Peta :: Petabyte +Exa :: Exabyte + is_power_of_two_u32 :: #force_inline proc "contextless" ( value : u32 ) -> b32 { return value != 0 && ( value & ( value - 1 )) == 0 diff --git a/code/sectr/grime/pool_allocator.odin b/code/grime/pool_allocator.odin similarity index 99% rename from code/sectr/grime/pool_allocator.odin rename to code/grime/pool_allocator.odin index 3823070..9e937a2 100644 --- a/code/sectr/grime/pool_allocator.odin +++ b/code/grime/pool_allocator.odin @@ -11,7 +11,7 @@ there can be a large discrepancy of memory localicty if buckets are small. The pool doesn't allocate any buckets on initialization unless the user specifies. */ -package sectr +package grime import "base:intrinsics" import "base:runtime" @@ -56,7 +56,7 @@ pool_init :: proc ( bucket_reserve_num : uint = 0, alignment : uint = mem.DEFAULT_ALIGNMENT, allocator : Allocator = context.allocator, - dbg_name : string, + dbg_name : string = "", ) -> ( pool : Pool, alloc_error : AllocatorError ) { header_size := align_forward_int( size_of(PoolHeader), int(alignment) ) @@ -334,7 +334,7 @@ pool_validate_ownership :: proc( using self : Pool, block : [] byte ) -> b32 within_bucket := b32(false) // Compiler Bug : Same as pool_reset - bucket : ^PoolBucket = bucket_list.first + bucket : ^PoolBucket = bucket_list.first for ; bucket != nil; bucket = bucket.next { start := uintptr( bucket.blocks ) diff --git a/code/sectr/grime/slab_allocator.odin b/code/grime/slab_allocator.odin similarity index 98% rename from code/sectr/grime/slab_allocator.odin rename to code/grime/slab_allocator.odin index bded63b..27623c8 100644 --- a/code/sectr/grime/slab_allocator.odin +++ b/code/grime/slab_allocator.odin @@ -7,10 +7,6 @@ or dedicated pool allocator fail to be enough to handle a data structure that either is too random with its size (ex: strings) or is intended to grow an abitrary degree with an unknown upper bound (dynamic arrays, and hashtables). -The protototype will use slab allocators for two purposes: -* String interning -* General purpose set for handling large arrays & hash tables within some underlying arena or stack. - Technically speaking the general purpose situations can instead be grown on demand with a dedicated segement of vmem, however this might be overkill if the worst case buckets allocated are < 500 mb for most app usage. @@ -26,7 +22,7 @@ A slab starts out with pools initialized with no buckets and grows as needed. When a slab is initialized the slab policy is provided to know how many size-classes there should be which each contain the ratio of bucket to block size. */ -package sectr +package grime import "base:runtime" import "core:mem" @@ -284,6 +280,8 @@ slab_reset :: proc( slab : Slab ) slab_validate_pools :: proc( slab : Slab ) { + when ! ODIN_DEBUG do return + slab := slab for id in 0 ..< slab.pools.idx { pool := slab.pools.items[id] diff --git a/code/sectr/font/provider.odin b/code/sectr/font/provider.odin index aaae7fc..a971c36 100644 --- a/code/sectr/font/provider.odin +++ b/code/sectr/font/provider.odin @@ -79,7 +79,7 @@ font_provider_startup :: proc() font_provider_data := & get_state().font_provider_data; using font_provider_data font_cache_alloc_error : AllocatorError - font_cache, font_cache_alloc_error = make( HMapChained(FontDef), hmap_closest_prime(1 * Kilo), persistent_allocator(), dbg_name = "font_cache" ) + font_cache, font_cache_alloc_error = make( HMapChained(FontDef), hmap_closest_prime(1 * Kilo), persistent_allocator() /*dbg_name = "font_cache"*/ ) verify( font_cache_alloc_error == AllocatorError.None, "Failed to allocate font_cache" ) log("font_cache created") diff --git a/code/sectr/grime/mappings.odin b/code/sectr/grime/mappings.odin index 280fd53..ee259be 100644 --- a/code/sectr/grime/mappings.odin +++ b/code/sectr/grime/mappings.odin @@ -165,6 +165,27 @@ import "codebase:grime" array_remove_at :: grime.array_remove_at array_resize :: grime.array_resize + HMapChained :: grime.HMapChained + + hmap_closest_prime :: grime.hmap_closest_prime + + hmap_chained_get :: grime.hmap_chained_get + hmap_chained_init :: grime.hmap_chained_init + hmap_chained_set :: grime.hmap_chained_set + hmap_chained_reload :: grime.hmap_chained_reload + + Pool :: grime.Pool + + Slab :: grime.Slab + SlabPolicy :: grime.SlabPolicy + SlabSizeClass :: grime.SlabSizeClass + + slab_allocator :: grime.slab_allocator + slab_alloc :: grime.slab_alloc + slab_init :: grime.slab_init + slab_reload :: grime.slab_reload + slab_validate_pools :: grime.slab_validate_pools + StackFixed :: grime.StackFixed stack_clear :: grime.stack_clear diff --git a/code/sectr/ui/floating.odin b/code/sectr/ui/floating.odin index c5ab163..bc68d7f 100644 --- a/code/sectr/ui/floating.odin +++ b/code/sectr/ui/floating.odin @@ -29,8 +29,8 @@ ui_floating_startup :: proc( self : ^UI_FloatingManager, build_queue_cap, tracke return error } - tracked_dbg_name := str_intern(str_fmt("%s: tracked", dbg_name)) - self.tracked, error = make( HMapChained(UI_Floating), uint(tracked_cap), allocator, dbg_name = tracked_dbg_name.str ) + // tracked_dbg_name := str_intern(str_fmt("%s: tracked", dbg_name)) + self.tracked, error = make( HMapChained(UI_Floating), uint(tracked_cap), allocator, /*dbg_name = tracked_dbg_name.str*/ ) if error != AllocatorError.None { ensure(false, "Failed to allocate tracking table")