2001-09-28 17:08:44 +04:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 Red Hat , Inc . All rights reserved .
2001-09-28 17:08:44 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-09-28 17:08:44 +04:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2001-10-02 02:12:10 +04:00
# include "hash.h"
2001-09-28 17:08:44 +04:00
struct hash_node {
struct hash_node * next ;
void * data ;
char key [ 1 ] ;
} ;
struct hash_table {
int num_nodes ;
int num_slots ;
struct hash_node * * slots ;
} ;
/* Permutation of the Integers 0 through 255 */
static unsigned char _nums [ ] = {
2002-04-24 22:20:51 +04:00
1 , 14 , 110 , 25 , 97 , 174 , 132 , 119 , 138 , 170 , 125 , 118 , 27 , 233 , 140 , 51 ,
87 , 197 , 177 , 107 , 234 , 169 , 56 , 68 , 30 , 7 , 173 , 73 , 188 , 40 , 36 , 65 ,
49 , 213 , 104 , 190 , 57 , 211 , 148 , 223 , 48 , 115 , 15 , 2 , 67 , 186 , 210 , 28 ,
12 , 181 , 103 , 70 , 22 , 58 , 75 , 78 , 183 , 167 , 238 , 157 , 124 , 147 , 172 ,
2002-11-18 17:01:16 +03:00
144 ,
2002-04-24 22:20:51 +04:00
176 , 161 , 141 , 86 , 60 , 66 , 128 , 83 , 156 , 241 , 79 , 46 , 168 , 198 , 41 , 254 ,
178 , 85 , 253 , 237 , 250 , 154 , 133 , 88 , 35 , 206 , 95 , 116 , 252 , 192 , 54 ,
2002-11-18 17:01:16 +03:00
221 ,
2002-04-24 22:20:51 +04:00
102 , 218 , 255 , 240 , 82 , 106 , 158 , 201 , 61 , 3 , 89 , 9 , 42 , 155 , 159 , 93 ,
166 , 80 , 50 , 34 , 175 , 195 , 100 , 99 , 26 , 150 , 16 , 145 , 4 , 33 , 8 , 189 ,
121 , 64 , 77 , 72 , 208 , 245 , 130 , 122 , 143 , 55 , 105 , 134 , 29 , 164 , 185 ,
2002-11-18 17:01:16 +03:00
194 ,
2002-04-24 22:20:51 +04:00
193 , 239 , 101 , 242 , 5 , 171 , 126 , 11 , 74 , 59 , 137 , 228 , 108 , 191 , 232 ,
2002-11-18 17:01:16 +03:00
139 ,
2002-04-24 22:20:51 +04:00
6 , 24 , 81 , 20 , 127 , 17 , 91 , 92 , 251 , 151 , 225 , 207 , 21 , 98 , 113 , 112 ,
84 , 226 , 18 , 214 , 199 , 187 , 13 , 32 , 94 , 220 , 224 , 212 , 247 , 204 , 196 ,
2002-11-18 17:01:16 +03:00
43 ,
2002-04-24 22:20:51 +04:00
249 , 236 , 45 , 244 , 111 , 182 , 153 , 136 , 129 , 90 , 217 , 202 , 19 , 165 , 231 ,
2002-11-18 17:01:16 +03:00
71 ,
2002-04-24 22:20:51 +04:00
230 , 142 , 96 , 227 , 62 , 179 , 246 , 114 , 162 , 53 , 160 , 215 , 205 , 180 , 47 ,
2002-11-18 17:01:16 +03:00
109 ,
2002-04-24 22:20:51 +04:00
44 , 38 , 31 , 149 , 135 , 0 , 216 , 52 , 63 , 23 , 37 , 69 , 39 , 117 , 146 , 184 ,
163 , 200 , 222 , 235 , 248 , 243 , 219 , 10 , 152 , 131 , 123 , 229 , 203 , 76 , 120 ,
2002-11-18 17:01:16 +03:00
209
2001-09-28 17:08:44 +04:00
} ;
static struct hash_node * _create_node ( const char * str )
{
/* remember sizeof(n) includes an extra char from key[1],
so not adding 1 to the strlen as you would expect */
struct hash_node * n = dbg_malloc ( sizeof ( * n ) + strlen ( str ) ) ;
if ( n )
strcpy ( n - > key , str ) ;
return n ;
}
2003-01-10 22:14:01 +03:00
static unsigned _hash ( const char * str )
2001-09-28 17:08:44 +04:00
{
2002-12-20 02:25:55 +03:00
unsigned long h = 0 , g ;
2003-01-10 22:14:01 +03:00
while ( * str ) {
2001-09-28 17:08:44 +04:00
h < < = 4 ;
h + = _nums [ ( int ) * str + + ] ;
g = h & ( ( unsigned long ) 0xf < < 16u ) ;
if ( g ) {
h ^ = g > > 16u ;
h ^ = g > > 5u ;
}
}
return h ;
}
2001-10-08 14:20:25 +04:00
struct hash_table * hash_create ( unsigned size_hint )
2001-09-28 17:08:44 +04:00
{
size_t len ;
unsigned new_size = 16u ;
2001-10-04 14:13:07 +04:00
struct hash_table * hc = dbg_malloc ( sizeof ( * hc ) ) ;
2001-09-28 17:08:44 +04:00
if ( ! hc ) {
stack ;
return 0 ;
}
memset ( hc , 0 , sizeof ( * hc ) ) ;
/* round size hint up to a power of two */
while ( new_size < size_hint )
2002-04-24 22:20:51 +04:00
new_size = new_size < < 1 ;
2001-09-28 17:08:44 +04:00
hc - > num_slots = new_size ;
len = sizeof ( * ( hc - > slots ) ) * new_size ;
if ( ! ( hc - > slots = dbg_malloc ( len ) ) ) {
stack ;
goto bad ;
}
memset ( hc - > slots , 0 , len ) ;
2001-10-04 14:13:07 +04:00
return hc ;
2001-09-28 17:08:44 +04:00
2002-04-24 22:20:51 +04:00
bad :
2001-09-28 17:08:44 +04:00
dbg_free ( hc - > slots ) ;
dbg_free ( hc ) ;
return 0 ;
}
2001-10-25 12:31:43 +04:00
static void _free_nodes ( struct hash_table * t )
2001-09-28 17:08:44 +04:00
{
2001-10-04 14:13:07 +04:00
struct hash_node * c , * n ;
2001-09-28 17:08:44 +04:00
int i ;
for ( i = 0 ; i < t - > num_slots ; i + + )
for ( c = t - > slots [ i ] ; c ; c = n ) {
n = c - > next ;
dbg_free ( c ) ;
}
2001-10-25 12:31:43 +04:00
}
2001-09-28 17:08:44 +04:00
2001-10-25 12:31:43 +04:00
void hash_destroy ( struct hash_table * t )
{
_free_nodes ( t ) ;
2001-10-04 14:13:07 +04:00
dbg_free ( t - > slots ) ;
dbg_free ( t ) ;
2001-09-28 17:08:44 +04:00
}
2004-02-13 18:36:58 +03:00
static struct hash_node * * _find ( struct hash_table * t , const char * key )
2001-09-28 17:08:44 +04:00
{
2003-01-10 22:14:01 +03:00
unsigned h = _hash ( key ) & ( t - > num_slots - 1 ) ;
2001-09-28 17:08:44 +04:00
struct hash_node * * c ;
2002-04-24 22:20:51 +04:00
for ( c = & t - > slots [ h ] ; * c ; c = & ( ( * c ) - > next ) )
2003-01-10 22:14:01 +03:00
if ( ! strcmp ( key , ( * c ) - > key ) )
2001-09-28 17:08:44 +04:00
break ;
2001-10-04 14:13:07 +04:00
return c ;
2001-09-28 17:08:44 +04:00
}
2001-10-22 18:14:00 +04:00
void * hash_lookup ( struct hash_table * t , const char * key )
2001-09-28 17:08:44 +04:00
{
struct hash_node * * c = _find ( t , key ) ;
return * c ? ( * c ) - > data : 0 ;
}
int hash_insert ( struct hash_table * t , const char * key , void * data )
{
struct hash_node * * c = _find ( t , key ) ;
2002-04-24 22:20:51 +04:00
if ( * c )
2001-09-28 17:08:44 +04:00
( * c ) - > data = data ;
else {
struct hash_node * n = _create_node ( key ) ;
if ( ! n )
return 0 ;
n - > data = data ;
n - > next = 0 ;
* c = n ;
t - > num_nodes + + ;
}
return 1 ;
}
void hash_remove ( struct hash_table * t , const char * key )
{
struct hash_node * * c = _find ( t , key ) ;
if ( * c ) {
struct hash_node * old = * c ;
2001-10-04 14:13:07 +04:00
* c = ( * c ) - > next ;
dbg_free ( old ) ;
2001-09-28 17:08:44 +04:00
t - > num_nodes - - ;
}
}
unsigned hash_get_num_entries ( struct hash_table * t )
{
return t - > num_nodes ;
}
2002-02-25 14:52:58 +03:00
void hash_iter ( struct hash_table * t , iterate_fn f )
2001-09-28 17:08:44 +04:00
{
struct hash_node * c ;
int i ;
for ( i = 0 ; i < t - > num_slots ; i + + )
for ( c = t - > slots [ i ] ; c ; c = c - > next )
f ( c - > data ) ;
}
2001-10-24 21:53:50 +04:00
void hash_wipe ( struct hash_table * t )
{
2001-10-25 12:31:43 +04:00
_free_nodes ( t ) ;
memset ( t - > slots , 0 , sizeof ( struct hash_node * ) * t - > num_slots ) ;
t - > num_nodes = 0 ;
2001-10-24 21:53:50 +04:00
}
2001-10-22 18:14:00 +04:00
char * hash_get_key ( struct hash_table * t , struct hash_node * n )
{
return n - > key ;
}
2001-10-03 15:06:31 +04:00
void * hash_get_data ( struct hash_table * t , struct hash_node * n )
{
return n - > data ;
}
2002-12-20 02:25:55 +03:00
static struct hash_node * _next_slot ( struct hash_table * t , unsigned s )
2001-10-03 15:06:31 +04:00
{
2001-10-08 17:58:52 +04:00
struct hash_node * c = NULL ;
2001-10-03 15:06:31 +04:00
int i ;
for ( i = s ; i < t - > num_slots & & ! c ; i + + )
c = t - > slots [ i ] ;
return c ;
}
struct hash_node * hash_get_first ( struct hash_table * t )
{
return _next_slot ( t , 0 ) ;
}
struct hash_node * hash_get_next ( struct hash_table * t , struct hash_node * n )
{
2003-01-10 22:14:01 +03:00
unsigned h = _hash ( n - > key ) & ( t - > num_slots - 1 ) ;
2001-10-08 17:58:52 +04:00
return n - > next ? n - > next : _next_slot ( t , h + 1 ) ;
2001-10-03 15:06:31 +04:00
}