home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 May / maximum-cd-2009-05.iso / DiscContents / vlc-0.9.8a-win32.exe / sdk / include / vlc / plugins / vlc_arrays.h < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-06  |  21.5 KB  |  595 lines

  1. /*****************************************************************************
  2.  * vlc_arrays.h : Arrays and data structures handling
  3.  *****************************************************************************
  4.  * Copyright (C) 1999-2004 the VideoLAN team
  5.  * $Id: 79e7722507463c5c4ad8104693381d9b7120f3fc $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *          Cl├⌐ment Stenac <zorglub@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/
  23.  
  24. #ifndef VLC_ARRAYS_H_
  25. #define VLC_ARRAYS_H_
  26.  
  27. /**
  28.  * \file
  29.  * This file defines functions, structures and macros for handling arrays in vlc
  30.  */
  31.  
  32. /**
  33.  * Simple dynamic array handling. Array is realloced at each insert/removal
  34.  */
  35. #if defined( _MSC_VER ) && _MSC_VER < 1300 && !defined( UNDER_CE )
  36. #   define VLCCVP (void**) /* Work-around for broken compiler */
  37. #else
  38. #   define VLCCVP
  39. #endif
  40. #define INSERT_ELEM( p_ar, i_oldsize, i_pos, elem )                           \
  41.     do                                                                        \
  42.     {                                                                         \
  43.         if( !i_oldsize ) (p_ar) = NULL;                                       \
  44.         (p_ar) = VLCCVP realloc( p_ar, ((i_oldsize) + 1) * sizeof(*(p_ar)) ); \
  45.         if( (i_oldsize) - (i_pos) )                                           \
  46.         {                                                                     \
  47.             memmove( (p_ar) + (i_pos) + 1, (p_ar) + (i_pos),                  \
  48.                      ((i_oldsize) - (i_pos)) * sizeof( *(p_ar) ) );           \
  49.         }                                                                     \
  50.         (p_ar)[i_pos] = elem;                                                 \
  51.         (i_oldsize)++;                                                        \
  52.     }                                                                         \
  53.     while( 0 )
  54.  
  55. #define REMOVE_ELEM( p_ar, i_oldsize, i_pos )                                 \
  56.     do                                                                        \
  57.     {                                                                         \
  58.         if( (i_oldsize) - (i_pos) - 1 )                                       \
  59.         {                                                                     \
  60.             memmove( (p_ar) + (i_pos),                                        \
  61.                      (p_ar) + (i_pos) + 1,                                    \
  62.                      ((i_oldsize) - (i_pos) - 1) * sizeof( *(p_ar) ) );       \
  63.         }                                                                     \
  64.         if( i_oldsize > 1 )                                                   \
  65.         {                                                                     \
  66.             (p_ar) = realloc( p_ar, ((i_oldsize) - 1) * sizeof( *(p_ar) ) );  \
  67.         }                                                                     \
  68.         else                                                                  \
  69.         {                                                                     \
  70.             free( p_ar );                                                     \
  71.             (p_ar) = NULL;                                                    \
  72.         }                                                                     \
  73.         (i_oldsize)--;                                                        \
  74.     }                                                                         \
  75.     while( 0 )
  76.  
  77. #define TAB_INIT( count, tab )                  \
  78.   do {                                          \
  79.     (count) = 0;                                \
  80.     (tab) = NULL;                               \
  81.   } while(0)
  82.  
  83. #define TAB_CLEAN( count, tab )                 \
  84.   do {                                          \
  85.     free( tab );                                \
  86.     (count)= 0;                                 \
  87.     (tab)= NULL;                                \
  88.   } while(0)
  89.  
  90. #define TAB_APPEND_CAST( cast, count, tab, p )             \
  91.   do {                                          \
  92.     if( (count) > 0 )                           \
  93.         (tab) = cast realloc( tab, sizeof( void ** ) * ( (count) + 1 ) ); \
  94.     else                                        \
  95.         (tab) = cast malloc( sizeof( void ** ) );    \
  96.     (tab)[count] = (p);                         \
  97.     (count)++;                                  \
  98.   } while(0)
  99.  
  100. #define TAB_APPEND( count, tab, p )             \
  101.     TAB_APPEND_CAST( , count, tab, p )
  102. #define TAB_APPEND_CPP( type, count, tab, p )   \
  103.     TAB_APPEND_CAST( (type**), count, tab, p )
  104.  
  105. #define TAB_FIND( count, tab, p, index )        \
  106.   do {                                          \
  107.         int _i_;                                \
  108.         (index) = -1;                           \
  109.         for( _i_ = 0; _i_ < (count); _i_++ )    \
  110.         {                                       \
  111.             if( (tab)[_i_] == (p) )             \
  112.             {                                   \
  113.                 (index) = _i_;                  \
  114.                 break;                          \
  115.             }                                   \
  116.         }                                       \
  117.   } while(0)
  118.  
  119.  
  120. #define TAB_REMOVE( count, tab, p )             \
  121.   do {                                          \
  122.         int _i_index_;                          \
  123.         TAB_FIND( count, tab, p, _i_index_ );   \
  124.         if( _i_index_ >= 0 )                    \
  125.         {                                       \
  126.             if( (count) > 1 )                   \
  127.             {                                   \
  128.                 memmove( ((void**)(tab) + _i_index_),    \
  129.                          ((void**)(tab) + _i_index_+1),  \
  130.                          ( (count) - _i_index_ - 1 ) * sizeof( void* ) );\
  131.             }                                   \
  132.             (count)--;                          \
  133.             if( (count) == 0 )                  \
  134.             {                                   \
  135.                 free( tab );                    \
  136.                 (tab) = NULL;                   \
  137.             }                                   \
  138.         }                                       \
  139.   } while(0)
  140.  
  141. #define TAB_INSERT_CAST( cast, count, tab, p, index ) do { \
  142.     if( (count) > 0 )                           \
  143.         (tab) = cast realloc( tab, sizeof( void ** ) * ( (count) + 1 ) ); \
  144.     else                                        \
  145.         (tab) = cast malloc( sizeof( void ** ) );       \
  146.     if( (count) - (index) > 0 )                 \
  147.         memmove( (void**)(tab) + (index) + 1,   \
  148.                  (void**)(tab) + (index),       \
  149.                  ((count) - (index)) * sizeof(*(tab)) );\
  150.     (tab)[(index)] = (p);                       \
  151.     (count)++;                                  \
  152. } while(0)
  153.  
  154. #define TAB_INSERT( count, tab, p, index )      \
  155.     TAB_INSERT_CAST( , count, tab, p, index )
  156.  
  157. /**
  158.  * Binary search in a sorted array. The key must be comparable by < and >
  159.  * \param entries array of entries
  160.  * \param count number of entries
  161.  * \param elem key to check within an entry (like .id, or ->i_id)
  162.  * \param zetype type of the key
  163.  * \param key value of the key
  164.  * \param answer index of answer within the array. -1 if not found
  165.  */
  166. #define BSEARCH( entries, count, elem, zetype, key, answer ) \
  167.    do {  \
  168.     int low = 0, high = count - 1;   \
  169.     answer = -1; \
  170.     while( low <= high ) {\
  171.         int mid = (low + high ) / 2; /* Just don't care about 2^30 tables */ \
  172.         zetype mid_val = entries[mid] elem;\
  173.         if( mid_val < key ) \
  174.             low = mid + 1; \
  175.         else if ( mid_val > key ) \
  176.             high = mid -1;  \
  177.         else    \
  178.         {   \
  179.             answer = mid;  break;   \
  180.         }\
  181.     } \
  182.  } while(0)
  183.  
  184.  
  185. /************************************************************************
  186.  * Dynamic arrays with progressive allocation
  187.  ************************************************************************/
  188.  
  189. /* Internal functions */
  190. #define _ARRAY_ALLOC(array, newsize) {                                      \
  191.     array.i_alloc = newsize;                                                \
  192.     array.p_elems = VLCCVP realloc( array.p_elems, array.i_alloc *          \
  193.                                     sizeof(*array.p_elems) );               \
  194. }
  195.  
  196. #define _ARRAY_GROW1(array) {                                               \
  197.     if( array.i_alloc < 10 )                                                \
  198.         _ARRAY_ALLOC(array, 10 )                                            \
  199.     else if( array.i_alloc == array.i_size )                                \
  200.         _ARRAY_ALLOC(array, (int)(array.i_alloc * 1.5) )                    \
  201. }
  202.  
  203. #define _ARRAY_GROW(array,additional) {                                     \
  204.      int i_first = array.i_alloc;                                           \
  205.      while( array.i_alloc - i_first < additional )                          \
  206.      {                                                                      \
  207.          if( array.i_alloc < 10 )                                           \
  208.             _ARRAY_ALLOC(array, 10 )                                        \
  209.         else if( array.i_alloc == array.i_size )                            \
  210.             _ARRAY_ALLOC(array, (int)(array.i_alloc * 1.5) )                \
  211.         else break;                                                         \
  212.      }                                                                      \
  213. }
  214.  
  215. #define _ARRAY_SHRINK(array) {                                              \
  216.     if( array.i_size > 10 && array.i_size < (int)(array.i_alloc / 1.5) ) {  \
  217.         _ARRAY_ALLOC(array, array.i_size + 5);                              \
  218.     }                                                                       \
  219. }
  220.  
  221. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  222.  
  223. /* API */
  224. #define DECL_ARRAY(type) struct {                                           \
  225.     int i_alloc;                                                            \
  226.     int i_size;                                                             \
  227.     type *p_elems;                                                          \
  228. }
  229.  
  230. #define TYPEDEF_ARRAY(type, name) typedef DECL_ARRAY(type) name;
  231.  
  232. #define ARRAY_INIT(array)                                                   \
  233.     array.i_alloc = 0;                                                      \
  234.     array.i_size = 0;                                                       \
  235.     array.p_elems = NULL;
  236.  
  237. #define ARRAY_RESET(array)                                                  \
  238.     array.i_alloc = 0;                                                      \
  239.     array.i_size = 0;                                                       \
  240.     free( array.p_elems ); array.p_elems = NULL;
  241.  
  242. #define ARRAY_APPEND(array, elem) {                                         \
  243.     _ARRAY_GROW1(array);                                                    \
  244.     array.p_elems[array.i_size] = elem;                                     \
  245.     array.i_size++;                                                         \
  246. }
  247.  
  248. #define ARRAY_INSERT(array,elem,pos) {                                      \
  249.     _ARRAY_GROW1(array);                                                    \
  250.     if( array.i_size - pos ) {                                              \
  251.         memmove( array.p_elems + pos + 1, array.p_elems + pos,              \
  252.                  (array.i_size-pos) * sizeof(*array.p_elems) );             \
  253.     }                                                                       \
  254.     array.p_elems[pos] = elem;                                              \
  255.     array.i_size++;                                                         \
  256. }
  257.  
  258. #define ARRAY_REMOVE(array,pos) {                                           \
  259.     if( array.i_size - (pos) - 1 )                                          \
  260.     {                                                                       \
  261.         memmove( array.p_elems + pos, array.p_elems + pos + 1,              \
  262.                  ( array.i_size - pos - 1 ) *sizeof(*array.p_elems) );      \
  263.     }                                                                       \
  264.     array.i_size--;                                                         \
  265.     _ARRAY_SHRINK(array);                                                   \
  266. }
  267.  
  268. #define ARRAY_VAL(array, pos) array.p_elems[pos]
  269.  
  270. #define ARRAY_BSEARCH(array, elem, zetype, key, answer) \
  271.     BSEARCH( array.p_elems, array.i_size, elem, zetype, key, answer)
  272.  
  273. #define FOREACH_ARRAY( item, array ) { \
  274.     int fe_idx; \
  275.     for( fe_idx = 0 ; fe_idx < array.i_size ; fe_idx++ ) \
  276.     { \
  277.         item = array.p_elems[fe_idx];
  278.  
  279. #define FOREACH_END() } }
  280.  
  281.  
  282. /************************************************************************
  283.  * Dynamic arrays with progressive allocation (Preferred API)
  284.  ************************************************************************/
  285. typedef struct vlc_array_t
  286. {
  287.     int i_count;
  288.     void ** pp_elems;
  289. } vlc_array_t;
  290.  
  291. static inline void vlc_array_init( vlc_array_t * p_array )
  292. {
  293.     memset( p_array, 0, sizeof(vlc_array_t) );
  294. }
  295.  
  296. static inline void vlc_array_clear( vlc_array_t * p_array )
  297. {
  298.     free( p_array->pp_elems );
  299.     memset( p_array, 0, sizeof(vlc_array_t) );
  300. }
  301.  
  302. static inline vlc_array_t * vlc_array_new( void )
  303. {
  304.     vlc_array_t * ret = (vlc_array_t *)malloc( sizeof(vlc_array_t) );
  305.     if( ret ) vlc_array_init( ret );
  306.     return ret;
  307. }
  308.  
  309. static inline void vlc_array_destroy( vlc_array_t * p_array )
  310. {
  311.     if( !p_array )
  312.         return;
  313.     vlc_array_clear( p_array );
  314.     free( p_array );
  315. }
  316.  
  317.  
  318. /* Read */
  319. static inline int
  320. vlc_array_count( vlc_array_t * p_array )
  321. {
  322.     return p_array->i_count;
  323. }
  324.  
  325. static inline void *
  326. vlc_array_item_at_index( vlc_array_t * p_array, int i_index )
  327. {
  328.     return p_array->pp_elems[i_index];
  329. }
  330.  
  331. static inline int
  332. vlc_array_index_of_item( vlc_array_t * p_array, void * item )
  333. {
  334.     int i;
  335.     for( i = 0; i < p_array->i_count; i++)
  336.     {
  337.         if( p_array->pp_elems[i] == item )
  338.             return i;
  339.     }
  340.     return -1;
  341. }
  342.  
  343. /* Write */
  344. static inline void
  345. vlc_array_insert( vlc_array_t * p_array, void * p_elem, int i_index )
  346. {
  347.     TAB_INSERT_CAST( (void **), p_array->i_count, p_array->pp_elems, p_elem, i_index );
  348. }
  349.  
  350. static inline void
  351. vlc_array_append( vlc_array_t * p_array, void * p_elem )
  352. {
  353.     vlc_array_insert( p_array, p_elem, p_array->i_count );
  354. }
  355.  
  356. static inline void
  357. vlc_array_remove( vlc_array_t * p_array, int i_index )
  358. {
  359.     if( i_index >= 0 )
  360.     {
  361.         if( p_array->i_count > 1 )
  362.         {
  363.             memmove( p_array->pp_elems + i_index,
  364.                      p_array->pp_elems + i_index+1,
  365.                      ( p_array->i_count - i_index - 1 ) * sizeof( void* ) );
  366.         }
  367.         p_array->i_count--;
  368.         if( p_array->i_count == 0 )
  369.         {
  370.             free( p_array->pp_elems );
  371.             p_array->pp_elems = NULL;
  372.         }
  373.     }
  374. }
  375.  
  376.  
  377. /************************************************************************
  378.  * Dictionaries
  379.  ************************************************************************/
  380.  
  381. /* This function is not intended to be crypto-secure, we only want it to be
  382.  * fast and not suck too much. This one is pretty fast and did 0 collisions
  383.  * in wenglish's dictionary.
  384.  */
  385. static inline uint64_t DictHash( const char *psz_string, int hashsize )
  386. {
  387.     uint64_t i_hash = 0;
  388.     if( psz_string )
  389.     {
  390.         while( *psz_string )
  391.         {
  392.             i_hash += *psz_string++;
  393.             i_hash += i_hash << 10;
  394.             i_hash ^= i_hash >> 8;
  395.         }
  396.     }
  397.     return i_hash % hashsize;
  398. }
  399.  
  400. struct vlc_dictionary_entry_t
  401. {
  402.     char *   psz_key;
  403.     void *   p_value;
  404.     struct vlc_dictionary_entry_t * p_next;
  405. };
  406.  
  407. typedef struct vlc_dictionary_t
  408. {
  409.     int i_size;
  410.     struct vlc_dictionary_entry_t ** p_entries;
  411. } vlc_dictionary_t;
  412.  
  413. static void * const kVLCDictionaryNotFound = NULL;
  414.  
  415. static inline void vlc_dictionary_init( vlc_dictionary_t * p_dict, int i_size )
  416. {
  417.     if( i_size > 0 )
  418.     {
  419.         p_dict->p_entries = (struct vlc_dictionary_entry_t **)malloc(sizeof(struct vlc_dictionary_entry_t *) * i_size);
  420.         memset( p_dict->p_entries, 0, sizeof(struct vlc_dictionary_entry_t *) * i_size );
  421.     }
  422.     else
  423.         p_dict->p_entries = NULL;
  424.     p_dict->i_size = i_size;
  425. }
  426.  
  427. static inline void vlc_dictionary_clear( vlc_dictionary_t * p_dict )
  428. {
  429.     int i;
  430.     struct vlc_dictionary_entry_t * p_current, * p_next;
  431.     if( p_dict->p_entries )
  432.     {
  433.         for( i = 0; i < p_dict->i_size; i++ )
  434.         {
  435.             p_current = p_dict->p_entries[i];
  436.             while( p_current )
  437.             {
  438.                 p_next = p_current->p_next;
  439.                 free( p_current->psz_key );
  440.                 free( p_current );
  441.                 p_current = p_next;
  442.             }
  443.         }
  444.         free( p_dict->p_entries );
  445.         p_dict->p_entries = NULL;
  446.     }
  447.     p_dict->i_size = 0;
  448. }
  449.  
  450.  
  451.  
  452. static inline void *
  453. vlc_dictionary_value_for_key( const vlc_dictionary_t * p_dict, const char * psz_key )
  454. {
  455.     if( !p_dict->p_entries )
  456.         return kVLCDictionaryNotFound;
  457.  
  458.     int i_pos = DictHash( psz_key, p_dict->i_size );
  459.     struct vlc_dictionary_entry_t * p_entry = p_dict->p_entries[i_pos];
  460.  
  461.     if( !p_entry )
  462.         return kVLCDictionaryNotFound;
  463.  
  464.     /* Make sure we return the right item. (Hash collision) */
  465.     do {
  466.         if( !strcmp( psz_key, p_entry->psz_key ) )
  467.             return p_entry->p_value;
  468.         p_entry = p_entry->p_next;
  469.     } while( p_entry );
  470.  
  471.     return kVLCDictionaryNotFound;
  472. }
  473.  
  474. static inline int
  475. vlc_dictionary_keys_count( const vlc_dictionary_t * p_dict )
  476. {
  477.     struct vlc_dictionary_entry_t * p_entry;
  478.     int i, count = 0;
  479.  
  480.     if( !p_dict->p_entries )
  481.         return 0;
  482.  
  483.     for( i = 0; i < p_dict->i_size; i++ )
  484.     {
  485.         for( p_entry = p_dict->p_entries[i]; p_entry; p_entry = p_entry->p_next ) count++;
  486.     }
  487.     return count;
  488. }
  489.  
  490. static inline char **
  491. vlc_dictionary_all_keys( const vlc_dictionary_t * p_dict )
  492. {
  493.     struct vlc_dictionary_entry_t * p_entry;
  494.     char ** ppsz_ret;
  495.     int i, count = vlc_dictionary_keys_count( p_dict );
  496.  
  497.     ppsz_ret = (char**)malloc(sizeof(char *) * (count + 1));
  498.  
  499.     count = 0;
  500.     for( i = 0; i < p_dict->i_size; i++ )
  501.     {
  502.         for( p_entry = p_dict->p_entries[i]; p_entry; p_entry = p_entry->p_next )
  503.             ppsz_ret[count++] = strdup( p_entry->psz_key );
  504.     }
  505.     ppsz_ret[count] = NULL;
  506.     return ppsz_ret;
  507. }
  508.  
  509. static inline void
  510. __vlc_dictionary_insert( vlc_dictionary_t * p_dict, const char * psz_key,
  511.                          void * p_value, bool rebuild )
  512. {
  513.     if( !p_dict->p_entries )
  514.         vlc_dictionary_init( p_dict, 1 );
  515.  
  516.     int i_pos = DictHash( psz_key, p_dict->i_size );
  517.     struct vlc_dictionary_entry_t * p_entry;
  518.  
  519.     p_entry = (struct vlc_dictionary_entry_t *)malloc(sizeof(struct vlc_dictionary_entry_t));
  520.     p_entry->psz_key = strdup( psz_key );
  521.     p_entry->p_value = p_value;
  522.     p_entry->p_next = p_dict->p_entries[i_pos];
  523.     p_dict->p_entries[i_pos] = p_entry;
  524.     if( rebuild )
  525.     {
  526.         /* Count how many items there was */
  527.         int count;
  528.         for( count = 1; p_entry->p_next; count++ ) p_entry = p_entry->p_next;
  529.         if( count > 3 ) /* XXX: this need tuning */
  530.         {
  531.             /* Here it starts to be not good, rebuild a bigger dictionary */
  532.             struct vlc_dictionary_t new_dict;
  533.             int i_new_size = ( (p_dict->i_size+2) * 3) / 2; /* XXX: this need tuning */
  534.             int i;
  535.             vlc_dictionary_init( &new_dict, i_new_size );
  536.             for( i = 0; i < p_dict->i_size; i++ )
  537.             {
  538.                 p_entry = p_dict->p_entries[i];
  539.                 while( p_entry )
  540.                 {
  541.                     __vlc_dictionary_insert( &new_dict, p_entry->psz_key,
  542.                                              p_entry->p_value,
  543.                                              0 /* To avoid multiple rebuild loop */);
  544.                     p_entry = p_entry->p_next;
  545.                 }
  546.             }
  547.  
  548.             vlc_dictionary_clear( p_dict );
  549.             p_dict->i_size = new_dict.i_size;
  550.             p_dict->p_entries = new_dict.p_entries;
  551.         }
  552.     }
  553. }
  554.  
  555. static inline void
  556. vlc_dictionary_insert( vlc_dictionary_t * p_dict, const char * psz_key, void * p_value )
  557. {
  558.     __vlc_dictionary_insert( p_dict, psz_key, p_value, 1 );
  559. }
  560.  
  561. static inline void
  562. vlc_dictionary_remove_value_for_key( const vlc_dictionary_t * p_dict, const char * psz_key )
  563. {
  564.     if( !p_dict->p_entries )
  565.         return;
  566.  
  567.     int i_pos = DictHash( psz_key, p_dict->i_size );
  568.     struct vlc_dictionary_entry_t * p_entry = p_dict->p_entries[i_pos];
  569.     struct vlc_dictionary_entry_t * p_prev;
  570.  
  571.     if( !p_entry )
  572.         return; /* Not found, nothing to do */
  573.  
  574.     /* Hash collision */
  575.     p_prev = NULL;
  576.     do {
  577.         if( !strcmp( psz_key, p_entry->psz_key ) )
  578.         {
  579.             if( !p_prev )
  580.                 p_dict->p_entries[i_pos] = p_entry->p_next;
  581.             else
  582.                 p_prev->p_next = p_entry->p_next;
  583.             free( p_entry->psz_key );
  584.             free( p_entry );
  585.             return;
  586.         }
  587.         p_prev = p_entry;
  588.         p_entry = p_entry->p_next;
  589.     } while( p_entry );
  590.  
  591.     /* No key was found */
  592. }
  593.  
  594. #endif
  595.