[FFmpeg-devel] [PATCH 5/5] lavu/dict: add hashtable index.
Clément Bœsch
ubitux at gmail.com
Sun Apr 14 12:11:38 CEST 2013
On Sun, Apr 14, 2013 at 03:07:58AM +0200, Clément Bœsch wrote:
> ---
> libavutil/dict.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 84 insertions(+), 9 deletions(-)
>
New version fixing a bug with av_dict_set and value=NULL
--
Clément B.
-------------- next part --------------
From a4b09dd6703b1f73bff3fcce15f8ef55946ecee4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= <ubitux at gmail.com>
Date: Sun, 14 Apr 2013 03:05:00 +0200
Subject: [PATCH 5/5] lavu/dict: add hashtable index.
---
libavutil/dict.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 88 insertions(+), 9 deletions(-)
diff --git a/libavutil/dict.c b/libavutil/dict.c
index 7a92c56..99af10f 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -25,37 +25,76 @@
#include "internal.h"
#include "mem.h"
+#define HASH_TABLE_LEN 512
+
+struct node {
+ int array_id;
+ struct node *next;
+};
+
struct AVDictionary {
int count;
AVDictionaryEntry *elems;
+ struct node *hashtable[HASH_TABLE_LEN];
};
+static uint32_t get_hash(const char *key)
+{
+ uint32_t hash = 0;
+ while (*key)
+ hash = (hash<<5) ^ (hash>>27) ^ av_toupper(*key++);
+ return hash % HASH_TABLE_LEN;
+}
+
int av_dict_count(const AVDictionary *m)
{
return m ? m->count : 0;
}
+static inline int entry_cmp(const char *s, const char *key, int flags)
+{
+ unsigned i;
+
+ if(flags & AV_DICT_MATCH_CASE) for(i=0; s[i] == key[i] && key[i]; i++);
+ else for(i=0; av_toupper(s[i]) == av_toupper(key[i]) && key[i]; i++);
+ if(key[i])
+ return -1;
+ if(s[i] && !(flags & AV_DICT_IGNORE_SUFFIX))
+ return -1;
+ return 0;
+}
+
+static inline struct node *get_node(const AVDictionary *m, const char *key, int flags)
+{
+ struct node *node;
+
+ for (node = m->hashtable[get_hash(key)]; node; node = node->next)
+ if (!entry_cmp(m->elems[node->array_id].key, key, flags))
+ return node;
+ return NULL;
+}
+
AVDictionaryEntry *
av_dict_get(AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
{
- unsigned int i, j;
-
if(!m)
return NULL;
+ if(prev || (flags & AV_DICT_IGNORE_SUFFIX)){
+ unsigned i;
+ /* TODO: reindent */
if(prev) i= prev - m->elems + 1;
else i= 0;
for(; i<m->count; i++){
- const char *s= m->elems[i].key;
- if(flags & AV_DICT_MATCH_CASE) for(j=0; s[j] == key[j] && key[j]; j++);
- else for(j=0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++);
- if(key[j])
- continue;
- if(s[j] && !(flags & AV_DICT_IGNORE_SUFFIX))
- continue;
+ if(!entry_cmp(m->elems[i].key, key, flags))
return &m->elems[i];
}
+ }else{
+ const struct node *node = get_node(m, key, flags);
+ if(node)
+ return &m->elems[node->array_id];
+ }
return NULL;
}
@@ -69,8 +108,28 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
m = *pm = av_mallocz(sizeof(*m));
if(tag) {
+ uint32_t id;
+ struct node *node, *ref_to_last, *prev = NULL;
+
if (flags & AV_DICT_DONT_OVERWRITE)
return 0;
+
+ /* make the reference to the last entry in the array (ref_to_last)
+ * focus on the array id of tag (last entry is going to move in place
+ * of tag, and tag will be recreated later at the end of the array if
+ * value is !NULL), and drop the reference to the current entry */
+ id = get_hash(key);
+ for (node = m->hashtable[id]; node; node = node->next) {
+ if (!entry_cmp(m->elems[node->array_id].key, key, flags))
+ break;
+ prev = node;
+ }
+ ref_to_last = get_node(m, m->elems[m->count - 1].key, flags);
+ ref_to_last->array_id = node->array_id;
+ if (!prev) m->hashtable[id] = node->next;
+ else prev->next = node->next;
+ av_freep(&node);
+
if (flags & AV_DICT_APPEND)
oldval = tag->value;
else
@@ -83,6 +142,7 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
m->count--;
}
if (value) {
+ struct node **index, *node;
AVDictionaryEntry *e = &m->elems[m->count++];
if (flags & AV_DICT_DONT_STRDUP_KEY) {
@@ -102,6 +162,15 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
e->value = newval;
} else
e->value = av_strdup(value);
+
+ /* reference the entry in the hash table */
+ index = &m->hashtable[get_hash(e->key)];
+ node = av_mallocz(sizeof(*node));
+ if (!node)
+ return AVERROR(ENOMEM);
+ node->array_id = m->count - 1;
+ node->next = *index;
+ *index = node;
}
if (!m->count) {
av_free(m->elems);
@@ -163,10 +232,20 @@ void av_dict_free(AVDictionary **pm)
AVDictionary *m = *pm;
if (m) {
+ unsigned i;
+
while(m->count--) {
av_free(m->elems[m->count].key);
av_free(m->elems[m->count].value);
}
+ for (i = 0; i < HASH_TABLE_LEN; i++) {
+ struct node *tmp, *node = m->hashtable[i];
+ while (node) {
+ tmp = node;
+ node = node->next;
+ av_freep(&tmp);
+ }
+ }
av_free(m->elems);
}
av_freep(pm);
--
1.8.2.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20130414/67507505/attachment.asc>
More information about the ffmpeg-devel
mailing list