-
Notifications
You must be signed in to change notification settings - Fork 0
/
icl_hash.c
executable file
·290 lines (242 loc) · 6.93 KB
/
icl_hash.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/*
* membox Progetto del corso di LSO 2017/2018
*
* Dipartimento di Informatica Università di Pisa
* Docenti: Prencipe, Torquati
*
*/
/**
* @file icl_hash.c
*
* Dependency free hash table implementation.
*
* This simple hash table implementation should be easy to drop into
* any other peice of code, it does not depend on anything else :-)
*
* @author Jakub Kurzak
*/
/* $Id: icl_hash.c 2838 2011-11-22 04:25:02Z mfaverge $ */
/* $UTK_Copyright: $ */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <pthread.h>
#include <config.h>
#include "icl_hash.h"
#include <limits.h>
#define BITS_IN_int ( sizeof(int) * CHAR_BIT )
#define THREE_QUARTERS ((int) ((BITS_IN_int * 3) / 4))
#define ONE_EIGHTH ((int) (BITS_IN_int / 8))
#define HIGH_BITS ( ~((unsigned int)(~0) >> ONE_EIGHTH ))
/**
* A simple string hash.
*
* An adaptation of Peter Weinberger's (PJW) generic hashing
* algorithm based on Allen Holub's version. Accepts a pointer
* to a datum to be hashed and returns an unsigned integer.
* From: Keith Seymour's proxy library code
*
* @param[in] key -- the string to be hashed
*
* @returns the hash index
*/
unsigned int
hash_pjw(void* key)
{
char *datum = (char *)key;
unsigned int hash_value, i;
if(!datum) return 0;
for (hash_value = 0; *datum; ++datum) {
hash_value = (hash_value << ONE_EIGHTH) + *datum;
if ((i = hash_value & HIGH_BITS) != 0)
hash_value = (hash_value ^ (i >> THREE_QUARTERS)) & ~HIGH_BITS;
}
return (hash_value);
}
/**
*
* @function string_compare
* @brief funzione che confronta due stringhe
*
* @param a stringa a
* @param b stringa b
* @returns 1 se le due stringhe sono uguali 0 altrimenti
*/
int string_compare(void* a, void* b)
{
return (strcmp( (char*)a, (char*)b ) == 0);
}
/**
* Create a new hash table.
*
* @param[in] nbuckets -- number of buckets to create
* @param[in] hash_function -- pointer to the hashing function to be used
* @param[in] hash_key_compare -- pointer to the hash key comparison function to be used
*
* @returns pointer to new hash table.
*/
icl_hash_t *
icl_hash_create( unsigned int (*hash_function)(void*), int (*hash_key_compare)(void*, void*) )
{
icl_hash_t *ht;
int i;
int nbuckets = MAX_DIM_HASH;
ht = (icl_hash_t*) malloc(sizeof(icl_hash_t));
if(!ht) return NULL;
ht->nentries = 0;
ht->buckets = (icl_entry_t**)malloc(nbuckets * sizeof(icl_entry_t*));
if(!ht->buckets) return NULL;
ht->nbuckets = nbuckets;
for(i=0;i<ht->nbuckets;i++)
ht->buckets[i] = NULL;
ht->hash_function = hash_function ? hash_function : hash_pjw;
ht->hash_key_compare = hash_key_compare ? hash_key_compare : string_compare;
return ht;
}
/**
* Search for an entry in a hash table.
*
* @param ht -- the hash table to be searched
* @param key -- the key of the item to search for
*
* @returns pointer to the data corresponding to the key.
* If the key was not found, returns NULL.
*/
void *
icl_hash_find(icl_hash_t *ht, void* key)
{
icl_entry_t* curr;
unsigned int hash_val;
if(!ht || !key) return NULL;
hash_val = (* ht->hash_function)(key) % ht->nbuckets;
for (curr=ht->buckets[hash_val]; curr != NULL; curr=curr->next)
if ( ht->hash_key_compare(curr->key, key)){
return(curr->data);
}
return NULL;
}
/**
* Insert an item into the hash table.
*
* @param ht -- the hash table
* @param key -- the key of the new item
* @param data -- pointer to the new item's data
*
* @returns pointer to the new item. Returns NULL on error.
*/
icl_entry_t *
icl_hash_insert(icl_hash_t *ht, void* key, void *data)
{
icl_entry_t *curr;
unsigned int hash_val;
if(!ht || !key) return NULL;
hash_val = (* ht->hash_function)(key) % ht->nbuckets;
for (curr=ht->buckets[hash_val]; curr != NULL; curr=curr->next)
if ( ht->hash_key_compare(curr->key, key)){
return(NULL); /* key already exists */
}
/* if key was not found */
curr = (icl_entry_t*)malloc(sizeof(icl_entry_t));
if(!curr) {
return NULL;
}
curr->key = key;
curr->data = data;
curr->next = ht->buckets[hash_val]; /* add at start */
ht->buckets[hash_val] = curr;
ht->nentries++;
return curr;
}
/**
* Free one hash table entry located by key (key and data are freed using functions).
*
* @param ht -- the hash table to be freed
* @param key -- the key of the new item
* @param free_key -- pointer to function that frees the key
* @param free_data -- pointer to function that frees the data
*
* @returns 0 on success, -1 on failure.
*/
int icl_hash_delete(icl_hash_t *ht, void* key, void (*free_key)(void*), void (*free_data)(void*))
{
icl_entry_t *curr, *prev;
unsigned int hash_val;
if(!ht || !key) return -1;
hash_val = (* ht->hash_function)(key) % ht->nbuckets;
prev = NULL;
for (curr=ht->buckets[hash_val]; curr != NULL; ) {
if ( ht->hash_key_compare(curr->key, key)) {
if (prev == NULL) {
ht->buckets[hash_val] = curr->next;
} else {
prev->next = curr->next;
}
if (curr->key) (*free_key)(curr->key);
if (curr->data) (*free_data)(curr->data);
ht->nentries--;
free(curr);
return 0;
}
prev = curr;
curr = curr->next;
}
return -1;
}
/**
* Free hash table structures (key and data are freed using functions).
*
* @param ht -- the hash table to be freed
* @param free_key -- pointer to function that frees the key
* @param free_data -- pointer to function that frees the data
*
* @returns 0 on success, -1 on failure.
*/
int
icl_hash_destroy(icl_hash_t *ht, void (*free_key)(void*), void (*free_data)(void*))
{
icl_entry_t *bucket, *curr, *next;
int i;
if(!ht) return -1;
for (i=0; i<ht->nbuckets; i++) {
bucket = ht->buckets[i];
for (curr=bucket; curr!=NULL; ) {
next=curr->next;
if (*free_key && curr->key){
(*free_key)(curr->key);
}
if (*free_data && curr->data){
(*free_data)(curr->data);
}
free(curr);
curr=next;
}
}
if(ht->buckets) free(ht->buckets);
if(ht) free(ht);
return 0;
}
/**
* Dump the hash table's contents to the given file pointer.
*
* @param stream -- the file to which the hash table should be dumped
* @param ht -- the hash table to be dumped
*
* @returns 0 on success, -1 on failure.
*/
int
icl_hash_dump(FILE* stream, icl_hash_t* ht)
{
icl_entry_t *bucket, *curr;
int i;
if(!ht) return -1;
for(i=0; i<ht->nbuckets; i++) {
bucket = ht->buckets[i];
for(curr=bucket; curr!=NULL; ) {
if(curr->key)
fprintf(stream, "icl_hash_dump: %s: %p\n", (char *)curr->key, curr->data);
curr=curr->next;
}
}
return 0;
}