rename hash_miltimap.c->cpp
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
/* =============================================================================
|
||||
* CDL (Configuration Definition Language) validator $Revision: 1.4 $
|
||||
* (C)2004-2007 Nikolai Nosov. All rights reserved.
|
||||
*
|
||||
* File: $RCSfile: hash_multimap.c,v $
|
||||
* Purpose: Hash Multimap implementation
|
||||
* Written by: Nikolai Nosov nnosov@gmail.com
|
||||
* Last modified: $Date: 2008/06/21 12:15:53 $ by $Author: nnosov $.
|
||||
*
|
||||
* For more information please visit
|
||||
* http://cdl.sourceforge.net
|
||||
* ===========================================================================*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "hash_multimap.h"
|
||||
|
||||
/* Default hash function
|
||||
@param key hash key
|
||||
@param size hash key size in bytes
|
||||
@return hash value, depends of the hash key
|
||||
*/
|
||||
static unsigned int default_hash_fn(const char *key, int size)
|
||||
{
|
||||
register int i, j;
|
||||
unsigned int cs = 0;
|
||||
unsigned int ps = 0;
|
||||
|
||||
if(key) {
|
||||
for(i = 0, j = 0; i < size; i++, j++) {
|
||||
ps |= ((unsigned int)key[i]) << (j * 8);
|
||||
if(j == 3 || j == (size - 1)) {
|
||||
cs ^= ps;
|
||||
ps = 0;
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
static int default_compare_fn(const char *key1, const char *key2, const int size)
|
||||
{
|
||||
return !memcmp(key1, key2, size);
|
||||
}
|
||||
|
||||
/** Initialize hash node. Must be called before first usage of the node.
|
||||
@param node pointer to the hash node descriptor
|
||||
*/
|
||||
void hash_node_init(struct hash_node *node)
|
||||
{
|
||||
node->key = NULL;
|
||||
node->key_size = 0;
|
||||
list_node_init(&node->node);
|
||||
}
|
||||
|
||||
/** Cleanup hash node
|
||||
@param node pointer to the hash node descriptor
|
||||
*/
|
||||
void hash_node_cleanup(struct hash_node *node)
|
||||
{
|
||||
if(node->key) free(node->key);
|
||||
list_node_init(&node->node);
|
||||
node->key = NULL;
|
||||
node->key_size = 0;
|
||||
}
|
||||
|
||||
/** Initialize hash table
|
||||
@param map pointer to the hash table descriptor
|
||||
@param hash_shift size of the hash table in bits. Should be greater than
|
||||
HASH_MIN_SHIFT and less than HASH_MAX_SHIFT. In case of less than HASH_MIN_SHIFT,
|
||||
will be followed by HASH_MIN_SHIFT, in case of greater HASH_MAX_SHIFT will be
|
||||
followed by HASH_MAX_SHIFT
|
||||
@param hf pointer to the user defined hash function. If NULL, then default hash
|
||||
function will be used
|
||||
@param cf pointer to the user defined compare function. if NULL, then the default
|
||||
compare function will be used
|
||||
*/
|
||||
int hash_head_init(struct hash_head *map, unsigned int hash_shift, _hash_fn hf, _compare_fn cf)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(map) {
|
||||
if(hash_shift <= HASH_MIN_SHIFT) {
|
||||
map->hash_shift = HASH_MIN_SHIFT;
|
||||
} else if(hash_shift >= HASH_MAX_SHIFT) {
|
||||
map->hash_shift = HASH_MAX_SHIFT;
|
||||
} else {
|
||||
map->hash_shift = hash_shift;
|
||||
}
|
||||
|
||||
map->hash_size = 1UL << map->hash_shift;
|
||||
map->hash_mask = (map->hash_size - 1);
|
||||
|
||||
map->bucket = (list_head*)malloc(sizeof(list_head) * map->hash_size);
|
||||
if(map->bucket) {
|
||||
for(uint16_t i = 0; i < map->hash_size; i++) {
|
||||
list_head_init(map->bucket + i);
|
||||
}
|
||||
|
||||
if(hf) {
|
||||
map->hash_fn = hf;
|
||||
} else {
|
||||
map->hash_fn = default_hash_fn;
|
||||
}
|
||||
|
||||
if(cf) {
|
||||
map->compare_fn = cf;
|
||||
} else {
|
||||
map->compare_fn = default_compare_fn;
|
||||
}
|
||||
} else {
|
||||
return ENOMEM;
|
||||
}
|
||||
} else {
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Cleanup hash table descriptor
|
||||
|
||||
@param map pointer to the hash table descriptor
|
||||
*/
|
||||
void hash_head_cleanup(struct hash_head *map)
|
||||
{
|
||||
struct list_node *p, *n;
|
||||
struct hash_node *node;
|
||||
int i;
|
||||
|
||||
if(map) {
|
||||
if(map->bucket) {
|
||||
for(i = 0; i < map->hash_size; i++) {
|
||||
list_for_each_safe(p, n, map->bucket + i) {
|
||||
node = list_entry(p, struct hash_node, node);
|
||||
hash_node_cleanup(node);
|
||||
}
|
||||
}
|
||||
free(map->bucket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Find first node which key is equal to the key represented
|
||||
|
||||
@param map pointer to the hash table descriptor
|
||||
@param key pointer to the hash key
|
||||
@param key_size size of the hash key
|
||||
@return pointer to the key found, or NULL in case of hash table have not nodes
|
||||
with the key equals to the key represented
|
||||
*/
|
||||
struct hash_node* hash_find(struct hash_head *map, const void *key, int key_size)
|
||||
{
|
||||
struct list_head *list;
|
||||
struct list_node *n;
|
||||
struct hash_node *node;
|
||||
|
||||
list = map->bucket + (map->hash_fn(key, key_size) & map->hash_mask);
|
||||
list_for_each(n, list) {
|
||||
node = list_entry(n, struct hash_node, node);
|
||||
if(key_size == node->key_size) {
|
||||
if(map->compare_fn(key, node->key, key_size)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Find next node, which key is equal to the key represented
|
||||
|
||||
@param hn1 pointer to the previous node found.
|
||||
@return pointer to the next node with the same key, or NULL in case of the current
|
||||
node is the last node with appropriate key
|
||||
*/
|
||||
struct hash_node* hash_find_next(struct hash_head *map, struct hash_node *hn1)
|
||||
{
|
||||
struct list_node *n = &hn1->node;
|
||||
struct hash_node *hn2;
|
||||
|
||||
|
||||
while((n = list_next(n)) != NULL) {
|
||||
hn2 = list_entry(n, struct hash_node, node);
|
||||
if(hn1->key_size == hn2->key_size) {
|
||||
if(map->compare_fn(hn1->key, hn2->key, hn2->key_size)) return hn2;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Add node to the hash table
|
||||
|
||||
@param map pointer to the hash table
|
||||
@param node pointer to the node, which will be added to the table
|
||||
@param key pointer to the hash key
|
||||
@param key_size size of the hash key
|
||||
|
||||
@return zero in case of success, ENOMEM in case of error
|
||||
*/
|
||||
int hash_add(struct hash_head *map, struct hash_node *node, void *key, int key_size)
|
||||
{
|
||||
node->key = (char*)malloc(key_size);
|
||||
if(node->key) {
|
||||
memcpy(node->key, key, key_size);
|
||||
node->key_size = key_size;
|
||||
list_add_bottom(map->bucket + (map->hash_fn(key, key_size) & map->hash_mask), &node->node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/** Remove node from the hash table
|
||||
|
||||
@param node pointer to the node descriptor
|
||||
*/
|
||||
void hash_del(struct hash_node *node)
|
||||
{
|
||||
list_del_init(&node->node);
|
||||
hash_node_cleanup(node);
|
||||
}
|
||||
|
||||
/** Initialize iterator for usage. Must be called before first iterator usage.
|
||||
|
||||
@param map pointer to the hash table descriptor
|
||||
@param iter pointer to the iterator descriptor
|
||||
*/
|
||||
void hash_iterator_init(struct hash_head *map, struct hash_iterator *iter)
|
||||
{
|
||||
iter->map = map;
|
||||
iter->map_idx = 0;
|
||||
iter->current = NULL;
|
||||
}
|
||||
|
||||
/** Move iterator to the first node in the table, and return pointer to the node
|
||||
|
||||
@param iter pointer to the iterator descriptor
|
||||
@return pointer to the first node in the table, or NULL in case of error
|
||||
*/
|
||||
struct hash_node * hash_node_first(struct hash_iterator *iter)
|
||||
{
|
||||
iter->current = list_first(iter->map->bucket);
|
||||
iter->map_idx = 0;
|
||||
|
||||
if (iter->current) {
|
||||
return list_entry(iter->current, struct hash_node, node);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Move iterator to the next node in the table and return pointer to the node
|
||||
|
||||
@param iter pointer to the iterator descriptor
|
||||
@return pointer to the next node in the table, or NULL in case of error
|
||||
*/
|
||||
struct hash_node * hash_node_next(struct hash_iterator *iter)
|
||||
{
|
||||
if(iter->map_idx >= iter->map->hash_size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(iter->current) {
|
||||
iter->current = list_next(iter->current);
|
||||
}
|
||||
|
||||
if(iter->current) {
|
||||
return list_entry(iter->current, struct hash_node, node);
|
||||
}
|
||||
|
||||
while(iter->map_idx < iter->map->hash_size) {
|
||||
iter->current = list_first(iter->map->bucket + iter->map_idx);
|
||||
iter->map_idx++;
|
||||
if(iter->current) {
|
||||
return list_entry(iter->current, struct hash_node, node);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Remove current node, pointed by iterator, and move iterator to the next node
|
||||
|
||||
@param iter pointer to the iterator descriptor
|
||||
*/
|
||||
void hash_node_del(struct hash_iterator *iter)
|
||||
{
|
||||
struct list_node *tmp;
|
||||
|
||||
tmp = iter->current;
|
||||
hash_node_next(iter);
|
||||
list_del_init(tmp);
|
||||
}
|
||||
|
||||
/** Return total count of elements in the hash table
|
||||
|
||||
@param head pointer to the hash table descriptor
|
||||
*/
|
||||
int hash_count(struct hash_head *head)
|
||||
{
|
||||
int i;
|
||||
int count = 0;
|
||||
|
||||
for(i = 0; i < head->hash_size; i++) {
|
||||
count += list_count(head->bucket + i);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
Reference in New Issue
Block a user