diff --git a/code/ast_formatting.odin b/code/ast_formatting.odin new file mode 100644 index 0000000..e69de29 diff --git a/code/ast_text.odin b/code/ast_text.odin new file mode 100644 index 0000000..e69de29 diff --git a/code/ast_whitespace.odin b/code/ast_whitespace.odin new file mode 100644 index 0000000..e69de29 diff --git a/code/grime.odin b/code/grime.odin index 0acf8cb..171f6e9 100644 --- a/code/grime.odin +++ b/code/grime.odin @@ -3,6 +3,9 @@ package sectr import "base:builtin" copy :: builtin.copy +import "base:intrinsics" + type_has_field :: intrinsics.type_has_field + type_elem_type :: intrinsics.type_elem_type import "base:runtime" Byte :: runtime.Byte Kilobyte :: runtime.Kilobyte @@ -54,6 +57,19 @@ import str "core:strings" str_builder_to_string :: str.to_string import "core:unicode/utf8" +OS_Type :: type_of(ODIN_OS) + +// Alias Tables + +get_bounds :: proc { + box_get_bounds, + view_get_bounds, +} + +is_power_of_two :: proc { + is_power_of_two_u32, +} + to_runes :: proc { utf8.string_to_runes, } @@ -61,47 +77,3 @@ to_runes :: proc { to_string :: proc { str_builder_to_string, } - -OS_Type :: type_of(ODIN_OS) - -kilobytes :: #force_inline proc "contextless" ( kb : $ integer_type ) -> integer_type { - return kb * Kilobyte -} -megabytes :: #force_inline proc "contextless" ( mb : $ integer_type ) -> integer_type { - return mb * Megabyte -} -gigabytes :: #force_inline proc "contextless" ( gb : $ integer_type ) -> integer_type { - return gb * Gigabyte -} -terabytes :: #force_inline proc "contextless" ( tb : $ integer_type ) -> integer_type { - return tb * Terabyte -} - -get_bounds :: proc { - box_get_bounds, - view_get_bounds, -} - -// TODO(Ed): Review -//region Doubly Linked List generic procs (verbose) - -dbl_linked_list_push_back :: proc(first: ^(^ $ Type), last: ^(^ Type), new_node: ^ Type) -{ - if first == nil || first^ == nil { - // List is empty, set first and last to the new node - (first ^) = new_node - (last ^) = new_node - new_node.next = nil - new_node.prev = nil - } - else - { - // List is not empty, add new node to the end - (last^).next = new_node - new_node.prev = last^ - (last ^) = new_node - new_node.next = nil - } -} - -//endregion diff --git a/code/grime_array.odin b/code/grime_array.odin index 94eb43e..de16409 100644 --- a/code/grime_array.odin +++ b/code/grime_array.odin @@ -15,9 +15,6 @@ Array :: struct ( $ Type : typeid ) { data : [^]Type, } -// @(private=file) -// Array :: Array_ZPL - array_to_slice :: proc( using self : Array( $ Type) ) -> []Type { return slice_ptr( data, num ) } diff --git a/code/grime_hashmap_msi.odin b/code/grime_hashmap_msi.odin new file mode 100644 index 0000000..69942fe --- /dev/null +++ b/code/grime_hashmap_msi.odin @@ -0,0 +1,27 @@ +// Mask-Step-Index (MSI) Hash Table implementation. +// See: https://nullprogram.com/blog/2022/08/08/ +package sectr +// TODO(Ed) : This is a wip, I haven't gotten the nuance of this mess down pact. + +// Compute a mask, then a step size, and finally an index. +// The exponent parameter is a power-of-two exponent for the hash-table size. +msi_hmap_lookup :: proc ( hash : u64, exponent, index : u32 ) -> (candidate_index : i32) +{ + mask := u32(1 << (exponent)) - 1 + step := u32(hash >> (64 - exponent)) | 1 + candidate_index = i32( (index + step) & mask ) + return +} + +HMap_MSI :: struct ( $ Type : typeid, $ Size : u32 ) + where is_power_of_two( Size ) +{ + hashes : [ Size ]( ^ Type ), + length : i32 +} + +HMap_MSI_Dyn :: struct ( $ Type : typeid ) { + hashes : Array( DLL_Node( ^ Type ) ), + size : u64, + length : i32, +} diff --git a/code/grime_hashmap_rjf.odin b/code/grime_hashmap_rjf.odin new file mode 100644 index 0000000..c33b213 --- /dev/null +++ b/code/grime_hashmap_rjf.odin @@ -0,0 +1,39 @@ +// This was an attempt to learn Ryan's hash table implementation used with the UI module of the RAD Debugger. +// Its not completed +package sectr + +HMapRJF :: struct ( $ Type : typeid ) { + slots : Array ( DLL_NodeFL( Type ) ), + size : u64, + first_free : ^ Type, +} + +rjf_hmap_init :: proc( $ Type : typeid, allocator : Allocator, size : u64 ) -> ( HMapRJF( Type ), AllocatorError ) { + result : HMapRJF( Type ) + alloc_error : AllocatorError + + result.slots, alloc_error := array_init_reserve( Type, allocator, size ) + if alloc_error != AllocatorError.None { + ensure( false, "Failed to allocate slots array" ) + return result, alloc_error + } + array_resize( & result.slots, size ) + + return result, AllocatorError.None +} + +rjf_hmap_slot_index :: #force_inline proc ( using self : HMapRJF( $ Type ), key : u64 ) -> u64 { + return key % size +} + +rjf_hmap_get_slot :: #force_inline proc ( using self : HMapRJF ( $ Type ), key : u64 ) -> ^ DLL_NodeFL ( Type ) { + slot_index := key % size + return & slots[ slot_index ] +} + +rjf_hmap_insert :: proc ( using self : HMapRJF ( $ Type ), key : u64, value : ^ Type ) { + slot_index := key % size + slot := & slots[ slot_index ] + + dll_insert_raw( nil, slot.first, slot.last, slot.last, value ) +} diff --git a/code/grime_hashmap_zpl_based.odin b/code/grime_hashmap_zpl.odin similarity index 97% rename from code/grime_hashmap_zpl_based.odin rename to code/grime_hashmap_zpl.odin index 4c6799e..bdaa8e7 100644 --- a/code/grime_hashmap_zpl_based.odin +++ b/code/grime_hashmap_zpl.odin @@ -17,6 +17,7 @@ HMapZPL_MapProc :: #type proc( $ Type : typeid, key : u64, value : Type ) HMapZPL_MapMutProc :: #type proc( $ Type : typeid, key : u64, value : ^ Type ) HMapZPL_CritialLoadScale :: 0.70 +HMapZPL_HashToEntryRatio :: 1.50 HMapZPL_FindResult :: struct { hash_index : i64, @@ -44,12 +45,14 @@ zpl_hmap_init_reserve :: proc( $ Type : typeid, allocator : Allocator, num : u64 result : HMapZPL(Type) hashes_result, entries_result : AllocatorError - result.hashes, hashes_result = array_init_reserve( i64, allocator, num ) + hashes_size := cast(u64) (HMapZPL_HashToEntryRatio * f32(num)) + + result.hashes, hashes_result = array_init_reserve( i64, allocator, hashes_size ) if hashes_result != AllocatorError.None { ensure( false, "Failed to allocate hashes array" ) return result, hashes_result } - array_resize( & result.hashes, num ) + array_resize( & result.hashes, hashes_size ) slice.fill( slice_ptr( result.hashes.data, cast(int) result.hashes.num), -1 ) result.entries, entries_result = array_init_reserve( HMapZPL_Entry(Type), allocator, num ) diff --git a/code/grime_linked_list.odin b/code/grime_linked_list.odin new file mode 100644 index 0000000..f11d589 --- /dev/null +++ b/code/grime_linked_list.odin @@ -0,0 +1,71 @@ +// I'm not sure about this, it was created to figure out Ryan's linked-list usage in the UI module of the RAD Debugger. +// The code takes advantage of macros for the linked list interface in a way that odin doesn't really permit without a much worse interface. +package sectr + +DLL_Node :: struct ( $ Type : typeid ) #raw_union { + using _ : struct { + left, right : ^ Type, + }, + using _ : struct { + prev, next : ^ Type, + }, + using _ : struct { + first, last : ^ Type, + }, +} + +DLL_NodeFull :: struct ( $ Type : typeid ) { + first, last, prev, next : ^ Type, +} + +DLL_NodeLR :: struct ( $ Type : typeid ) { + left, right : ^ Type, +} + +DLL_NodePN :: struct ( $ Type : typeid ) { + prev, next : ^ Type, +} + +DLL_NodeFL :: struct ( $ Type : typeid ) { + first, last : ^ Type, +} + +type_is_node :: #force_inline proc "contextless" ( $ Type : typeid ) -> b32 +{ + // elem_type := type_elem_type(Type) + return type_has_field( type_elem_type(Type), "prev" ) && type_has_field( type_elem_type(Type), "next" ) +} + +dll_insert_raw :: proc "contextless" ( null, first, last, position, new : ^ DLL_Node( $ Type ) ) +{ + // Empty Case + if first == null { + first = new + last = new + new.next = null + new.prev = null + } + else if position == null { + // Position is not set, insert at beginning + new.next = first + first.prev = new + first = new + new.prev = null + } + else if position == last { + // Positin is set to last, insert at end + last.next = new + new.prev = last + last = new + new.next = null + } + else { + // Insert around position + if position.next != null { + position.next.prev = new + } + new.next = position.next + position.next = new + new.prev = position + } +} diff --git a/code/grime_memory.odin b/code/grime_memory.odin index ab3d1d5..588f3f6 100644 --- a/code/grime_memory.odin +++ b/code/grime_memory.odin @@ -7,6 +7,19 @@ import "core:mem/virtual" import "core:runtime" import "core:os" +kilobytes :: #force_inline proc "contextless" ( kb : $ integer_type ) -> integer_type { + return kb * Kilobyte +} +megabytes :: #force_inline proc "contextless" ( mb : $ integer_type ) -> integer_type { + return mb * Megabyte +} +gigabytes :: #force_inline proc "contextless" ( gb : $ integer_type ) -> integer_type { + return gb * Gigabyte +} +terabytes :: #force_inline proc "contextless" ( tb : $ integer_type ) -> integer_type { + return tb * Terabyte +} + // Initialize a sub-section of our virtual memory as a sub-arena sub_arena_init :: proc( address : ^ byte, size : int ) -> ( ^ Arena) { Arena :: mem.Arena diff --git a/code/math.odin b/code/math.odin index 6432a88..69151bf 100644 --- a/code/math.odin +++ b/code/math.odin @@ -1,5 +1,10 @@ package sectr +is_power_of_two_u32 :: proc( value : u32 ) -> b32 +{ + return value != 0 && ( value & ( value - 1 )) == 0 +} + import "core:math/linalg" Vec2 :: linalg.Vector2f32 @@ -7,31 +12,3 @@ Vec3 :: linalg.Vector3f32 Vec2i :: [2]i32 Vec3i :: [3]i32 - -when false { -// TODO(Ed) : Evaluate if this is needed - -Vec2 :: Vec2_f32 -Vec2_f32 :: struct #raw_union { - basis : [2] f32, - using components : struct { - x, y : f32 - } -} - -// make_vec2 :: proc( x, y : f32 ) { - -// } - -Vec3 :: Vec3_f32 -Vec3_f32 :: struct #raw_union { - basis : [3] f32, - using components : struct { - x, y, z : f32 - } -} -} - - - - diff --git a/code/ui.odin b/code/ui.odin index 80288b7..972b095 100644 --- a/code/ui.odin +++ b/code/ui.odin @@ -187,7 +187,8 @@ UI_Box :: struct { label : string, // Regenerated per frame. - first, last, prev, next, parent : ^ UI_Box, + using _ : DLL_NodeFull( UI_Box ), // first, last, prev, next + parent : ^ UI_Box, num_children : i32, flags : UI_BoxFlags, @@ -195,8 +196,9 @@ UI_Box :: struct { style : UI_Style, // Persistent Data + // hash_links : DLL_Node_PN( ^ UI_Box), // This isn't necessary if not using RJF hash table. // prev_computed : UI_Computed, - // prev_style : UI_Style, + // prev_style : UI_Style,v mouse : UI_InteractState, keyboard : UI_InteractState, } @@ -240,7 +242,6 @@ UI_State :: struct { drag_start_mouse : Vec2, // drag_state_arena : ^ Arena, // drag_state data : string, - } ui_key_from_string :: proc( value : string ) -> UI_Key { diff --git a/code/ui_proto.odin b/code/ui_proto.odin deleted file mode 100644 index 599978d..0000000 --- a/code/ui_proto.odin +++ /dev/null @@ -1,5 +0,0 @@ -package sectr - - - - diff --git a/code/ui_rjf.odin b/code/ui_rjf.odin new file mode 100644 index 0000000..58f965b --- /dev/null +++ b/code/ui_rjf.odin @@ -0,0 +1,43 @@ +package sectr + +when false { + ui_box_cache_insert :: proc( using cache : HMap_RJF( ^ UI_Box ), key : u64, value : ^ UI_Box ) -> ^ UI_Box { + slot := rjf_hmap_get_slot( cache, key ) + + // dll_insert_raw( nil, slot.first, slot.last, slot.last, value ) + { + new_links := & new.hash_links + + // Empty Case + if first == null { + first = new + last = new + new_links.next = null + new_links.prev = null + } + else if position == null { + // Position is not set, insert at beginning + new_links.next = first + first.first = new + first = new + new_links.prev = null + } + else if position == last { + // Positin is set to last, insert at end + last.last = new + new_links.prev = last + last = new + new_links.next = null + } + else { + // Insert around position + if position.next != null { + position.next.prev = new + } + new.next = position.next + position.next = new + new.prev = position + } + } + } +}