Add test about issue with no commit on a branch
[cvsps-hv.git] / cbtcommon / hash.c
blobddc081b90427bfc02ae1c1279bf6f273b5f6dfca
1 /*
2 * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc.
3 * See COPYING file for license information
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
10 #include "debug.h"
11 #include "hash.h"
12 #include "rcsid.h"
14 RCSID("$Id: hash.c,v 1.6 2003/05/07 15:42:38 david Exp $");
16 #define HASH_CONST 37
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;
25 unsigned int i;
27 tbl = (struct hash_table *)malloc(sizeof(*tbl) + sz*sizeof(struct list_head));
29 if (!tbl)
31 debug(DEBUG_APPERROR, "malloc for hash_table failed");
32 return NULL;
35 tbl->ht_size = sz;
36 tbl->ht_lists = (struct list_head *)(tbl + 1);
37 tbl->iterator = 0;
39 for (i = 0; i < sz; i++)
40 INIT_LIST_HEAD(&tbl->ht_lists[i]);
42 return tbl;
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;
49 int i;
51 for (i = 0; i < tbl->ht_size; i++)
53 head = &tbl->ht_lists[i];
54 next = head->next;
56 while (next != head)
58 tmp = next->next;
59 entry = list_entry(next, struct hash_entry, he_list);
60 if (delete_obj)
61 delete_obj(entry->he_obj);
62 free(entry);
64 next = tmp;
68 free(tbl);
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)
76 void * retval;
77 put_hash_object_ex(tbl, key, obj, HT_KEYCOPY, NULL, &retval);
78 return 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;
85 unsigned int hash;
87 hash = hash_string(key) % tbl->ht_size;
88 head = &tbl->ht_lists[hash];
89 entry = scan_list(head, key);
91 return entry;
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);
103 void *retval = NULL;
105 if (entry)
107 list_del(&entry->he_list);
108 retval = entry->he_obj;
109 free(entry);
112 return retval;
115 static unsigned int hash_string(register const char *key)
117 register unsigned int hash = 0;
119 while(*key)
120 hash = hash * HASH_CONST + *key++;
122 return hash;
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;
130 while (next != head)
132 entry = list_entry(next, struct hash_entry, he_list);
133 if (strcmp(entry->he_key, key) == 0)
134 return entry;
136 next = next->next;
139 return NULL;
142 void reset_hash_iterator(struct hash_table *tbl)
144 tbl->iterator = 0;
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 ) );
164 else
166 tbl->iterator++;
167 tbl->iterator_ptr = NULL;
171 return( 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;
179 unsigned int hash;
180 int retval = 0;
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);
189 if (entry)
191 if (oldkey)
192 *oldkey = entry->he_key;
193 if (oldobj)
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
200 * key
202 if (!copy)
203 entry->he_key = (char*)key; /* discard the const */
204 entry->he_obj = obj;
206 else
208 size_t s = sizeof(*entry);
210 if (oldkey)
211 *oldkey = NULL;
212 if (oldobj)
213 *oldobj = NULL;
215 if (copy)
216 s += strlen(key) + 1;
218 entry = (struct hash_entry *)malloc(s);
220 if (!entry)
222 debug(DEBUG_APPERROR,"malloc failed put_hash_object key='%s'",key);
223 retval = -1;
225 else
227 if (copy)
229 entry->he_key = (char *)(entry + 1);
230 strcpy(entry->he_key, key);
232 else
234 entry->he_key = (char*)key; /* discard the const */
237 entry->he_obj = obj;
239 list_add(&entry->he_list, head);
243 return retval;
246 void destroy_hash_table_ex(struct hash_table *tbl,
247 void (*delete_entry)(const void *, char *, void *),
248 const void * cookie)
250 struct list_head *head, *next, *tmp;
251 struct hash_entry *entry;
252 int i;
254 for (i = 0; i < tbl->ht_size; i++)
256 head = &tbl->ht_lists[i];
257 next = head->next;
259 while (next != head)
261 tmp = next->next;
262 entry = list_entry(next, struct hash_entry, he_list);
263 if (delete_entry)
264 delete_entry(cookie, entry->he_key, entry->he_obj);
265 free(entry);
267 next = tmp;
271 free(tbl);