Commit 23d27c9c authored by Clément Stenac's avatar Clément Stenac

* B-search macro

* Redo dictionnary handling to remove recursion and bugs
parent 2c2ebc9c
...@@ -203,7 +203,8 @@ typedef struct libvlc_t libvlc_t; ...@@ -203,7 +203,8 @@ typedef struct libvlc_t libvlc_t;
typedef struct vlc_t vlc_t; typedef struct vlc_t vlc_t;
typedef struct variable_t variable_t; typedef struct variable_t variable_t;
typedef struct date_t date_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 ; typedef struct gc_object_t gc_object_t ;
/* Messages */ /* Messages */
...@@ -717,19 +718,44 @@ static int64_t GCD( int64_t a, int64_t b ) ...@@ -717,19 +718,44 @@ static int64_t GCD( int64_t a, int64_t b )
} \ } \
} }
/* Hash tables handling */ /* Binary search in an array */
struct hashtable_entry_t #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; int i_int;
char *psz_name; char *psz_string;
uint64_t i_hash; uint64_t i_hash;
void *p_data; void *p_data;
}; };
VLC_EXPORT( void, vlc_HashInsert, (hashtable_entry_t **, int *, int, const char *, void *)); struct dict_t
VLC_EXPORT( void*, vlc_HashRetrieve, (hashtable_entry_t*, int, int, const char *) ); {
VLC_EXPORT( int, vlc_HashLookup, (hashtable_entry_t *, int, int, const char *) ); 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 (big endian)/LSB (little endian) conversions - network order is always
* MSB, and should be used for both network communications and files. Note that * MSB, and should be used for both network communications and files. Note that
......
...@@ -463,9 +463,9 @@ struct module_symbols_t ...@@ -463,9 +463,9 @@ struct module_symbols_t
unsigned int (*update_iterator_ChooseMirrorAndFile_inner) (update_iterator_t *, int, int, int); unsigned int (*update_iterator_ChooseMirrorAndFile_inner) (update_iterator_t *, int, int, int);
update_t * (*__update_New_inner) (vlc_object_t *); update_t * (*__update_New_inner) (vlc_object_t *);
void (*update_download_inner) (update_iterator_t *, char *); void (*update_download_inner) (update_iterator_t *, char *);
void (*vlc_HashInsert_inner) (hashtable_entry_t **, int *, int, const char *, void *); void *vlc_HashInsert_deprecated;
int (*vlc_HashLookup_inner) (hashtable_entry_t *, int, int, const char *); void *vlc_HashLookup_deprecated;
void* (*vlc_HashRetrieve_inner) (hashtable_entry_t*, int, int, const char *); void *vlc_HashRetrieve_deprecated;
void * (*utf8_opendir_inner) (const char *dirname); void * (*utf8_opendir_inner) (const char *dirname);
FILE * (*utf8_fopen_inner) (const char *filename, const char *mode); FILE * (*utf8_fopen_inner) (const char *filename, const char *mode);
const char * (*utf8_readdir_inner) (void *dir); const char * (*utf8_readdir_inner) (void *dir);
...@@ -525,6 +525,11 @@ struct module_symbols_t ...@@ -525,6 +525,11 @@ struct module_symbols_t
int (*__intf_Progress_inner) (vlc_object_t*, const char*, const char*, float, int); 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); 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); 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__) # if defined (__PLUGIN__)
# define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner # define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner
...@@ -936,9 +941,6 @@ struct module_symbols_t ...@@ -936,9 +941,6 @@ struct module_symbols_t
# define update_iterator_ChooseMirrorAndFile (p_symbols)->update_iterator_ChooseMirrorAndFile_inner # define update_iterator_ChooseMirrorAndFile (p_symbols)->update_iterator_ChooseMirrorAndFile_inner
# define __update_New (p_symbols)->__update_New_inner # define __update_New (p_symbols)->__update_New_inner
# define update_download (p_symbols)->update_download_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_opendir (p_symbols)->utf8_opendir_inner
# define utf8_fopen (p_symbols)->utf8_fopen_inner # define utf8_fopen (p_symbols)->utf8_fopen_inner
# define utf8_readdir (p_symbols)->utf8_readdir_inner # define utf8_readdir (p_symbols)->utf8_readdir_inner
...@@ -988,6 +990,11 @@ struct module_symbols_t ...@@ -988,6 +990,11 @@ struct module_symbols_t
# define __intf_Progress (p_symbols)->__intf_Progress_inner # define __intf_Progress (p_symbols)->__intf_Progress_inner
# define __intf_ProgressUpdate (p_symbols)->__intf_ProgressUpdate_inner # define __intf_ProgressUpdate (p_symbols)->__intf_ProgressUpdate_inner
# define playlist_AddInput (p_symbols)->playlist_AddInput_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__) # elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__)
/****************************************************************** /******************************************************************
* STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access. * STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access.
...@@ -1402,9 +1409,6 @@ struct module_symbols_t ...@@ -1402,9 +1409,6 @@ struct module_symbols_t
((p_symbols)->update_iterator_ChooseMirrorAndFile_inner) = update_iterator_ChooseMirrorAndFile; \ ((p_symbols)->update_iterator_ChooseMirrorAndFile_inner) = update_iterator_ChooseMirrorAndFile; \
((p_symbols)->__update_New_inner) = __update_New; \ ((p_symbols)->__update_New_inner) = __update_New; \
((p_symbols)->update_download_inner) = update_download; \ ((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_opendir_inner) = utf8_opendir; \
((p_symbols)->utf8_fopen_inner) = utf8_fopen; \ ((p_symbols)->utf8_fopen_inner) = utf8_fopen; \
((p_symbols)->utf8_readdir_inner) = utf8_readdir; \ ((p_symbols)->utf8_readdir_inner) = utf8_readdir; \
...@@ -1454,6 +1458,11 @@ struct module_symbols_t ...@@ -1454,6 +1458,11 @@ struct module_symbols_t
((p_symbols)->__intf_Progress_inner) = __intf_Progress; \ ((p_symbols)->__intf_Progress_inner) = __intf_Progress; \
((p_symbols)->__intf_ProgressUpdate_inner) = __intf_ProgressUpdate; \ ((p_symbols)->__intf_ProgressUpdate_inner) = __intf_ProgressUpdate; \
((p_symbols)->playlist_AddInput_inner) = playlist_AddInput; \ ((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)->net_ConvertIPv4_deprecated = NULL; \
(p_symbols)->__playlist_ItemNew_deprecated = NULL; \ (p_symbols)->__playlist_ItemNew_deprecated = NULL; \
(p_symbols)->__playlist_ItemCopy_deprecated = NULL; \ (p_symbols)->__playlist_ItemCopy_deprecated = NULL; \
...@@ -1489,6 +1498,9 @@ struct module_symbols_t ...@@ -1489,6 +1498,9 @@ struct module_symbols_t
(p_symbols)->__stats_CounterGet_deprecated = NULL; \ (p_symbols)->__stats_CounterGet_deprecated = NULL; \
(p_symbols)->stats_HandlerDestroy_deprecated = NULL; \ (p_symbols)->stats_HandlerDestroy_deprecated = NULL; \
(p_symbols)->__stats_TimerDumpAll_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_ItemNewFromInput_deprecated = NULL; \
(p_symbols)->playlist_PlaylistAdd_deprecated = NULL; \ (p_symbols)->playlist_PlaylistAdd_deprecated = NULL; \
(p_symbols)->playlist_PlaylistAddExt_deprecated = NULL; \ (p_symbols)->playlist_PlaylistAddExt_deprecated = NULL; \
......
...@@ -325,7 +325,7 @@ SOURCES_libvlc_common = \ ...@@ -325,7 +325,7 @@ SOURCES_libvlc_common = \
misc/update.c \ misc/update.c \
misc/vlm.c \ misc/vlm.c \
misc/xml.c \ misc/xml.c \
misc/hashtables.c \ misc/dict.c \
misc/devices.c \ misc/devices.c \
extras/libc.c \ extras/libc.c \
control/core.c \ control/core.c \
......
...@@ -70,7 +70,7 @@ char *vlc_input_item_GetInfo( input_item_t *p_i, ...@@ -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 ) static void vlc_input_item_Destroy ( gc_object_t *p_this )
{ {
vlc_object_t *p_obj = (vlc_object_t *)p_this->p_destructor_arg; 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; input_item_t *p_input = (input_item_t *) p_this;
playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_obj, playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_obj,
......
/***************************************************************************** /*****************************************************************************
* hashtables.c: Hash tables handling * dict.c: Dictionnary handling
***************************************************************************** *****************************************************************************
* Copyright (C) 2002-2004 the VideoLAN team * Copyright (C) 2002-2004 the VideoLAN team
* $Id: variables.c 13991 2006-01-22 17:12:24Z zorglub $ * $Id: variables.c 13991 2006-01-22 17:12:24Z zorglub $
* *
* Authors: Samuel Hocevar <sam@zoy.org> * Authors: Samuel Hocevar <sam@zoy.org>
* Clment Stenac <zorglub@videolan.org> * Clément Stenac <zorglub@videolan.org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -22,202 +22,142 @@ ...@@ -22,202 +22,142 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/ *****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <vlc/vlc.h> #include <vlc/vlc.h>
#include <assert.h>
static uint64_t HashString ( const char *, int ); /*****************************************************************************
static int FindSlot ( hashtable_entry_t *, int, uint64_t ); * Associative array
static int LookupInner ( hashtable_entry_t *, int, uint64_t ); *****************************************************************************
* 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
void vlc_HashInsert( hashtable_entry_t **pp_array, int *pi_count, int i_id, dict_t *vlc_DictNew()
const char *psz_name, void *p_data )
{ {
hashtable_entry_t *p_new; DECMALLOC_NULL( p_dict, dict_t );
int64_t i_hash = HashString( psz_name, i_id ); p_dict->i_entries = 0;
int i_new = FindSlot( *pp_array, *pi_count, i_hash ); p_dict->p_entries = NULL;
return p_dict;
*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, void vlc_DictClear( dict_t *p_dict )
const char *psz_name )
{ {
int i_new = vlc_HashLookup( p_array, i_count, i_id, psz_name ); int i = 0;
for( i = 0 ; i< DSIZE; i++ )
if( i_new >= 0 && i_new < i_count )
{ {
return p_array[i_new].p_data; FREE( DARRAY[i].psz_string );
} }
return NULL; free( DARRAY );
free( p_dict );
} }
/***************************************************************************** void vlc_DictInsert( dict_t *p_dict, int i_int, const char *psz_string,
* FindSlot: find an empty slot to insert a new variable void *p_data )
*****************************************************************************
* 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; uint64_t i_hash = DoHash( psz_string, i_int );
int i_new;
if( i_count == 0 || i_hash <= p_array[0].i_hash )
{ /* Find a free slot */
return 0; if( DSIZE == 0 || i_hash <= DARRAY[0].i_hash )
} i_new = 0;
else if( i_hash >= DARRAY[DSIZE-1].i_hash )
if( i_hash >= p_array[i_count - 1].i_hash ) i_new = DSIZE;
{ else
return i_count; {
} int i_low = 0, i_high = DSIZE;
while( i_low != i_high )
i_middle = i_count / 2; {
int i_mid = (i_low + i_high)/2;
/* We know that 0 < i_middle */ if( DARRAY[i_mid].i_hash < i_hash )
if( i_hash < p_array[i_middle].i_hash ) i_low = i_mid + 1;
{ if( DARRAY[i_mid].i_hash > i_hash )
return FindSlot( p_array, i_middle, i_hash ); i_high = i_low + 1;
} }
i_new = i_low;
/* We know that i_middle + 1 < i_count */ }
if( i_hash > p_array[i_middle + 1].i_hash ) DARRAY = realloc( DARRAY, (DSIZE + 1) * sizeof( dict_entry_t ) );
{ DSIZE++;
return i_middle + 1 + FindSlot( p_array + i_middle + 1,
i_count - i_middle - 1, if( i_new != DSIZE -1 )
i_hash ); 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;
}
return i_middle + 1; 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 )
* 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; uint64_t i_hash;
int i, i_pos; int i, i_pos;
if( DSIZE == 0 ) return -1;
if( i_count == 0 ) i_hash = DoHash( psz_string, i_int );
{ BSEARCH( p_dict->p_entries, p_dict->i_entries, .i_hash, uint64_t,
return -1; i_hash, i_pos );
} if( i_pos == -1 ) return -1;
i_hash = HashString( psz_name, i_id );
i_pos = LookupInner( p_array, i_count, i_hash ); /* Hash found, let's check it looks like the entry */
if( !strcmp( psz_string, DARRAY[i_pos].psz_string ) )
/* 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; return i_pos;
}
/* Hash collision! This should be very rare, but we cannot guarantee /* Hash collision! This should be very rare, but we cannot guarantee
* it will never happen. Just do an exhaustive search amongst all * it will never happen. Just do an exhaustive search amongst all
* entries with the same hash. */ * entries with the same hash. */
for( i = i_pos - 1 ; i > 0 && i_hash == p_array[i].i_hash ; i-- ) for( i = i_pos - 1 ; i > 0 && i_hash == DARRAY[i].i_hash ; i-- )
{
if( !strcmp( psz_name, p_array[i].psz_name ) && p_array[i].i_id == i_id )
{ {
if( !strcmp( psz_string, DARRAY[i].psz_string ) &&
DARRAY[i].i_int == i_int )
return i; return i;
} }
} for( i = i_pos + 1 ; i < DSIZE && i_hash == DARRAY[i].i_hash ; 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 )
{ {
if( !strcmp( psz_string, DARRAY[i].psz_string ) &&
DARRAY[i].i_int == i_int )
return i; return i;
} }
} /* Hash found, but entry not found (quite strange !) */
assert( 0 );
/* Hash found, but entry not found */
return -1; 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 * DoHash: our cool hash function
***************************************************************************** *****************************************************************************
* This function is not intended to be crypto-secure, we only want it to be * 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 * fast and not suck too much. This one is pretty fast and did 0 collisions
* in wenglish's dictionary. * in wenglish's dictionary.
*****************************************************************************/ *****************************************************************************/
static uint64_t HashString( const char *psz_string, int i_id ) static uint64_t DoHash( const char *psz_string, int i_int )
{ {
uint64_t i_hash = 0; uint64_t i_hash = 0;
if( psz_string )
{
while( *psz_string ) while( *psz_string )
{ {
i_hash += *psz_string++; i_hash += *psz_string++;
i_hash += i_hash << 10; i_hash += i_hash << 10;
i_hash ^= i_hash >> 8; i_hash ^= i_hash >> 8;
} }
}
i_hash += ( (uint64_t)i_id << 32 ); return i_hash + ( (uint64_t)i_int << 32 );
return i_hash;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment