]> git.sesse.net Git - vlc/commitdiff
* B-search macro
authorClément Stenac <zorglub@videolan.org>
Sat, 19 Aug 2006 16:19:31 +0000 (16:19 +0000)
committerClément Stenac <zorglub@videolan.org>
Sat, 19 Aug 2006 16:19:31 +0000 (16:19 +0000)
* Redo dictionnary handling to remove recursion and bugs

include/vlc_common.h
include/vlc_symbols.h
src/Makefile.am
src/input/item.c
src/misc/dict.c [new file with mode: 0644]
src/misc/hashtables.c [deleted file]

index 2f3e156d2acc8c753c9feecdc3542529fd43b107..3be65bb5c4c66c8447a6cab6f7e2f12980d8c0b3 100644 (file)
@@ -203,7 +203,8 @@ typedef struct libvlc_t libvlc_t;
 typedef struct vlc_t vlc_t;
 typedef struct variable_t variable_t;
 typedef struct date_t date_t;
-typedef struct hashtable_entry_t hashtable_entry_t;
+typedef struct dict_entry_t dict_entry_t;
+typedef struct dict_t dict_t;
 typedef struct gc_object_t gc_object_t ;
 
 /* Messages */
@@ -717,19 +718,44 @@ static int64_t GCD( int64_t a, int64_t b )
         }                                       \
     }
 
-/* Hash tables handling */
-struct hashtable_entry_t
+/* Binary search in an array */
+#define BSEARCH( entries, count, elem, zetype, key, answer ) {  \
+    int low = 0, high = count - 1;   \
+    answer = -1; \
+    while( low <= high ) {\
+        int mid = (low + high ) / 2; /* Just don't care about 2^30 tables */ \
+        zetype mid_val = entries[mid] elem;\
+        if( mid_val < key ) \
+            low = mid + 1; \
+        else if ( mid_val > key ) \
+            high = mid -1;  \
+        else    \
+        {   \
+            answer = mid;  break;   \
+        }\
+    } \
+}
+
+/* Dictionnary handling */
+struct dict_entry_t
 {
-    int       i_id;
-    char     *psz_name;
+    int       i_int;
+    char     *psz_string;
     uint64_t  i_hash;
     void     *p_data;
 };
 
-VLC_EXPORT( void, vlc_HashInsert, (hashtable_entry_t **, int *, int, const char *, void *));
-VLC_EXPORT( void*, vlc_HashRetrieve, (hashtable_entry_t*, int, int, const char *) );
-VLC_EXPORT( int, vlc_HashLookup, (hashtable_entry_t *, int, int, const char *) );
+struct dict_t
+{
+    dict_entry_t *p_entries;
+    int i_entries;
+};
 
+VLC_EXPORT( dict_t *, vlc_DictNew, (void) );
+VLC_EXPORT( void, vlc_DictClear, (dict_t * ) );
+VLC_EXPORT( void, vlc_DictInsert, (dict_t *, int, const char *, void * ) );
+VLC_EXPORT( void*, vlc_DictGet, (dict_t *, int, const char * ) );
+VLC_EXPORT( int, vlc_DictLookup, (dict_t *, int, const char * ) );
 
 /* MSB (big endian)/LSB (little endian) conversions - network order is always
  * MSB, and should be used for both network communications and files. Note that
index 09393102b150263313244f6dbd5df2e72f38a4c4..a3659b5ab811ca0cdb81cda5e1d27df07073cddc 100644 (file)
@@ -463,9 +463,9 @@ struct module_symbols_t
     unsigned int (*update_iterator_ChooseMirrorAndFile_inner) (update_iterator_t *, int, int, int);
     update_t * (*__update_New_inner) (vlc_object_t *);
     void (*update_download_inner) (update_iterator_t *, char *);
-    void (*vlc_HashInsert_inner) (hashtable_entry_t **, int *, int, const char *, void *);
-    int (*vlc_HashLookup_inner) (hashtable_entry_t *, int, int, const char *);
-    void* (*vlc_HashRetrieve_inner) (hashtable_entry_t*, int, int, const char *);
+    void *vlc_HashInsert_deprecated;
+    void *vlc_HashLookup_deprecated;
+    void *vlc_HashRetrieve_deprecated;
     void * (*utf8_opendir_inner) (const char *dirname);
     FILE * (*utf8_fopen_inner) (const char *filename, const char *mode);
     const char * (*utf8_readdir_inner) (void *dir);
@@ -525,6 +525,11 @@ struct module_symbols_t
     int (*__intf_Progress_inner) (vlc_object_t*, const char*, const char*, float, int);
     void (*__intf_ProgressUpdate_inner) (vlc_object_t*, int, const char*, float, int);
     int (*playlist_AddInput_inner) (playlist_t *, input_item_t *,int , int, vlc_bool_t);
+    void (*vlc_DictInsert_inner) (dict_t *, int, const char *, void *);
+    void* (*vlc_DictGet_inner) (dict_t *, int, const char *);
+    int (*vlc_DictLookup_inner) (dict_t *, int, const char *);
+    void (*vlc_DictClear_inner) (dict_t *);
+    dict_t * (*vlc_DictNew_inner) (void);
 };
 # if defined (__PLUGIN__)
 #  define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner
@@ -936,9 +941,6 @@ struct module_symbols_t
 #  define update_iterator_ChooseMirrorAndFile (p_symbols)->update_iterator_ChooseMirrorAndFile_inner
 #  define __update_New (p_symbols)->__update_New_inner
 #  define update_download (p_symbols)->update_download_inner
-#  define vlc_HashInsert (p_symbols)->vlc_HashInsert_inner
-#  define vlc_HashLookup (p_symbols)->vlc_HashLookup_inner
-#  define vlc_HashRetrieve (p_symbols)->vlc_HashRetrieve_inner
 #  define utf8_opendir (p_symbols)->utf8_opendir_inner
 #  define utf8_fopen (p_symbols)->utf8_fopen_inner
 #  define utf8_readdir (p_symbols)->utf8_readdir_inner
@@ -988,6 +990,11 @@ struct module_symbols_t
 #  define __intf_Progress (p_symbols)->__intf_Progress_inner
 #  define __intf_ProgressUpdate (p_symbols)->__intf_ProgressUpdate_inner
 #  define playlist_AddInput (p_symbols)->playlist_AddInput_inner
+#  define vlc_DictInsert (p_symbols)->vlc_DictInsert_inner
+#  define vlc_DictGet (p_symbols)->vlc_DictGet_inner
+#  define vlc_DictLookup (p_symbols)->vlc_DictLookup_inner
+#  define vlc_DictClear (p_symbols)->vlc_DictClear_inner
+#  define vlc_DictNew (p_symbols)->vlc_DictNew_inner
 # elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__)
 /******************************************************************
  * STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access.
@@ -1402,9 +1409,6 @@ struct module_symbols_t
     ((p_symbols)->update_iterator_ChooseMirrorAndFile_inner) = update_iterator_ChooseMirrorAndFile; \
     ((p_symbols)->__update_New_inner) = __update_New; \
     ((p_symbols)->update_download_inner) = update_download; \
-    ((p_symbols)->vlc_HashInsert_inner) = vlc_HashInsert; \
-    ((p_symbols)->vlc_HashLookup_inner) = vlc_HashLookup; \
-    ((p_symbols)->vlc_HashRetrieve_inner) = vlc_HashRetrieve; \
     ((p_symbols)->utf8_opendir_inner) = utf8_opendir; \
     ((p_symbols)->utf8_fopen_inner) = utf8_fopen; \
     ((p_symbols)->utf8_readdir_inner) = utf8_readdir; \
@@ -1454,6 +1458,11 @@ struct module_symbols_t
     ((p_symbols)->__intf_Progress_inner) = __intf_Progress; \
     ((p_symbols)->__intf_ProgressUpdate_inner) = __intf_ProgressUpdate; \
     ((p_symbols)->playlist_AddInput_inner) = playlist_AddInput; \
+    ((p_symbols)->vlc_DictInsert_inner) = vlc_DictInsert; \
+    ((p_symbols)->vlc_DictGet_inner) = vlc_DictGet; \
+    ((p_symbols)->vlc_DictLookup_inner) = vlc_DictLookup; \
+    ((p_symbols)->vlc_DictClear_inner) = vlc_DictClear; \
+    ((p_symbols)->vlc_DictNew_inner) = vlc_DictNew; \
     (p_symbols)->net_ConvertIPv4_deprecated = NULL; \
     (p_symbols)->__playlist_ItemNew_deprecated = NULL; \
     (p_symbols)->__playlist_ItemCopy_deprecated = NULL; \
@@ -1489,6 +1498,9 @@ struct module_symbols_t
     (p_symbols)->__stats_CounterGet_deprecated = NULL; \
     (p_symbols)->stats_HandlerDestroy_deprecated = NULL; \
     (p_symbols)->__stats_TimerDumpAll_deprecated = NULL; \
+    (p_symbols)->vlc_HashInsert_deprecated = NULL; \
+    (p_symbols)->vlc_HashLookup_deprecated = NULL; \
+    (p_symbols)->vlc_HashRetrieve_deprecated = NULL; \
     (p_symbols)->playlist_ItemNewFromInput_deprecated = NULL; \
     (p_symbols)->playlist_PlaylistAdd_deprecated = NULL; \
     (p_symbols)->playlist_PlaylistAddExt_deprecated = NULL; \
index 942e4ed9720f0c2c4546a9baec0294f554dd7163..f68101a1173ab590815bac17eef8ef27b8889a8a 100644 (file)
@@ -325,7 +325,7 @@ SOURCES_libvlc_common = \
        misc/update.c \
        misc/vlm.c \
        misc/xml.c \
-       misc/hashtables.c \
+       misc/dict.c \
        misc/devices.c \
        extras/libc.c \
        control/core.c \
index 870c274185d4a22d1a13e5fad42fe59e7f824e41..6443d5964f3f5ed8e05395481d4d1355df9d57b2 100644 (file)
@@ -70,7 +70,7 @@ char *vlc_input_item_GetInfo( input_item_t *p_i,
 static void vlc_input_item_Destroy ( gc_object_t *p_this )
 {
     vlc_object_t *p_obj = (vlc_object_t *)p_this->p_destructor_arg;
-    int i, i_top, i_bottom;
+    int i;
     input_item_t *p_input = (input_item_t *) p_this;
 
     playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_obj,
diff --git a/src/misc/dict.c b/src/misc/dict.c
new file mode 100644 (file)
index 0000000..36b5c36
--- /dev/null
@@ -0,0 +1,163 @@
+/*****************************************************************************
+ * dict.c: Dictionnary handling
+ *****************************************************************************
+ * Copyright (C) 2002-2004 the VideoLAN team
+ * $Id: variables.c 13991 2006-01-22 17:12:24Z zorglub $
+ *
+ * Authors: Samuel Hocevar <sam@zoy.org>
+ *          Clément Stenac <zorglub@videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include <vlc/vlc.h>
+#include <assert.h>
+
+/*****************************************************************************
+ * Associative array
+ *****************************************************************************
+ * This is quite a weak implementation of an associative array.
+ * It hashes the key and stores the entry in a sorted array that gets 
+ * reallocated to insert new entries (so, this is SLOW)
+ * Lookup is done by using binary search on the array
+ */
+
+static uint64_t DoHash    ( const char *, int );
+
+#define DARRAY p_dict->p_entries
+#define DSIZE p_dict->i_entries
+
+dict_t *vlc_DictNew()
+{
+    DECMALLOC_NULL( p_dict, dict_t );
+    p_dict->i_entries = 0;
+    p_dict->p_entries = NULL;
+    return p_dict;
+}
+
+void vlc_DictClear( dict_t *p_dict )
+{
+    int i = 0;
+    for( i = 0 ; i< DSIZE; i++ )
+    {
+        FREE( DARRAY[i].psz_string );
+    }
+    free( DARRAY );
+    free( p_dict );
+}
+
+void vlc_DictInsert( dict_t *p_dict, int i_int, const char *psz_string, 
+                     void *p_data )
+{
+    uint64_t i_hash = DoHash( psz_string, i_int );
+    int i_new;
+
+    /* Find a free slot */
+    if( DSIZE == 0 || i_hash <= DARRAY[0].i_hash )
+        i_new = 0;
+    else if( i_hash >= DARRAY[DSIZE-1].i_hash )
+        i_new = DSIZE;
+    else 
+    {
+        int i_low = 0, i_high = DSIZE;
+        while( i_low != i_high )
+        {
+            int i_mid = (i_low + i_high)/2;
+            if( DARRAY[i_mid].i_hash < i_hash )
+                i_low = i_mid + 1;
+            if( DARRAY[i_mid].i_hash > i_hash )
+                i_high = i_low + 1;
+        }
+        i_new = i_low;
+    }
+    DARRAY = realloc( DARRAY, (DSIZE + 1) * sizeof( dict_entry_t ) );
+    DSIZE++;
+
+    if( i_new != DSIZE -1 )
+        memmove( DARRAY + i_new + 1 , DARRAY + i_new, ( DSIZE - i_new - 1 ) *
+                    sizeof( dict_entry_t ) );
+    DARRAY[i_new].i_hash = i_hash;
+    DARRAY[i_new].i_int = i_int;
+    if( psz_string )
+        DARRAY[i_new].psz_string = strdup( psz_string );
+    else
+        DARRAY[i_new].psz_string = NULL;
+    DARRAY[i_new].p_data = p_data;
+}
+
+void * vlc_DictGet( dict_t *p_dict, int i_int, const char *psz_string )
+{
+    int i_new = vlc_DictLookup( p_dict, i_int, psz_string );
+    if( i_new >=  0 )
+        return DARRAY[i_new].p_data;
+    return NULL;
+}
+
+int vlc_DictLookup( dict_t *p_dict, int i_int, const char *psz_string )
+{
+    uint64_t i_hash;
+    int i, i_pos;
+    if( DSIZE == 0 ) return -1;
+
+    i_hash = DoHash( psz_string, i_int );
+    BSEARCH( p_dict->p_entries, p_dict->i_entries, .i_hash, uint64_t,
+             i_hash, i_pos );
+    if( i_pos == -1 ) return -1;
+
+    /* Hash found, let's check it looks like the entry */
+    if( !strcmp( psz_string, DARRAY[i_pos].psz_string ) )
+        return i_pos;
+
+    /* Hash collision! This should be very rare, but we cannot guarantee
+     * it will never happen. Just do an exhaustive search amongst all
+     * entries with the same hash. */
+    for( i = i_pos - 1 ; i > 0 && i_hash == DARRAY[i].i_hash ; i-- )
+    {
+        if( !strcmp( psz_string, DARRAY[i].psz_string ) &&
+                   DARRAY[i].i_int == i_int ) 
+            return i;
+    }
+    for( i = i_pos + 1 ; i < DSIZE && i_hash == DARRAY[i].i_hash ; i++ )
+    {
+         if( !strcmp( psz_string, DARRAY[i].psz_string ) &&
+                   DARRAY[i].i_int == i_int ) 
+            return i;
+    }
+    /* Hash found, but entry not found (quite strange !) */
+    assert( 0 );
+    return -1;
+}
+
+/*****************************************************************************
+ * DoHash: our cool hash function
+ *****************************************************************************
+ * This function is not intended to be crypto-secure, we only want it to be
+ * fast and not suck too much. This one is pretty fast and did 0 collisions
+ * in wenglish's dictionary.
+ *****************************************************************************/
+static uint64_t DoHash( const char *psz_string, int i_int )
+{
+    uint64_t i_hash = 0;
+    if( psz_string )
+    {
+        while( *psz_string )
+        {
+            i_hash += *psz_string++;
+            i_hash += i_hash << 10;
+            i_hash ^= i_hash >> 8;
+        }
+    }
+    return i_hash + ( (uint64_t)i_int << 32 );
+}
diff --git a/src/misc/hashtables.c b/src/misc/hashtables.c
deleted file mode 100644 (file)
index 1bb3164..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/*****************************************************************************
- * hashtables.c: Hash tables handling
- *****************************************************************************
- * Copyright (C) 2002-2004 the VideoLAN team
- * $Id: variables.c 13991 2006-01-22 17:12:24Z zorglub $
- *
- * Authors: Samuel Hocevar <sam@zoy.org>
- *          Clément Stenac <zorglub@videolan.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <vlc/vlc.h>
-
-static uint64_t HashString    ( const char *, int );
-static int      FindSlot      ( hashtable_entry_t *, int, uint64_t );
-static int      LookupInner   ( hashtable_entry_t *, int, uint64_t );
-
-
-
-void vlc_HashInsert( hashtable_entry_t **pp_array, int *pi_count, int i_id,
-                     const char *psz_name, void *p_data )
-{
-    hashtable_entry_t *p_new;
-    int64_t i_hash = HashString( psz_name, i_id );
-    int i_new = FindSlot( *pp_array, *pi_count, i_hash );
-
-    *pp_array = realloc( *pp_array, ( *pi_count + 2) * sizeof( hashtable_entry_t ) );
-
-    memmove( *pp_array + i_new + 1 , *pp_array + i_new, ( *pi_count - i_new ) *
-                sizeof( hashtable_entry_t ) );
-    (*pi_count)++;
-
-    p_new = &((*pp_array)[i_new]);
-    p_new->i_hash = i_hash;
-    p_new->i_id = i_id;
-    p_new->psz_name = strdup( psz_name );
-    p_new->p_data = p_data;
-
-}
-
-void * vlc_HashRetrieve( hashtable_entry_t *p_array, int i_count, int i_id,
-                         const char *psz_name )
-{
-    int i_new = vlc_HashLookup( p_array, i_count, i_id, psz_name );
-
-    if( i_new >=  0 && i_new < i_count )
-    {
-        return p_array[i_new].p_data;
-    }
-    return NULL;
-}
-
-/*****************************************************************************
- * FindSlot: find an empty slot to insert a new variable
- *****************************************************************************
- * We use a recursive inner function indexed on the hash. This function does
- * nothing in the rare cases where a collision may occur, see Lookup()
- * to see how we handle them.
- * XXX: does this really need to be written recursively?
- *****************************************************************************/
-static int FindSlot( hashtable_entry_t *p_array, int i_count, uint64_t i_hash )
-{
-    int i_middle;
-
-    if( i_count == 0 || i_hash <= p_array[0].i_hash )
-    {
-        return 0;
-    }
-
-    if( i_hash >= p_array[i_count - 1].i_hash )
-    {
-        return i_count;
-    }
-
-    i_middle = i_count / 2;
-
-    /* We know that 0 < i_middle */
-    if( i_hash < p_array[i_middle].i_hash )
-    {
-        return FindSlot( p_array, i_middle, i_hash );
-    }
-
-    /* We know that i_middle + 1 < i_count */
-    if( i_hash > p_array[i_middle + 1].i_hash )
-    {
-        return i_middle + 1 + FindSlot( p_array + i_middle + 1,
-                                        i_count - i_middle - 1,
-                                        i_hash );
-    }
-
-    return i_middle + 1;
-}
-
-/*****************************************************************************
- * Lookup: find an existing variable given its name and id
- *****************************************************************************
- * We use a recursive inner function indexed on the hash. Care is taken of
- * possible hash collisions.
- * XXX: does this really need to be written recursively?
- *****************************************************************************/
-int vlc_HashLookup( hashtable_entry_t *p_array, int i_count,
-                    int i_id, const char *psz_name )
-{
-    uint64_t i_hash;
-    int i, i_pos;
-
-    if( i_count == 0 )
-    {
-        return -1;
-    }
-
-    i_hash = HashString( psz_name, i_id );
-
-    i_pos = LookupInner( p_array, i_count, i_hash );
-
-    /* Hash not found */
-    if( i_hash != p_array[i_pos].i_hash )
-    {
-        return -1;
-    }
-
-    /* Hash found, let's check it looks like the entry
-     * We don't check the whole entry, this could lead to bad surprises :( */
-    if( psz_name[0] == p_array[i_pos].psz_name[0] )
-    {
-        return i_pos;
-    }
-
-    /* Hash collision! This should be very rare, but we cannot guarantee
-     * it will never happen. Just do an exhaustive search amongst all
-     * entries with the same hash. */
-    for( i = i_pos - 1 ; i > 0 && i_hash == p_array[i].i_hash ; i-- )
-    {
-        if( !strcmp( psz_name, p_array[i].psz_name ) && p_array[i].i_id == i_id )
-        {
-            return i;
-        }
-    }
-
-    for( i = i_pos + 1 ; i < i_count && i_hash == p_array[i].i_hash ; i++ )
-    {
-        if( !strcmp( psz_name, p_array[i].psz_name ) && p_array[i].i_id == i_id )
-        {
-            return i;
-        }
-    }
-
-    /* Hash found, but entry not found */
-    return -1;
-}
-
-static int LookupInner( hashtable_entry_t *p_array, int i_count, uint64_t i_hash )
-{
-    int i_middle;
-
-    if( i_hash <= p_array[0].i_hash )
-    {
-        return 0;
-    }
-
-    if( i_hash >= p_array[i_count-1].i_hash )
-    {
-        return i_count - 1;
-    }
-
-    i_middle = i_count / 2;
-
-    /* We know that 0 < i_middle */
-    if( i_hash < p_array[i_middle].i_hash )
-    {
-        return LookupInner( p_array, i_middle, i_hash );
-    }
-
-    /* We know that i_middle + 1 < i_count */
-    if( i_hash > p_array[i_middle].i_hash )
-    {
-        return i_middle + LookupInner( p_array + i_middle,
-                                       i_count - i_middle,
-                                       i_hash );
-    }
-
-    return i_middle;
-}
-
-
-/*****************************************************************************
- * HashString: our cool hash function
- *****************************************************************************
- * This function is not intended to be crypto-secure, we only want it to be
- * fast and not suck too much. This one is pretty fast and did 0 collisions
- * in wenglish's dictionary.
- *****************************************************************************/
-static uint64_t HashString( const char *psz_string, int i_id )
-{
-    uint64_t i_hash = 0;
-
-    while( *psz_string )
-    {
-        i_hash += *psz_string++;
-        i_hash += i_hash << 10;
-        i_hash ^= i_hash >> 8;
-    }
-
-    i_hash += ( (uint64_t)i_id << 32 );
-
-    return i_hash;
-}