libobs: Use uthash for properties

This commit is contained in:
derrod 2023-02-09 16:15:41 +01:00
parent eff3cf134c
commit 78aa4e03dc

View file

@ -191,16 +191,16 @@ struct obs_property {
obs_property_modified_t modified;
obs_property_modified2_t modified2;
struct obs_property *next;
UT_hash_handle hh;
};
struct obs_properties {
void *param;
void (*destroy)(void *param);
uint32_t flags;
uint32_t groups;
struct obs_property *first_property;
struct obs_property **last;
struct obs_property *properties;
struct obs_property *parent;
};
@ -208,7 +208,6 @@ obs_properties_t *obs_properties_create(void)
{
struct obs_properties *props;
props = bzalloc(sizeof(struct obs_properties));
props->last = &props->first_property;
return props;
}
@ -277,15 +276,14 @@ static void obs_property_destroy(struct obs_property *property)
void obs_properties_destroy(obs_properties_t *props)
{
if (props) {
struct obs_property *p = props->first_property;
struct obs_property *p, *tmp;
if (props->destroy && props->param)
props->destroy(props->param);
while (p) {
struct obs_property *next = p->next;
HASH_ITER (hh, props->properties, p, tmp) {
HASH_DEL(props->properties, p);
obs_property_destroy(p);
p = next;
}
bfree(props);
@ -294,31 +292,32 @@ void obs_properties_destroy(obs_properties_t *props)
obs_property_t *obs_properties_first(obs_properties_t *props)
{
return (props != NULL) ? props->first_property : NULL;
return (props != NULL) ? props->properties : NULL;
}
obs_property_t *obs_properties_get(obs_properties_t *props, const char *name)
{
struct obs_property *property;
struct obs_property *property, *tmp;
if (!props)
return NULL;
property = props->first_property;
while (property) {
if (strcmp(property->name, name) == 0)
return property;
HASH_FIND_STR(props->properties, name, property);
if (property)
return property;
if (property->type == OBS_PROPERTY_GROUP) {
obs_properties_t *group =
obs_property_group_content(property);
obs_property_t *found = obs_properties_get(group, name);
if (found != NULL) {
return found;
}
}
if (!props->groups)
return NULL;
property = property->next;
/* Recursively check groups as well, if any */
HASH_ITER (hh, props->properties, property, tmp) {
if (property->type != OBS_PROPERTY_GROUP)
continue;
obs_properties_t *group = obs_property_group_content(property);
obs_property_t *found = obs_properties_get(group, name);
if (found)
return found;
}
return NULL;
@ -334,51 +333,29 @@ void obs_properties_remove_by_name(obs_properties_t *props, const char *name)
if (!props)
return;
/* obs_properties_t is a forward-linked-list, so we need to keep both
* previous and current pointers around. That way we can fix up the
* pointers for the previous element if we find a match.
*/
struct obs_property *cur = props->first_property;
struct obs_property *prev = props->first_property;
struct obs_property *cur, *tmp;
while (cur) {
if (strcmp(cur->name, name) == 0) {
// Fix props->last pointer.
if (props->last == &cur->next) {
if (cur == prev) {
// If we are the last entry and there
// is no previous entry, reset.
props->last = &props->first_property;
} else {
// If we are the last entry and there
// is a previous entry, update.
props->last = &prev->next;
}
}
HASH_FIND_STR(props->properties, name, cur);
// Fix props->first_property.
if (props->first_property == cur)
props->first_property = cur->next;
if (cur) {
HASH_DELETE(hh, props->properties, cur);
// Update the previous element next pointer with our
// next pointer. This is an automatic no-op if both
// elements alias the same memory.
prev->next = cur->next;
if (cur->type == OBS_PROPERTY_GROUP)
props->groups--;
// Finally clear our own next pointer and destroy.
cur->next = NULL;
obs_property_destroy(cur);
obs_property_destroy(cur);
return;
}
break;
}
if (!props->groups)
return;
if (cur->type == OBS_PROPERTY_GROUP) {
obs_properties_remove_by_name(
obs_property_group_content(cur), name);
}
HASH_ITER (hh, props->properties, cur, tmp) {
if (cur->type != OBS_PROPERTY_GROUP)
continue;
prev = cur;
cur = cur->next;
obs_properties_remove_by_name(obs_property_group_content(cur),
name);
}
}
@ -386,10 +363,9 @@ void obs_properties_apply_settings_internal(obs_properties_t *props,
obs_data_t *settings,
obs_properties_t *realprops)
{
struct obs_property *p;
struct obs_property *p, *tmp;
p = props->first_property;
while (p) {
HASH_ITER (hh, props->properties, p, tmp) {
if (p->type == OBS_PROPERTY_GROUP) {
obs_properties_apply_settings_internal(
obs_property_group_content(p), settings,
@ -399,7 +375,6 @@ void obs_properties_apply_settings_internal(obs_properties_t *props,
p->modified(realprops, p, settings);
else if (p->modified2)
p->modified2(p->priv, realprops, p, settings);
p = p->next;
}
}
@ -414,13 +389,6 @@ void obs_properties_apply_settings(obs_properties_t *props,
/* ------------------------------------------------------------------------- */
static inline void propertes_add(struct obs_properties *props,
struct obs_property *p)
{
*props->last = p;
props->last = &p->next;
}
static inline size_t get_property_size(enum obs_property_type type)
{
switch (type) {
@ -471,7 +439,8 @@ static inline struct obs_property *new_prop(struct obs_properties *props,
p->type = type;
p->name = bstrdup(name);
p->desc = bstrdup(desc);
propertes_add(props, p);
HASH_ADD_STR(props->properties, name, p);
return p;
}
@ -489,22 +458,22 @@ static inline obs_properties_t *get_topmost_parent(obs_properties_t *props)
static inline bool contains_prop(struct obs_properties *props, const char *name)
{
struct obs_property *p = props->first_property;
struct obs_property *p, *tmp;
HASH_FIND_STR(props->properties, name, p);
while (p) {
if (strcmp(p->name, name) == 0) {
blog(LOG_WARNING, "Property '%s' exists", name);
if (p) {
blog(LOG_WARNING, "Property '%s' exists", name);
return true;
}
if (!props->groups)
return false;
HASH_ITER (hh, props->properties, p, tmp) {
if (p->type != OBS_PROPERTY_GROUP)
continue;
if (contains_prop(obs_property_group_content(p), name))
return true;
}
if (p->type == OBS_PROPERTY_GROUP) {
if (contains_prop(obs_property_group_content(p),
name)) {
return true;
}
}
p = p->next;
}
return false;
@ -753,24 +722,23 @@ static bool check_property_group_recursion(obs_properties_t *parent,
obs_properties_t *group)
{
/* Scan the group for the parent. */
obs_property_t *current_property = group->first_property;
while (current_property) {
if (current_property->type == OBS_PROPERTY_GROUP) {
obs_properties_t *cprops =
obs_property_group_content(current_property);
if (cprops == parent) {
/* Contains find_props */
return true;
} else if (cprops == group) {
/* Contains self, shouldn't be possible but
* lets verify anyway. */
return true;
}
if (check_property_group_recursion(parent, cprops))
return true;
}
obs_property_t *p, *tmp;
current_property = current_property->next;
HASH_ITER (hh, group->properties, p, tmp) {
if (p->type != OBS_PROPERTY_GROUP)
continue;
obs_properties_t *cprops = obs_property_group_content(p);
if (cprops == parent) {
/* Contains find_props */
return true;
} else if (cprops == group) {
/* Contains self, shouldn't be possible but
* lets verify anyway. */
return true;
}
if (check_property_group_recursion(parent, cprops))
return true;
}
return false;
@ -779,13 +747,11 @@ static bool check_property_group_recursion(obs_properties_t *parent,
static bool check_property_group_duplicates(obs_properties_t *parent,
obs_properties_t *group)
{
obs_property_t *current_property = group->first_property;
while (current_property) {
if (has_prop(parent, current_property->name)) {
return true;
}
obs_property_t *p, *tmp;
current_property = current_property->next;
HASH_ITER (hh, group->properties, p, tmp) {
if (has_prop(parent, p->name))
return true;
}
return false;
@ -812,6 +778,7 @@ obs_property_t *obs_properties_add_group(obs_properties_t *props,
return NULL;
obs_property_t *p = new_prop(props, name, desc, OBS_PROPERTY_GROUP);
props->groups++;
group->parent = p;
struct group_data *data = get_property_data(p);
@ -849,7 +816,7 @@ bool obs_property_next(obs_property_t **p)
if (!p || !*p)
return false;
*p = (*p)->next;
*p = (*p)->hh.next;
return *p != NULL;
}