mirror of https://github.com/mpv-player/mpv
options: simplify somewhat by introducing a union for option values
The m_option_value union is supposed to contain a field for each possible option type (as long as it actually stores data). This helps avoiding silly temporary memory alocations. Using a pointer to an union and to a field of the union interchangeably should be allowed by standard C.
This commit is contained in:
parent
1a5a7a4929
commit
426640204b
11
m_config.c
11
m_config.c
|
@ -330,15 +330,14 @@ static void m_config_add_option(struct m_config *config,
|
||||||
} else if (arg->type->flags & M_OPT_TYPE_DYNAMIC) {
|
} else if (arg->type->flags & M_OPT_TYPE_DYNAMIC) {
|
||||||
// Initialize dynamically managed fields from static data (like
|
// Initialize dynamically managed fields from static data (like
|
||||||
// string options): copy the option into temporary memory,
|
// string options): copy the option into temporary memory,
|
||||||
// clear the original option (to void m_option freeing the
|
// clear the original option (to stop m_option from freeing the
|
||||||
// static data), copy it back.
|
// static data), copy it back.
|
||||||
if (co->data) {
|
if (co->data) {
|
||||||
void *temp = talloc_zero_size(NULL, arg->type->size);
|
union m_option_value temp = {0};
|
||||||
m_option_copy(arg, temp, co->data);
|
m_option_copy(arg, &temp, co->data);
|
||||||
memset(co->data, 0, arg->type->size);
|
memset(co->data, 0, arg->type->size);
|
||||||
m_option_copy(arg, co->data, temp);
|
m_option_copy(arg, co->data, &temp);
|
||||||
m_option_free(arg, temp);
|
m_option_free(arg, &temp);
|
||||||
talloc_free(temp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
m_option.h
19
m_option.h
|
@ -176,6 +176,25 @@ struct m_sub_options {
|
||||||
#define CONF_TYPE_TIME (&m_option_type_time)
|
#define CONF_TYPE_TIME (&m_option_type_time)
|
||||||
#define CONF_TYPE_TIME_SIZE (&m_option_type_time_size)
|
#define CONF_TYPE_TIME_SIZE (&m_option_type_time_size)
|
||||||
|
|
||||||
|
// Possible option values. Code is allowed to access option data without going
|
||||||
|
// through this union. It serves for self-documentation and to get minimal
|
||||||
|
// size/alignment requirements for option values in general.
|
||||||
|
union m_option_value {
|
||||||
|
int flag; // not the C type "bool"!
|
||||||
|
int int_;
|
||||||
|
int64_t int64;
|
||||||
|
float float_;
|
||||||
|
double double_;
|
||||||
|
char *string;
|
||||||
|
char **string_list;
|
||||||
|
int imgfmt;
|
||||||
|
int afmt;
|
||||||
|
m_span_t span;
|
||||||
|
m_obj_settings_t *obj_settings_list;
|
||||||
|
double time;
|
||||||
|
m_time_size_t time_size;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Option type description
|
// Option type description
|
||||||
|
|
41
m_property.c
41
m_property.c
|
@ -67,7 +67,7 @@ int m_property_do(const m_option_t *prop_list, const char *name,
|
||||||
int action, void *arg, void *ctx)
|
int action, void *arg, void *ctx)
|
||||||
{
|
{
|
||||||
const m_option_t *opt;
|
const m_option_t *opt;
|
||||||
void *val;
|
union m_option_value val = {0};
|
||||||
int r;
|
int r;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
|
@ -78,13 +78,10 @@ int m_property_do(const m_option_t *prop_list, const char *name,
|
||||||
if ((r =
|
if ((r =
|
||||||
do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
|
do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
|
||||||
return r;
|
return r;
|
||||||
val = calloc(1, opt->type->size);
|
// Fallback to m_option
|
||||||
if ((r = do_action(prop_list, name, M_PROPERTY_GET, val, ctx)) <= 0) {
|
if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0)
|
||||||
free(val);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
str = m_option_pretty_print(opt, &val);
|
||||||
str = m_option_pretty_print(opt, val);
|
|
||||||
free(val);
|
|
||||||
*(char **)arg = str;
|
*(char **)arg = str;
|
||||||
return str != NULL;
|
return str != NULL;
|
||||||
case M_PROPERTY_TO_STRING:
|
case M_PROPERTY_TO_STRING:
|
||||||
|
@ -95,13 +92,9 @@ int m_property_do(const m_option_t *prop_list, const char *name,
|
||||||
if ((r =
|
if ((r =
|
||||||
do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
|
do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
|
||||||
return r;
|
return r;
|
||||||
val = calloc(1, opt->type->size);
|
if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0)
|
||||||
if ((r = do_action(prop_list, name, M_PROPERTY_GET, val, ctx)) <= 0) {
|
|
||||||
free(val);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
str = m_option_print(opt, &val);
|
||||||
str = m_option_print(opt, val);
|
|
||||||
free(val);
|
|
||||||
*(char **)arg = str;
|
*(char **)arg = str;
|
||||||
return str != NULL;
|
return str != NULL;
|
||||||
case M_PROPERTY_PARSE:
|
case M_PROPERTY_PARSE:
|
||||||
|
@ -113,14 +106,10 @@ int m_property_do(const m_option_t *prop_list, const char *name,
|
||||||
if ((r =
|
if ((r =
|
||||||
do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
|
do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
|
||||||
return r;
|
return r;
|
||||||
val = calloc(1, opt->type->size);
|
if ((r = m_option_parse(opt, bstr0(opt->name), bstr0(arg), &val)) <= 0)
|
||||||
if ((r = m_option_parse(opt, bstr0(opt->name), bstr0(arg), val)) <= 0) {
|
|
||||||
free(val);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
r = do_action(prop_list, name, M_PROPERTY_SET, &val, ctx);
|
||||||
r = do_action(prop_list, name, M_PROPERTY_SET, val, ctx);
|
m_option_free(opt, &val);
|
||||||
m_option_free(opt, val);
|
|
||||||
free(val);
|
|
||||||
return r;
|
return r;
|
||||||
case M_PROPERTY_SWITCH:
|
case M_PROPERTY_SWITCH:
|
||||||
if ((r = do_action(prop_list, name, M_PROPERTY_SWITCH, arg, ctx)) !=
|
if ((r = do_action(prop_list, name, M_PROPERTY_SWITCH, arg, ctx)) !=
|
||||||
|
@ -132,17 +121,13 @@ int m_property_do(const m_option_t *prop_list, const char *name,
|
||||||
// Fallback to m_option
|
// Fallback to m_option
|
||||||
if (!opt->type->add)
|
if (!opt->type->add)
|
||||||
return M_PROPERTY_NOT_IMPLEMENTED;
|
return M_PROPERTY_NOT_IMPLEMENTED;
|
||||||
val = calloc(1, opt->type->size);
|
if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0)
|
||||||
if ((r = do_action(prop_list, name, M_PROPERTY_GET, val, ctx)) <= 0) {
|
|
||||||
free(val);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
bool wrap = opt->type == &m_option_type_choice ||
|
bool wrap = opt->type == &m_option_type_choice ||
|
||||||
opt->type == &m_option_type_flag;
|
opt->type == &m_option_type_flag;
|
||||||
opt->type->add(opt, val, *(double*)arg, wrap);
|
opt->type->add(opt, &val, *(double*)arg, wrap);
|
||||||
r = do_action(prop_list, name, M_PROPERTY_SET, val, ctx);
|
r = do_action(prop_list, name, M_PROPERTY_SET, &val, ctx);
|
||||||
m_option_free(opt, val);
|
m_option_free(opt, &val);
|
||||||
free(val);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
return do_action(prop_list, name, action, arg, ctx);
|
return do_action(prop_list, name, action, arg, ctx);
|
||||||
|
|
Loading…
Reference in New Issue