From ec07c70dcf6ec802b15be7e6d2606feffa876df4 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 5 Dec 2024 23:02:26 -0500 Subject: [PATCH] verified the C hashtable has parity with the C++ templated gencpp hashtable. --- gen_c_library/c_library.cpp | 3 +- gen_c_library/components/containers.array.hpp | 35 +-- .../components/containers.hashtable.hpp | 241 ++++++++++++------ gen_c_library/components/misc.hpp | 8 + project/dependencies/containers.hpp | 86 +++++-- project/dependencies/macros.hpp | 13 +- .../helpers/pop_container_defines.inline.hpp | 7 +- .../helpers/push_container_defines.inline.hpp | 7 +- 8 files changed, 268 insertions(+), 132 deletions(-) diff --git a/gen_c_library/c_library.cpp b/gen_c_library/c_library.cpp index 162bb3d..ecfe547 100644 --- a/gen_c_library/c_library.cpp +++ b/gen_c_library/c_library.cpp @@ -397,8 +397,9 @@ int gen_main() containers.append( gen_array_base() ); containers.append( gen_array_generic_selection_interface()); containers.append( gen_hashtable_base() ); - containers.append(fmt_newline); + containers.append( gen_hashtable_generic_selection_interface()); + containers.append(array_ssize); containers.append( def_pragma(code(endregion Containers))); diff --git a/gen_c_library/components/containers.array.hpp b/gen_c_library/components/containers.array.hpp index 5d25bae..7a6b470 100644 --- a/gen_c_library/components/containers.array.hpp +++ b/gen_c_library/components/containers.array.hpp @@ -5,7 +5,7 @@ using namespace gen; // Used to know what slot the array will be for generic selection -global s32 ArrayDefinitionCounter = 0; +global s32 Array_DefinitionCounter = 0; CodeBody gen_array_base() { @@ -359,8 +359,8 @@ CodeBody gen_array( StrC type, StrC array_name ) #pragma pop_macro( "typeof" ) #pragma pop_macro( "forceinline" ) - ++ ArrayDefinitionCounter; - StrC slot_str = String::fmt_buf(GlobalAllocator, "%d", ArrayDefinitionCounter).to_strc(); + ++ Array_DefinitionCounter; + StrC slot_str = String::fmt_buf(GlobalAllocator, "%d", Array_DefinitionCounter).to_strc(); Code generic_interface_slot = untyped_str(token_fmt( "type_delimiter", (StrC)array_type, "slot", (StrC)slot_str, R"(#define GENERIC_SLOT___array_init , _init @@ -398,19 +398,20 @@ R"(#define GENERIC_SLOT___array_init , ; typedef struct HTE_ HTE_; - struct HTE_ - { + struct HTE_ { u64 Key; ssize Next; Value; @@ -61,8 +63,17 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) #pragma push_macro( "GEN_ASSERT" ) #pragma push_macro( "GEN_ASSERT_NOT_NULL" ) +#pragma push_macro( "rcast" ) +#pragma push_macro( "cast" ) +#pragma push_macro( "typeof" ) +#pragma push_macro( "forceinline" ) #undef GEN_ASSERT #undef GEN_ASSERT_NOT_NULL +#undef GEN_ASSERT +#undef rcast +#undef cast +#undef typeof +#undef forceinline CodeBody hashtable_def = parse_global_body( token_fmt( "type", (StrC) type, "tbl_name", (StrC) hashtable_name, @@ -72,146 +83,151 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) "array_entry", (StrC) entry_array_name, "fn_array", (StrC) entry_array_fn_ns, stringize( - struct HashTable_ - { + struct HashTable_ { Array_ssize Hashes; Entries; }; - _make ( AllocatorInfo allocator ); - _make_reserve( AllocatorInfo allocator, ssize num ); - void _clear ( self ); - void _destroy ( self ); - * _get ( self, u64 key ); - void _map ( self, _MapProc map_proc ); - void _map_mut ( self, _MapMutProc map_proc ); + _init ( AllocatorInfo allocator ); + _init_reserve( AllocatorInfo allocator, ssize num ); + void _clear ( self ); + void _destroy ( * self ); + * _get ( self, u64 key ); + void _map ( self, _MapProc map_proc ); + void _map_mut ( self, _MapMutProc map_proc ); void _grow ( * self ); void _rehash ( * self, ssize new_num ); - void _rehash_fast ( self ); - void _remove ( self, u64 key ); - void _remove_entry( self, ssize idx ); + void _rehash_fast ( self ); + void _remove ( self, u64 key ); + void _remove_entry( self, ssize idx ); void _set ( * self, u64 key, value ); - ssize _slot ( self, u64 key ); + ssize _slot ( self, u64 key ); - ssize __add_entry( self, u64 key ); - HT_FindResult __find ( self, u64 key ); - b32 __full ( self ); + ssize __add_entry( * self, u64 key ); + HT_FindResult __find ( self, u64 key ); + b32 __full ( self ); - _make( AllocatorInfo allocator ) + init( AllocatorInfo allocator ) { - - result = { NULL, NULL }; - result.Hashes = array_init(Array_ssize, allocator ); - result.Entries = array_init(, allocator ); - + result = hashtable_init_reserve(, allocator, 8); return result; } - _make_reserve( AllocatorInfo allocator, ssize num ) + _init_reserve( AllocatorInfo allocator, ssize num ) { - - result = { NULL, NULL }; + result = { NULL, NULL }; result.Hashes = array_init_reserve(Array_ssize, allocator, num ); - result.Entries = array_init_reserve(, allocator, num ); + array_get_header(result.Hashes)->Num = num; + array_resize(result.Hashes, num); + array_fill(result.Hashes, 0, num, -1); + result.Entries = array_init_reserve(, allocator, num ); return result; } void _clear( self ) { - for ( ssize idx = 0; idx < array_get_header( self.Hashes )->Num; idx++ ) - self.Hashes[idx] = -1; - - array_clear( self.Hashes ); + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); array_clear( self.Entries ); + s32 what = array_num(self.Hashes); + array_fill( self.Hashes, 0, what, (ssize)-1 ); } - void _destroy( self ) + void _destroy( * self ) { - if ( self.Hashes && self.Entries ) - { - array_free( self.Hashes ); - array_free( self.Entries ); + GEN_ASSERT_NOT_NULL(self); + GEN_ASSERT_NOT_NULL(self->Hashes); + GEN_ASSERT_NOT_NULL(self->Entries); + if ( self->Hashes && array_get_header(self->Hashes)->Capacity) { + array_free( self->Hashes ); + array_free( self->Entries ); } } * _get( self, u64 key ) { + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); ssize idx = __find( self, key ).EntryIndex; if ( idx > 0 ) return & self.Entries[idx].Value; - return NULL; + return nullptr; } void _map( self, _MapProc map_proc ) { + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); GEN_ASSERT_NOT_NULL( map_proc ); - for ( ssize idx = 0; idx < array_get_header( self.Entries )->Num; idx++ ) - { + for ( ssize idx = 0; idx < array_get_header( self.Entries )->Num; idx++ ) { map_proc( self, self.Entries[idx].Key, self.Entries[idx].Value ); } } void _map_mut( self, _MapMutProc map_proc ) { + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); GEN_ASSERT_NOT_NULL( map_proc ); - for ( ssize idx = 0; idx < array_get_header( self.Entries )->Num; idx++ ) - { + for ( ssize idx = 0; idx < array_get_header( self.Entries )->Num; idx++ ) { map_proc( self, self.Entries[idx].Key, & self.Entries[idx].Value ); } } void _grow( * self ) { + GEN_ASSERT_NOT_NULL(self); + GEN_ASSERT_NOT_NULL(self->Hashes); + GEN_ASSERT_NOT_NULL(self->Entries); ssize new_num = array_grow_formula( array_get_header( self->Entries )->Num ); - _rehash( self, new_num ); + hashtable_rehash( self, new_num ); } void _rehash( * self, ssize new_num ) { + GEN_ASSERT_NOT_NULL(self); + GEN_ASSERT_NOT_NULL(self->Hashes); + GEN_ASSERT_NOT_NULL(self->Entries); + GEN_ASSERT( new_num > 0 ); ssize idx; ssize last_added_index; ArrayHeader* old_hash_header = array_get_header( self->Hashes ); ArrayHeader* old_entries_header = array_get_header( self->Entries ); - new_tbl = _make_reserve( old_hash_header->Allocator, old_hash_header->Num ); + new_tbl = hashtable_init_reserve( , old_hash_header->Allocator, old_hash_header->Num ); ArrayHeader* new_hash_header = array_get_header( new_tbl.Hashes ); - for ( idx = 0; idx < new_hash_header->Num; idx++ ) - new_tbl.Hashes[idx] = -1; - - for ( idx = 0; idx < old_entries_header->Num; idx++ ) + for (ssize idx = 0; idx < cast(ssize, old_hash_header->Num); ++idx) { - * entry; - HT_FindResult find_result; + * entry = & self->Entries[idx]; + HT_FindResult find_result; - if ( new_hash_header->Num == 0 ) - _grow( & new_tbl ); + find_result = __find( new_tbl, entry->Key); + last_added_index = __add_entry( & new_tbl, entry->Key); - entry = & self->Entries[ idx ]; - find_result = __find( new_tbl, entry->Key ); - last_added_index = __add_entry( new_tbl, entry->Key ); - - if ( find_result.PrevIndex < 0 ) - new_tbl.Hashes[ find_result.HashIndex ] = last_added_index; + if (find_result.PrevIndex < 0) + new_tbl.Hashes[find_result.HashIndex] = last_added_index; else - new_tbl.Entries[ find_result.PrevIndex ].Next = last_added_index; + new_tbl.Entries[find_result.PrevIndex].Next = last_added_index; - new_tbl.Entries[ last_added_index ].Next = find_result.EntryIndex; - new_tbl.Entries[ last_added_index ].Value = entry->Value; + new_tbl.Entries[last_added_index].Next = find_result.EntryIndex; + new_tbl.Entries[last_added_index].Value = entry->Value; } - _destroy( *self ); + _destroy( self ); * self = new_tbl; } void _rehash_fast( self ) { + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); ssize idx; for ( idx = 0; idx < array_get_header( self.Entries )->Num; idx++ ) @@ -237,44 +253,47 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) void _remove( self, u64 key ) { + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); HT_FindResult find_result = __find( self, key ); - if ( find_result.EntryIndex >= 0 ) - { + if ( find_result.EntryIndex >= 0 ) { array_remove_at( self.Entries, find_result.EntryIndex ); - _rehash_fast( self ); + hashtable_rehash_fast( self ); } } void _remove_entry( self, ssize idx ) { + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); array_remove_at( self.Entries, idx ); } void _set( * self, u64 key, value ) { + GEN_ASSERT_NOT_NULL(self); + GEN_ASSERT_NOT_NULL(self->Hashes); + GEN_ASSERT_NOT_NULL(self->Entries); ssize idx; HT_FindResult find_result; if ( array_get_header( self->Hashes )->Num == 0 ) - _grow( self ); + hashtable_grow( self ); find_result = __find( * self, key ); - if ( find_result.EntryIndex >= 0 ) - { + if ( find_result.EntryIndex >= 0 ) { idx = find_result.EntryIndex; } else { - idx = __add_entry( * self, key ); + idx = __add_entry( self, key ); - if ( find_result.PrevIndex >= 0 ) - { + if ( find_result.PrevIndex >= 0 ) { self->Entries[ find_result.PrevIndex ].Next = idx; } - else - { + else { self->Hashes[ find_result.HashIndex ] = idx; } } @@ -282,11 +301,13 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) self->Entries[ idx ].Value = value; if ( __full( * self ) ) - _grow( self ); + hashtable_grow( self ); } ssize _slot( self, u64 key ) { + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); for ( ssize idx = 0; idx < array_get_header( self.Hashes )->Num; ++idx ) if ( self.Hashes[ idx ] == key ) return idx; @@ -294,22 +315,26 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) return -1; } - ssize __add_entry( self, u64 key ) + ssize __add_entry( * self, u64 key ) { + GEN_ASSERT_NOT_NULL(self); + GEN_ASSERT_NOT_NULL(self->Hashes); + GEN_ASSERT_NOT_NULL(self->Entries); ssize idx; entry = { key, -1 }; - idx = array_get_header( self.Entries )->Num; - array_append( self.Entries, entry ); + idx = array_get_header( self->Entries )->Num; + array_append( self->Entries, entry ); return idx; } HT_FindResult __find( self, u64 key ) { + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); HT_FindResult result = { -1, -1, -1 }; ArrayHeader* hash_header = array_get_header( self.Hashes ); - if ( hash_header->Num > 0 ) { result.HashIndex = key % hash_header->Num; @@ -330,14 +355,46 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) b32 __full( self ) { + GEN_ASSERT_NOT_NULL(self.Hashes); + GEN_ASSERT_NOT_NULL(self.Entries); ArrayHeader* hash_header = array_get_header( self.Hashes ); ArrayHeader* entries_header = array_get_header( self.Entries ); - return 0.75f * hash_header->Num < entries_header->Num; + usize critical_load = cast(usize, HashTable_CriticalLoadScale * cast(f32, hash_header->Num)); + b32 result = entries_header->Num > critical_load; + return result; } ))); #pragma pop_macro( "GEN_ASSERT" ) #pragma pop_macro( "GEN_ASSERT_NOT_NULL" ) +#pragma pop_macro( "rcast" ) +#pragma pop_macro( "cast" ) +#pragma pop_macro( "typeof" ) +#pragma pop_macro( "forceinline" ) + + ++ HashTable_DefinitionCounter; + StrC slot_str = String::fmt_buf(GlobalAllocator, "%d", Array_DefinitionCounter).to_strc(); + + Code generic_interface_slot = untyped_str(token_fmt( "type_delimiter", (StrC)tbl_type, "slot", (StrC)slot_str, +R"(#define GENERIC_SLOT___hashtable_init , _init +#define GENERIC_SLOT___hashtable_init_reserve , _init_reserve +#define GENERIC_SLOT___hashtable_clear , _clear +#define GENERIC_SLOT___hashtable_destroy *, _destroy +#define GENERIC_SLOT___hashtable_get , _get +#define GENERIC_SLOT___hashtable_map , _map +#define GENERIC_SLOT___hashtable_map_mut , _map_mut +#define GENERIC_SLOT___hashtable_grow *, _grow +#define GENERIC_SLOT___hashtable_rehash *, _rehash +#define GENERIC_SLOT___hashtable_rehash_fast , _rehash_fast +#define GENERIC_SLOT___hashtable_remove_entry , _remove_entry +#define GENERIC_SLOT___hashtable_set *, _set +#define GENERIC_SLOT___hashtable_slot , _slot + +#define GENERIC_SLOT___hashtable__add_entry *, __add_entry +#define GENERIC_SLOT___hashtable__find , __find +#define GENERIC_SLOT___hashtable__full , __full +)" + )); char const* cmt_str = str_fmt_buf( "Name: %.*s Type: %.*s" , tbl_type.length(), tbl_type.Data @@ -346,6 +403,8 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) return def_global_body(args( def_pragma( string_to_strc( string_fmt_buf( GlobalAllocator, "region %S", tbl_type ))), fmt_newline, + generic_interface_slot, + fmt_newline, hashtable_types, fmt_newline, entry_array, @@ -355,3 +414,21 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) fmt_newline )); } + +CodeBody gen_hashtable_generic_selection_interface() +{ + CodeBody interface_defines = def_body(CT_Global_Body); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_init"), GenericSel_Direct_Type )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_init_reserve"), GenericSel_Direct_Type )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_clear"), GenericSel_Default, GenericSel_One_Arg )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_destroy"), GenericSel_By_Ref, GenericSel_One_Arg ) ); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_get") )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_grow"), GenericSel_Default, GenericSel_One_Arg )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_rehash") )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_rehash_fast"), GenericSel_Default, GenericSel_One_Arg )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_remove") )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_remove_entry") )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_set"), GenericSel_By_Ref )); + interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_slot") )); + return interface_defines; +} diff --git a/gen_c_library/components/misc.hpp b/gen_c_library/components/misc.hpp index 61e80c5..1190e0c 100644 --- a/gen_c_library/components/misc.hpp +++ b/gen_c_library/components/misc.hpp @@ -96,6 +96,14 @@ R"(#define (selector_arg, ...) _Generic( (selector_arg), \ R"( GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT___ ) \ )" )); + // if ( one_arg ) + // define_builder.append(token_fmt( "macro_name", macro_name, stringize( + // default: static_assert(false, ": Failed to select correct function signature (Did you pass the type?)") + // ))); + // else + // define_builder.append(token_fmt( "macro_name", macro_name, stringize( + // default: static_assert(false, ": Failed to select correct function signature") + // ))); continue; } diff --git a/project/dependencies/containers.hpp b/project/dependencies/containers.hpp index b97f4ef..befecda 100644 --- a/project/dependencies/containers.hpp +++ b/project/dependencies/containers.hpp @@ -481,12 +481,13 @@ template void hashtable_remove (HashTable void hashtable_remove_entry(HashTable table, ssize idx); template void hashtable_set (HashTable* table, u64 key, Type value); template ssize hashtable_slot (HashTable table, u64 key); -template ssize hashtable_add_entry (HashTable* table, u64 key); -template HashTableFindResult hashtable_find (HashTable table, u64 key); -template bool hashtable_full (HashTable table); template void hashtable_map (HashTable table, void (*map_proc)(u64 key, Type value)); template void hashtable_map_mut (HashTable table, void (*map_proc)(u64 key, Type* value)); +template ssize hashtable__add_entry (HashTable* table, u64 key); +template HashTableFindResult hashtable__find (HashTable table, u64 key); +template bool hashtable__full (HashTable table); + static constexpr f32 HashTable_CriticalLoadScale = 0.7f; template @@ -540,37 +541,45 @@ HashTable hashtable_init_reserve(AllocatorInfo allocator, usize num) result.Hashes = array_init_reserve(allocator, num); array_get_header(result.Hashes)->Num = num; array_resize(& result.Hashes, num); - array_fill(result.Hashes, 0, num, -1); + array_fill(result.Hashes, 0, num, (ssize)-1); result.Entries = array_init_reserve>(allocator, num); return result; } -template inline +template forceinline void hashtable_clear(HashTable table) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); array_clear(table.Entries); array_fill(table.Hashes, 0, array_num(table.Hashes), (ssize)-1); } -template inline +template forceinline void hashtable_destroy(HashTable* table) { + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); if (table->Hashes && array_get_header(table->Hashes)->Capacity) { array_free(table->Hashes); array_free(table->Entries); } } -template inline +template forceinline Type* hashtable_get(HashTable table, u64 key) { - ssize idx = hashtable_find(table, key).EntryIndex; + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + ssize idx = hashtable__find(table, key).EntryIndex; if (idx >= 0) return & table.Entries[idx].Value; return nullptr; } -template inline +template forceinline void hashtable_map(HashTable table, void (*map_proc)(u64 key, Type value)) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); GEN_ASSERT_NOT_NULL(map_proc); for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { @@ -578,8 +587,10 @@ void hashtable_map(HashTable table, void (*map_proc)(u64 key, Type value)) } } -template inline +template forceinline void hashtable_map_mut(HashTable table, void (*map_proc)(u64 key, Type* value)) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); GEN_ASSERT_NOT_NULL(map_proc); for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { @@ -587,8 +598,11 @@ void hashtable_map_mut(HashTable table, void (*map_proc)(u64 key, Type* va } } -template inline +template forceinline void hashtable_grow(HashTable* table) { + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); ssize new_num = array_grow_formula( array_num(table->Entries)); hashtable_rehash(table, new_num); } @@ -596,6 +610,9 @@ void hashtable_grow(HashTable* table) { template inline void hashtable_rehash(HashTable* table, ssize new_num) { + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); ssize last_added_index; HashTable new_ht = hashtable_init_reserve( array_get_header(table->Hashes)->Allocator, new_num); @@ -604,8 +621,8 @@ void hashtable_rehash(HashTable* table, ssize new_num) HashTableFindResult find_result; HashTableEntry& entry = table->Entries[idx]; - find_result = hashtable_find(new_ht, entry.Key); - last_added_index = hashtable_add_entry(& new_ht, entry.Key); + find_result = hashtable__find(new_ht, entry.Key); + last_added_index = hashtable__add_entry(& new_ht, entry.Key); if (find_result.PrevIndex < 0) new_ht.Hashes[find_result.HashIndex] = last_added_index; @@ -623,6 +640,8 @@ void hashtable_rehash(HashTable* table, ssize new_num) template inline void hashtable_rehash_fast(HashTable table) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); ssize idx; for (idx = 0; idx < ssize(num(table.Entries)); idx++) @@ -646,8 +665,10 @@ void hashtable_rehash_fast(HashTable table) } } -template inline +template forceinline void hashtable_remove(HashTable table, u64 key) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); HashTableFindResult find_result = find(table, key); if (find_result.EntryIndex >= 0) { @@ -656,27 +677,32 @@ void hashtable_remove(HashTable table, u64 key) { } } -template inline +template forceinline void hashtable_remove_entry(HashTable table, ssize idx) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); remove_at(table.Entries, idx); } template inline void hashtable_set(HashTable* table, u64 key, Type value) { + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); ssize idx; HashTableFindResult find_result; if (hashtable_full(* table)) hashtable_grow(table); - find_result = hashtable_find(* table, key); + find_result = hashtable__find(* table, key); if (find_result.EntryIndex >= 0) { idx = find_result.EntryIndex; } else { - idx = hashtable_add_entry(table, key); + idx = hashtable__add_entry(table, key); if (find_result.PrevIndex >= 0) { table->Entries[find_result.PrevIndex].Next = idx; @@ -692,8 +718,10 @@ void hashtable_set(HashTable* table, u64 key, Type value) hashtable_grow(table); } -template inline +template forceinline ssize hashtable_slot(HashTable table, u64 key) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); for (ssize idx = 0; idx < ssize(num(table.Hashes)); ++idx) if (table.Hashes[idx] == key) return idx; @@ -701,8 +729,11 @@ ssize hashtable_slot(HashTable table, u64 key) { return -1; } -template inline -ssize hashtable_add_entry(HashTable* table, u64 key) { +template forceinline +ssize hashtable__add_entry(HashTable* table, u64 key) { + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); ssize idx; HashTableEntry entry = { key, -1 }; @@ -712,8 +743,10 @@ ssize hashtable_add_entry(HashTable* table, u64 key) { } template inline -HashTableFindResult hashtable_find(HashTable table, u64 key) +HashTableFindResult hashtable__find(HashTable table, u64 key) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); HashTableFindResult result = { -1, -1, -1 }; if (array_num(table.Hashes) > 0) @@ -734,8 +767,10 @@ HashTableFindResult hashtable_find(HashTable table, u64 key) return result; } -template inline +template forceinline bool hashtable_full(HashTable table) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); usize critical_load = usize(HashTable_CriticalLoadScale * f32(array_num(table.Hashes))); b32 result = array_num(table.Entries) > critical_load; return result; @@ -753,12 +788,13 @@ bool hashtable_full(HashTable table) { #define hashtable_remove_entry(table, idx) hashtable_remove_entry< get_hashtable_underlying_type(table) >(table, idx) #define hashtable_set(table, key, value) hashtable_set < get_hashtable_underlying_type(table) >(& table, key, value) #define hashtable_slot(table, key) hashtable_slot < get_hashtable_underlying_type(table) >(table, key) -#define hashtable_add_entry(table, key) hashtable_add_entry < get_hashtable_underlying_type(table) >(& table, key) -#define hashtable_find(table, key) hashtable_find < get_hashtable_underlying_type(table) >(table, key) -#define hashtable_full(table) hashtable_full < get_hashtable_underlying_type(table) >(table) #define hashtable_map(table, map_proc) hashtable_map < get_hashtable_underlying_type(table) >(table, map_proc) #define hashtable_map_mut(table, map_proc) hashtable_map_mut < get_hashtable_underlying_type(table) >(table, map_proc) +//#define hashtable_add_entry(table, key) hashtable_add_entry < get_hashtable_underlying_type(table) >(& table, key) +//#define hashtable_find(table, key) hashtable_find < get_hashtable_underlying_type(table) >(table, key) +//#define hashtable_full(table) hashtable_full < get_hashtable_underlying_type(table) >(table) + #pragma endregion HashTable #pragma endregion Containers diff --git a/project/dependencies/macros.hpp b/project/dependencies/macros.hpp index 5a30018..ff0b07c 100644 --- a/project/dependencies/macros.hpp +++ b/project/dependencies/macros.hpp @@ -187,6 +187,17 @@ # endif #endif +#if GEN_COMPILER_C +#ifndef static_assert +#undef static_assert + #if GEN_COMPILER_C && __STDC_VERSION__ >= 201112L + #define static_assert(condition, message) _Static_assert(condition, message) + #else + #define static_assert(condition, message) typedef char static_assertion_##__LINE__[(condition)?1:-1] + #endif +#endif +#endif + #if GEN_COMPILER_CPP // Already Defined #elif GEN_COMPILER_C && __STDC_VERSION__ >= 201112L @@ -277,7 +288,7 @@ // Extensive effort was put in below to make this as easy as possible to understand what is going on with this mess of a preoprocessor. // Where the signature would be defined using: -#define GEN_TYPE_TO_EXP(type) (type*)NULL +#define GEN_TYPE_TO_EXP(type) (* (type*)NULL) #define GEN_COMMA_OPERATOR , // The comma operator is used by preprocessor macros to delimit arguments, so we have to represent it via a macro to prevent parsing incorrectly. diff --git a/project/helpers/pop_container_defines.inline.hpp b/project/helpers/pop_container_defines.inline.hpp index cb6f8e1..4786057 100644 --- a/project/helpers/pop_container_defines.inline.hpp +++ b/project/helpers/pop_container_defines.inline.hpp @@ -31,8 +31,9 @@ #undef hashtable_remove_entry #undef hashtable_set #undef hashtable_slot -#undef hashtable_add_entry -#undef hashtable_find -#undef hashtable_full #undef hashtable_map #undef hashtable_map_mut + +//#undef hashtable_add_entry +//#undef hashtable_find +//#undef hashtable_full diff --git a/project/helpers/push_container_defines.inline.hpp b/project/helpers/push_container_defines.inline.hpp index fcaa3cd..45b3072 100644 --- a/project/helpers/push_container_defines.inline.hpp +++ b/project/helpers/push_container_defines.inline.hpp @@ -31,8 +31,9 @@ #define hashtable_remove_entry(table, idx) hashtable_remove_entry< get_hashtable_underlying_type(table) >(table, idx) #define hashtable_set(table, key, value) hashtable_set < get_hashtable_underlying_type(table) >(& table, key, value) #define hashtable_slot(table, key) hashtable_slot < get_hashtable_underlying_type(table) >(table, key) -#define hashtable_add_entry(table, key) hashtable_add_entry < get_hashtable_underlying_type(table) >(& table, key) -#define hashtable_find(table, key) hashtable_find < get_hashtable_underlying_type(table) >(table, key) -#define hashtable_full(table) hashtable_full < get_hashtable_underlying_type(table) >(table) #define hashtable_map(table, map_proc) hashtable_map < get_hashtable_underlying_type(table) >(table, map_proc) #define hashtable_map_mut(table, map_proc) hashtable_map_mut < get_hashtable_underlying_type(table) >(table, map_proc) + +//#define hashtable_add_entry(table, key) hashtable_add_entry < get_hashtable_underlying_type(table) >(& table, key) +//#define hashtable_find(table, key) hashtable_find < get_hashtable_underlying_type(table) >(table, key) +//#define hashtable_full(table) hashtable_full < get_hashtable_underlying_type(table) >(table)