2 * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc.
3 * See COPYING file for license information
14 RCSID("$Id: hash.c,v 1.6 2003/05/07 15:42:38 david Exp $");
18 static unsigned int hash_string(const char *);
19 static struct hash_entry
*scan_list(struct list_head
*, const char *);
20 static struct hash_entry
*get_hash_entry(struct hash_table
*tbl
, const char *key
);
22 struct hash_table
*create_hash_table(unsigned int sz
)
24 struct hash_table
*tbl
;
27 tbl
= (struct hash_table
*)malloc(sizeof(*tbl
) + sz
*sizeof(struct list_head
));
31 debug(DEBUG_APPERROR
, "malloc for hash_table failed");
36 tbl
->ht_lists
= (struct list_head
*)(tbl
+ 1);
39 for (i
= 0; i
< sz
; i
++)
40 INIT_LIST_HEAD(&tbl
->ht_lists
[i
]);
45 void destroy_hash_table(struct hash_table
*tbl
, void (*delete_obj
)(void *))
47 struct list_head
*head
, *next
, *tmp
;
48 struct hash_entry
*entry
;
51 for (i
= 0; i
< tbl
->ht_size
; i
++)
53 head
= &tbl
->ht_lists
[i
];
59 entry
= list_entry(next
, struct hash_entry
, he_list
);
61 delete_obj(entry
->he_obj
);
71 /* FIXME: there is no way for the user of this to determine the difference
72 * between a put to a new key value and a malloc failure
74 void *put_hash_object(struct hash_table
*tbl
, const char *key
, void *obj
)
77 put_hash_object_ex(tbl
, key
, obj
, HT_KEYCOPY
, NULL
, &retval
);
81 static struct hash_entry
*get_hash_entry(struct hash_table
*tbl
, const char *key
)
83 struct list_head
*head
;
84 struct hash_entry
*entry
;
87 hash
= hash_string(key
) % tbl
->ht_size
;
88 head
= &tbl
->ht_lists
[hash
];
89 entry
= scan_list(head
, key
);
94 void *get_hash_object(struct hash_table
*tbl
, const char *key
)
96 struct hash_entry
*entry
= get_hash_entry(tbl
, key
);
97 return (entry
) ? entry
->he_obj
: NULL
;
100 void *remove_hash_object(struct hash_table
*tbl
, const char *key
)
102 struct hash_entry
*entry
= get_hash_entry(tbl
, key
);
107 list_del(&entry
->he_list
);
108 retval
= entry
->he_obj
;
115 static unsigned int hash_string(register const char *key
)
117 register unsigned int hash
= 0;
120 hash
= hash
* HASH_CONST
+ *key
++;
125 static struct hash_entry
*scan_list(struct list_head
*head
, const char *key
)
127 struct list_head
*next
= head
->next
;
128 struct hash_entry
*entry
;
132 entry
= list_entry(next
, struct hash_entry
, he_list
);
133 if (strcmp(entry
->he_key
, key
) == 0)
142 void reset_hash_iterator(struct hash_table
*tbl
)
145 tbl
->iterator_ptr
= NULL
;
148 struct hash_entry
*next_hash_entry(struct hash_table
*tbl
)
150 while( tbl
->iterator
< tbl
->ht_size
)
152 struct list_head
*head
= &tbl
->ht_lists
[ tbl
->iterator
];
154 if( tbl
->iterator_ptr
== NULL
)
155 tbl
->iterator_ptr
= head
->next
;
157 if( tbl
->iterator_ptr
!= head
)
159 struct list_head
*tmp
= tbl
->iterator_ptr
;
160 tbl
->iterator_ptr
= tbl
->iterator_ptr
->next
;
161 return( list_entry( tmp
, struct hash_entry
, he_list
) );
167 tbl
->iterator_ptr
= NULL
;
174 int put_hash_object_ex(struct hash_table
*tbl
, const char *key
, void *obj
, int copy
,
175 char ** oldkey
, void ** oldobj
)
177 struct list_head
*head
;
178 struct hash_entry
*entry
;
182 /* FIXME: how can get_hash_entry be changed to be usable here?
183 * we need the value of head later if the entry is not found...
185 hash
= hash_string(key
) % tbl
->ht_size
;
186 head
= &tbl
->ht_lists
[hash
];
187 entry
= scan_list(head
, key
);
192 *oldkey
= entry
->he_key
;
194 *oldobj
= entry
->he_obj
;
196 /* if 'copy' is set, then we already have an exact
197 * private copy of the key (by definition of having
198 * found the match in scan_list) so we do nothing.
199 * if !copy, then we can simply assign the new
203 entry
->he_key
= (char*)key
; /* discard the const */
208 size_t s
= sizeof(*entry
);
216 s
+= strlen(key
) + 1;
218 entry
= (struct hash_entry
*)malloc(s
);
222 debug(DEBUG_APPERROR
,"malloc failed put_hash_object key='%s'",key
);
229 entry
->he_key
= (char *)(entry
+ 1);
230 strcpy(entry
->he_key
, key
);
234 entry
->he_key
= (char*)key
; /* discard the const */
239 list_add(&entry
->he_list
, head
);
246 void destroy_hash_table_ex(struct hash_table
*tbl
,
247 void (*delete_entry
)(const void *, char *, void *),
250 struct list_head
*head
, *next
, *tmp
;
251 struct hash_entry
*entry
;
254 for (i
= 0; i
< tbl
->ht_size
; i
++)
256 head
= &tbl
->ht_lists
[i
];
262 entry
= list_entry(next
, struct hash_entry
, he_list
);
264 delete_entry(cookie
, entry
->he_key
, entry
->he_obj
);