2005-10-16 18:33:22 +04:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2011-03-10 15:48:40 +03:00
* Copyright ( C ) 2004 - 2011 Red Hat , Inc . All rights reserved .
2005-10-16 18:33:22 +04:00
*
* This file is part of the device - mapper userspace tools .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 20:26:07 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2005-10-16 18:33:22 +04:00
*
2007-08-21 20:26:07 +04:00
* You should have received a copy of the GNU Lesser General Public License
2005-10-16 18:33:22 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2008-11-03 21:59:59 +03:00
# include "dmlib.h"
2005-10-16 18:33:22 +04:00
2005-10-17 02:57:20 +04:00
struct dm_hash_node {
struct dm_hash_node * next ;
2005-10-16 18:33:22 +04:00
void * data ;
2015-11-14 01:54:22 +03:00
unsigned data_len ;
2006-01-04 19:07:27 +03:00
unsigned keylen ;
2005-10-16 18:33:22 +04:00
char key [ 0 ] ;
} ;
2005-10-17 02:57:20 +04:00
struct dm_hash_table {
2006-01-04 19:07:27 +03:00
unsigned num_nodes ;
unsigned num_slots ;
2005-10-17 02:57:20 +04:00
struct dm_hash_node * * slots ;
2005-10-16 18:33:22 +04:00
} ;
/* Permutation of the Integers 0 through 255 */
static unsigned char _nums [ ] = {
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 ,
144 ,
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 ,
221 ,
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 ,
194 ,
193 , 239 , 101 , 242 , 5 , 171 , 126 , 11 , 74 , 59 , 137 , 228 , 108 , 191 , 232 ,
139 ,
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 ,
43 ,
249 , 236 , 45 , 244 , 111 , 182 , 153 , 136 , 129 , 90 , 217 , 202 , 19 , 165 , 231 ,
71 ,
230 , 142 , 96 , 227 , 62 , 179 , 246 , 114 , 162 , 53 , 160 , 215 , 205 , 180 , 47 ,
109 ,
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 ,
209
} ;
2006-01-04 19:07:27 +03:00
static struct dm_hash_node * _create_node ( const char * str , unsigned len )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
struct dm_hash_node * n = dm_malloc ( sizeof ( * n ) + len ) ;
2005-10-16 18:33:22 +04:00
if ( n ) {
memcpy ( n - > key , str , len ) ;
n - > keylen = len ;
}
return n ;
}
2007-04-27 18:52:41 +04:00
static unsigned long _hash ( const char * str , unsigned len )
2005-10-16 18:33:22 +04:00
{
2006-01-04 19:07:27 +03:00
unsigned long h = 0 , g ;
unsigned i ;
2005-10-16 18:33:22 +04:00
for ( i = 0 ; i < len ; i + + ) {
h < < = 4 ;
2007-04-27 18:52:41 +04:00
h + = _nums [ ( unsigned char ) * str + + ] ;
2005-10-16 18:33:22 +04:00
g = h & ( ( unsigned long ) 0xf < < 16u ) ;
if ( g ) {
h ^ = g > > 16u ;
h ^ = g > > 5u ;
}
}
return h ;
}
2005-10-17 02:57:20 +04:00
struct dm_hash_table * dm_hash_create ( unsigned size_hint )
2005-10-16 18:33:22 +04:00
{
size_t len ;
unsigned new_size = 16u ;
2010-10-01 01:06:50 +04:00
struct dm_hash_table * hc = dm_zalloc ( sizeof ( * hc ) ) ;
2005-10-16 18:33:22 +04:00
2010-10-01 01:06:50 +04:00
if ( ! hc )
return_0 ;
2005-10-16 18:33:22 +04:00
/* round size hint up to a power of two */
while ( new_size < size_hint )
new_size = new_size < < 1 ;
hc - > num_slots = new_size ;
len = sizeof ( * ( hc - > slots ) ) * new_size ;
2005-10-17 02:57:20 +04:00
if ( ! ( hc - > slots = dm_malloc ( len ) ) ) {
2005-10-16 18:33:22 +04:00
stack ;
goto bad ;
}
memset ( hc - > slots , 0 , len ) ;
return hc ;
bad :
2005-10-17 02:57:20 +04:00
dm_free ( hc - > slots ) ;
dm_free ( hc ) ;
2005-10-16 18:33:22 +04:00
return 0 ;
}
2005-10-17 02:57:20 +04:00
static void _free_nodes ( struct dm_hash_table * t )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
struct dm_hash_node * c , * n ;
2006-01-04 19:07:27 +03:00
unsigned i ;
2005-10-16 18:33:22 +04:00
for ( i = 0 ; i < t - > num_slots ; i + + )
for ( c = t - > slots [ i ] ; c ; c = n ) {
n = c - > next ;
2005-10-17 02:57:20 +04:00
dm_free ( c ) ;
2005-10-16 18:33:22 +04:00
}
}
2005-10-17 02:57:20 +04:00
void dm_hash_destroy ( struct dm_hash_table * t )
2005-10-16 18:33:22 +04:00
{
_free_nodes ( t ) ;
2005-10-17 02:57:20 +04:00
dm_free ( t - > slots ) ;
dm_free ( t ) ;
2005-10-16 18:33:22 +04:00
}
2011-03-10 15:48:40 +03:00
static struct dm_hash_node * * _find ( struct dm_hash_table * t , const void * key ,
2006-01-04 19:07:27 +03:00
uint32_t len )
2005-10-16 18:33:22 +04:00
{
unsigned h = _hash ( key , len ) & ( t - > num_slots - 1 ) ;
2005-10-17 02:57:20 +04:00
struct dm_hash_node * * c ;
2005-10-16 18:33:22 +04:00
2009-11-03 03:45:35 +03:00
for ( c = & t - > slots [ h ] ; * c ; c = & ( ( * c ) - > next ) ) {
if ( ( * c ) - > keylen ! = len )
continue ;
2005-10-16 18:33:22 +04:00
if ( ! memcmp ( key , ( * c ) - > key , len ) )
break ;
2009-11-03 03:45:35 +03:00
}
2005-10-16 18:33:22 +04:00
return c ;
}
2011-03-10 15:48:40 +03:00
void * dm_hash_lookup_binary ( struct dm_hash_table * t , const void * key ,
uint32_t len )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
struct dm_hash_node * * c = _find ( t , key , len ) ;
2006-01-04 19:07:27 +03:00
2005-10-16 18:33:22 +04:00
return * c ? ( * c ) - > data : 0 ;
}
2011-03-10 15:48:40 +03:00
int dm_hash_insert_binary ( struct dm_hash_table * t , const void * key ,
2006-01-04 19:07:27 +03:00
uint32_t len , void * data )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
struct dm_hash_node * * c = _find ( t , key , len ) ;
2005-10-16 18:33:22 +04:00
if ( * c )
( * c ) - > data = data ;
else {
2005-10-17 02:57:20 +04:00
struct dm_hash_node * n = _create_node ( key , len ) ;
2005-10-16 18:33:22 +04:00
if ( ! n )
return 0 ;
n - > data = data ;
n - > next = 0 ;
* c = n ;
t - > num_nodes + + ;
}
return 1 ;
}
2011-03-10 15:48:40 +03:00
void dm_hash_remove_binary ( struct dm_hash_table * t , const void * key ,
2005-10-16 18:33:22 +04:00
uint32_t len )
{
2005-10-17 02:57:20 +04:00
struct dm_hash_node * * c = _find ( t , key , len ) ;
2005-10-16 18:33:22 +04:00
if ( * c ) {
2005-10-17 02:57:20 +04:00
struct dm_hash_node * old = * c ;
2005-10-16 18:33:22 +04:00
* c = ( * c ) - > next ;
2005-10-17 02:57:20 +04:00
dm_free ( old ) ;
2005-10-16 18:33:22 +04:00
t - > num_nodes - - ;
}
}
2005-10-17 02:57:20 +04:00
void * dm_hash_lookup ( struct dm_hash_table * t , const char * key )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
return dm_hash_lookup_binary ( t , key , strlen ( key ) + 1 ) ;
2005-10-16 18:33:22 +04:00
}
2005-10-17 02:57:20 +04:00
int dm_hash_insert ( struct dm_hash_table * t , const char * key , void * data )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
return dm_hash_insert_binary ( t , key , strlen ( key ) + 1 , data ) ;
2005-10-16 18:33:22 +04:00
}
2005-10-17 02:57:20 +04:00
void dm_hash_remove ( struct dm_hash_table * t , const char * key )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
dm_hash_remove_binary ( t , key , strlen ( key ) + 1 ) ;
2005-10-16 18:33:22 +04:00
}
2015-11-12 19:05:56 +03:00
static struct dm_hash_node * * _find_str_withval ( struct dm_hash_table * t ,
const void * key , const void * val ,
uint32_t len , uint32_t val_len )
{
struct dm_hash_node * * c ;
unsigned h ;
h = _hash ( key , len ) & ( t - > num_slots - 1 ) ;
for ( c = & t - > slots [ h ] ; * c ; c = & ( ( * c ) - > next ) ) {
if ( ( * c ) - > keylen ! = len )
continue ;
if ( ! memcmp ( key , ( * c ) - > key , len ) & & ( * c ) - > data ) {
2015-11-14 01:54:22 +03:00
if ( ( ( * c ) - > data_len = = val_len ) & &
! memcmp ( val , ( * c ) - > data , val_len ) )
2015-11-12 19:05:56 +03:00
return c ;
}
}
return NULL ;
}
2015-11-14 01:54:22 +03:00
int dm_hash_insert_multival ( struct dm_hash_table * t , const char * key ,
const void * val , uint32_t val_len )
2015-11-12 19:05:56 +03:00
{
struct dm_hash_node * n ;
struct dm_hash_node * first ;
int len = strlen ( key ) + 1 ;
unsigned h ;
n = _create_node ( key , len ) ;
if ( ! n )
return 0 ;
n - > data = ( void * ) val ;
2015-11-14 01:54:22 +03:00
n - > data_len = val_len ;
2015-11-12 19:05:56 +03:00
h = _hash ( key , len ) & ( t - > num_slots - 1 ) ;
first = t - > slots [ h ] ;
if ( first )
n - > next = first ;
else
n - > next = 0 ;
t - > slots [ h ] = n ;
t - > num_nodes + + ;
return 1 ;
}
/*
* Look through multiple entries with the same key for one that has a
* matching val and return that . If none have maching val , return NULL .
*/
2015-11-14 01:54:22 +03:00
void * dm_hash_lookup_withval ( struct dm_hash_table * t , const char * key ,
const void * val , uint32_t val_len )
2015-11-12 19:05:56 +03:00
{
struct dm_hash_node * * c ;
2015-11-14 01:54:22 +03:00
c = _find_str_withval ( t , key , val , strlen ( key ) + 1 , val_len ) ;
2015-11-12 19:05:56 +03:00
return ( c & & * c ) ? ( * c ) - > data : 0 ;
}
/*
* Look through multiple entries with the same key for one that has a
* matching val and remove that .
*/
2015-11-14 01:54:22 +03:00
void dm_hash_remove_withval ( struct dm_hash_table * t , const char * key ,
const void * val , uint32_t val_len )
2015-11-12 19:05:56 +03:00
{
struct dm_hash_node * * c ;
2015-11-14 01:54:22 +03:00
c = _find_str_withval ( t , key , val , strlen ( key ) + 1 , val_len ) ;
2015-11-12 19:05:56 +03:00
if ( c & & * c ) {
struct dm_hash_node * old = * c ;
* c = ( * c ) - > next ;
dm_free ( old ) ;
t - > num_nodes - - ;
}
}
/*
* Look for multiple entries with the same key .
*
* If no entries have key , return NULL .
*
* If one entry has the key , the function returns the val ,
* and sets val2 to NULL .
*
* If two entries have the key , the function returns the val
* from the first entry , and the val2 arg is set to the val
* from the second entry .
*
* If more than two entries have the key , the function looks
* at only the first two .
*/
2015-11-14 01:54:22 +03:00
void * dm_hash_lookup_multival ( struct dm_hash_table * t , const char * key , const void * * val2 )
2015-11-12 19:05:56 +03:00
{
struct dm_hash_node * * c ;
struct dm_hash_node * * c1 = NULL ;
struct dm_hash_node * * c2 = NULL ;
uint32_t len = strlen ( key ) + 1 ;
unsigned h ;
h = _hash ( key , len ) & ( t - > num_slots - 1 ) ;
for ( c = & t - > slots [ h ] ; * c ; c = & ( ( * c ) - > next ) ) {
if ( ( * c ) - > keylen ! = len )
continue ;
if ( ! memcmp ( key , ( * c ) - > key , len ) ) {
if ( ! c1 ) {
c1 = c ;
} else if ( ! c2 ) {
c2 = c ;
break ;
}
}
}
if ( ! c2 )
* val2 = NULL ;
else
* val2 = ( * c2 ) - > data ;
if ( ! c1 )
return NULL ;
else
return * c1 ? ( * c1 ) - > data : 0 ;
}
2005-10-17 02:57:20 +04:00
unsigned dm_hash_get_num_entries ( struct dm_hash_table * t )
2005-10-16 18:33:22 +04:00
{
return t - > num_nodes ;
}
2005-10-17 02:57:20 +04:00
void dm_hash_iter ( struct dm_hash_table * t , dm_hash_iterate_fn f )
2005-10-16 18:33:22 +04:00
{
2008-05-21 20:14:46 +04:00
struct dm_hash_node * c , * n ;
2006-01-04 19:07:27 +03:00
unsigned i ;
2005-10-16 18:33:22 +04:00
for ( i = 0 ; i < t - > num_slots ; i + + )
2008-05-21 20:14:46 +04:00
for ( c = t - > slots [ i ] ; c ; c = n ) {
n = c - > next ;
2005-10-16 18:33:22 +04:00
f ( c - > data ) ;
2008-05-21 20:14:46 +04:00
}
2005-10-16 18:33:22 +04:00
}
2005-10-17 02:57:20 +04:00
void dm_hash_wipe ( struct dm_hash_table * t )
2005-10-16 18:33:22 +04:00
{
_free_nodes ( t ) ;
2005-10-17 02:57:20 +04:00
memset ( t - > slots , 0 , sizeof ( struct dm_hash_node * ) * t - > num_slots ) ;
2006-01-04 19:07:27 +03:00
t - > num_nodes = 0u ;
2005-10-16 18:33:22 +04:00
}
2010-07-09 19:34:40 +04:00
char * dm_hash_get_key ( struct dm_hash_table * t __attribute__ ( ( unused ) ) ,
2007-01-22 18:03:57 +03:00
struct dm_hash_node * n )
2005-10-16 18:33:22 +04:00
{
return n - > key ;
}
2010-07-09 19:34:40 +04:00
void * dm_hash_get_data ( struct dm_hash_table * t __attribute__ ( ( unused ) ) ,
2007-01-22 18:03:57 +03:00
struct dm_hash_node * n )
2005-10-16 18:33:22 +04:00
{
return n - > data ;
}
2005-10-17 02:57:20 +04:00
static struct dm_hash_node * _next_slot ( struct dm_hash_table * t , unsigned s )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
struct dm_hash_node * c = NULL ;
2006-01-04 19:07:27 +03:00
unsigned i ;
2005-10-16 18:33:22 +04:00
for ( i = s ; i < t - > num_slots & & ! c ; i + + )
c = t - > slots [ i ] ;
return c ;
}
2005-10-17 02:57:20 +04:00
struct dm_hash_node * dm_hash_get_first ( struct dm_hash_table * t )
2005-10-16 18:33:22 +04:00
{
return _next_slot ( t , 0 ) ;
}
2005-10-17 02:57:20 +04:00
struct dm_hash_node * dm_hash_get_next ( struct dm_hash_table * t , struct dm_hash_node * n )
2005-10-16 18:33:22 +04:00
{
unsigned h = _hash ( n - > key , n - > keylen ) & ( t - > num_slots - 1 ) ;
2006-01-04 19:07:27 +03:00
2005-10-16 18:33:22 +04:00
return n - > next ? n - > next : _next_slot ( t , h + 1 ) ;
}