Additional cmake tweaks for cygwin
[hiphop-php.git] / hphp / neo / neo_hash.c
blob7d08c5256b765a0887077231552a9b7e0556a20f
1 /*
2 * Copyright 2003-2004 Brandon Long
3 * All Rights Reserved.
5 * ClearSilver Templating System
7 * This code is made available under the terms of the ClearSilver License.
8 * http://www.clearsilver.net/license.hdf
12 #include "cs_config.h"
14 #include <stdlib.h>
15 #include <string.h>
17 #include "neo_misc.h"
18 #include "neo_err.h"
19 #include "neo_hash.h"
21 static NEOERR *_hash_resize(NE_HASH *hash);
22 static NE_HASHNODE **_hash_lookup_node (NE_HASH *hash, void *key, UINT32 *hashv);
24 NEOERR *ne_hash_init (NE_HASH **hash, NE_HASH_FUNC hash_func, NE_COMP_FUNC comp_func)
26 NE_HASH *my_hash = NULL;
28 my_hash = (NE_HASH *) calloc(1, sizeof(NE_HASH));
29 if (my_hash == NULL)
30 return nerr_raise(NERR_NOMEM, "Unable to allocate memory for NE_HASH");
32 my_hash->size = 256;
33 my_hash->num = 0;
34 my_hash->hash_func = hash_func;
35 my_hash->comp_func = comp_func;
37 my_hash->nodes = (NE_HASHNODE **) calloc (my_hash->size, sizeof(NE_HASHNODE *));
38 if (my_hash->nodes == NULL)
40 free(my_hash);
41 return nerr_raise(NERR_NOMEM, "Unable to allocate memory for NE_HASHNODES");
44 *hash = my_hash;
46 return STATUS_OK;
49 void ne_hash_destroy (NE_HASH **hash)
51 NE_HASH *my_hash;
52 NE_HASHNODE *node, *next;
53 int x;
55 if (hash == NULL || *hash == NULL)
56 return;
58 my_hash = *hash;
60 for (x = 0; x < my_hash->size; x++)
62 node = my_hash->nodes[x];
63 while (node)
65 next = node->next;
66 free(node);
67 node = next;
70 free(my_hash->nodes);
71 my_hash->nodes = NULL;
72 free(my_hash);
73 *hash = NULL;
76 NEOERR *ne_hash_insert(NE_HASH *hash, void *key, void *value)
78 UINT32 hashv;
79 NE_HASHNODE **node;
81 node = _hash_lookup_node(hash, key, &hashv);
83 if (*node)
85 (*node)->value = value;
87 else
89 *node = (NE_HASHNODE *) malloc(sizeof(NE_HASHNODE));
90 if (node == NULL)
91 return nerr_raise(NERR_NOMEM, "Unable to allocate NE_HASHNODE");
93 (*node)->hashv = hashv;
94 (*node)->key = key;
95 (*node)->value = value;
96 (*node)->next = NULL;
98 hash->num++;
100 return _hash_resize(hash);
103 void *ne_hash_lookup(NE_HASH *hash, void *key)
105 NE_HASHNODE *node;
107 node = *_hash_lookup_node(hash, key, NULL);
109 return (node) ? node->value : NULL;
112 void *ne_hash_remove(NE_HASH *hash, void *key)
114 NE_HASHNODE **node, *rem;
115 void *value = NULL;
117 node = _hash_lookup_node(hash, key, NULL);
118 if (*node)
120 rem = *node;
121 *node = rem->next;
122 value = rem->value;
123 free(rem);
124 hash->num--;
126 return value;
129 int ne_hash_has_key(NE_HASH *hash, void *key)
131 NE_HASHNODE *node;
133 node = *_hash_lookup_node(hash, key, NULL);
135 if (node) return 1;
136 return 0;
139 void *ne_hash_next(NE_HASH *hash, void **key)
141 NE_HASHNODE **node = 0;
142 UINT32 hashv, bucket;
144 if (*key)
146 node = _hash_lookup_node(hash, key, NULL);
148 if (*node)
150 bucket = (*node)->hashv & (hash->size - 1);
152 else
154 hashv = hash->hash_func(*key);
155 bucket = hashv & (hash->size - 1);
158 else
160 bucket = 0;
163 if (*node)
165 if ((*node)->next)
167 *key = (*node)->next->key;
168 return (*node)->next->value;
170 bucket++;
173 while (bucket < hash->size)
175 if (hash->nodes[bucket])
177 *key = hash->nodes[bucket]->key;
178 return hash->nodes[bucket]->value;
180 bucket++;
183 return NULL;
186 static NE_HASHNODE **_hash_lookup_node (NE_HASH *hash, void *key, UINT32 *o_hashv)
188 UINT32 hashv, bucket;
189 NE_HASHNODE **node;
191 hashv = hash->hash_func(key);
192 if (o_hashv) *o_hashv = hashv;
193 bucket = hashv & (hash->size - 1);
194 /* ne_warn("Lookup %s %d %d", key, hashv, bucket); */
196 node = &(hash->nodes[bucket]);
198 if (hash->comp_func)
200 while (*node && !(hash->comp_func((*node)->key, key)))
201 node = &(*node)->next;
203 else
205 /* No comp_func means we're doing pointer comparisons */
206 while (*node && (*node)->key != key)
207 node = &(*node)->next;
210 /* ne_warn("Node %x", node); */
211 return node;
214 /* Ok, we're doing some weirdness here... */
215 static NEOERR *_hash_resize(NE_HASH *hash)
217 NE_HASHNODE **new_nodes;
218 NE_HASHNODE *entry, *prev;
219 int x, next_bucket;
220 int orig_size = hash->size;
221 UINT32 hash_mask;
223 if (hash->size > hash->num)
224 return STATUS_OK;
226 /* We always double in size */
227 new_nodes = (NE_HASHNODE **) realloc (hash->nodes, (hash->size*2) * sizeof(NE_HASHNODE));
228 if (new_nodes == NULL)
229 return nerr_raise(NERR_NOMEM, "Unable to allocate memory to resize NE_HASH");
231 hash->nodes = new_nodes;
232 orig_size = hash->size;
233 hash->size = hash->size*2;
235 /* Initialize new parts */
236 for (x = orig_size; x < hash->size; x++)
238 hash->nodes[x] = NULL;
241 hash_mask = hash->size - 1;
243 for (x = 0; x < orig_size; x++)
245 prev = NULL;
246 next_bucket = x + orig_size;
247 for (entry = hash->nodes[x];
248 entry;
249 entry = prev ? prev->next : hash->nodes[x])
251 if ((entry->hashv & hash_mask) != x)
253 if (prev)
255 prev->next = entry->next;
257 else
259 hash->nodes[x] = entry->next;
261 entry->next = hash->nodes[next_bucket];
262 hash->nodes[next_bucket] = entry;
264 else
266 prev = entry;
271 return STATUS_OK;
274 int ne_hash_str_comp(const void *a, const void *b)
276 return !strcmp((const char *)a, (const char *)b);
279 UINT32 ne_hash_str_hash(const void *a)
281 return ne_crc((unsigned char *)a, strlen((const char *)a));
284 int ne_hash_int_comp(const void *a, const void *b)
286 if (a == b) return 1;
287 return 0;
290 UINT32 ne_hash_int_hash(const void *a)
292 return (UINT32)(long)(a);