2016-11-09 16:36:34 +01:00
/*
* BIRD Library -- Hash Tests
*
* (c) 2015 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#undef LOCAL_DEBUG
#include "test/birdtest.h"
#include "lib/hash.h"
struct test_node {
struct test_node * next ; /* Hash chain */
u32 key ;
};
#define TEST_KEY(n) n->key
#define TEST_NEXT(n) n->next
#define TEST_EQ(n1,n2) n1 == n2
#define TEST_FN(n) (n) ^ u32_hash((n))
#define TEST_ORDER 13
#define TEST_PARAMS /TEST_ORDER, *2, 2, 2, TEST_ORDER, 20
#define TEST_REHASH test_rehash
HASH_DEFINE_REHASH_FN ( TEST , struct test_node );
HASH ( struct test_node ) hash ;
struct pool * my_pool ;
#define MAX_NUM (1 << TEST_ORDER)
struct test_node nodes [ MAX_NUM ];
static void
print_rate_of_fulfilment ( void )
{
int i ;
int num_stacked_items = 0 ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
if ( ! hash . data [ i ])
num_stacked_items ++ ;
double percent_stacked_items = (( double ) num_stacked_items / ( double ) MAX_NUM ) * 100. ;
bt_debug ( "%d (%.2f %%) chained of %d hashes \n " , num_stacked_items , percent_stacked_items , MAX_NUM );
}
#ifdef LOCAL_DEBUG
static void
dump_nodes ( void )
{
int i ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
bt_debug ( "nodes[%3d] is at address %14p has .key %3d, .next %14p \n " , i , & nodes [ i ], nodes [ i ]. key , nodes [ i ]. next );
}
#endif
static void
init_hash_ ( uint order )
{
my_pool = rp_new ( & root_pool , "Test pool" );
HASH_INIT ( hash , my_pool , order );
int i ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
{
nodes [ i ]. key = i ;
nodes [ i ]. next = NULL ;
}
bt_debug ( "MAX_NUM %d \n " , MAX_NUM );
}
static void
init_hash ( void )
{
init_hash_ ( TEST_ORDER );
}
static void
validate_filled_hash ( void )
{
int i ;
struct test_node * node ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
{
node = HASH_FIND ( hash , TEST , nodes [ i ]. key );
bt_assert_msg ( node -> key == nodes [ i ]. key , "Hash should be filled, to find (%p) the node[%d] (%p) with .key = %u, .next %p" , node , i , & nodes [ i ], nodes [ i ]. key , nodes [ i ]. next );
}
print_rate_of_fulfilment ();
}
static void
validate_empty_hash ( void )
{
int i ;
struct test_node * node ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
{
node = HASH_FIND ( hash , TEST , nodes [ i ]. key );
bt_assert_msg ( node == NULL , "Hash should be empty, to find (%p) the node[%d] (%p) with .key %u, .next %p" , node , i , & nodes [ i ], nodes [ i ]. key , nodes [ i ]. next );
}
}
static void
fill_hash ( void )
{
int i ;
struct test_node * node ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
{
nodes [ i ]. key = i ;
node = & nodes [ i ];
HASH_INSERT ( hash , TEST , node );
}
}
static int
t_insert_find ( void )
{
init_hash ();
fill_hash ();
validate_filled_hash ();
2016-11-11 17:43:09 +01:00
return 1 ;
2016-11-09 16:36:34 +01:00
}
static int
t_insert_find_random ( void )
{
init_hash ();
int i ;
struct test_node * node ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
{
nodes [ i ]. key = bt_random ();
node = & nodes [ i ];
HASH_INSERT ( hash , TEST , node );
}
validate_filled_hash ();
2016-11-11 17:43:09 +01:00
return 1 ;
2016-11-09 16:36:34 +01:00
}
static int
t_insert2_find ( void )
{
init_hash_ ( 1 );
int i ;
struct test_node * node ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
{
nodes [ i ]. key = i ;
node = & nodes [ i ];
HASH_INSERT2 ( hash , TEST , my_pool , node );
}
bt_assert_msg ( hash . order != 1 , "The hash should auto-resize from order 2^1. The order of the hash is 2^%u." , hash . order );
validate_filled_hash ();
2016-11-11 17:43:09 +01:00
return 1 ;
2016-11-09 16:36:34 +01:00
}
static int
t_walk ( void )
{
init_hash ();
fill_hash ();
uint i ;
uint check [ MAX_NUM ];
for ( i = 0 ; i < MAX_NUM ; i ++ )
check [ i ] = 0 ;
HASH_WALK ( hash , next , n )
{
check [ n -> key ] ++ ;
}
HASH_WALK_END ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
bt_assert ( check [ i ] == 1 );
2016-11-11 17:43:09 +01:00
return 1 ;
2016-11-09 16:36:34 +01:00
}
static int
t_walk_delsafe_delete ( void )
{
init_hash ();
fill_hash ();
HASH_WALK_DELSAFE ( hash , next , n )
{
HASH_DELETE ( hash , TEST , n -> key );
}
HASH_WALK_DELSAFE_END ;
validate_empty_hash ();
2016-11-11 17:43:09 +01:00
return 1 ;
2016-11-09 16:36:34 +01:00
}
static int
t_walk_delsafe_remove ( void )
{
init_hash ();
fill_hash ();
HASH_WALK_DELSAFE ( hash , next , n )
{
HASH_REMOVE ( hash , TEST , n );
}
HASH_WALK_DELSAFE_END ;
validate_empty_hash ();
2016-11-11 17:43:09 +01:00
return 1 ;
2016-11-09 16:36:34 +01:00
}
static int
t_walk_delsafe_delete2 ( void )
{
init_hash ();
fill_hash ();
HASH_WALK_DELSAFE ( hash , next , n )
{
HASH_DELETE2 ( hash , TEST , my_pool , n -> key );
}
HASH_WALK_DELSAFE_END ;
validate_empty_hash ();
2016-11-11 17:43:09 +01:00
return 1 ;
2016-11-09 16:36:34 +01:00
}
static int
t_walk_delsafe_remove2 ( void )
{
init_hash ();
fill_hash ();
HASH_WALK_DELSAFE ( hash , next , n )
{
HASH_REMOVE2 ( hash , TEST , my_pool , n );
}
HASH_WALK_DELSAFE_END ;
validate_empty_hash ();
2016-11-11 17:43:09 +01:00
return 1 ;
2016-11-09 16:36:34 +01:00
}
static int
t_walk_filter ( void )
{
init_hash ();
fill_hash ();
uint i ;
uint check [ MAX_NUM ];
for ( i = 0 ; i < MAX_NUM ; i ++ )
check [ i ] = 0 ;
HASH_WALK_FILTER ( hash , next , n , m )
{
bt_assert ( n == * m );
check [ n -> key ] ++ ;
}
HASH_WALK_FILTER_END ;
for ( i = 0 ; i < MAX_NUM ; i ++ )
bt_assert ( check [ i ] == 1 );
2016-11-11 17:43:09 +01:00
return 1 ;
2016-11-09 16:36:34 +01:00
}
int
main ( int argc , char * argv [])
{
bt_init ( argc , argv );
bt_test_suite ( t_insert_find , "HASH_INSERT and HASH_FIND" );
bt_test_suite ( t_insert_find_random , "HASH_INSERT pseudo-random keys and HASH_FIND" );
bt_test_suite ( t_insert2_find , "HASH_INSERT2 and HASH_FIND. HASH_INSERT2 is HASH_INSERT and a smart auto-resize function" );
bt_test_suite ( t_walk , "HASH_WALK" );
bt_test_suite ( t_walk_delsafe_delete , "HASH_WALK_DELSAFE and HASH_DELETE" );
bt_test_suite ( t_walk_delsafe_delete2 , "HASH_WALK_DELSAFE and HASH_DELETE2. HASH_DELETE2 is HASH_DELETE and smart auto-resize function" );
bt_test_suite ( t_walk_delsafe_remove , "HASH_WALK_DELSAFE and HASH_REMOVE" );
bt_test_suite ( t_walk_delsafe_remove2 , "HASH_WALK_DELSAFE and HASH_REMOVE2. HASH_REMOVE2 is HASH_REMOVE and smart auto-resize function" );
bt_test_suite ( t_walk_filter , "HASH_WALK_FILTER" );
return bt_exit_value ();
}