-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathn_hash_new.c
122 lines (95 loc) · 2.45 KB
/
n_hash_new.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "n_hash_int.h"
static tn_hash *do_n_hash_new_ex(tn_alloc *na,
size_t size, void (*freefn) (void *))
{
tn_hash *ht = NULL;
if (na == NULL)
ht = n_calloc(1, sizeof(*ht));
else
ht = na->na_calloc(na, sizeof(*ht));
if (ht == NULL)
return NULL;
ht->flags = 0;
ht->table = n_calloc(size, sizeof(*ht->table));
#if ENABLE_TRACE
if (size % 2 == 0 && size > 100)
printf("n_hash_new %p %d\n", ht, size);
#endif
ht->size = size;
ht->free_fn = freefn;
ht->hash_fn = NULL;
ht->_refcnt = 0;
ht->na = na;
return ht;
}
static
tn_hash *n_hash_new2(tn_alloc *na, size_t size, void (*freefn) (void *))
{
register size_t rsize = 4;
while (rsize < size)
rsize <<= 1;
return do_n_hash_new_ex(na, rsize, freefn);
}
tn_hash *n_hash_new_ex(size_t size, void (*freefn) (void *),
unsigned int (*hashfn) (const char*))
{
tn_hash *ht = NULL;
if (hashfn == NULL)
return n_hash_new2(NULL, size, freefn);
ht = do_n_hash_new_ex(NULL, size, freefn);
ht->hash_fn = hashfn;
return ht;
}
tn_hash *n_hash_new_na(tn_alloc *na, size_t size, void (*freefn) (void *))
{
if (na == NULL)
na = n_alloc_new(16, TN_ALLOC_OBSTACK);
else
na = n_ref(na);
return n_hash_new2(na, size, freefn);
}
/* djb hash */
# define CDB_HASHSTART 5381
int n_hash_dohash(const tn_hash *ht, const char *s, int *slen)
{
register unsigned int v;
const char *ss = s;
if (ht->hash_fn)
return ht->hash_fn(s) % ht->size;
v = CDB_HASHSTART;
while (*s) {
v += (v << 5);
v ^= (unsigned)*s;
s++;
}
if (slen)
*slen = s - ss;
return v & (ht->size - 1);
}
#if 0 /* disabled */
/*
FNV hash (see http://www.isthe.com/chongo/tech/comp/fnv)
A bit slower and gives a bit lower collision rate than djb's
*/
int n_hash_dohash(const tn_hash *ht, const char *s, int *slen)
{
register unsigned v = 0;
const char *ss = s;
while (*s) {
/* xor the bottom with the current octet */
v ^= (unsigned)*s++;
// v += (v<<1) + (v<<4) + (v<<7) + (v<<8) + (v<<24);
v *= 0x01000193;
}
if (slen)
*slen = s - ss;
return v & (ht->size - 1);
}
#endif
int n_hash_size(const tn_hash *ht)
{
return ht->items;
}