[FFmpeg-devel] [PATCH 5/5] lavu/dict: add hashtable index.

Clément Bœsch ubitux at gmail.com
Sun Apr 14 03:07:58 CEST 2013


---
 libavutil/dict.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 84 insertions(+), 9 deletions(-)

diff --git a/libavutil/dict.c b/libavutil/dict.c
index 7a92c56..fd1176c 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -25,37 +25,78 @@
 #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 = m->hashtable[get_hash(key)];
+
+    while (node) {
+        if (!entry_cmp(m->elems[node->array_id].key, key, flags))
+            return node;
+        node = node->next;
+    }
+    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;
 }
 
@@ -64,13 +105,27 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
     AVDictionary      *m = *pm;
     AVDictionaryEntry *tag = av_dict_get(m, key, NULL, flags);
     char *oldval = NULL;
+    int add_index_entry = 1;
 
     if(!m)
         m = *pm = av_mallocz(sizeof(*m));
 
     if(tag) {
+        int old_id;
+        struct node *node;
+
         if (flags & AV_DICT_DONT_OVERWRITE)
             return 0;
+
+        /* entry already exists: that one and the last one in the array will be
+         * toggled, so the hashtable needs some adjustments as well. */
+        add_index_entry = 0;
+        node = get_node(m, tag->key, flags);
+        old_id = node->array_id;
+        node->array_id = m->count - 1;
+        node = get_node(m, m->elems[m->count - 1].key, flags);
+        node->array_id = old_id;
+
         if (flags & AV_DICT_APPEND)
             oldval = tag->value;
         else
@@ -102,6 +157,16 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
             e->value = newval;
         } else
             e->value = av_strdup(value);
+
+        if (add_index_entry) {
+            struct node **index = &m->hashtable[get_hash(e->key)];
+            struct node *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 +228,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



More information about the ffmpeg-devel mailing list