2005-04-17 02:20:36 +04:00
/*
* Implementation of the hash table type .
*
* Author : Stephen Smalley , < sds @ epoch . ncsc . mil >
*/
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/errno.h>
# include "hashtab.h"
struct hashtab * hashtab_create ( u32 ( * hash_value ) ( struct hashtab * h , void * key ) ,
int ( * keycmp ) ( struct hashtab * h , void * key1 , void * key2 ) ,
u32 size )
{
struct hashtab * p ;
u32 i ;
2005-10-31 01:59:21 +03:00
p = kzalloc ( sizeof ( * p ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( p = = NULL )
return p ;
p - > size = size ;
p - > nel = 0 ;
p - > hash_value = hash_value ;
p - > keycmp = keycmp ;
p - > htable = kmalloc ( sizeof ( * ( p - > htable ) ) * size , GFP_KERNEL ) ;
if ( p - > htable = = NULL ) {
kfree ( p ) ;
return NULL ;
}
for ( i = 0 ; i < size ; i + + )
p - > htable [ i ] = NULL ;
return p ;
}
int hashtab_insert ( struct hashtab * h , void * key , void * datum )
{
u32 hvalue ;
struct hashtab_node * prev , * cur , * newnode ;
if ( ! h | | h - > nel = = HASHTAB_MAX_NODES )
return - EINVAL ;
hvalue = h - > hash_value ( h , key ) ;
prev = NULL ;
cur = h - > htable [ hvalue ] ;
while ( cur & & h - > keycmp ( h , key , cur - > key ) > 0 ) {
prev = cur ;
cur = cur - > next ;
}
if ( cur & & ( h - > keycmp ( h , key , cur - > key ) = = 0 ) )
return - EEXIST ;
2005-10-31 01:59:21 +03:00
newnode = kzalloc ( sizeof ( * newnode ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( newnode = = NULL )
return - ENOMEM ;
newnode - > key = key ;
newnode - > datum = datum ;
if ( prev ) {
newnode - > next = prev - > next ;
prev - > next = newnode ;
} else {
newnode - > next = h - > htable [ hvalue ] ;
h - > htable [ hvalue ] = newnode ;
}
h - > nel + + ;
return 0 ;
}
void * hashtab_search ( struct hashtab * h , void * key )
{
u32 hvalue ;
struct hashtab_node * cur ;
if ( ! h )
return NULL ;
hvalue = h - > hash_value ( h , key ) ;
cur = h - > htable [ hvalue ] ;
while ( cur ! = NULL & & h - > keycmp ( h , key , cur - > key ) > 0 )
cur = cur - > next ;
if ( cur = = NULL | | ( h - > keycmp ( h , key , cur - > key ) ! = 0 ) )
return NULL ;
return cur - > datum ;
}
void hashtab_destroy ( struct hashtab * h )
{
u32 i ;
struct hashtab_node * cur , * temp ;
if ( ! h )
return ;
for ( i = 0 ; i < h - > size ; i + + ) {
cur = h - > htable [ i ] ;
while ( cur ! = NULL ) {
temp = cur ;
cur = cur - > next ;
kfree ( temp ) ;
}
h - > htable [ i ] = NULL ;
}
kfree ( h - > htable ) ;
h - > htable = NULL ;
kfree ( h ) ;
}
int hashtab_map ( struct hashtab * h ,
int ( * apply ) ( void * k , void * d , void * args ) ,
void * args )
{
u32 i ;
int ret ;
struct hashtab_node * cur ;
if ( ! h )
return 0 ;
for ( i = 0 ; i < h - > size ; i + + ) {
cur = h - > htable [ i ] ;
while ( cur ! = NULL ) {
ret = apply ( cur - > key , cur - > datum , args ) ;
if ( ret )
return ret ;
cur = cur - > next ;
}
}
return 0 ;
}
void hashtab_stat ( struct hashtab * h , struct hashtab_info * info )
{
u32 i , chain_len , slots_used , max_chain_len ;
struct hashtab_node * cur ;
slots_used = 0 ;
max_chain_len = 0 ;
for ( slots_used = max_chain_len = i = 0 ; i < h - > size ; i + + ) {
cur = h - > htable [ i ] ;
if ( cur ) {
slots_used + + ;
chain_len = 0 ;
while ( cur ) {
chain_len + + ;
cur = cur - > next ;
}
if ( chain_len > max_chain_len )
max_chain_len = chain_len ;
}
}
info - > slots_used = slots_used ;
info - > max_chain_len = max_chain_len ;
}