1
0
mirror of https://github.com/Llewellynvdm/conky.git synced 2024-11-18 19:15:12 +00:00
conky/src/hash.c
Philip Kovacs c493fe416f addded cvs id tags
git-svn-id: https://conky.svn.sourceforge.net/svnroot/conky/trunk/conky@380 7f574dfc-610e-0410-a909-a81674777703
2005-11-09 02:01:10 +00:00

209 lines
5.6 KiB
C

/* ------------------------------------------------------
* Open-addressed hash using double hash probing
*
* for i in 0 to m-1:
* h(k, i) = ( h1(k) + i*h2(k) ) mod m
*
* requires: 1) m must be a power of two
* 2) h2(k) must return an odd number
*
* Besed on code published in _Mastering Algorithms in C_
* by Kyle Loudon (O'Reilly 1999).
* Modified by Philip Kovacs (kovacsp3@comcast.net)
*
* $Id$
* ------------------------------------------------------ */
#ifdef HASH_DEBUG
#include <stdio.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "hash.h"
/* Create and initialize a hash table on the heap.
Returns 0 on success, -1 otherwise. */
int hash_create( hash_table_t *p_hash_table,
int positions,
int (*p_hash_fun1)(const void *p_data),
int (*p_hash_fun2)(const void *p_data),
int (*p_match_fun)(const void *p_data1, const void *p_data2),
void (*p_destroy_fun)(void *p_data)
)
{
if ( ( p_hash_table->pp_table = (void **)calloc(positions, sizeof(void *))) == NULL )
return -1;
p_hash_table->positions = positions;
p_hash_table->size = 0;
p_hash_table->vacated = 0;
/* sentinel address indicating a vacated slot */
p_hash_table->p_vacated = &p_hash_table->sentinel_vacated;
p_hash_table->p_hash_fun1 = p_hash_fun1;
p_hash_table->p_hash_fun2 = p_hash_fun2;
p_hash_table->p_match_fun = p_match_fun;
p_hash_table->p_destroy_fun = p_destroy_fun;
return 0;
}
/* Destroy a hash table */
void hash_destroy( hash_table_t *p_hash_table )
{
int i;
if ( !p_hash_table )
return;
/* Destroy the elements the hash points to, if a destroy function was provided */
if (p_hash_table->p_destroy_fun != NULL) {
for (i = 0; i < p_hash_table->positions; i++) {
if ( p_hash_table->pp_table[i] != NULL && p_hash_table->pp_table[i] != p_hash_table->p_vacated )
p_hash_table->p_destroy_fun( p_hash_table->pp_table[i] );
}
}
free( p_hash_table->pp_table );
memset( p_hash_table, 0, sizeof(hash_table_t) );
return;
}
/* Insert an element into a hash table.
Returns 0 on successful insert, 1 if data already in hash and -1 if unable to insert. */
int hash_insert( hash_table_t *p_hash_table, const void *p_data )
{
void *temp;
int position, i;
int hashed_1, hashed_2;
if ( !p_hash_table )
return -1;
if ( p_hash_table->size == p_hash_table->positions )
return -1;
temp = (void *)p_data;
if ( hash_lookup( p_hash_table, &temp ) == 0 )
return 1;
/* Loudon's original algorithm needlessly repeated running the hash algorithms with each iteration
to find a slot. Just running the hash algorithms once is enough since they are deterministic. */
hashed_1 = p_hash_table->p_hash_fun1( p_data );
hashed_2 = p_hash_table->p_hash_fun2( p_data );
for ( i = 0; i < p_hash_table->positions; i++ ) {
position = ( hashed_1 + (i * hashed_2) ) % p_hash_table->positions;
#ifdef HASH_DEBUG
printf("--- hash_insert: probe %d, position %d\n",i,position);
#endif
if ( p_hash_table->pp_table[ position ] == NULL ) /* empty slot */
{
p_hash_table->pp_table[ position ] = (void *)p_data;
p_hash_table->size++;
return 0;
}
if ( p_hash_table->pp_table[ position ] == p_hash_table->p_vacated ) /* vacated slot */
{
p_hash_table->pp_table[ position ] = (void *)p_data;
p_hash_table->size++;
p_hash_table->vacated--;
return 0;
}
}
/* hash functions not selected correctly since the above algorithm should visit all slots in the hash. */
return -1;
}
/* Delete an element from a hash table.
Returns 0 on successful delete, -1 if not found. */
int hash_remove( hash_table_t *p_hash_table, void **pp_data)
{
int position, i;
int hashed_1, hashed_2;
if ( !p_hash_table || !pp_data )
return -1;
hashed_1 = p_hash_table->p_hash_fun1( *pp_data );
hashed_2 = p_hash_table->p_hash_fun2( *pp_data );
for (i = 0; i < p_hash_table->positions; i++) {
position= ( hashed_1 + (i * hashed_2) ) % p_hash_table->positions;
#ifdef HASH_DEBUG
printf("--- hash_remove: probe %d, position %d\n",i,position);
#endif
if ( p_hash_table->pp_table[ position ] == NULL ) {
return -1;
}
else if ( p_hash_table->pp_table[ position ] == p_hash_table->p_vacated ) {
continue;
}
else if ( p_hash_table->p_match_fun( p_hash_table->pp_table[ position ], *pp_data)) {
*pp_data = p_hash_table->pp_table[ position ];
p_hash_table->pp_table[ position ] = p_hash_table->p_vacated;
p_hash_table->vacated++;
p_hash_table->size--;
return 0;
}
}
return -1;
}
/* Lookup an element in a hash table.
Returns 0 if found (data passed back byref), -1 if not found. */
int hash_lookup(const hash_table_t *p_hash_table, void **pp_data)
{
int position, i;
int hashed_1, hashed_2;
if ( !p_hash_table || !pp_data )
return -1;
hashed_1 = p_hash_table->p_hash_fun1( *pp_data );
hashed_2 = p_hash_table->p_hash_fun2( *pp_data );
for (i = 0; i < p_hash_table->positions; i++) {
position= ( hashed_1 + (i * hashed_2) ) % p_hash_table->positions;
#ifdef HASH_DEBUG
printf("--- hash_lookup: probe %d, position %d\n",i,position);
#endif
if ( p_hash_table->pp_table[ position ] == NULL ) {
return -1;
}
else if ( p_hash_table->p_match_fun(p_hash_table->pp_table[ position ], *pp_data) ) {
*pp_data = p_hash_table->pp_table[ position ];
return 0;
}
}
return -1;
}