Skip to content

Commit

Permalink
made support of strings and enums
Browse files Browse the repository at this point in the history
  • Loading branch information
aodinokov committed Sep 17, 2024
1 parent f6f79ba commit fcf6932
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ The original approach requires some non-documented capabilities of va_arg to wor
va_list (it's not easy to extract struct or va_list from va_list which we used as a storage).
The current approach in its turn requires `typeof` compiler extension.
Also this apporach has a limitation of number of arguments: it's necessary to regenerate mr_pp.generated.h using mr_pp.sh and provide the maximum number of arguments. For now it's generated with maximum 1024 arguments
which is mentioned as a minimum supported number of arguments in C in some referenses.
which is mentioned as a minimum supported number of arguments in C in some referenses.
And the last limitation is - I wasn't able to find a way to handle arguments with string along with arguments as structs or va_list. When macro unrolls cycle it generates the code which handles each case and I wasn't able
to find a construction which can be universal. Added TODO there.
15 changes: 13 additions & 2 deletions examples/c_print_args_alt/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ int my_printf(const char * format, ...) {
}
METAC_GSYM_LINK(my_printf);

enum x {
xOne = 1,
xTwo = 2,
xMinusOne = -1,
};
int test_function4_with_enum_args(enum x arg0, enum x arg1, enum x arg2) {
return 0;
}
METAC_GSYM_LINK(test_function4_with_enum_args);

metac_tag_map_t * p_tagmap = NULL;
METAC_TAG_MAP_NEW(va_args_tag_map, NULL, {.mask =
Expand Down Expand Up @@ -65,8 +74,10 @@ int main() {
list_t * p_list = (list_t[]){{.x = 42.42, .p_next = (list_t[]){{ .x = 45.4, .p_next = NULL}}}};
printf("fn returned: %f\n", METAC_WRAP_FN_RES(NULL, test_function3_with_args, p_list));

// doesn't work yet
//printf("fn returned: %i\n", METAC_WRAP_FN_RES(p_tagmap, my_printf, "%d %d", 10, 22));
printf("fn returned: %i\n", METAC_WRAP_FN_RES(p_tagmap, my_printf, "%d %d\n", 10, 22));

printf("fn returned: %i\n", METAC_WRAP_FN_RES(p_tagmap, test_function4_with_enum_args, xOne, xTwo, xMinusOne));
printf("fn returned: %i\n", METAC_WRAP_FN_RES(p_tagmap, test_function4_with_enum_args, 1, 2, -1));

metac_tag_map_delete(p_tagmap);
return 0;
Expand Down
89 changes: 72 additions & 17 deletions examples/c_print_args_alt/print_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static int _process_unspecified_params(
if (p_tag != NULL && p_tag->handler) {
metac_value_event_t ev = {
.type = METAC_RQVST_va_list,
.va_list_param_id = param_id, /* TODO: to remove?*/
.va_list_param_id = param_id,
.p_return_value = metac_parameter_storage_new_param_value(p_param_storage, param_id),
.p_va_list_container = &cntr,
};
Expand All @@ -50,51 +50,107 @@ static int _process_unspecified_params(
return failed;
}

#define _APPEND_PARAM_2(_NEXT_, _N_, args...) if (failure == 0) { \
#define _process_bt_(arg, _type_, _pseudoname_, _short_type_name_) \
if (strcmp(param_base_type_name, #_pseudoname_) == 0 && param_entry_byte_size == sizeof(_type_)) { \
metac_value_set_##_short_type_name_(p_param_value, *((_type_*)arg)); \
} else

#define _process_enum_(arg, _type_, _short_type_name_) \
if (param_entry_byte_size == sizeof(_type_)) { \
_type_ v = *((_type_*)arg); \
memcpy(metac_value_addr(p_param_value), &v, param_entry_byte_size); \
} else

#define _QSTRING(_string_...) \
#_string_
#define _QSTRING_ARG(_args) \
_QSTRING(_args)

#define _APPEND_PARAM(_NEXT_, _N_, args...) if (failure == 0) { \
metac_entry_t *p_param_entry = metac_entry_by_paremeter_id(p_val_entry, param_id); \
if (metac_entry_is_unspecified_parameter(p_param_entry) == 0 && metac_entry_is_va_list_parameter(p_param_entry) == 0) { \
/* normal argument */ \
typeof(MR_FIRST(args)) _x_val = MR_FIRST(args); \
metac_entry_t *p_param_entry = metac_entry_by_paremeter_id(p_val_entry, param_id); \
metac_entry_t * p_param_type_entry = metac_entry_parameter_entry(p_param_entry); \
if (p_param_type_entry == NULL) { \
failure = 1; \
break; \
} \
metac_size_t param_entry_byte_size = 0; \
if (metac_entry_byte_size(p_param_entry, &param_entry_byte_size) != 0) { \
printf("param %d metac_entry_byte_size failed\n", param_id); \
failure = 1; \
failure = 2; \
break; \
} \
typeof(MR_FIRST(args)) _x_val = MR_FIRST(args); \
if (metac_parameter_storage_append_by_buffer(p_param_storage, p_param_entry, param_entry_byte_size) == 0) { \
metac_value_t * p_param_value = metac_parameter_storage_new_param_value(p_param_storage, param_id); \
if (p_param_value != NULL) { \
if (param_entry_byte_size != sizeof(_x_val)) { \
printf("param %d got sz %d, expectect sz %d\n", param_id, (int)sizeof(_x_val), (int)param_entry_byte_size); \
/*TODO: - handle that */ \
} \
memcpy(metac_value_addr(p_param_value), &_x_val, param_entry_byte_size); \
\
if (metac_entry_is_base_type(p_param_type_entry) != 0) { \
metac_name_t param_base_type_name = metac_entry_base_type_name(p_param_type_entry); \
_process_bt_(&_x_val, char, char, char) \
_process_bt_(&_x_val, unsigned char, unsigned char, uchar) \
_process_bt_(&_x_val, short, short int, short) \
_process_bt_(&_x_val, unsigned short, unsigned short int, ushort) \
_process_bt_(&_x_val, int, int, int) \
_process_bt_(&_x_val, unsigned int, unsigned int, uint) \
_process_bt_(&_x_val, long, long int, long) \
_process_bt_(&_x_val, unsigned long, unsigned long int, ulong) \
_process_bt_(&_x_val, long long, long long int, llong) \
_process_bt_(&_x_val, unsigned long long, unsigned long long int, ullong) \
_process_bt_(&_x_val, bool, _Bool, bool) \
_process_bt_(&_x_val, float, float, float) \
_process_bt_(&_x_val, double, double, double) \
_process_bt_(&_x_val, long double, long double, ldouble) \
_process_bt_(&_x_val, float complex, complex float, float_complex) \
_process_bt_(&_x_val, double complex, complex double, double_complex) \
_process_bt_(&_x_val, long double complex, long complex double, ldouble_complex); \
} else if (metac_entry_is_enumeration(p_param_type_entry) != 0) { \
_process_enum_(&_x_val, char, char) \
_process_enum_(&_x_val, short, short) \
_process_enum_(&_x_val, int, int) \
_process_enum_(&_x_val, long, long) \
_process_enum_(&_x_val, long long, llong); \
} else if (metac_entry_is_pointer(p_param_type_entry) != 0) { \
/* ensure arg isn't string constant */ \
char _s_arg[] = _QSTRING_ARG(MR_FIRST(args)); \
if (_s_arg[0] == '\"') { \
/* TODO: can't handle structs, va_list as arguments because of this line */ \
char * s = ((char*)MR_FIRST(args)); \
memcpy(metac_value_addr(p_param_value), &s, param_entry_byte_size); \
} else { \
memcpy(metac_value_addr(p_param_value), &_x_val, param_entry_byte_size); \
} \
} else { \
/* not supported */ \
failure = 3; \
metac_value_delete(p_param_value); \
break; \
} \
/*cleanup*/ \
metac_value_delete(p_param_value); \
} \
} else if (metac_entry_is_va_list_parameter(p_param_entry) != 0) { \
/* not supported */ \
failure = 4; \
break; \
} else if (metac_entry_is_unspecified_parameter(p_param_entry) != 0) { \
if (metac_parameter_storage_append_by_parameter_storage(p_param_storage, p_param_entry) != 0) { \
failure = 5; \
break; \
} \
if (_process_unspecified_params(p_param_storage, p_val, p_param_entry, p_tag_map, param_id, _N_ , args) != 0) { \
failure = 4; \
failure = 6; \
break; \
} \
break; \
} else { \
failure = 3; \
break; \
} \
if (failure == 0) { \
++param_id; \
_NEXT_ \
} \
}


// this gets called in the context where p_param_storage is declared
#define _WRAP(_tag_map_, _fn_, _args_...) ({ \
metac_tag_map_t * p_tag_map = _tag_map_; \
Expand All @@ -104,11 +160,10 @@ static int _process_unspecified_params(
metac_num_t param_id = 0; \
/* append params*/ \
do { \
MR_FOREACH_EX(_APPEND_PARAM_2, _args_) \
MR_FOREACH_EX(_APPEND_PARAM, _args_) \
} while(0); \
if (failure != 0) { \
printf("failure %d\n", failure); \
/* TODO: */ \
} \
p_val; \
})
Expand Down
4 changes: 0 additions & 4 deletions include/metac/reflect/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,6 @@ metac_name_t metac_value_name(metac_value_t * p_val);
/** @brief return value's final entry kind */
metac_kind_t metac_value_final_kind(metac_value_t * p_val, metac_quals_t * p_quals); /* returns actual type kind, skips quals, typedefs, variable */

/* kind = METAC_KND_subroutine_type */
/* metac_flag_t metac_value_is_subroutine(metac_value_t *p_val);
TODO: we may have a call if pointer to subroutine, using libffi */

/* kind = METAC_KND_array */

/** @brief return non-zero if value's final kind is array */
Expand Down

0 comments on commit fcf6932

Please sign in to comment.