Last active
December 6, 2024 01:54
-
-
Save Ed94/23ab8e5aa534114e2a5a48f037e065e2 to your computer and use it in GitHub Desktop.
_Generic function overloading example in C11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma region Array_ssize | |
| #define GENERIC_SLOT_2__array_init Array_ssize, Array_ssize_init | |
| #define GENERIC_SLOT_2__array_init_reserve Array_ssize, Array_ssize_init_reserve | |
| #define GENERIC_SLOT_2__array_append Array_ssize, Array_ssize_append | |
| #define GENERIC_SLOT_2__array_append_items Array_ssize, Array_ssize_append_items | |
| #define GENERIC_SLOT_2__array_append_at Array_ssize, Array_ssize_append_at | |
| #define GENERIC_SLOT_2__array_append_items_at Array_ssize, Array_ssize_append_items_at | |
| #define GENERIC_SLOT_2__array_back Array_ssize, Array_ssize_back | |
| #define GENERIC_SLOT_2__array_clear Array_ssize, Array_ssize_clear | |
| #define GENERIC_SLOT_2__array_fill Array_ssize, Array_ssize_fill | |
| #define GENERIC_SLOT_2__array_free Array_ssize, Array_ssize_free | |
| #define GENERIC_SLOT_2__array_grow Array_ssize*, Array_ssize_grow | |
| #define GENERIC_SLOT_2__array_num Array_ssize, Array_ssize_num | |
| #define GENERIC_SLOT_2__array_pop Array_ssize, Array_ssize_pop | |
| #define GENERIC_SLOT_2__array_remove_at Array_ssize, Array_ssize_remove_at | |
| #define GENERIC_SLOT_2__array_reserve Array_ssize, Array_ssize_reserve | |
| #define GENERIC_SLOT_2__array_resize Array_ssize, Array_ssize_resize | |
| #define GENERIC_SLOT_2__array_set_capacity Array_ssize*, Array_ssize_set_capacity | |
| typedef ssize* Array_ssize; | |
| Array_ssize Array_ssize_init( AllocatorInfo allocator ); | |
| Array_ssize Array_ssize_init_reserve( AllocatorInfo allocator, usize capacity ); | |
| bool Array_ssize_append_array( Array_ssize* self, Array_ssize other ); | |
| bool Array_ssize_append( Array_ssize* self, ssize value ); | |
| bool Array_ssize_append_items( Array_ssize* self, ssize* items, usize item_num ); | |
| bool Array_ssize_append_at( Array_ssize* self, ssize item, usize idx ); | |
| bool Array_ssize_append_items_at( Array_ssize* self, ssize* items, usize item_num, usize idx ); | |
| ssize* Array_ssize_back( Array_ssize self ); | |
| void Array_ssize_clear( Array_ssize self ); | |
| bool Array_ssize_fill( Array_ssize self, usize begin, usize end, ssize value ); | |
| void Array_ssize_free( Array_ssize* self ); | |
| bool Array_ssize_grow( Array_ssize* self, usize min_capacity ); | |
| usize Array_ssize_num( Array_ssize self ); | |
| ssize Array_ssize_pop( Array_ssize self ); | |
| void Array_ssize_remove_at( Array_ssize self, usize idx ); | |
| bool Array_ssize_reserve( Array_ssize* self, usize new_capacity ); | |
| bool Array_ssize_resize( Array_ssize* self, usize num ); | |
| bool Array_ssize_set_capacity( Array_ssize* self, usize new_capacity ); | |
| forceinline Array_ssize Array_ssize_init( AllocatorInfo allocator ) | |
| { | |
| size_t initial_size = array_grow_formula( 0 ); | |
| return array_init_reserve( Array_ssize, allocator, initial_size ); | |
| } | |
| inline Array_ssize Array_ssize_init_reserve( AllocatorInfo allocator, usize capacity ) | |
| { | |
| GEN_ASSERT( capacity > 0 ); | |
| ArrayHeader* header = rcast( ArrayHeader*, alloc( allocator, sizeof( ArrayHeader ) + sizeof( ssize ) * capacity ) ); | |
| if ( header == nullptr ) | |
| return nullptr; | |
| header->Allocator = allocator; | |
| header->Capacity = capacity; | |
| header->Num = 0; | |
| return rcast( ssize*, header + 1 ); | |
| } | |
| forceinline bool Array_ssize_append_array( Array_ssize* self, Array_ssize other ) | |
| { | |
| return array_append_items( *self, (Array_ssize)other, Array_ssize_num( other ) ); | |
| } | |
| inline bool Array_ssize_append( Array_ssize* self, ssize value ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( *self != nullptr ); | |
| ArrayHeader* header = array_get_header( *self ); | |
| if ( header->Num == header->Capacity ) | |
| { | |
| if ( ! array_grow( self, header->Capacity ) ) | |
| return false; | |
| header = array_get_header( *self ); | |
| } | |
| ( *self )[header->Num] = value; | |
| header->Num++; | |
| return true; | |
| } | |
| inline bool Array_ssize_append_items( Array_ssize* self, ssize* items, usize item_num ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( *self != nullptr ); | |
| GEN_ASSERT( items != nullptr ); | |
| GEN_ASSERT( item_num > 0 ); | |
| ArrayHeader* header = array_get_header( *self ); | |
| if ( header->Num + item_num > header->Capacity ) | |
| { | |
| if ( ! array_grow( self, header->Capacity + item_num ) ) | |
| return false; | |
| header = array_get_header( *self ); | |
| } | |
| mem_copy( ( *self ) + header->Num, items, sizeof( ssize ) * item_num ); | |
| header->Num += item_num; | |
| return true; | |
| } | |
| inline bool Array_ssize_append_at( Array_ssize* self, ssize item, usize idx ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( *self != nullptr ); | |
| ArrayHeader* header = array_get_header( *self ); | |
| if ( idx >= header->Num ) | |
| idx = header->Num - 1; | |
| if ( idx < 0 ) | |
| idx = 0; | |
| if ( header->Capacity < header->Num + 1 ) | |
| { | |
| if ( ! array_grow( self, header->Capacity + 1 ) ) | |
| return false; | |
| header = array_get_header( *self ); | |
| } | |
| Array_ssize target = ( *self ) + idx; | |
| mem_move( target + 1, target, ( header->Num - idx ) * sizeof( ssize ) ); | |
| header->Num++; | |
| return true; | |
| } | |
| inline bool Array_ssize_append_items_at( Array_ssize* self, ssize* items, usize item_num, usize idx ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( *self != nullptr ); | |
| ArrayHeader* header = array_get_header( *self ); | |
| if ( idx >= header->Num ) | |
| { | |
| return array_append_items( *self, items, item_num ); | |
| } | |
| if ( item_num > header->Capacity ) | |
| { | |
| if ( ! array_grow( self, item_num + header->Capacity ) ) | |
| return false; | |
| header = array_get_header( *self ); | |
| } | |
| ssize* target = ( *self ) + idx + item_num; | |
| ssize* src = ( *self ) + idx; | |
| mem_move( target, src, ( header->Num - idx ) * sizeof( ssize ) ); | |
| mem_copy( src, items, item_num * sizeof( ssize ) ); | |
| header->Num += item_num; | |
| return true; | |
| } | |
| inline ssize* Array_ssize_back( Array_ssize self ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| ArrayHeader* header = array_get_header( self ); | |
| if ( header->Num == 0 ) | |
| return 0; | |
| return self + header->Num - 1; | |
| } | |
| inline void Array_ssize_clear( Array_ssize self ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| ArrayHeader* header = array_get_header( self ); | |
| header->Num = 0; | |
| } | |
| inline bool Array_ssize_fill( Array_ssize self, usize begin, usize end, ssize value ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( begin <= end ); | |
| ArrayHeader* header = array_get_header( self ); | |
| if ( begin < 0 || end >= header->Num ) | |
| return false; | |
| for ( ssize idx = begin; idx < end; idx++ ) | |
| self[idx] = value; | |
| return true; | |
| } | |
| inline void Array_ssize_free( Array_ssize* self ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( *self != nullptr ); | |
| ArrayHeader* header = array_get_header( *self ); | |
| allocator_free( header->Allocator, header ); | |
| self = 0; | |
| } | |
| inline bool Array_ssize_grow( Array_ssize* self, usize min_capacity ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( *self != nullptr ); | |
| GEN_ASSERT( min_capacity > 0 ); | |
| ArrayHeader* header = array_get_header( *self ); | |
| usize new_capacity = array_grow_formula( header->Capacity ); | |
| if ( new_capacity < min_capacity ) | |
| new_capacity = min_capacity; | |
| return array_set_capacity( self, new_capacity ); | |
| } | |
| forceinline usize Array_ssize_num( Array_ssize self ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| return array_get_header( self )->Num; | |
| } | |
| inline ssize Array_ssize_pop( Array_ssize self ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| ArrayHeader* header = array_get_header( self ); | |
| GEN_ASSERT( header->Num > 0 ); | |
| ssize result = self[header->Num - 1]; | |
| header->Num--; | |
| return result; | |
| } | |
| forceinline void Array_ssize_remove_at( Array_ssize self, usize idx ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| ArrayHeader* header = array_get_header( self ); | |
| GEN_ASSERT( idx < header->Num ); | |
| mem_move( self + idx, self + idx + 1, sizeof( ssize ) * ( header->Num - idx - 1 ) ); | |
| header->Num--; | |
| } | |
| inline bool Array_ssize_reserve( Array_ssize* self, usize new_capacity ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( *self != nullptr ); | |
| GEN_ASSERT( new_capacity > 0 ); | |
| ArrayHeader* header = array_get_header( *self ); | |
| if ( header->Capacity < new_capacity ) | |
| return array_set_capacity( self, new_capacity ); | |
| return true; | |
| } | |
| inline bool Array_ssize_resize( Array_ssize* self, usize num ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( *self != nullptr ); | |
| GEN_ASSERT( num > 0 ); | |
| ArrayHeader* header = array_get_header( *self ); | |
| if ( header->Capacity < num ) | |
| { | |
| if ( ! array_grow( self, num ) ) | |
| return false; | |
| header = array_get_header( *self ); | |
| } | |
| header->Num = num; | |
| return true; | |
| } | |
| inline bool Array_ssize_set_capacity( Array_ssize* self, usize new_capacity ) | |
| { | |
| GEN_ASSERT( self != nullptr ); | |
| GEN_ASSERT( *self != nullptr ); | |
| GEN_ASSERT( new_capacity > 0 ); | |
| ArrayHeader* header = array_get_header( *self ); | |
| if ( new_capacity == header->Capacity ) | |
| return true; | |
| if ( new_capacity < header->Num ) | |
| { | |
| header->Num = new_capacity; | |
| return true; | |
| } | |
| usize size = sizeof( ArrayHeader ) + sizeof( ssize ) * new_capacity; | |
| ArrayHeader* new_header = cast( ArrayHeader*, alloc( header->Allocator, size ) ); | |
| if ( new_header == 0 ) | |
| return false; | |
| mem_move( new_header, header, sizeof( ArrayHeader ) + sizeof( ssize ) * header->Num ); | |
| new_header->Capacity = new_capacity; | |
| allocator_free( header->Allocator, &header ); | |
| *self = cast( ssize*, new_header + 1 ); | |
| return true; | |
| } | |
| #pragma endregion Array_ssize |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| typedef struct ArrayHeader ArrayHeader; | |
| struct ArrayHeader | |
| { | |
| AllocatorInfo Allocator; | |
| usize Capacity; | |
| usize Num; | |
| }; | |
| #define array_grow_formula( value ) ( 2 * value + 8 ) | |
| #define array_get_header( self ) ( (ArrayHeader*)( self ) - 1 ) | |
| #define array_init( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( *(selector_arg*)NULL ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_init ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_init ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( __VA_ARGS__ ) | |
| #define array_init_reserve( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( *(selector_arg*)NULL ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_init_reserve ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_init_reserve ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( __VA_ARGS__ ) | |
| #define array_append( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_append ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_append ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( &selector_arg, __VA_ARGS__ ) | |
| #define array_append_items( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_append_items ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_append_items ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( &selector_arg, __VA_ARGS__ ) | |
| #define array_back( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_back ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_back ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ ) | |
| #define array_clear( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_clear ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_clear ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ ) | |
| #define array_fill( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_fill ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_fill ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ ) | |
| #define array_free( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_free ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_free ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( &selector_arg ) | |
| #define array_grow( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_grow ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_grow ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ ) | |
| #define array_num( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_num ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_num ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ ) | |
| #define array_pop( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_pop ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_pop ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ ) | |
| #define array_remove_at( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_remove_at ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_remove_at ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ ) | |
| #define array_reserve( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_reserve ) GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_reserve ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( &selector_arg, __VA_ARGS__ ) | |
| #define array_set_capacity( selector_arg, ... ) \ | |
| _Generic( \ | |
| ( selector_arg ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__array_set_capacity ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_2__array_set_capacity ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #if GEN_COMPILER_C | |
| // ------------------------ _Generic function overloading ----------------------------------------- | |
| // This implemnents macros for utilizing "The Naive Extendible _Generic Macro" explained in: | |
| // https://github.com/JacksonAllan/CC/blob/main/articles/Better_C_Generics_Part_1_The_Extendible_Generic.md | |
| // Since gencpp is used to generate the c-library, it was choosen over the more novel implementations to keep the macros as easy to understand and unopaque as possible. | |
| // 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_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. | |
| // Helper macros for argument selection | |
| #define GEN_SELECT_ARG_1( _1, ... ) _1 // <-- Of all th args passed pick _1. | |
| #define GEN_SELECT_ARG_2( _1, _2, ... ) _2 // <-- Of all the args passed pick _2. | |
| #define GEN_SELECT_ARG_3( _1, _2, _3, ... ) _3 // etc.. (by induction until _8, which we don't support any more beyond) | |
| // #define GEN_SELECT_ARG_4( _1, _2, _3, _4, ... ) _4 | |
| // #define GEN_SELECT_ARG_5( _1, _2, _3, _4, _5, ... ) _5 | |
| // #define GEN_SELECT_ARG_6( _1, _2, _3, _4, _5, _6, ... ) _6 | |
| // #define GEN_SELECT_ARG_7( _1, _2, _3, _4, _5, _6, _7, ... ) _7 | |
| // #define GEN_SELECT_ARG_8( _1, _2, _3, _4, _5, _6, _7, _8, ... ) _8 | |
| #define GEN_GENERIC_SEL_ENTRY_TYPE GEN_SELECT_ARG_1 // Use the arg expansion macro to select arg 1 which should have the type. | |
| #define GEN_GENERIC_SEL_ENTRY_FUNCTION GEN_SELECT_ARG_2 // Use the arg expansion macro to select arg 2 which should have the function. | |
| #define GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER GEN_SELECT_ARG_3 // Use the arg expansion macro to select arg 3 which should have the comma delimiter ','. | |
| #define GEN_RESOLVED_FUNCTION_CALL // Just used to indicate where the call "occurs" | |
| // ---------------------------------------------------------------------------------------------------------------------------------- | |
| // GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( macro ) includes a _Generic slot only if the specified macro is defined (as type, function_name). | |
| // It takes advantage of the fact that if the macro is defined, then the expanded text will contain a comma. | |
| // Expands to ',' if it can find (type): (function) <comma_operator: ',' > | |
| // Where GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER is specifically looking for that <comma> , | |
| #define GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( slot_exp ) GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER( slot_exp, GEN_GENERIC_SEL_ENTRY_TYPE( slot_exp, ): GEN_GENERIC_SEL_ENTRY_FUNCTION( slot_exp, ) GEN_COMMA_OPERATOR, , ) | |
| // ^ Selects the comma ^ is the type ^ is the function ^ Insert a comma | |
| // The slot won't exist if that comma is not found. | | |
| // | | |
| // This is the same as above but it does not insert a comma V no comma here. | |
| #define GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( slot_exp ) GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER( slot_exp, GEN_GENERIC_SEL_ENTRY_TYPE( slot_exp, ): GEN_GENERIC_SEL_ENTRY_FUNCTION( slot_exp, ), , ) | |
| // Needed for the last slot as they don't allow trailing commas. | |
| // ---------------------------------------------------------------------------------------------------------------------------------- | |
| // Below are generated on demand for an overlaod depdendent on a type: | |
| // ---------------------------------------------------------------------------------------------------------------------------------- | |
| #define GEN_FUNCTION_GENERIC_EXAMPLE( selector_arg ) _Generic( \ | |
| (selector_arg), /* Select Via Expression*/ \ | |
| /* Extendibility slots: */ \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST(FunctionID__ARGS_SIG_1 ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg ) | |
| // ---------------------------------------------------------------------------------------------------------------------------------- | |
| // Then each definiton of a function has an associated define: | |
| // #define <function_id_macro> GEN_GENERIC_FUNCTION_ARG_SIGNATURE( <function_id>, <arguments> ) | |
| #define GEN_GENERIC_FUNCTION_ARG_SIGNATURE( name_of_function, type_delimiter ) type_delimiter name_of_function | |
| // Then somehwere later on | |
| // <etc> <return_type> <function_id> ( <arguments> ) { <implementation> } | |
| // Concrete example: | |
| // To add support for long: | |
| #define GEN_EXAMPLE_HASH__ARGS_SIG_1 GEN_GENERIC_FUNCTION_ARG_SIGNATURE( hash__P_long, long long ) | |
| size_t gen_example_hash__P_long( long val ) { return val * 2654435761ull; } | |
| // To add support for long long: | |
| #define GEN_EXAMPLE_HASH__ARGS_SIG_2 GEN_GENERIC_FUNCTION_ARG_SIGNATURE( hash__P_long_long, long long ) | |
| size_t gen_example_hash__P_long_long( long long val ) { return val * 2654435761ull; } | |
| // If using an Editor with support for syntax hightlighting macros: HASH__ARGS_SIG_1 and HASH_ARGS_SIG_2 should show color highlighting indicating the slot is enabled, | |
| // or, "defined" for usage during the compilation pass that handles the _Generic instrinsic. | |
| #define hash( function_arguments ) _Generic( \ | |
| (function_arguments), /* Select Via Expression*/ \ | |
| /* Extendibility slots: */ \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_2 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_3 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_4 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_5 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_6 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_7 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( HASH__ARGS_SIG_8 ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( function_arguments ) | |
| // Additional Variations: | |
| // If the function takes more than one argument the following is used: | |
| #define GEN_FUNCTION_GENERIC_EXAMPLE_VARADIC( selector_arg, ... ) _Generic( \ | |
| (selector_arg), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_2 ) \ | |
| ... \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST(FunctionID__ARGS_SIG_N ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARG__ ) | |
| // If the function does not take the arugment as a parameter: | |
| #define GEN_FUNCTION_GENERIC_EXAMPLE_DIRECT_TYPE( selector_arg ) _Generic( \ | |
| ( GEN_TYPE_TO_EXP(selector_arg) ), \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_2 ) \ | |
| /* ... */ \ | |
| GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST(FunctionID__ARGS_SIG_N ) \ | |
| ) GEN_RESOLVED_FUNCTION_CALL() | |
| // typedef void* GEN_GenericExampleType; | |
| // GEN_FUNCTION_GENERIC_EXAMPLE_DIRECT_TYPE( GEN_GenericExampleType ); | |
| // END OF ------------------------ _Generic function overloading ----------------------------------------- END OF | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment