2 * Copyright 2003-2004 Brandon Long
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"
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
));
30 return nerr_raise(NERR_NOMEM
, "Unable to allocate memory for NE_HASH");
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
)
41 return nerr_raise(NERR_NOMEM
, "Unable to allocate memory for NE_HASHNODES");
49 void ne_hash_destroy (NE_HASH
**hash
)
52 NE_HASHNODE
*node
, *next
;
55 if (hash
== NULL
|| *hash
== NULL
)
60 for (x
= 0; x
< my_hash
->size
; x
++)
62 node
= my_hash
->nodes
[x
];
71 my_hash
->nodes
= NULL
;
76 NEOERR
*ne_hash_insert(NE_HASH
*hash
, void *key
, void *value
)
81 node
= _hash_lookup_node(hash
, key
, &hashv
);
85 (*node
)->value
= value
;
89 *node
= (NE_HASHNODE
*) malloc(sizeof(NE_HASHNODE
));
91 return nerr_raise(NERR_NOMEM
, "Unable to allocate NE_HASHNODE");
93 (*node
)->hashv
= hashv
;
95 (*node
)->value
= value
;
100 return _hash_resize(hash
);
103 void *ne_hash_lookup(NE_HASH
*hash
, void *key
)
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
;
117 node
= _hash_lookup_node(hash
, key
, NULL
);
129 int ne_hash_has_key(NE_HASH
*hash
, void *key
)
133 node
= *_hash_lookup_node(hash
, key
, NULL
);
139 void *ne_hash_next(NE_HASH
*hash
, void **key
)
141 NE_HASHNODE
**node
= 0;
142 UINT32 hashv
, bucket
;
146 node
= _hash_lookup_node(hash
, key
, NULL
);
150 bucket
= (*node
)->hashv
& (hash
->size
- 1);
154 hashv
= hash
->hash_func(*key
);
155 bucket
= hashv
& (hash
->size
- 1);
167 *key
= (*node
)->next
->key
;
168 return (*node
)->next
->value
;
173 while (bucket
< hash
->size
)
175 if (hash
->nodes
[bucket
])
177 *key
= hash
->nodes
[bucket
]->key
;
178 return hash
->nodes
[bucket
]->value
;
186 static NE_HASHNODE
**_hash_lookup_node (NE_HASH
*hash
, void *key
, UINT32
*o_hashv
)
188 UINT32 hashv
, bucket
;
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
]);
200 while (*node
&& !(hash
->comp_func((*node
)->key
, key
)))
201 node
= &(*node
)->next
;
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); */
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
;
220 int orig_size
= hash
->size
;
223 if (hash
->size
> hash
->num
)
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
++)
246 next_bucket
= x
+ orig_size
;
247 for (entry
= hash
->nodes
[x
];
249 entry
= prev
? prev
->next
: hash
->nodes
[x
])
251 if ((entry
->hashv
& hash_mask
) != x
)
255 prev
->next
= entry
->next
;
259 hash
->nodes
[x
] = entry
->next
;
261 entry
->next
= hash
->nodes
[next_bucket
];
262 hash
->nodes
[next_bucket
] = entry
;
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;
290 UINT32
ne_hash_int_hash(const void *a
)
292 return (UINT32
)(long)(a
);