mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-31 06:50:53 -07:00 
			
		
		
		
	verified the C hashtable has parity with the C++ templated gencpp hashtable.
This commit is contained in:
		| @@ -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))); | ||||
|   | ||||
| @@ -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_<slot>__array_init         <type_delimiter>,  <type_delimiter>_init | ||||
| @@ -398,19 +398,20 @@ R"(#define GENERIC_SLOT_<slot>__array_init         <type_delimiter>,  <type_deli | ||||
| CodeBody gen_array_generic_selection_interface() | ||||
| { | ||||
| 	CodeBody interface_defines = def_body(CT_Global_Body); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_init"), GenericSel_Direct_Type )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_init_reserve"), GenericSel_Direct_Type )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_append"), GenericSel_By_Ref )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_append_items"), GenericSel_By_Ref )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_back"), GenericSel_Default, GenericSel_One_Arg )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_clear"), GenericSel_Default, GenericSel_One_Arg )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_fill")) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_free"), GenericSel_By_Ref, GenericSel_One_Arg ) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_grow")) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_num")) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_pop"), GenericSel_Default, GenericSel_One_Arg )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_remove_at")) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_reserve"), GenericSel_By_Ref) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( ArrayDefinitionCounter, txt("array_set_capacity")) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_init"), GenericSel_Direct_Type )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_init_reserve"), GenericSel_Direct_Type )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_append"), GenericSel_By_Ref )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_append_items"), GenericSel_By_Ref )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_back"), GenericSel_Default, GenericSel_One_Arg )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_clear"), GenericSel_Default, GenericSel_One_Arg )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_fill")) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_free"), GenericSel_By_Ref, GenericSel_One_Arg ) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_grow")) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_num"), GenericSel_Default, GenericSel_One_Arg )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_pop"), GenericSel_Default, GenericSel_One_Arg )); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_remove_at")) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_reserve"), GenericSel_By_Ref) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_resize"), GenericSel_By_Ref) ); | ||||
| 	interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_set_capacity")) ); | ||||
| 	return interface_defines; | ||||
| } | ||||
|   | ||||
| @@ -5,11 +5,13 @@ | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| global s32 HashTable_DefinitionCounter = 0; | ||||
|  | ||||
| CodeBody gen_hashtable_base() | ||||
| { | ||||
| 	CodeBody struct_def = parse_global_body( code( | ||||
| 		typedef struct HT_FindResult HT_FindResult; | ||||
| 		struct HT_FindResult | ||||
| 		typedef struct HT_FindResult_Def HT_FindResult; | ||||
| 		struct HT_FindResult_Def | ||||
| 		{ | ||||
| 			ssize HashIndex; | ||||
| 			ssize PrevIndex; | ||||
| @@ -22,7 +24,8 @@ R"(#define HashTable(_type) struct _type | ||||
| )" | ||||
| 	)); | ||||
|  | ||||
| 	return def_global_body(args(struct_def, define_type)); | ||||
| 	Code define_critical_load_scale = untyped_str(txt("#define HashTable_CriticalLoadScale 0.7f\n")); | ||||
| 	return def_global_body(args(struct_def, define_type, define_critical_load_scale)); | ||||
| } | ||||
|  | ||||
| CodeBody gen_hashtable( StrC type, StrC hashtable_name ) | ||||
| @@ -46,8 +49,7 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) | ||||
| 	stringize( | ||||
| 		typedef struct HashTable_<type> <tbl_type>; | ||||
| 		typedef struct HTE_<tbl_name> HTE_<tbl_name>; | ||||
| 		struct HTE_<tbl_name> | ||||
| 		{ | ||||
| 		struct HTE_<tbl_name> { | ||||
| 			u64    Key; | ||||
| 			ssize  Next; | ||||
| 			<type> 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,16 +83,15 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) | ||||
| 		"array_entry",    (StrC) entry_array_name, | ||||
| 		"fn_array",       (StrC) entry_array_fn_ns, | ||||
| 	stringize( | ||||
| 		struct HashTable_<type> | ||||
| 		{ | ||||
| 		struct HashTable_<type> { | ||||
| 			Array_ssize   Hashes; | ||||
| 			<array_entry> Entries; | ||||
| 		}; | ||||
|  | ||||
| 		<tbl_type> <fn>_make        ( AllocatorInfo allocator ); | ||||
| 		<tbl_type> <fn>_make_reserve( AllocatorInfo allocator, ssize num ); | ||||
| 		<tbl_type> <fn>_init        ( AllocatorInfo allocator ); | ||||
| 		<tbl_type> <fn>_init_reserve( AllocatorInfo allocator, ssize num ); | ||||
| 		void       <fn>_clear       ( <tbl_type>  self ); | ||||
| 		void       <fn>_destroy     ( <tbl_type> self ); | ||||
| 		void       <fn>_destroy     ( <tbl_type>* self ); | ||||
| 		<type>*    <fn>_get         ( <tbl_type>  self, u64 key ); | ||||
| 		void       <fn>_map         ( <tbl_type>  self, <tbl_type>_MapProc map_proc ); | ||||
| 		void       <fn>_map_mut     ( <tbl_type>  self, <tbl_type>_MapMutProc map_proc ); | ||||
| @@ -93,109 +103,113 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) | ||||
| 		void       <fn>_set         ( <tbl_type>* self, u64 key, <type> value ); | ||||
| 		ssize      <fn>_slot        ( <tbl_type>  self, u64 key ); | ||||
|  | ||||
| 		ssize         <fn>__add_entry( <tbl_type> self, u64 key ); | ||||
| 		ssize         <fn>__add_entry( <tbl_type>* self, u64 key ); | ||||
| 		HT_FindResult <fn>__find     ( <tbl_type>  self, u64 key ); | ||||
| 		b32           <fn>__full     ( <tbl_type>  self ); | ||||
|  | ||||
| 		<tbl_type> <fn>_make( AllocatorInfo allocator ) | ||||
| 		<tbl_type> <fn>init( AllocatorInfo allocator ) | ||||
| 		{ | ||||
| 			<tbl_type> | ||||
| 			result         = { NULL, NULL }; | ||||
| 			result.Hashes  = array_init(Array_ssize, allocator ); | ||||
| 			result.Entries = array_init(<array_entry>, allocator ); | ||||
|  | ||||
| 			<tbl_type> result = hashtable_init_reserve(<tbl_type>, allocator, 8); | ||||
| 			return result; | ||||
| 		} | ||||
|  | ||||
| 		<tbl_type> <fn>_make_reserve( AllocatorInfo allocator, ssize num ) | ||||
| 		<tbl_type> <fn>_init_reserve( AllocatorInfo allocator, ssize num ) | ||||
| 		{ | ||||
| 			<tbl_type> | ||||
| 			result         = { NULL, NULL }; | ||||
| 			<tbl_type> result = { NULL, NULL }; | ||||
| 			result.Hashes  = array_init_reserve(Array_ssize, allocator, num ); | ||||
| 			result.Entries = array_init_reserve(<array_entry>, 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(<array_entry>, allocator, num ); | ||||
| 			return result; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_clear( <tbl_type> 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 <fn>_destroy( <tbl_type> self ) | ||||
| 		void <fn>_destroy( <tbl_type>* 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 ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		<type>* <fn>_get( <tbl_type> self, u64 key ) | ||||
| 		{ | ||||
| 			GEN_ASSERT_NOT_NULL(self.Hashes); | ||||
| 			GEN_ASSERT_NOT_NULL(self.Entries); | ||||
| 			ssize idx = <fn>__find( self, key ).EntryIndex; | ||||
| 			if ( idx > 0 ) | ||||
| 				return & self.Entries[idx].Value; | ||||
|  | ||||
| 			return NULL; | ||||
| 			return nullptr; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_map( <tbl_type> self, <tbl_type>_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 <fn>_map_mut( <tbl_type> self, <tbl_type>_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 <fn>_grow( <tbl_type>* 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 ); | ||||
| 			<fn>_rehash( self, new_num ); | ||||
| 			hashtable_rehash( self, new_num ); | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_rehash( <tbl_type>* 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 ); | ||||
|  | ||||
| 			<tbl_type> new_tbl = <fn>_make_reserve( old_hash_header->Allocator, old_hash_header->Num ); | ||||
| 			<tbl_type> new_tbl = hashtable_init_reserve( <tbl_type>, 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_type>*  entry; | ||||
| 				<entry_type>* entry = & self->Entries[idx]; | ||||
| 				HT_FindResult find_result; | ||||
|  | ||||
| 				if ( new_hash_header->Num == 0 ) | ||||
| 					<fn>_grow( & new_tbl ); | ||||
|  | ||||
| 				entry            = & self->Entries[ idx ]; | ||||
| 				find_result      = <fn>__find( new_tbl, entry->Key); | ||||
| 				last_added_index = <fn>__add_entry( new_tbl, entry->Key ); | ||||
| 				last_added_index = <fn>__add_entry( & new_tbl, entry->Key); | ||||
|  | ||||
| 				if (find_result.PrevIndex < 0) | ||||
| 					new_tbl.Hashes[find_result.HashIndex] = last_added_index; | ||||
| @@ -206,12 +220,14 @@ CodeBody gen_hashtable( StrC type, StrC hashtable_name ) | ||||
| 				new_tbl.Entries[last_added_index].Value = entry->Value; | ||||
| 			} | ||||
|  | ||||
| 			<fn>_destroy( *self ); | ||||
| 			<fn>_destroy( self ); | ||||
| 			* self = new_tbl; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_rehash_fast( <tbl_type> 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 <fn>_remove( <tbl_type> self, u64 key ) | ||||
| 		{ | ||||
| 			GEN_ASSERT_NOT_NULL(self.Hashes); | ||||
| 			GEN_ASSERT_NOT_NULL(self.Entries); | ||||
| 			HT_FindResult find_result = <fn>__find( self, key ); | ||||
|  | ||||
| 			if ( find_result.EntryIndex >= 0 ) | ||||
| 			{ | ||||
| 			if ( find_result.EntryIndex >= 0 ) { | ||||
| 				array_remove_at( self.Entries, find_result.EntryIndex ); | ||||
| 				<fn>_rehash_fast( self ); | ||||
| 				hashtable_rehash_fast( self ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_remove_entry( <tbl_type> self, ssize idx ) | ||||
| 		{ | ||||
| 			GEN_ASSERT_NOT_NULL(self.Hashes); | ||||
| 			GEN_ASSERT_NOT_NULL(self.Entries); | ||||
| 			array_remove_at( self.Entries, idx ); | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_set( <tbl_type>* self, u64 key, <type> 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 ) | ||||
| 				<fn>_grow( self ); | ||||
| 				hashtable_grow( self ); | ||||
|  | ||||
| 			find_result = <fn>__find( * self, key ); | ||||
|  | ||||
| 			if ( find_result.EntryIndex >= 0 ) | ||||
| 			{ | ||||
| 			if ( find_result.EntryIndex >= 0 ) { | ||||
| 				idx = find_result.EntryIndex; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				idx = <fn>__add_entry( * self, key ); | ||||
| 				idx = <fn>__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 ( <fn>__full( * self ) ) | ||||
| 				<fn>_grow( self ); | ||||
| 				hashtable_grow( self ); | ||||
| 		} | ||||
|  | ||||
| 		ssize <fn>_slot( <tbl_type> 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 <fn>__add_entry( <tbl_type> self, u64 key ) | ||||
| 		ssize <fn>__add_entry( <tbl_type>* self, u64 key ) | ||||
| 		{ | ||||
| 			GEN_ASSERT_NOT_NULL(self); | ||||
| 			GEN_ASSERT_NOT_NULL(self->Hashes); | ||||
| 			GEN_ASSERT_NOT_NULL(self->Entries); | ||||
| 			ssize idx; | ||||
| 			<entry_type> 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 <fn>__find( <tbl_type> 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 <fn>__full( <tbl_type> 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_<slot>__hashtable_init          <type_delimiter>,  <type_delimiter>_init | ||||
| #define GENERIC_SLOT_<slot>__hashtable_init_reserve     <type_delimiter>,  <type_delimiter>_init_reserve | ||||
| #define GENERIC_SLOT_<slot>__hashtable_clear            <type_delimiter>,  <type_delimiter>_clear | ||||
| #define GENERIC_SLOT_<slot>__hashtable_destroy          <type_delimiter>*, <type_delimiter>_destroy | ||||
| #define GENERIC_SLOT_<slot>__hashtable_get              <type_delimiter>,  <type_delimiter>_get | ||||
| #define GENERIC_SLOT_<slot>__hashtable_map              <type_delimiter>,  <type_delimiter>_map | ||||
| #define GENERIC_SLOT_<slot>__hashtable_map_mut          <type_delimiter>,  <type_delimiter>_map_mut | ||||
| #define GENERIC_SLOT_<slot>__hashtable_grow             <type_delimiter>*, <type_delimiter>_grow | ||||
| #define GENERIC_SLOT_<slot>__hashtable_rehash           <type_delimiter>*, <type_delimiter>_rehash | ||||
| #define GENERIC_SLOT_<slot>__hashtable_rehash_fast      <type_delimiter>,  <type_delimiter>_rehash_fast | ||||
| #define GENERIC_SLOT_<slot>__hashtable_remove_entry     <type_delimiter>,  <type_delimiter>_remove_entry | ||||
| #define GENERIC_SLOT_<slot>__hashtable_set              <type_delimiter>*, <type_delimiter>_set | ||||
| #define GENERIC_SLOT_<slot>__hashtable_slot             <type_delimiter>,  <type_delimiter>_slot | ||||
|  | ||||
| #define GENERIC_SLOT_<slot>__hashtable__add_entry       <type_delimiter>*, <type_delimiter>__add_entry | ||||
| #define GENERIC_SLOT_<slot>__hashtable__find            <type_delimiter>,  <type_delimiter>__find | ||||
| #define GENERIC_SLOT_<slot>__hashtable__full            <type_delimiter>,  <type_delimiter>__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; | ||||
| } | ||||
|   | ||||
| @@ -96,6 +96,14 @@ R"(#define <macro_name>(selector_arg, ...) _Generic( (selector_arg), \ | ||||
| R"(		GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST(  GENERIC_SLOT_<slot>__<macro_name> ) \ | ||||
| )" | ||||
| 			)); | ||||
| 			// if ( one_arg ) | ||||
| 			// 	define_builder.append(token_fmt( "macro_name", macro_name, stringize( | ||||
| 			// 		default: static_assert(false, "<macro_name>: 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, "<macro_name>: Failed to select correct function signature") | ||||
| 			// 	))); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -481,12 +481,13 @@ template<class Type> void                  hashtable_remove      (HashTable<Type | ||||
| template<class Type> void                  hashtable_remove_entry(HashTable<Type>  table, ssize idx); | ||||
| template<class Type> void                  hashtable_set         (HashTable<Type>* table, u64 key, Type value); | ||||
| template<class Type> ssize                 hashtable_slot        (HashTable<Type>  table, u64 key); | ||||
| template<class Type> ssize                 hashtable_add_entry   (HashTable<Type>* table, u64 key); | ||||
| template<class Type> HashTableFindResult   hashtable_find        (HashTable<Type>  table, u64 key); | ||||
| template<class Type> bool                  hashtable_full        (HashTable<Type>  table); | ||||
| template<class Type> void                  hashtable_map         (HashTable<Type>  table, void (*map_proc)(u64 key, Type value)); | ||||
| template<class Type> void                  hashtable_map_mut     (HashTable<Type>  table, void (*map_proc)(u64 key, Type* value)); | ||||
|  | ||||
| template<class Type> ssize                 hashtable__add_entry  (HashTable<Type>* table, u64 key); | ||||
| template<class Type> HashTableFindResult   hashtable__find       (HashTable<Type>  table, u64 key); | ||||
| template<class Type> bool                  hashtable__full       (HashTable<Type>  table); | ||||
|  | ||||
| static constexpr f32 HashTable_CriticalLoadScale = 0.7f; | ||||
|  | ||||
| template<typename Type> | ||||
| @@ -540,37 +541,45 @@ HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num) | ||||
| 	result.Hashes = array_init_reserve<ssize>(allocator, num); | ||||
| 	array_get_header(result.Hashes)->Num = num; | ||||
| 	array_resize(& result.Hashes, num); | ||||
| 	array_fill<ssize>(result.Hashes, 0, num, -1); | ||||
| 	array_fill(result.Hashes, 0, num, (ssize)-1); | ||||
|  | ||||
| 	result.Entries = array_init_reserve<HashTableEntry<Type>>(allocator, num); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| void hashtable_clear(HashTable<Type> 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<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| void hashtable_destroy(HashTable<Type>* 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<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| Type* hashtable_get(HashTable<Type> 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<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| void hashtable_map(HashTable<Type> 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<Type> table, void (*map_proc)(u64 key, Type value)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| void hashtable_map_mut(HashTable<Type> 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<Type> table, void (*map_proc)(u64 key, Type* va | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| void hashtable_grow(HashTable<Type>* 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<Type>* table) { | ||||
| template<typename Type> inline | ||||
| void hashtable_rehash(HashTable<Type>* 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<Type> new_ht = hashtable_init_reserve<Type>( array_get_header(table->Hashes)->Allocator, new_num); | ||||
|  | ||||
| @@ -604,8 +621,8 @@ void hashtable_rehash(HashTable<Type>* table, ssize new_num) | ||||
| 		HashTableFindResult find_result; | ||||
| 		HashTableEntry<Type>& 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<Type>* table, ssize new_num) | ||||
| template<typename Type> inline | ||||
| void hashtable_rehash_fast(HashTable<Type> 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<Type> table) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| void hashtable_remove(HashTable<Type> 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<Type> table, u64 key) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| void hashtable_remove_entry(HashTable<Type> table, ssize idx) { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	remove_at(table.Entries, idx); | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| void hashtable_set(HashTable<Type>* 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<Type>* table, u64 key, Type value) | ||||
| 		hashtable_grow(table); | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| ssize hashtable_slot(HashTable<Type> 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<Type> table, u64 key) { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| ssize hashtable_add_entry(HashTable<Type>* table, u64 key) { | ||||
| template<typename Type> forceinline | ||||
| ssize hashtable__add_entry(HashTable<Type>* table, u64 key) { | ||||
| 	GEN_ASSERT_NOT_NULL(table); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Entries); | ||||
| 	ssize idx; | ||||
| 	HashTableEntry<Type> entry = { key, -1 }; | ||||
|  | ||||
| @@ -712,8 +743,10 @@ ssize hashtable_add_entry(HashTable<Type>* table, u64 key) { | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| HashTableFindResult hashtable_find(HashTable<Type> table, u64 key) | ||||
| HashTableFindResult hashtable__find(HashTable<Type> 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<Type> table, u64 key) | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| template<typename Type> forceinline | ||||
| bool hashtable_full(HashTable<Type> 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<Type> 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 | ||||
|   | ||||
| @@ -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. | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user