m_option: add option comparison

Looks like this will be needed for fine-grained option change
notifications. There are some other parts in the player which implement
parts of this.
This commit is contained in:
wm4 2019-11-28 16:52:46 +01:00
parent 82735d1287
commit 63270ff898
2 changed files with 156 additions and 1 deletions

View File

@ -40,6 +40,7 @@
#include "common/msg.h"
#include "common/msg_control.h"
#include "misc/json.h"
#include "misc/node.h"
#include "m_option.h"
#include "m_config.h"
@ -169,6 +170,11 @@ static int flag_get(const m_option_t *opt, void *ta_parent,
return 1;
}
static bool flag_equal(const m_option_t *opt, void *a, void *b)
{
return VAL(a) == VAL(b);
}
const m_option_type_t m_option_type_flag = {
// need yes or no in config files
.name = "Flag",
@ -180,6 +186,7 @@ const m_option_type_t m_option_type_flag = {
.add = add_flag,
.set = flag_set,
.get = flag_get,
.equal = flag_equal,
};
// Integer
@ -359,6 +366,16 @@ static int int_get(const m_option_t *opt, void *ta_parent,
return 1;
}
static bool int_equal(const m_option_t *opt, void *a, void *b)
{
return *(int *)a == *(int *)b;
}
static bool int64_equal(const m_option_t *opt, void *a, void *b)
{
return *(int64_t *)a == *(int64_t *)b;
}
const m_option_type_t m_option_type_int = {
.name = "Integer",
.size = sizeof(int),
@ -369,6 +386,7 @@ const m_option_type_t m_option_type_int = {
.multiply = multiply_int,
.set = int_set,
.get = int_get,
.equal = int_equal,
};
const m_option_type_t m_option_type_int64 = {
@ -381,6 +399,7 @@ const m_option_type_t m_option_type_int64 = {
.multiply = multiply_int64,
.set = int64_set,
.get = int64_get,
.equal = int64_equal,
};
static int parse_byte_size(struct mp_log *log, const m_option_t *opt,
@ -478,6 +497,7 @@ const m_option_type_t m_option_type_byte_size = {
.multiply = multiply_int64,
.set = int64_set,
.get = int64_get,
.equal = int64_equal,
};
static int parse_intpair(struct mp_log *log, const struct m_option *opt,
@ -746,6 +766,7 @@ const struct m_option_type m_option_type_choice = {
.add = add_choice,
.set = choice_set,
.get = choice_get,
.equal = int_equal,
};
static int apply_flag(const struct m_option *opt, int *val, bstr flag)
@ -868,6 +889,7 @@ const struct m_option_type m_option_type_flags = {
.copy = copy_opt,
.set = flags_set,
.get = flags_get,
.equal = int_equal,
};
// Float
@ -1002,6 +1024,14 @@ static int double_get(const m_option_t *opt, void *ta_parent,
return 1;
}
static bool double_equal(const m_option_t *opt, void *a, void *b)
{
double fa = VAL(a), fb = VAL(b);
if (isnan(fa) || isnan(fb))
return isnan(fa) == isnan(fb);
return fa == fb;
}
const m_option_type_t m_option_type_double = {
// double precision float or ratio (numerator[:/]denominator)
.name = "Double",
@ -1014,6 +1044,7 @@ const m_option_type_t m_option_type_double = {
.multiply = multiply_double,
.set = double_set,
.get = double_get,
.equal = double_equal,
};
#undef VAL
@ -1071,6 +1102,11 @@ static int float_get(const m_option_t *opt, void *ta_parent,
return double_get(opt, ta_parent, dst, &tmp);
}
static bool float_equal(const m_option_t *opt, void *a, void *b)
{
return double_equal(opt, &(double){VAL(a)}, &(double){VAL(b)});
}
const m_option_type_t m_option_type_float = {
// floating point number or ratio (numerator[:/]denominator)
.name = "Float",
@ -1083,6 +1119,7 @@ const m_option_type_t m_option_type_float = {
.multiply = multiply_float,
.set = float_set,
.get = float_get,
.equal = float_equal,
};
static int parse_float_aspect(struct mp_log *log, const m_option_t *opt,
@ -1108,6 +1145,7 @@ const m_option_type_t m_option_type_aspect = {
.multiply = multiply_float,
.set = float_set,
.get = float_get,
.equal = float_equal,
};
///////////// String
@ -1188,6 +1226,11 @@ static int str_get(const m_option_t *opt, void *ta_parent,
return 1;
}
static bool str_equal(const m_option_t *opt, void *a, void *b)
{
return bstr_equals(bstr0(VAL(a)), bstr0(VAL(b)));
}
static void free_str(void *src)
{
if (src && VAL(src)) {
@ -1205,6 +1248,7 @@ const m_option_type_t m_option_type_string = {
.free = free_str,
.set = str_set,
.get = str_get,
.equal = str_equal,
};
//////////// String list
@ -1530,6 +1574,26 @@ static int parse_str_list(struct mp_log *log, const m_option_t *opt,
return parse_str_list_impl(log, opt, name, param, dst, OP_NONE);
}
static bool str_list_equal(const m_option_t *opt, void *a, void *b)
{
char **la = VAL(a);
char **lb = VAL(b);
bool a_empty = !la || !la[0];
bool b_empty = !lb || !lb[0];
if (a_empty || b_empty)
return a_empty == b_empty;
for (int n = 0; la[n] || lb[n]; n++) {
if (!la[n] || !lb[n])
return false;
if (strcmp(la[n], lb[n]) != 0)
return false;
}
return true;
}
const m_option_type_t m_option_type_string_list = {
.name = "String list",
.size = sizeof(char **),
@ -1539,6 +1603,7 @@ const m_option_type_t m_option_type_string_list = {
.free = free_str_list,
.get = str_list_get,
.set = str_list_set,
.equal = str_list_equal,
.actions = (const struct m_option_action[]){
{"add"},
{"append"},
@ -1688,6 +1753,7 @@ const m_option_type_t m_option_type_keyvalue_list = {
.free = free_str_list,
.get = keyvalue_list_get,
.set = keyvalue_list_set,
.equal = str_list_equal,
.actions = (const struct m_option_action[]){
{"add"},
{"append"},
@ -1760,6 +1826,7 @@ const m_option_type_t m_option_type_msglevels = {
.free = free_str_list,
.get = keyvalue_list_get,
.set = set_msglevels,
.equal = str_list_equal,
};
static int parse_print(struct mp_log *log, const m_option_t *opt,
@ -1972,12 +2039,20 @@ static char *print_color(const m_option_t *opt, const void *val)
return talloc_asprintf(NULL, "#%02X%02X%02X%02X", c->a, c->r, c->g, c->b);
}
static bool color_equal(const m_option_t *opt, void *a, void *b)
{
struct m_color *ca = a;
struct m_color *cb = b;
return ca->a == cb->a && ca->r == cb->r && ca->g == cb->g && ca->b == cb->b;
}
const m_option_type_t m_option_type_color = {
.name = "Color",
.size = sizeof(struct m_color),
.parse = parse_color,
.print = print_color,
.copy = copy_opt,
.equal = color_equal,
};
@ -2154,12 +2229,24 @@ exit:
return is_help ? M_OPT_EXIT : M_OPT_INVALID;
}
static bool geometry_equal(const m_option_t *opt, void *a, void *b)
{
struct m_geometry *ga = a;
struct m_geometry *gb = b;
return ga->x == gb->x && ga->y == gb->y && ga->w == gb->w && ga->h == gb->h &&
ga->xy_valid == gb->xy_valid && ga->wh_valid == gb->wh_valid &&
ga->w_per == gb->w_per && ga->h_per == gb->h_per &&
ga->x_per == gb->x_per && ga->y_per == gb->y_per &&
ga->x_sign == gb->x_sign && ga->y_sign == gb->y_sign;
}
const m_option_type_t m_option_type_geometry = {
.name = "Window geometry",
.size = sizeof(struct m_geometry),
.parse = parse_geometry,
.print = print_geometry,
.copy = copy_opt,
.equal = geometry_equal,
};
static int parse_size_box(struct mp_log *log, const m_option_t *opt,
@ -2196,6 +2283,7 @@ const m_option_type_t m_option_type_size_box = {
.parse = parse_size_box,
.print = print_geometry,
.copy = copy_opt,
.equal = geometry_equal,
};
@ -2246,6 +2334,7 @@ const m_option_type_t m_option_type_imgfmt = {
.parse = parse_imgfmt,
.print = print_imgfmt,
.copy = copy_opt,
.equal = int_equal,
};
static int parse_fourcc(struct mp_log *log, const m_option_t *opt,
@ -2287,6 +2376,7 @@ const m_option_type_t m_option_type_fourcc = {
.parse = parse_fourcc,
.print = print_fourcc,
.copy = copy_opt,
.equal = int_equal,
};
#include "audio/format.h"
@ -2334,6 +2424,7 @@ const m_option_type_t m_option_type_afmt = {
.parse = parse_afmt,
.print = print_afmt,
.copy = copy_opt,
.equal = int_equal,
};
#include "audio/chmap.h"
@ -2436,13 +2527,21 @@ static void copy_channels(const m_option_t *opt, void *dst, const void *src)
talloc_memdup(NULL, ch->chmaps, sizeof(ch->chmaps[0]) * ch->num_chmaps);
}
static bool channels_equal(const m_option_t *opt, void *a, void *b)
{
struct mp_chmap *ca = a;
struct mp_chmap *cb = b;
return mp_chmap_equals(ca, cb);
}
const m_option_type_t m_option_type_channels = {
.name = "Audio channels or channel map",
.size = sizeof(struct m_channels),
.parse = parse_channels,
.print = print_channels,
.copy = copy_channels,
.free = free_channels,
.free = free_channels,
.equal = channels_equal,
};
static int parse_timestring(struct bstr str, double *time, char endchar)
@ -2535,6 +2634,7 @@ const m_option_type_t m_option_type_time = {
.add = add_double,
.set = time_set,
.get = time_get,
.equal = double_equal,
};
@ -2611,12 +2711,20 @@ static char *print_rel_time(const m_option_t *opt, const void *val)
return talloc_strdup(NULL, "none");
}
static bool rel_time_equal(const m_option_t *opt, void *a, void *b)
{
struct m_rel_time *ta = a;
struct m_rel_time *tb = b;
return ta->type == tb->type && ta->pos == tb->pos;
}
const m_option_type_t m_option_type_rel_time = {
.name = "Relative time or percent position",
.size = sizeof(struct m_rel_time),
.parse = parse_rel_time,
.print = print_rel_time,
.copy = copy_opt,
.equal = rel_time_equal,
};
@ -3447,6 +3555,26 @@ static int get_obj_settings_list(const m_option_t *opt, void *ta_parent,
return 1;
}
static bool obj_settings_list_equal(const m_option_t *opt, void *pa, void *pb)
{
struct m_obj_settings *a = VAL(pa);
struct m_obj_settings *b = VAL(pb);
if (a == b || !a || !b)
return a == b;
if (!str_equal(NULL, &a->name, &b->name))
return false;
if (!str_equal(NULL, &a->label, &b->label))
return false;
if (a->enabled != b->enabled)
return false;
return str_list_equal(NULL, &a->attribs, &b->attribs);
}
const m_option_type_t m_option_type_obj_settings_list = {
.name = "Object settings list",
.size = sizeof(m_obj_settings_t *),
@ -3456,6 +3584,7 @@ const m_option_type_t m_option_type_obj_settings_list = {
.free = free_obj_settings_list,
.set = set_obj_settings_list,
.get = get_obj_settings_list,
.equal = obj_settings_list_equal,
.actions = (const struct m_option_action[]){
{"add"},
{"clr", M_OPT_TYPE_OPTIONAL_PARAM},
@ -3587,6 +3716,11 @@ static int node_get(const m_option_t *opt, void *ta_parent,
return 1;
}
static bool node_equal(const m_option_t *opt, void *a, void *b)
{
return equal_mpv_node(&VAL(a), &VAL(b));
}
const m_option_type_t m_option_type_node = {
.name = "Complex",
.size = sizeof(struct mpv_node),
@ -3597,6 +3731,7 @@ const m_option_type_t m_option_type_node = {
.free = free_node,
.set = node_set,
.get = node_get,
.equal = node_equal,
};
// Special-cased by m_config.c.

View File

@ -338,6 +338,17 @@ struct m_option_type {
int (*get)(const m_option_t *opt, void *ta_parent, struct mpv_node *dst,
void *src);
// Return whether the values are the same. (There are no "unordered"
// results; for example, two floats with the value NaN compare equal. Other
// ambiguous floats, such as +0 and -0 compare equal. Some option types may
// incorrectly report unequal for values that are equal, such as sets (if
// the element order is different, which incorrectly matters), but values
// duplicated with m_option_copy() always return as equal. Empty strings
// and NULL strings are equal. Ambiguous unicode representations compare
// unequal.)
// If not set, values are always considered equal (=> not really optional).
bool (*equal)(const m_option_t *opt, void *a, void *b);
// Optional: list of suffixes, terminated with a {0} entry. An empty list
// behaves like the list being NULL.
const struct m_option_action *actions;
@ -543,6 +554,15 @@ static inline int m_option_get_node(const m_option_t *opt, void *ta_parent,
return M_OPT_UNKNOWN;
}
static inline bool m_option_equal(const m_option_t *opt, void *a, void *b)
{
// Handle trivial equivalence.
// If not implemented, assume this type has no actual values => always equal.
if (a == b || !opt->type->equal)
return true;
return opt->type->equal(opt, a, b);
}
int m_option_required_params(const m_option_t *opt);
extern const char m_option_path_separator;