You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/lib/cds/hash_table.c

231 lines
4.7 KiB

/*
* Copyright (C) 2005 iptelorg GmbH
*
* This file is part of ser, a free SIP server.
*
* ser is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cds/hash_table.h>
#include <cds/memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ht_init(hash_table_t *ht, hash_func_t hash_func, key_cmp_func_t cmp_keys, int size)
{
if (!ht) return -1;
if ((!hash_func) || (!cmp_keys)) return -1;
ht->cslots = (ht_cslot_t*)cds_malloc(size * sizeof(ht_cslot_t));
if (!ht->cslots) return -1;
memset(ht->cslots, 0, size * sizeof(ht_cslot_t));
ht->size = size;
ht->hash = hash_func;
ht->cmp = cmp_keys;
ht->find_cnt = 0;
ht->cmp_cnt = 0;
ht->nocmp_cnt = 0;
ht->missed_cnt = 0;
return 0;
}
void ht_destroy(hash_table_t *ht)
{
ht_element_t *e, *n;
int i;
if (!ht) return;
if (ht->cslots) {
for (i = 0; i < ht->size; i++) {
e = ht->cslots[i].first;
while (e) {
n = e->next;
cds_free(e);
e = n;
}
}
cds_free(ht->cslots);
}
ht->cslots = NULL;
}
int ht_add(hash_table_t *ht, ht_key_t key, ht_data_t data)
{
int h;
ht_element_t *new_e;
if (!ht) return -1;
new_e = (ht_element_t*)cds_malloc(sizeof(ht_element_t));
if (!new_e) return -1;
new_e->next = NULL;
new_e->key = key;
new_e->data = data;
h = ht->hash(key) % ht->size;
if (h < 0) h = -h;
if (!ht->cslots[h].last) {
ht->cslots[h].first = new_e;
}
else {
ht->cslots[h].last->next = new_e;
}
ht->cslots[h].cnt++;
ht->cslots[h].last = new_e;
return 0;
}
ht_data_t ht_find(hash_table_t *ht, ht_key_t key)
{
int h;
ht_element_t *e;
if (!ht) return NULL;
ht->find_cnt++; //monitor
h = ht->hash(key) % ht->size;
if (h < 0) h = -h;
e = ht->cslots[h].first;
if (!e) ht->nocmp_cnt++; //monitor
while (e) {
ht->cmp_cnt++; //monitor
if (ht->cmp(e->key, key) == 0) return e->data;
e = e->next;
}
ht->missed_cnt++; //monitor
return NULL;
}
ht_data_t ht_remove(hash_table_t *ht, ht_key_t key)
{
int h;
ht_element_t *e,*p;
ht_data_t data;
if (!ht) return NULL;
h = ht->hash(key) % ht->size;
if (h < 0) h = -h;
e = ht->cslots[h].first;
p = NULL;
while (e) {
if (ht->cmp(e->key, key) == 0) {
if (p) p->next = e->next;
else ht->cslots[h].first = e->next;
ht->cslots[h].cnt--;
if (!e->next) ht->cslots[h].last = p;
data = e->data;
cds_free(e);
return data;
}
p = e;
e = e->next;
}
return NULL;
}
void ht_get_statistic(hash_table_t *ht, ht_statistic_t *s)
{
if (!s) return;
if (!ht) {
s->find_cnt = 0;
s->cmp_cnt = 0;
s->nocmp_cnt = 0;
s->missed_cnt = 0;
}
else {
s->find_cnt = ht->find_cnt;
s->cmp_cnt = ht->cmp_cnt;
s->nocmp_cnt = ht->nocmp_cnt;
s->missed_cnt = ht->missed_cnt;
}
}
void ht_clear_statistic(hash_table_t *ht)
{
if (!ht) return;
ht->find_cnt = 0;
ht->cmp_cnt = 0;
ht->nocmp_cnt = 0;
ht->missed_cnt = 0;
}
/* --------- hash table traversing functions -------- */
ht_element_t *get_first_ht_element(hash_table_t *ht, ht_traversal_info_t *info)
{
int i;
if (!info) return NULL;
info->ht = ht;
info->current = NULL;
for (i = 0; i < ht->size; i++) {
if (ht->cslots[i].first) {
info->current = ht->cslots[i].first;
break;
}
}
info->slot_pos = i;
return info->current;
}
ht_element_t *get_next_ht_element(ht_traversal_info_t *info)
{
int i;
if (!info) return NULL;
if (info->current) info->current = info->current->next;
if (info->current) return info->current;
else {
for (i = info->slot_pos + 1; i < info->ht->size; i++) {
if (info->ht->cslots[i].first) {
info->current = info->ht->cslots[i].first;
break;
}
}
info->slot_pos = i;
}
return info->current;
}
/* --------- HASH functions -------- */
unsigned int rshash(const char* str, unsigned int len)
{
unsigned int b = 378551;
unsigned int a = 63689;
unsigned int hash = 0;
unsigned int i = 0;
for(i = 0; i < len; str++, i++) {
hash = hash * a + (*str);
a = a * b;
}
return (hash & 0x7FFFFFFF);
}