浏览代码

libobs: Use uthash for hotkey name map

derrod 2 年之前
父节点
当前提交
eff3cf134c
共有 2 个文件被更改,包括 33 次插入313 次删除
  1. 31 311
      libobs/obs-hotkey-name-map.c
  2. 2 2
      libobs/obs-internal.h

+ 31 - 311
libobs/obs-hotkey-name-map.c

@@ -20,305 +20,55 @@
 
 #include <util/bmem.h>
 #include <util/c99defs.h>
-#include <util/darray.h>
 
 #include "obs-internal.h"
 
-struct obs_hotkey_name_map_edge;
-struct obs_hotkey_name_map_node;
 struct obs_hotkey_name_map;
 
-typedef struct obs_hotkey_name_map_edge obs_hotkey_name_map_edge_t;
-typedef struct obs_hotkey_name_map_node obs_hotkey_name_map_node_t;
-typedef struct obs_hotkey_name_map obs_hotkey_name_map_t;
+typedef struct obs_hotkey_name_map_item obs_hotkey_name_map_item_t;
 
-struct obs_hotkey_name_map_node {
-	bool is_leaf;
-	union {
-		int val;
-		DARRAY(obs_hotkey_name_map_edge_t) children;
-	};
+struct obs_hotkey_name_map_item {
+	char *key;
+	int val;
+	UT_hash_handle hh;
 };
 
-struct obs_hotkey_name_map {
-	obs_hotkey_name_map_node_t root;
-	obs_hotkey_name_map_node_t *leaves;
-	size_t num_leaves;
-	size_t next_leaf;
-};
-
-struct obs_hotkey_name_map_edge_prefix {
-	uint8_t prefix_len;
-	char *prefix;
-};
-
-#define NAME_MAP_COMPRESS_LENGTH \
-	(sizeof(struct obs_hotkey_name_map_edge_prefix) - sizeof(uint8_t))
-
-struct obs_hotkey_name_map_edge {
-	union {
-		struct {
-			uint8_t prefix_len;
-			char *prefix;
-		};
-		struct {
-			uint8_t compressed_len;
-			char compressed_prefix[NAME_MAP_COMPRESS_LENGTH];
-		};
-	};
-	struct obs_hotkey_name_map_node *node;
-};
-
-static inline obs_hotkey_name_map_node_t *new_node(void)
-{
-	return bzalloc(sizeof(obs_hotkey_name_map_node_t));
-}
-
-static inline obs_hotkey_name_map_node_t *new_leaf(void)
-{
-	obs_hotkey_name_map_t *name_map = obs->hotkeys.name_map;
-	obs_hotkey_name_map_node_t *node =
-		&name_map->leaves[name_map->next_leaf];
-	name_map->next_leaf += 1;
-
-	node->is_leaf = true;
-	return node;
-}
-
-static inline char *get_prefix(obs_hotkey_name_map_edge_t *e)
-{
-	return e->prefix_len >= NAME_MAP_COMPRESS_LENGTH ? e->prefix
-							 : e->compressed_prefix;
-}
-
-static void set_prefix(obs_hotkey_name_map_edge_t *e, const char *prefix,
-		       size_t l)
-{
-	assert(e->prefix_len == 0);
-
-	e->compressed_len = (uint8_t)l;
-	if (l < NAME_MAP_COMPRESS_LENGTH)
-		strncpy(e->compressed_prefix, prefix, l);
-	else
-		e->prefix = bstrdup_n(prefix, l);
-}
-
-static obs_hotkey_name_map_edge_t *add_leaf(obs_hotkey_name_map_node_t *node,
-					    const char *key, size_t l, int v)
-{
-	obs_hotkey_name_map_edge_t *e = da_push_back_new(node->children);
-
-	set_prefix(e, key, l);
-
-	e->node = new_leaf();
-	e->node->val = v;
-
-	return e;
-}
-
-static void shrink_prefix(obs_hotkey_name_map_edge_t *e, size_t l)
-{
-	bool old_comp = e->prefix_len < NAME_MAP_COMPRESS_LENGTH;
-	bool new_comp = l < NAME_MAP_COMPRESS_LENGTH;
-
-	char *str = get_prefix(e);
-
-	e->prefix_len = (uint8_t)l;
-	if (get_prefix(e) != str)
-		strncpy(get_prefix(e), str, l);
-	else
-		str[l] = 0;
-
-	if (!old_comp && new_comp)
-		bfree(str);
-}
-
-static void connect(obs_hotkey_name_map_edge_t *e,
-		    obs_hotkey_name_map_node_t *n)
-{
-	e->node = n;
-}
-
-static void reduce_edge(obs_hotkey_name_map_edge_t *e, const char *key,
-			size_t l, int v)
-{
-	const char *str = get_prefix(e), *str_ = key;
-	size_t common_length = 0;
-	while (*str == *str_) {
-		common_length += 1;
-		str += 1;
-		str_ += 1;
-	}
-
-	obs_hotkey_name_map_node_t *new_node_ = new_node();
-	obs_hotkey_name_map_edge_t *tail =
-		da_push_back_new(new_node_->children);
-
-	connect(tail, e->node);
-	set_prefix(tail, str, e->prefix_len - common_length);
-
-	add_leaf(new_node_, str_, l - common_length, v);
-
-	connect(e, new_node_);
-	shrink_prefix(e, common_length);
-}
-
-enum obs_hotkey_name_map_edge_compare_result {
-	RES_MATCHES,
-	RES_NO_MATCH,
-	RES_COMMON_PREFIX,
-	RES_PREFIX_MATCHES,
-};
-
-static enum obs_hotkey_name_map_edge_compare_result
-compare_prefix(obs_hotkey_name_map_edge_t *edge, const char *key, size_t l)
-{
-	uint8_t pref_len = edge->prefix_len;
-	const char *str = get_prefix(edge);
-	size_t i = 0;
-
-	for (; i < l && i < pref_len; i++)
-		if (str[i] != key[i])
-			break;
-
-	if (i != 0 && pref_len == i)
-		return l == i ? RES_MATCHES : RES_PREFIX_MATCHES;
-	if (i != 0)
-		return pref_len == i ? RES_PREFIX_MATCHES : RES_COMMON_PREFIX;
-	return RES_NO_MATCH;
-}
-
-static void insert(obs_hotkey_name_map_edge_t *edge,
-		   obs_hotkey_name_map_node_t *node, const char *key, size_t l,
-		   int v)
+static void obs_hotkey_name_map_insert(obs_hotkey_name_map_item_t **hmap,
+				       const char *key, int v)
 {
-	if (node->is_leaf && l > 0) {
-		obs_hotkey_name_map_node_t *new_node_ = new_node();
-		connect(edge, new_node_);
-
-		obs_hotkey_name_map_edge_t *edge =
-			da_push_back_new(new_node_->children);
-		connect(edge, node);
-		add_leaf(new_node_, key, l, v);
+	if (!hmap || !key)
 		return;
-	}
 
-	if (node->is_leaf && l == 0) {
-		node->val = v;
+	obs_hotkey_name_map_item_t *t;
+	HASH_FIND_STR(*hmap, key, t);
+	if (t)
 		return;
-	}
-
-	for (size_t i = 0; i < node->children.num; i++) {
-		obs_hotkey_name_map_edge_t *e = &node->children.array[i];
-
-		switch (compare_prefix(e, key, l)) {
-		case RES_NO_MATCH:
-			continue;
-
-		case RES_MATCHES:
-		case RES_PREFIX_MATCHES:
-			insert(e, e->node, key + e->prefix_len,
-			       l - e->prefix_len, v);
-			return;
 
-		case RES_COMMON_PREFIX:
-			reduce_edge(e, key, l, v);
-			return;
-		}
-	}
-
-	add_leaf(node, key, l, v);
-}
-
-static void obs_hotkey_name_map_insert(obs_hotkey_name_map_t *trie,
-				       const char *key, int v)
-{
-	if (!trie || !key)
-		return;
+	t = bzalloc(sizeof(obs_hotkey_name_map_item_t));
+	t->key = bstrdup(key);
+	t->val = v;
 
-	insert(NULL, &trie->root, key, strlen(key), v);
+	HASH_ADD_STR(*hmap, key, t);
 }
 
-static bool obs_hotkey_name_map_lookup(obs_hotkey_name_map_t *trie,
+static bool obs_hotkey_name_map_lookup(obs_hotkey_name_map_item_t *hmap,
 				       const char *key, int *v)
 {
-	if (!trie || !key)
+	if (!hmap || !key)
 		return false;
 
-	size_t len = strlen(key);
-	obs_hotkey_name_map_node_t *n = &trie->root;
-
-	size_t i = 0;
-	for (; i < n->children.num;) {
-		obs_hotkey_name_map_edge_t *e = &n->children.array[i];
-
-		switch (compare_prefix(e, key, len)) {
-		case RES_NO_MATCH:
-			i++;
-			continue;
-
-		case RES_COMMON_PREFIX:
-			return false;
+	obs_hotkey_name_map_item_t *elem;
 
-		case RES_PREFIX_MATCHES:
-			key += e->prefix_len;
-			len -= e->prefix_len;
-			n = e->node;
-			i = 0;
-			continue;
+	HASH_FIND_STR(hmap, key, elem);
 
-		case RES_MATCHES:
-			n = e->node;
-			if (!n->is_leaf) {
-				for (size_t j = 0; j < n->children.num; j++) {
-					if (n->children.array[j].prefix_len)
-						continue;
-
-					if (v)
-						*v = n->children.array[j]
-							     .node->val;
-					return true;
-				}
-				return false;
-			}
-
-			if (v)
-				*v = n->val;
-			return true;
-		}
+	if (elem) {
+		*v = elem->val;
+		return true;
 	}
 
 	return false;
 }
 
-static void show_node(obs_hotkey_name_map_node_t *node, int in)
-{
-	if (node->is_leaf) {
-		printf(": % 3d\n", node->val);
-		return;
-	}
-
-	printf("\n");
-	for (int i = 0; i < in; i += 2)
-		printf("| ");
-	printf("%lu:\n", (unsigned long)node->children.num);
-
-	for (size_t i = 0; i < node->children.num; i++) {
-		for (int i = 0; i < in; i += 2)
-			printf("| ");
-		printf("\\ ");
-
-		obs_hotkey_name_map_edge_t *e = &node->children.array[i];
-		printf("%s", get_prefix(e));
-		show_node(e->node, in + 2);
-	}
-}
-
-void trie_print_size(obs_hotkey_name_map_t *trie)
-{
-	show_node(&trie->root, 0);
-}
-
 static const char *obs_key_names[] = {
 #define OBS_HOTKEY(x) #x,
 #include "obs-hotkeys.h"
@@ -350,17 +100,7 @@ static obs_key_t obs_key_from_name_fallback(const char *name)
 
 static void init_name_map(void)
 {
-	obs->hotkeys.name_map = bzalloc(sizeof(struct obs_hotkey_name_map));
-	obs_hotkey_name_map_t *name_map = obs->hotkeys.name_map;
-
-#define OBS_HOTKEY(x) name_map->num_leaves += 1;
-#include "obs-hotkeys.h"
-#undef OBS_HOTKEY
-
-	size_t size = sizeof(obs_hotkey_name_map_node_t) * name_map->num_leaves;
-	name_map->leaves = bzalloc(size);
-
-#define OBS_HOTKEY(x) obs_hotkey_name_map_insert(name_map, #x, x);
+#define OBS_HOTKEY(x) obs_hotkey_name_map_insert(&obs->hotkeys.name_map, #x, x);
 #include "obs-hotkeys.h"
 #undef OBS_HOTKEY
 }
@@ -380,37 +120,17 @@ obs_key_t obs_key_from_name(const char *name)
 	return OBS_KEY_NONE;
 }
 
-static void free_node(obs_hotkey_name_map_node_t *node, bool release);
-
-static void free_edge(obs_hotkey_name_map_edge_t *edge)
-{
-	free_node(edge->node, true);
-
-	if (edge->prefix_len < NAME_MAP_COMPRESS_LENGTH)
-		return;
-
-	bfree(get_prefix(edge));
-}
-
-static void free_node(obs_hotkey_name_map_node_t *node, bool release)
-{
-	if (!node->is_leaf) {
-		for (size_t i = 0; i < node->children.num; i++)
-			free_edge(&node->children.array[i]);
-
-		da_free(node->children);
-	}
-
-	if (release && !node->is_leaf)
-		bfree(node);
-}
-
 void obs_hotkey_name_map_free(void)
 {
 	if (!obs || !obs->hotkeys.name_map)
 		return;
 
-	free_node(&obs->hotkeys.name_map->root, false);
-	bfree(obs->hotkeys.name_map->leaves);
-	bfree(obs->hotkeys.name_map);
+	obs_hotkey_name_map_item_t *root = obs->hotkeys.name_map;
+	obs_hotkey_name_map_item_t *n, *tmp;
+
+	HASH_ITER (hh, root, n, tmp) {
+		HASH_DEL(root, n);
+		bfree(n->key);
+		bfree(n);
+	}
 }

+ 2 - 2
libobs/obs-internal.h

@@ -193,7 +193,7 @@ struct obs_hotkey_binding {
 	obs_hotkey_t *hotkey;
 };
 
-struct obs_hotkey_name_map;
+struct obs_hotkey_name_map_item;
 void obs_hotkey_name_map_free(void);
 
 /* ------------------------------------------------------------------------- */
@@ -431,7 +431,7 @@ struct obs_core_hotkeys {
 	obs_hotkeys_platform_t *platform_context;
 
 	pthread_once_t name_map_init_token;
-	struct obs_hotkey_name_map *name_map;
+	struct obs_hotkey_name_map_item *name_map;
 
 	signal_handler_t *signals;