浏览代码

libobs: Use uthash for properties

derrod 2 年之前
父节点
当前提交
78aa4e03dc
共有 1 个文件被更改,包括 82 次插入115 次删除
  1. 82 115
      libobs/obs-properties.c

+ 82 - 115
libobs/obs-properties.c

@@ -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;
-
-		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;
-			}
-		}
+	HASH_FIND_STR(props->properties, name, property);
+	if (property)
+		return property;
+
+	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;
-
-	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;
-				}
-			}
-
-			// Fix props->first_property.
-			if (props->first_property == cur)
-				props->first_property = cur->next;
-
-			// 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;
-
-			// Finally clear our own next pointer and destroy.
-			cur->next = NULL;
-			obs_property_destroy(cur);
-
-			break;
-		}
+	struct obs_property *cur, *tmp;
 
-		if (cur->type == OBS_PROPERTY_GROUP) {
-			obs_properties_remove_by_name(
-				obs_property_group_content(cur), name);
-		}
+	HASH_FIND_STR(props->properties, name, cur);
+
+	if (cur) {
+		HASH_DELETE(hh, props->properties, cur);
+
+		if (cur->type == OBS_PROPERTY_GROUP)
+			props->groups--;
+
+		obs_property_destroy(cur);
+		return;
+	}
+
+	if (!props->groups)
+		return;
+
+	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);
-			return true;
-		}
+	if (p) {
+		blog(LOG_WARNING, "Property '%s' exists", name);
+		return true;
+	}
 
-		if (p->type == OBS_PROPERTY_GROUP) {
-			if (contains_prop(obs_property_group_content(p),
-					  name)) {
-				return true;
-			}
-		}
+	if (!props->groups)
+		return false;
 
-		p = p->next;
+	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;
 	}
 
 	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
+	obs_property_t *p, *tmp;
+
+	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 true;
 		}
-
-		current_property = current_property->next;
+		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;
 }