summaryrefslogtreecommitdiffstats
path: root/options
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-03-13 00:42:48 +0100
committerwm4 <wm4@nowhere>2020-03-13 16:50:27 +0100
commit28de668173b0c142d4d227eddbc15d7e25b3efbe (patch)
tree761d05f3e2e3684566701a5d6a2fdae32e1334cb /options
parenteb381cbd4b38dd496ee0be609f1a66c360a76448 (diff)
downloadmpv-28de668173b0c142d4d227eddbc15d7e25b3efbe.tar.bz2
mpv-28de668173b0c142d4d227eddbc15d7e25b3efbe.tar.xz
options: more pushing code around
Try to remove m_config implementation details from m_config_frontend. Not sure if I like it. Seems to be ~100 lines of awkward code more, and not much is gained from it. Also it took way too long to do it, and there might be bugs.
Diffstat (limited to 'options')
-rw-r--r--options/m_config_core.c288
-rw-r--r--options/m_config_core.h55
-rw-r--r--options/m_config_frontend.c51
-rw-r--r--options/m_config_frontend.h2
4 files changed, 245 insertions, 151 deletions
diff --git a/options/m_config_core.c b/options/m_config_core.c
index 0b7d40ea6e..f82b886670 100644
--- a/options/m_config_core.c
+++ b/options/m_config_core.c
@@ -33,9 +33,6 @@
#include "misc/dispatch.h"
#include "osdep/atomic.h"
-// Maximum possibly option name length (as it appears to the user).
-#define MAX_OPT_NAME_LEN 80
-
// For use with m_config_cache.
struct m_config_shadow {
pthread_mutex_t lock;
@@ -57,6 +54,7 @@ struct m_config_shadow {
// Represents a sub-struct (OPT_SUBSTRUCT()).
struct m_config_group {
const struct m_sub_options *group;
+ int opt_count; // cached opt. count; group->opts[opt_count].name==NULL
int group_count; // 1 + number of all sub groups owned by this (so
// m_config_shadow.groups[idx..idx+group_count] is used
// by the entire tree of sub groups included by this
@@ -84,6 +82,7 @@ struct config_cache {
struct m_config_data *data; // public data
struct m_config_data *src; // global data (currently ==shadow->data)
struct m_config_shadow *shadow; // global metadata
+ int group_start, group_end; // derived from data->group_index etc.
uint64_t ts; // timestamp of this data copy
bool in_list; // part of m_config_shadow->listeners[]
int upd_group; // for "incremental" change notification
@@ -106,6 +105,7 @@ struct m_group_data {
uint64_t ts; // timestamp of the data copy
};
+static const union m_option_value default_value = {0};
static void add_sub_group(struct m_config_shadow *shadow, const char *name_prefix,
int parent_group_index, int parent_ptr,
@@ -140,71 +140,150 @@ static const char *concat_name_buf(char *buf, size_t buf_size,
// a, b, or a talloc'ed string under ta_parent.
static const char *concat_name(void *ta_parent, const char *a, const char *b)
{
- char buf[MAX_OPT_NAME_LEN];
+ char buf[M_CONFIG_MAX_OPT_NAME_LEN];
const char *r = concat_name_buf(buf, sizeof(buf), a, b);
return r == buf ? talloc_strdup(ta_parent, r) : r;
}
-struct opt_iterate_state {
- // User can read these fields.
- int group_index;
- int opt_index;
- const struct m_option *opt;
- const char *full_name; // may point to name_buf
+static bool iter_next(struct m_config_shadow *shadow, int group_start,
+ int group_end, int32_t *p_id)
+{
+ int32_t id = *p_id;
+ int group_index = id == -1 ? group_start : id >> 16;
+ int opt_index = id == -1 ? -1 : id & 0xFFFF;
+
+ assert(group_index >= group_start && group_index <= group_end);
- // Internal.
- int group_index_end;
- char name_buf[MAX_OPT_NAME_LEN];
- struct m_config_shadow *shadow;
-};
+ while (1) {
+ if (group_index >= group_end)
+ return false;
+
+ struct m_config_group *g = &shadow->groups[group_index];
+ const struct m_option *opts = g->group->opts;
+
+ assert(opt_index >= -1 && opt_index < g->opt_count);
+
+ opt_index += 1;
+
+ if (!opts || !opts[opt_index].name) {
+ group_index += 1;
+ opt_index = -1;
+ continue;
+ }
-// Start iterating all options and sub-options in the given group.
-static void opt_iterate_init(struct opt_iterate_state *iter,
- struct m_config_shadow *shadow, int group_index)
+ if (opts[opt_index].type == &m_option_type_subconfig)
+ continue;
+
+ *p_id = (group_index << 16) | opt_index;
+ return true;
+ }
+}
+
+bool m_config_shadow_get_next_opt(struct m_config_shadow *shadow, int32_t *p_id)
+{
+ return iter_next(shadow, 0, shadow->num_groups, p_id);
+}
+
+bool m_config_cache_get_next_opt(struct m_config_cache *cache, int32_t *p_id)
{
+ return iter_next(cache->shadow, cache->internal->group_start,
+ cache->internal->group_end, p_id);
+}
+
+static void get_opt_from_id(struct m_config_shadow *shadow, int32_t id,
+ int *out_group_index, int *out_opt_index)
+{
+ int group_index = id >> 16;
+ int opt_index = id & 0xFFFF;
+
assert(group_index >= 0 && group_index < shadow->num_groups);
- iter->group_index = group_index;
- iter->group_index_end = group_index + shadow->groups[group_index].group_count;
- iter->opt_index = -1;
- iter->shadow = shadow;
+ assert(opt_index >= 0 && opt_index < shadow->groups[group_index].opt_count);
+
+ *out_group_index = group_index;
+ *out_opt_index = opt_index;
}
-// Get the first or next option. Returns false if end reached. If this returns
-// true, most fields in *iter are valid.
-// This does not return pseudo-option entries (like m_option_type_subconfig).
-static bool opt_iterate_next(struct opt_iterate_state *iter)
+const struct m_option *m_config_shadow_get_opt(struct m_config_shadow *shadow,
+ int32_t id)
{
- if (iter->group_index < 0)
- return false;
+ int group_index, opt_index;
+ get_opt_from_id(shadow, id, &group_index, &opt_index);
+ return &shadow->groups[group_index].group->opts[opt_index];
+}
- while (1) {
- if (iter->group_index >= iter->group_index_end) {
- iter->group_index = -1;
- return false;
- }
+const char *m_config_shadow_get_opt_name(struct m_config_shadow *shadow,
+ int32_t id, char *buf, size_t buf_size)
+{
+ int group_index, opt_index;
+ get_opt_from_id(shadow, id, &group_index, &opt_index);
+
+ struct m_config_group *g = &shadow->groups[group_index];
+ return concat_name_buf(buf, buf_size, g->prefix,
+ g->group->opts[opt_index].name);
+}
- iter->opt_index += 1;
+const void *m_config_shadow_get_opt_default(struct m_config_shadow *shadow,
+ int32_t id)
+{
+ int group_index, opt_index;
+ get_opt_from_id(shadow, id, &group_index, &opt_index);
- struct m_config_group *g = &iter->shadow->groups[iter->group_index];
- const struct m_option *opts = g->group->opts;
+ const struct m_sub_options *subopt = shadow->groups[group_index].group;
+ const struct m_option *opt = &subopt->opts[opt_index];
- if (!opts || !opts[iter->opt_index].name) {
- iter->group_index += 1;
- iter->opt_index = -1;
- continue;
- }
+ if (opt->offset < 0)
+ return NULL;
- iter->opt = &opts[iter->opt_index];
+ if (opt->defval)
+ return opt->defval;
- if (iter->opt->type == &m_option_type_subconfig)
- continue;
+ if (subopt->defaults)
+ return (char *)subopt->defaults + opt->offset;
- iter->full_name = concat_name_buf(iter->name_buf, sizeof(iter->name_buf),
- g->prefix, iter->opt->name);
- return true;
+ return &default_value;
+}
+
+void *m_config_cache_get_opt_data(struct m_config_cache *cache, int32_t id)
+{
+ int group_index, opt_index;
+ get_opt_from_id(cache->shadow, id, &group_index, &opt_index);
+
+ assert(group_index >= cache->internal->group_start &&
+ group_index < cache->internal->group_end);
+
+ struct m_group_data *gd = m_config_gdata(cache->internal->data, group_index);
+ const struct m_option *opt =
+ &cache->shadow->groups[group_index].group->opts[opt_index];
+
+ return gd && opt->offset >= 0 ? gd->udata + opt->offset : NULL;
+}
+
+static uint64_t get_opt_change_mask(struct m_config_shadow *shadow, int group_index,
+ int group_root, const struct m_option *opt)
+{
+ uint64_t changed = opt->flags & UPDATE_OPTS_MASK;
+ while (group_index != group_root) {
+ struct m_config_group *g = &shadow->groups[group_index];
+ changed |= g->group->change_flags;
+ group_index = g->parent_group;
}
- assert(0);
+ return changed;
+}
+
+uint64_t m_config_cache_get_option_change_mask(struct m_config_cache *cache,
+ int32_t id)
+{
+ struct m_config_shadow *shadow = cache->shadow;
+ int group_index, opt_index;
+ get_opt_from_id(shadow, id, &group_index, &opt_index);
+
+ assert(group_index >= cache->internal->group_start &&
+ group_index < cache->internal->group_end);
+
+ return get_opt_change_mask(cache->shadow, group_index,
+ cache->internal->data->group_index,
+ &shadow->groups[group_index].group->opts[opt_index]);
}
// The memcpys are supposed to work around the strict aliasing violation,
@@ -359,54 +438,6 @@ struct m_config_shadow *m_config_shadow_new(const struct m_sub_options *root)
return shadow;
}
-#include "m_config_frontend.h"
-
-static void config_destroy(void *p)
-{
- struct m_config *config = p;
- config->option_change_callback = NULL;
- m_config_restore_backups(config);
-
- talloc_free(config->cache);
- talloc_free(config->shadow);
-}
-
-struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
- const struct m_sub_options *root)
-{
- struct m_config *config = talloc(talloc_ctx, struct m_config);
- talloc_set_destructor(config, config_destroy);
- *config = (struct m_config){.log = log,};
-
- config->shadow = m_config_shadow_new(root);
-
- if (root->size) {
- config->cache = m_config_cache_from_shadow(config, config->shadow, root);
- config->optstruct = config->cache->opts;
- }
-
- struct opt_iterate_state it;
- opt_iterate_init(&it, config->shadow, 0);
- while (opt_iterate_next(&it)) {
- struct m_config_option co = {
- .name = talloc_strdup(config, it.full_name),
- .opt = it.opt,
- .group_index = it.group_index,
- };
-
- struct m_group_data *gdata = config->cache
- ? m_config_gdata(config->cache->internal->data, it.group_index)
- : NULL;
-
- if (gdata && co.opt->offset >= 0)
- co.data = gdata->udata + co.opt->offset;
-
- MP_TARRAY_APPEND(config, config->opts, config->num_opts, co);
- }
-
- return config;
-}
-
static void init_obj_settings_list(struct m_config_shadow *shadow,
int parent_group_index,
const struct m_obj_list *list)
@@ -480,6 +511,8 @@ static void add_sub_group(struct m_config_shadow *shadow, const char *name_prefi
const struct m_obj_list *objlist = opt->priv;
init_obj_settings_list(shadow, group_index, objlist);
}
+
+ shadow->groups[group_index].opt_count = i + 1;
}
if (subopts->get_sub_options) {
@@ -495,19 +528,6 @@ static void add_sub_group(struct m_config_shadow *shadow, const char *name_prefi
shadow->groups[group_index].group_count = shadow->num_groups - group_index;
}
-uint64_t m_config_shadow_get_option_change_mask(struct m_config_shadow *shadow,
- int group_index, int group_root,
- const struct m_option *opt)
-{
- uint64_t changed = opt->flags & UPDATE_OPTS_MASK;
- while (group_index != group_root) {
- struct m_config_group *g = &shadow->groups[group_index];
- changed |= g->group->change_flags;
- group_index = g->parent_group;
- }
- return changed;
-}
-
static void cache_destroy(void *p)
{
struct m_config_cache *cache = p;
@@ -542,6 +562,7 @@ struct m_config_cache *m_config_cache_from_shadow(void *ta_parent,
struct m_config_cache *cache = &alloc->a;
talloc_set_destructor(cache, cache_destroy);
cache->internal = &alloc->b;
+ cache->shadow = shadow;
struct config_cache *in = cache->internal;
in->shadow = shadow;
@@ -553,6 +574,10 @@ struct m_config_cache *m_config_cache_from_shadow(void *ta_parent,
cache->opts = in->data->gdata[0].udata;
+ in->group_start = in->data->group_index;
+ in->group_end = in->group_start + in->data->num_gdata;
+ assert(shadow->groups[in->group_start].group_count == in->data->num_gdata);
+
in->upd_group = -1;
return cache;
@@ -592,8 +617,7 @@ static void update_next_option(struct m_config_cache *cache, void **p_opt)
void *ddst = gdst->udata + opt->offset;
if (!m_option_equal(opt, ddst, dsrc)) {
- uint64_t ch =
- m_config_shadow_get_option_change_mask(dst->shadow,
+ uint64_t ch = get_opt_change_mask(dst->shadow,
in->upd_group, dst->group_index, opt);
if (cache->debug) {
@@ -831,19 +855,26 @@ void mp_read_option_raw(struct mpv_global *global, const char *name,
{
struct m_config_shadow *shadow = global->config;
- struct opt_iterate_state it;
- opt_iterate_init(&it, shadow, 0);
- while (opt_iterate_next(&it)) {
- if (strcmp(name, it.full_name) == 0) {
- struct m_group_data *gdata =
- m_config_gdata(shadow->data, it.group_index);
+ int32_t optid = -1;
+ while (m_config_shadow_get_next_opt(shadow, &optid)) {
+ char buf[M_CONFIG_MAX_OPT_NAME_LEN];
+ const char *opt_name =
+ m_config_shadow_get_opt_name(shadow, optid, buf, sizeof(buf));
+
+ if (strcmp(name, opt_name) == 0) {
+ const struct m_option *opt = m_config_shadow_get_opt(shadow, optid);
+
+ int group_index, opt_index;
+ get_opt_from_id(shadow, optid, &group_index, &opt_index);
+
+ struct m_group_data *gdata = m_config_gdata(shadow->data, group_index);
assert(gdata);
- assert(it.opt->offset >= 0);
- assert(it.opt->type == type);
+ assert(opt->offset >= 0);
+ assert(opt->type == type);
- memset(dst, 0, it.opt->type->size);
- m_option_copy(it.opt, dst, gdata->udata + it.opt->offset);
+ memset(dst, 0, opt->type->size);
+ m_option_copy(opt, dst, gdata->udata + opt->offset);
return;
}
}
@@ -877,18 +908,3 @@ void *m_config_group_from_desc(void *ta_parent, struct mp_log *log,
return d;
}
}
-
-const void *m_config_shadow_get_opt_default(struct m_config_shadow *shadow,
- int group_index,
- const struct m_option *opt)
-{
- if (opt->defval)
- return opt->defval;
-
- const struct m_sub_options *subopt = shadow->groups[group_index].group;
-
- if (opt->offset >= 0 && subopt->defaults)
- return (char *)subopt->defaults + opt->offset;
-
- return NULL;
-}
diff --git a/options/m_config_core.h b/options/m_config_core.h
index f3fc716aa9..c4902be9d1 100644
--- a/options/m_config_core.h
+++ b/options/m_config_core.h
@@ -25,8 +25,8 @@
struct mp_dispatch_queue;
struct m_sub_options;
struct m_option_type;
+struct m_option;
struct mpv_global;
-struct m_config_shadow;
// This can be used to create and synchronize per-thread option structs,
// which then can be read without synchronization. No concurrent access to
@@ -44,10 +44,16 @@ struct m_config_cache {
// with one of the update functions (like m_config_cache_update()).
struct mp_log *debug;
+ // Global instance of option data. Read only.
+ struct m_config_shadow *shadow;
+
// Do not access.
struct config_cache *internal;
};
+// Maximum possibly option name buffer length (as it appears to the user).
+#define M_CONFIG_MAX_OPT_NAME_LEN 80
+
// Create a mirror copy from the global options.
// Keep in mind that a m_config_cache object is not thread-safe; it merely
// provides thread-safe access to the global options. All API functions for
@@ -152,15 +158,44 @@ struct m_config_cache *m_config_cache_from_shadow(void *ta_parent,
struct m_config_shadow *shadow,
const struct m_sub_options *group);
-// Bad function.
-struct m_option;
-uint64_t m_config_shadow_get_option_change_mask(struct m_config_shadow *shadow,
- int group_index, int group_root,
- const struct m_option *opt);
-
-// Bad function.
+// Iterate over all registered global options. *p_id must be set to -1 when this
+// is called for the first time. Each time this call returns true, *p_id is set
+// to a new valid option ID. p_id must not be changed for the next call. If
+// false is returned, iteration ends.
+bool m_config_shadow_get_next_opt(struct m_config_shadow *shadow, int32_t *p_id);
+
+// Similar to m_config_shadow_get_next_opt(), but return only options that are
+// covered by the m_config_cache.
+bool m_config_cache_get_next_opt(struct m_config_cache *cache, int32_t *p_id);
+
+// Return the m_option that was used to declare this option.
+// id must be a valid option ID as returned by m_config_shadow_get_next_opt() or
+// m_config_cache_get_next_opt().
+const struct m_option *m_config_shadow_get_opt(struct m_config_shadow *shadow,
+ int32_t id);
+
+// Return the full (global) option name. buf must be supplied, but may not
+// always be used. It should have the size M_CONFIG_MAX_OPT_NAME_LEN.
+// The returned point points either to buf or a static string.
+// id must be a valid option ID as returned by m_config_shadow_get_next_opt() or
+// m_config_cache_get_next_opt().
+const char *m_config_shadow_get_opt_name(struct m_config_shadow *shadow,
+ int32_t id, char *buf, size_t buf_size);
+
+// Pointer to default value, using m_option.type. NULL if option without data.
+// id must be a valid option ID as returned by m_config_shadow_get_next_opt() or
+// m_config_cache_get_next_opt().
const void *m_config_shadow_get_opt_default(struct m_config_shadow *shadow,
- int group_index,
- const struct m_option *opt);
+ int32_t id);
+
+// Return the pointer to the allocated option data (the same pointers that are
+// returned by m_config_cache_get_next_changed()). NULL if option without data.
+// id must be a valid option ID as returned by m_config_cache_get_next_opt().
+void *m_config_cache_get_opt_data(struct m_config_cache *cache, int32_t id);
+
+// Return or-ed UPDATE_OPTS_MASK part of the option and containing sub-options.
+// id must be a valid option ID as returned by m_config_cache_get_next_opt().
+uint64_t m_config_cache_get_option_change_mask(struct m_config_cache *cache,
+ int32_t id);
#endif /* MPLAYER_M_CONFIG_H */
diff --git a/options/m_config_frontend.c b/options/m_config_frontend.c
index 6eeea084c4..ab93203645 100644
--- a/options/m_config_frontend.c
+++ b/options/m_config_frontend.c
@@ -309,8 +309,7 @@ struct m_config_option *m_config_get_co_index(struct m_config *config, int index
const void *m_config_get_co_default(const struct m_config *config,
struct m_config_option *co)
{
- return m_config_shadow_get_opt_default(config->shadow, co->group_index,
- co->opt);
+ return m_config_shadow_get_opt_default(config->shadow, co->opt_id);
}
const char *m_config_get_positional_option(const struct m_config *config, int p)
@@ -464,6 +463,51 @@ void m_config_set_update_dispatch_queue(struct m_config *config,
async_change_cb, config);
}
+static void config_destroy(void *p)
+{
+ struct m_config *config = p;
+ config->option_change_callback = NULL;
+ m_config_restore_backups(config);
+
+ talloc_free(config->cache);
+ talloc_free(config->shadow);
+}
+
+struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
+ const struct m_sub_options *root)
+{
+ struct m_config *config = talloc(talloc_ctx, struct m_config);
+ talloc_set_destructor(config, config_destroy);
+ *config = (struct m_config){.log = log,};
+
+ config->shadow = m_config_shadow_new(root);
+
+ if (root->size) {
+ config->cache = m_config_cache_from_shadow(config, config->shadow, root);
+ config->optstruct = config->cache->opts;
+ }
+
+ int32_t optid = -1;
+ while (m_config_shadow_get_next_opt(config->shadow, &optid)) {
+ char buf[M_CONFIG_MAX_OPT_NAME_LEN];
+ const char *opt_name =
+ m_config_shadow_get_opt_name(config->shadow, optid, buf, sizeof(buf));
+
+ struct m_config_option co = {
+ .name = talloc_strdup(config, opt_name),
+ .opt = m_config_shadow_get_opt(config->shadow, optid),
+ .opt_id = optid,
+ };
+
+ if (config->cache)
+ co.data = m_config_cache_get_opt_data(config->cache, optid);
+
+ MP_TARRAY_APPEND(config, config->opts, config->num_opts, co);
+ }
+
+ return config;
+}
+
// Normally m_config_cache will not send notifications when _we_ change our
// own stuff. For whatever funny reasons, we need that, though.
static void force_self_notify_change_opt(struct m_config *config,
@@ -471,8 +515,7 @@ static void force_self_notify_change_opt(struct m_config *config,
bool self_notification)
{
int changed =
- m_config_shadow_get_option_change_mask(config->shadow, co->group_index,
- 0, co->opt);
+ m_config_cache_get_option_change_mask(config->cache, co->opt_id);
if (config->option_change_callback) {
config->option_change_callback(config->option_change_callback_ctx, co,
diff --git a/options/m_config_frontend.h b/options/m_config_frontend.h
index 82d2ded2d6..19fbcadf25 100644
--- a/options/m_config_frontend.h
+++ b/options/m_config_frontend.h
@@ -50,7 +50,7 @@ struct m_config_option {
bool is_set_from_config : 1; // Set by a config file
bool is_set_locally : 1; // Has a backup entry
bool warning_was_printed : 1;
- int16_t group_index; // Index into m_config.groups
+ int32_t opt_id; // For some m_config APIs
const char *name; // Full name (ie option-subopt)
const struct m_option *opt; // Option description
void *data; // Raw value of the option