aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/tests/evas_hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/tests/evas_hash.c')
-rw-r--r--libraries/eina/src/tests/evas_hash.c536
1 files changed, 536 insertions, 0 deletions
diff --git a/libraries/eina/src/tests/evas_hash.c b/libraries/eina/src/tests/evas_hash.c
new file mode 100644
index 0000000..33615af
--- /dev/null
+++ b/libraries/eina/src/tests/evas_hash.c
@@ -0,0 +1,536 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdlib.h>
6#include <string.h>
7
8#include "Evas_Data.h"
9
10typedef struct _Evas_Hash_El Evas_Hash_El;
11
12struct _Evas_Hash_El
13{
14 Evas_Object_List _list_data;
15 const char *key;
16 void *data;
17};
18
19static inline int _evas_hash_gen(const char *key);
20
21static int _evas_hash_alloc_error = 0;
22
23static inline int
24_evas_hash_gen(const char *key)
25{
26 unsigned int hash_num = 5381;
27 const unsigned char *ptr;
28
29 if (!key)
30 return 0;
31
32 for (ptr = (unsigned char *)key; *ptr; ptr++)
33 hash_num = (hash_num * 33) ^ *ptr;
34
35 hash_num &= 0xff;
36 return (int)hash_num;
37}
38
39/**
40 * @defgroup Evas_Hash_Data Hash Data Functions
41 *
42 * Functions that add, access or remove data from hashes.
43 *
44 * The following example shows how to add and then access data in a
45 * hash table:
46 * @code
47 * Evas_Hash *hash = NULL;
48 * extern void *my_data;
49 *
50 * hash = evas_hash_add(hash, "My Data", my_data);
51 * if (evas_hash_alloc_error())
52 * {
53 * fprintf(stderr, "ERROR: Memory is low. Hash allocation failed.\n");
54 * exit(-1);
55 * }
56 * if (evas_hash_find(hash, "My Data") == my_data)
57 * {
58 * printf("My Data inserted and successfully found.\n");
59 * }
60 * @endcode
61 *
62 * What follows is another example, showing how the @ref evas_hash_del
63 * function is used:
64 * @code
65 * extern Evas_Hash *hash;
66 * extern void *data;
67 *
68 * printf("Insert some data...\n");
69 * hash = evas_hash_add(hash, "My Data", my_data);
70 * printf("Removing by key...\n");
71 * hash = evas_hash_del(hash, "My Data", NULL);
72 * printf("Insert some more data as a NULL key...\n");
73 * hash = evas_hash_add(hash, NULL, my_data);
74 * printf("Removing by data as a NULL key...\n");
75 * hash = evas_hash_del(hash, NULL, my_data);
76 * @endcode
77 */
78
79/**
80 * Adds an entry to the given hash table.
81 *
82 * @p key is expected to be a unique string within the hash table.
83 * Otherwise, you cannot be sure which inserted data pointer will be
84 * accessed with @ref evas_hash_find , and removed with
85 * @ref evas_hash_del .
86 *
87 * Key strings are case sensitive.
88 *
89 * @ref evas_hash_alloc_error should be used to determine if an
90 * allocation error occurred during this function.
91 *
92 * @param hash The given hash table. Can be @c NULL, in which case a
93 * new hash table is allocated and returned.
94 * @param key A unique string. Can be @c NULL.
95 * @param data Data to associate with the string given by @p key.
96 * @return Either the given hash table, or if the given value for @p
97 * hash is @c NULL, then a new one. @c NULL will be returned
98 * if memory could not be allocated for a new table.
99 * @ingroup Evas_Hash_Data
100 */
101EAPI Evas_Hash *
102evas_hash_add(Evas_Hash *hash, const char *key, const void *data)
103{
104 int hash_num;
105 Evas_Hash_El *el;
106
107 if ((!key) || (!data))
108 return hash;
109
110 _evas_hash_alloc_error = 0;
111 if (!hash)
112 {
113 hash = calloc(1, sizeof(struct _Evas_Hash));
114 if (!hash)
115 {
116 _evas_hash_alloc_error = 1;
117 return NULL;
118 }
119 }
120
121 if (!(el = malloc(sizeof(struct _Evas_Hash_El) + strlen(key) + 1)))
122 {
123 if (hash->population <= 0)
124 {
125 free(hash);
126 hash = NULL;
127 }
128
129 _evas_hash_alloc_error = 1;
130 return hash;
131 }
132
133 el->key = ((char *)el) + sizeof(struct _Evas_Hash_El);
134 strcpy((char *)el->key, key);
135 el->data = (void *)data;
136 hash_num = _evas_hash_gen(key);
137 hash->buckets[hash_num] = evas_object_list_prepend(hash->buckets[hash_num],
138 el);
139 hash->population++;
140 return hash;
141}
142
143/**
144 * Adds an entry to the given hash table and does not duplicate the string key.
145 *
146 * @p key is expected to be a unique string within the hash table.
147 * Otherwise, you cannot be sure which inserted data pointer will be
148 * accessed with @ref evas_hash_find , and removed with
149 * @ref evas_hash_del . This call does not make a copy of the key so it must
150 * be a string constant or stored elsewhere (in the object being added) etc.
151 *
152 * Key strings are case sensitive.
153 *
154 * @ref evas_hash_alloc_error should be used to determine if an
155 * allocation error occurred during this function.
156 *
157 * @param hash The given hash table. Can be @c NULL, in which case a
158 * new hash table is allocated and returned.
159 * @param key A unique string. Can be @c NULL.
160 * @param data Data to associate with the string given by @p key.
161 * @return Either the given hash table, or if the given value for @p
162 * hash is @c NULL, then a new one. @c NULL will be returned
163 * if memory could not be allocated for a new table.
164 * @ingroup Evas_Hash_Data
165 */
166EAPI Evas_Hash *
167evas_hash_direct_add(Evas_Hash *hash, const char *key, const void *data)
168{
169 int hash_num;
170 Evas_Hash_El *el;
171
172 if ((!key) || (!data))
173 return hash;
174
175 _evas_hash_alloc_error = 0;
176 if (!hash)
177 {
178 hash = calloc(1, sizeof(struct _Evas_Hash));
179 if (!hash)
180 {
181 _evas_hash_alloc_error = 1;
182 return NULL;
183 }
184 }
185
186 if (!(el = malloc(sizeof(struct _Evas_Hash_El))))
187 {
188 if (hash->population <= 0)
189 {
190 free(hash);
191 hash = NULL;
192 }
193
194 _evas_hash_alloc_error = 1;
195 return hash;
196 }
197
198 el->key = key;
199 el->data = (void *)data;
200 hash_num = _evas_hash_gen(key);
201 hash->buckets[hash_num] = evas_object_list_prepend(hash->buckets[hash_num],
202 el);
203 hash->population++;
204 return hash;
205}
206
207/**
208 * Removes the entry identified by @p key or @p data from the given
209 * hash table.
210 *
211 * If @p key is @c NULL, then @p data is used to find a match to
212 * remove.
213 *
214 * @param hash The given hash table.
215 * @param key The key string. Can be @c NULL.
216 * @param data The data pointer to remove if @p key is @c NULL.
217 * Otherwise, not required and can be @c NULL.
218 * @return The modified hash table. If there are no entries left, the
219 * hash table will be freed and @c NULL will be returned.
220 * @ingroup Evas_Hash_Data
221 */
222EAPI Evas_Hash *
223evas_hash_del(Evas_Hash *hash, const char *key, const void *data)
224{
225 int hash_num;
226 Evas_Hash_El *el;
227 Evas_Object_List *l;
228
229 if (!hash)
230 return NULL;
231
232 if (!key)
233 for (hash_num = 0; hash_num < 256; hash_num++)
234 {
235 for (l = hash->buckets[hash_num]; l; l = l->next)
236 {
237 el = (Evas_Hash_El *)l;
238 if (el->data == data)
239 {
240 hash->buckets[hash_num] = evas_object_list_remove(
241 hash->buckets[hash_num],
242 el);
243 free(el);
244 hash->population--;
245 if (hash->population <= 0)
246 {
247 free(hash);
248 hash = NULL;
249 }
250
251 return hash;
252 }
253 }
254 }
255 else
256 {
257 hash_num = _evas_hash_gen(key);
258 for (l = hash->buckets[hash_num]; l; l = l->next)
259 {
260 el = (Evas_Hash_El *)l;
261 if (!strcmp(el->key, key))
262 if ((!data) || (el->data == data))
263 {
264 hash->buckets[hash_num] = evas_object_list_remove(
265 hash->buckets[hash_num],
266 el);
267 free(el);
268 hash->population--;
269 if (hash->population <= 0)
270 {
271 free(hash);
272 hash = NULL;
273 }
274
275 return hash;
276 }
277
278 }
279 }
280
281 return hash;
282}
283
284/**
285 * Retrieves a specific entry in the given hash table.
286 * @param hash The given hash table.
287 * @param key The key string of the entry to find.
288 * @return The data pointer for the stored entry, or @c NULL if not
289 * found.
290 * @ingroup Evas_Hash_Data
291 */
292EAPI void *
293evas_hash_find(const Evas_Hash *hash, const char *key)
294{
295 int hash_num;
296 Evas_Hash_El *el;
297 Evas_Object_List *l;
298
299 _evas_hash_alloc_error = 0;
300 if ((!hash) || (!key))
301 return NULL;
302
303 hash_num = _evas_hash_gen(key);
304 for (l = hash->buckets[hash_num]; l; l = l->next)
305 {
306 el = (Evas_Hash_El *)l;
307 if (!strcmp(el->key, key))
308 {
309 if (l != hash->buckets[hash_num])
310 {
311 Evas_Object_List *bucket;
312
313 bucket = hash->buckets[hash_num];
314 bucket = evas_object_list_remove(bucket, el);
315 bucket = evas_object_list_prepend(bucket, el);
316 ((Evas_Hash *)hash)->buckets[hash_num] = bucket;
317 }
318
319 return el->data;
320 }
321 }
322 return NULL;
323}
324
325/**
326 * Modifies the entry pointer at the specified key and returns the old entry
327 * @param hash The given hash table.
328 * @param key The key string of the entry to modify.
329 * @param data The data to replace the old entry, if it exists.
330 * @return The data pointer for the old stored entry, or @c NULL if not
331 * found. If an existing entry is not found, nothing is added to the
332 * hash.
333 * @ingroup Evas_Hash_Data
334 */
335EAPI void *
336evas_hash_modify(Evas_Hash *hash, const char *key, const void *data)
337{
338 int hash_num;
339 Evas_Hash_El *el;
340 Evas_Object_List *l;
341
342 _evas_hash_alloc_error = 0;
343 if (!hash)
344 return NULL;
345
346 hash_num = _evas_hash_gen(key);
347 for (l = hash->buckets[hash_num]; l; l = l->next)
348 {
349 el = (Evas_Hash_El *)l;
350 if ((key) && (!strcmp(el->key, key)))
351 {
352 void *old_data;
353
354 if (l != hash->buckets[hash_num])
355 {
356 hash->buckets[hash_num] = evas_object_list_remove(
357 hash->buckets[hash_num],
358 el);
359 hash->buckets[hash_num] = evas_object_list_prepend(
360 hash->buckets[hash_num],
361 el);
362 }
363
364 old_data = el->data;
365 el->data = (void *)data;
366 return old_data;
367 }
368 }
369 return NULL;
370}
371
372/**
373 * @defgroup Evas_Hash_General_Group Hash General Functions
374 *
375 * Miscellaneous functions that operate on hash objects.
376 */
377
378/**
379 * Retrieves the number of buckets available in the given hash table.
380 * @param hash The given hash table.
381 * @return @c 256 if @p hash is not @c NULL. @c 0 otherwise.
382 * @ingroup Evas_Hash_General_Group
383 */
384EAPI int
385evas_hash_size(const Evas_Hash *hash)
386{
387 if (!hash)
388 return 0;
389
390 return 256;
391}
392
393/**
394 * @todo Complete polishing documentation for evas_hash.c. The
395 * functions' docs may be grouped, but they need some simplification.
396 */
397
398/**
399 * Free an entire hash table
400 * @param hash The hash table to be freed
401 *
402 * This function frees up all the memory allocated to storing the specified
403 * hash tale pointed to by @p hash. Any entries in the table that the program
404 * has no more pointers for elsewhere may now be lost, so this should only be
405 * called if the program has lready freed any allocated data in the hash table
406 * or has the pointers for data in the table stored elswehere as well.
407 *
408 * Example:
409 * @code
410 * extern Evas_Hash *hash;
411 *
412 * evas_hash_free(hash);
413 * hash = NULL;
414 * @endcode
415 * @ingroup Evas_Hash_General_Group
416 */
417EAPI void
418evas_hash_free(Evas_Hash *hash)
419{
420 int i, size;
421
422 if (!hash)
423 return;
424
425 size = evas_hash_size(hash);
426 for (i = 0; i < size; i++)
427 {
428 while (hash->buckets[i])
429 {
430 Evas_Hash_El *el;
431
432 el = (Evas_Hash_El *)hash->buckets[i];
433 hash->buckets[i] = evas_object_list_remove(hash->buckets[i], el);
434 free(el);
435 }
436 }
437 free(hash);
438}
439
440/**
441 * Call a function on every member stored in the hash table
442 * @param hash The hash table whose members will be walked
443 * @param func The function to call on each parameter
444 * @param fdata The data pointer to pass to the function being called
445 *
446 * This function goes through every entry in the hash table @p hash and calls
447 * the function @p func on each member. The function should NOT modify the
448 * hash table contents if it returns 1. IF the hash table contents are
449 * modified by this function or the function wishes to stop processing it must
450 * return 0, otherwise return 1 to keep processing.
451 *
452 * Example:
453 * @code
454 * extern Evas_Hash *hash;
455 *
456 * Evas_Bool hash_fn(Evas_Hash *hash, const char *key, void *data, void *fdata)
457 * {
458 * printf("Func data: %s, Hash entry: %s / %p\n", fdata, key, data);
459 * return 1;
460 * }
461 *
462 * int main(int argc, char **argv)
463 * {
464 * char *hash_fn_data;
465 *
466 * hash_fn_data = strdup("Hello World");
467 * evas_hash_foreach(hash, hash_fn, hash_fn_data);
468 * free(hash_fn_data);
469 * }
470 * @endcode
471 * @ingroup Evas_Hash_General_Group
472 */
473EAPI void
474evas_hash_foreach(const Evas_Hash *hash, Evas_Bool (*func)(
475 const Evas_Hash *hash,
476 const char *key,
477 void *data,
478 void *fdata), const void *fdata)
479{
480 int i, size;
481
482 if (!hash)
483 return;
484
485 size = evas_hash_size(hash);
486 for (i = 0; i < size; i++)
487 {
488 Evas_Object_List *l, *next_l;
489
490 for (l = hash->buckets[i]; l; )
491 {
492 Evas_Hash_El *el;
493
494 next_l = l->next;
495 el = (Evas_Hash_El *)l;
496 if (!func(hash, el->key, el->data, (void *)fdata))
497 return;
498
499 l = next_l;
500 }
501 }
502}
503
504/**
505 * Return memory allocation failure flag after an function requiring allocation
506 * @return The state of the allocation flag
507 *
508 * This function returns the state of the memory allocation flag. This flag is
509 * set if memory allocations fail during evas_hash_add() calls. If they do, 1
510 * will be returned, otherwise 0 will be returned. The flag will remain in its
511 * current state until the next call that requires allocation is called, and
512 * is then reset.
513 *
514 * Example:
515 * @code
516 * Evas_Hash *hash = NULL;
517 * extern void *my_data;
518 *
519 * hash = evas_hash_add(hash, "My Data", my_data);
520 * if (evas_hash_alloc_error())
521 * {
522 * fprintf(stderr, "ERROR: Memory is low. Hash allocation failed.\n");
523 * exit(-1);
524 * }
525 * if (evas_hash_find(hash, "My Data") == my_data)
526 * {
527 * printf("My Data inserted and successfully found.\n");
528 * }
529 * @endcode
530 * @ingroup Evas_Hash_General_Group
531 */
532EAPI int
533evas_hash_alloc_error(void)
534{
535 return _evas_hash_alloc_error;
536}