@@ -27,6 +27,8 @@ struct st_table_entry {
2727
2828#define ST_DEFAULT_MAX_DENSITY 5
2929#define ST_DEFAULT_INIT_TABLE_SIZE 11
30+ #define ST_DEFAULT_SECOND_TABLE_SIZE 19
31+ #define MAX_PACKED_NUMHASH (ST_DEFAULT_INIT_TABLE_SIZE/2)
3032
3133 /*
3234 * DEFAULT_MAX_DENSITY is the default for the largest we allow the
@@ -76,6 +78,24 @@ static void rehash(st_table *);
7678#define do_hash (key ,table ) (unsigned int)(st_index_t)(*(table)->type->hash)((key))
7779#define do_hash_bin (key ,table ) (do_hash((key), (table))%(table)->num_bins)
7880
81+ /* preparation for possible packing improvements */
82+ #define PKEY_POS (i , num_bins ) ((i)*2)
83+ #define PVAL_POS (i , num_bins ) ((i)*2+1)
84+ #define PKEY (table , i ) (st_data_t)(table)->bins[PKEY_POS(i, (table)->num_bins)]
85+ #define PVAL (table , i ) (st_data_t)(table)->bins[PVAL_POS(i, (table)->num_bins)]
86+ #define PKEY_SET (table , i , v ) do{ (table)->bins[PKEY_POS(i, (table)->num_bins)] = (st_table_entry *)(v); } while(0)
87+ #define PVAL_SET (table , i , v ) do{ (table)->bins[PVAL_POS(i, (table)->num_bins)] = (st_table_entry *)(v); } while(0)
88+ /* this function depends much on packed layout, so that it placed here */
89+ static inline void
90+ remove_packed_entry (st_table * table , st_index_t i )
91+ {
92+ table -> num_entries -- ;
93+ if (i < table -> num_entries ) {
94+ memmove (table -> bins + 2 * i , table -> bins + 2 * (i + 1 ),
95+ sizeof (st_table_entry * ) * 2 * (table -> num_entries - i ));
96+ }
97+ }
98+
7999/*
80100 * MINSIZE is the minimum size of a dictionary.
81101 */
@@ -87,7 +107,7 @@ Table of prime numbers 2^n+a, 2<=n<=30.
87107*/
88108static const unsigned int primes [] = {
89109 ST_DEFAULT_INIT_TABLE_SIZE ,
90- 16 + 3 ,
110+ ST_DEFAULT_SECOND_TABLE_SIZE ,
91111 32 + 5 ,
92112 64 + 3 ,
93113 128 + 3 ,
@@ -162,8 +182,6 @@ stat_col(void)
162182}
163183#endif
164184
165- #define MAX_PACKED_NUMHASH (ST_DEFAULT_INIT_TABLE_SIZE/2)
166-
167185st_table *
168186st_init_table_with_size (const struct st_hash_type * type , st_index_t size )
169187{
@@ -326,7 +344,7 @@ static inline st_index_t
326344find_packed_index (st_table * table , st_data_t key )
327345{
328346 st_index_t i = 0 ;
329- while (i < table -> num_entries && ( st_data_t ) table -> bins [ i * 2 ] != key ) i ++ ;
347+ while (i < table -> num_entries && PKEY ( table , i ) != key ) i ++ ;
330348 return i ;
331349}
332350
@@ -341,7 +359,7 @@ st_lookup(st_table *table, register st_data_t key, st_data_t *value)
341359 if (table -> entries_packed ) {
342360 st_index_t i = find_packed_index (table , key );
343361 if (i < table -> num_entries ) {
344- if (value != 0 ) * value = ( st_data_t ) table -> bins [ i * 2 + 1 ] ;
362+ if (value != 0 ) * value = PVAL ( table , i ) ;
345363 return 1 ;
346364 }
347365 return 0 ;
@@ -368,7 +386,7 @@ st_get_key(st_table *table, register st_data_t key, st_data_t *result)
368386 if (table -> entries_packed ) {
369387 st_index_t i = find_packed_index (table , key );
370388 if (i < table -> num_entries ) {
371- if (result != 0 ) * result = ( st_data_t ) table -> bins [ i * 2 ] ;
389+ if (result != 0 ) * result = PKEY ( table , i ) ;
372390 return 1 ;
373391 }
374392 return 0 ;
@@ -389,10 +407,6 @@ st_get_key(st_table *table, register st_data_t key, st_data_t *result)
389407#undef collision_check
390408#define collision_check 1
391409
392- #define MORE_PACKABLE_P (table ) \
393- ((st_index_t)((table)->num_entries+1) * 2 <= (table)->num_bins && \
394- (table)->num_entries+1 <= MAX_PACKED_NUMHASH)
395-
396410static void
397411add_direct (st_table * table , st_data_t key , st_data_t value ,
398412 st_index_t hash_val , st_index_t bin_pos )
@@ -426,16 +440,18 @@ static void
426440unpack_entries (register st_table * table )
427441{
428442 st_index_t i ;
429- struct st_table_entry * packed_bins [MAX_PACKED_NUMHASH * 2 ];
443+ struct st_table_entry * packed_bins [ST_DEFAULT_INIT_TABLE_SIZE ];
430444 st_table tmp_table = * table ;
431445
432- memcpy (packed_bins , table -> bins , sizeof (struct st_table_entry * ) * table -> num_entries * 2 );
446+ memcpy (packed_bins , table -> bins , sizeof (st_table_entry * ) * ST_DEFAULT_INIT_TABLE_SIZE );
433447 table -> bins = packed_bins ;
434448 tmp_table .entries_packed = 0 ;
435449 tmp_table .num_entries = 0 ;
436450 memset (tmp_table .bins , 0 , sizeof (struct st_table_entry * ) * tmp_table .num_bins );
437451 for (i = 0 ; i < table -> num_entries ; i ++ ) {
438- st_insert (& tmp_table , (st_data_t )packed_bins [i * 2 ], (st_data_t )packed_bins [i * 2 + 1 ]);
452+ st_index_t hash_val = PKEY (table , i ); /* do_hash(PKEY(table, i), &tmp_table); */
453+ add_direct (& tmp_table , PKEY (table , i ), PVAL (table , i ),
454+ hash_val , hash_val % tmp_table .num_bins );
439455 }
440456 * table = tmp_table ;
441457}
@@ -444,10 +460,10 @@ static int
444460add_packed_direct (st_table * table , st_data_t key , st_data_t value )
445461{
446462 int res = 1 ;
447- if (MORE_PACKABLE_P ( table ) ) {
463+ if (table -> num_entries < MAX_PACKED_NUMHASH ) {
448464 st_index_t i = table -> num_entries ++ ;
449- table -> bins [ i * 2 ] = ( struct st_table_entry * ) key ;
450- table -> bins [ i * 2 + 1 ] = ( struct st_table_entry * ) value ;
465+ PKEY_SET ( table , i , key ) ;
466+ PVAL_SET ( table , i , value ) ;
451467 }
452468 else {
453469 unpack_entries (table );
@@ -466,7 +482,7 @@ st_insert(register st_table *table, register st_data_t key, st_data_t value)
466482 if (table -> entries_packed ) {
467483 st_index_t i = find_packed_index (table , key );
468484 if (i < table -> num_entries ) {
469- table -> bins [ i * 2 + 1 ] = ( struct st_table_entry * ) value ;
485+ PVAL_SET ( table , i , value ) ;
470486 return 1 ;
471487 }
472488 if (add_packed_direct (table , key , value )) {
@@ -498,7 +514,7 @@ st_insert2(register st_table *table, register st_data_t key, st_data_t value,
498514 if (table -> entries_packed ) {
499515 st_index_t i = find_packed_index (table , key );
500516 if (i < table -> num_entries ) {
501- table -> bins [ i * 2 + 1 ] = ( struct st_table_entry * ) value ;
517+ PVAL_SET ( table , i , value ) ;
502518 return 1 ;
503519 }
504520 if (add_packed_direct (table , key , value )) {
@@ -626,16 +642,6 @@ remove_entry(st_table *table, st_table_entry *ptr)
626642 table -> num_entries -- ;
627643}
628644
629- static inline void
630- remove_packed_entry (st_table * table , st_index_t pos )
631- {
632- table -> num_entries -- ;
633- if (pos < table -> num_entries ) {
634- memmove (& table -> bins [pos * 2 ], & table -> bins [(pos + 1 )* 2 ],
635- sizeof (struct st_table_entry * ) * 2 * (table -> num_entries - pos ));
636- }
637- }
638-
639645int
640646st_delete (register st_table * table , register st_data_t * key , st_data_t * value )
641647{
@@ -646,7 +652,7 @@ st_delete(register st_table *table, register st_data_t *key, st_data_t *value)
646652 if (table -> entries_packed ) {
647653 st_index_t i = find_packed_index (table , * key );
648654 if (i < table -> num_entries ) {
649- if (value != 0 ) * value = ( st_data_t ) table -> bins [ i * 2 + 1 ] ;
655+ if (value != 0 ) * value = PVAL ( table , i ) ;
650656 remove_packed_entry (table , i );
651657 return 1 ;
652658 }
@@ -680,8 +686,8 @@ st_delete_safe(register st_table *table, register st_data_t *key, st_data_t *val
680686 if (table -> entries_packed ) {
681687 st_index_t i = find_packed_index (table , * key );
682688 if (i < table -> num_entries ) {
683- if (value != 0 ) * value = ( st_data_t ) table -> bins [ i * 2 + 1 ] ;
684- table -> bins [ i * 2 ] = ( void * ) never ;
689+ if (value != 0 ) * value = PVAL ( table , i ) ;
690+ PKEY_SET ( table , i , never ) ;
685691 return 1 ;
686692 }
687693 if (value != 0 ) * value = 0 ;
@@ -713,13 +719,13 @@ st_cleanup_safe(st_table *table, st_data_t never)
713719
714720 if (table -> entries_packed ) {
715721 st_index_t i = 0 , j = 0 ;
716- while (( st_data_t ) table -> bins [ i * 2 ] != never ) {
722+ while (PKEY ( table , i ) != never ) {
717723 if (i ++ == table -> num_entries ) return ;
718724 }
719725 for (j = i ; ++ i < table -> num_entries ;) {
720- if (( st_data_t ) table -> bins [ i * 2 ] == never ) continue ;
721- table -> bins [ j * 2 ] = table -> bins [ i * 2 ] ;
722- table -> bins [ j * 2 + 1 ] = table -> bins [ i * 2 + 1 ] ;
726+ if (PKEY ( table , i ) == never ) continue ;
727+ PKEY_SET ( table , j , PKEY ( table , i )) ;
728+ PVAL_SET ( table , j , PVAL ( table , i )) ;
723729 j ++ ;
724730 }
725731 table -> num_entries = j ;
@@ -751,10 +757,10 @@ st_update(st_table *table, st_data_t key, int (*func)(st_data_t key, st_data_t *
751757 if (table -> entries_packed ) {
752758 st_index_t i = find_packed_index (table , key );
753759 if (i < table -> num_entries ) {
754- value = ( st_data_t ) table -> bins [ i * 2 + 1 ] ;
760+ value = PVAL ( table , i ) ;
755761 switch ((* func )(key , & value , arg )) {
756762 case ST_CONTINUE :
757- table -> bins [ i * 2 + 1 ] = ( struct st_table_entry * ) value ;
763+ PVAL_SET ( table , i , value ) ;
758764 break ;
759765 case ST_DELETE :
760766 remove_packed_entry (table , i );
@@ -805,14 +811,14 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
805811 for (i = 0 ; i < table -> num_entries ; i ++ ) {
806812 st_index_t j ;
807813 st_data_t key , val ;
808- key = ( st_data_t ) table -> bins [ i * 2 ] ;
809- val = ( st_data_t ) table -> bins [ i * 2 + 1 ] ;
814+ key = PKEY ( table , i ) ;
815+ val = PVAL ( table , i ) ;
810816 retval = (* func )(key , val , arg );
811817 if (!table -> entries_packed ) goto unpacked ;
812818 switch (retval ) {
813819 case ST_CHECK : /* check if hash is modified during iteration */
814820 for (j = 0 ; j < table -> num_entries ; j ++ ) {
815- if (( st_data_t ) table -> bins [ j * 2 ] == key )
821+ if (PKEY ( table , j ) == key )
816822 break ;
817823 }
818824 if (j == table -> num_entries ) {
@@ -892,13 +898,13 @@ st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
892898 for (i = table -> num_entries - 1 ; 0 <= i ; i -- ) {
893899 int j ;
894900 st_data_t key , val ;
895- key = ( st_data_t ) table -> bins [ i * 2 ] ;
896- val = ( st_data_t ) table -> bins [ i * 2 + 1 ] ;
901+ key = PKEY ( table , i ) ;
902+ val = PVAL ( table , i ) ;
897903 retval = (* func )(key , val , arg );
898904 switch (retval ) {
899905 case ST_CHECK : /* check if hash is modified during iteration */
900906 for (j = 0 ; j < table -> num_entries ; j ++ ) {
901- if (( st_data_t ) table -> bins [ j * 2 ] == key )
907+ if (PKEY ( table , j ) == key )
902908 break ;
903909 }
904910 if (j == table -> num_entries ) {
0 commit comments