efl
536 строк · 14.4 Кб
1#ifdef HAVE_CONFIG_H2# include "config.h"3#endif4
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_El13{
14Evas_Object_List _list_data;15const char *key;16void *data;17};18
19static inline int _evas_hash_gen(const char *key);20
21static int _evas_hash_alloc_error = 0;22
23static inline int24_evas_hash_gen(const char *key)25{
26unsigned int hash_num = 5381;27const unsigned char *ptr;28
29if (!key)30return 0;31
32for (ptr = (unsigned char *)key; *ptr; ptr++)33hash_num = (hash_num * 33) ^ *ptr;34
35hash_num &= 0xff;36return (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{
104int hash_num;105Evas_Hash_El *el;106
107if ((!key) || (!data))108return hash;109
110_evas_hash_alloc_error = 0;111if (!hash)112{113hash = calloc(1, sizeof(struct _Evas_Hash));114if (!hash)115{116_evas_hash_alloc_error = 1;117return NULL;118}119}120
121if (!(el = malloc(sizeof(struct _Evas_Hash_El) + strlen(key) + 1)))122{123if (hash->population <= 0)124{125free(hash);126hash = NULL;127}128
129_evas_hash_alloc_error = 1;130return hash;131}132
133el->key = ((char *)el) + sizeof(struct _Evas_Hash_El);134strcpy((char *)el->key, key);135el->data = (void *)data;136hash_num = _evas_hash_gen(key);137hash->buckets[hash_num] = evas_object_list_prepend(hash->buckets[hash_num],138el);139hash->population++;140return 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{
169int hash_num;170Evas_Hash_El *el;171
172if ((!key) || (!data))173return hash;174
175_evas_hash_alloc_error = 0;176if (!hash)177{178hash = calloc(1, sizeof(struct _Evas_Hash));179if (!hash)180{181_evas_hash_alloc_error = 1;182return NULL;183}184}185
186if (!(el = malloc(sizeof(struct _Evas_Hash_El))))187{188if (hash->population <= 0)189{190free(hash);191hash = NULL;192}193
194_evas_hash_alloc_error = 1;195return hash;196}197
198el->key = key;199el->data = (void *)data;200hash_num = _evas_hash_gen(key);201hash->buckets[hash_num] = evas_object_list_prepend(hash->buckets[hash_num],202el);203hash->population++;204return 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{
225int hash_num;226Evas_Hash_El *el;227Evas_Object_List *l;228
229if (!hash)230return NULL;231
232if (!key)233for (hash_num = 0; hash_num < 256; hash_num++)234{235for (l = hash->buckets[hash_num]; l; l = l->next)236{237el = (Evas_Hash_El *)l;238if (el->data == data)239{240hash->buckets[hash_num] = evas_object_list_remove(241hash->buckets[hash_num],242el);243free(el);244hash->population--;245if (hash->population <= 0)246{247free(hash);248hash = NULL;249}250
251return hash;252}253}254}255else256{257hash_num = _evas_hash_gen(key);258for (l = hash->buckets[hash_num]; l; l = l->next)259{260el = (Evas_Hash_El *)l;261if (!strcmp(el->key, key))262if ((!data) || (el->data == data))263{264hash->buckets[hash_num] = evas_object_list_remove(265hash->buckets[hash_num],266el);267free(el);268hash->population--;269if (hash->population <= 0)270{271free(hash);272hash = NULL;273}274
275return hash;276}277
278}279}280
281return 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{
295int hash_num;296Evas_Hash_El *el;297Evas_Object_List *l;298
299_evas_hash_alloc_error = 0;300if ((!hash) || (!key))301return NULL;302
303hash_num = _evas_hash_gen(key);304for (l = hash->buckets[hash_num]; l; l = l->next)305{306el = (Evas_Hash_El *)l;307if (!strcmp(el->key, key))308{309if (l != hash->buckets[hash_num])310{311Evas_Object_List *bucket;312
313bucket = hash->buckets[hash_num];314bucket = evas_object_list_remove(bucket, el);315bucket = evas_object_list_prepend(bucket, el);316((Evas_Hash *)hash)->buckets[hash_num] = bucket;317}318
319return el->data;320}321}322return 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{
338int hash_num;339Evas_Hash_El *el;340Evas_Object_List *l;341
342_evas_hash_alloc_error = 0;343if (!hash)344return NULL;345
346hash_num = _evas_hash_gen(key);347for (l = hash->buckets[hash_num]; l; l = l->next)348{349el = (Evas_Hash_El *)l;350if ((key) && (!strcmp(el->key, key)))351{352void *old_data;353
354if (l != hash->buckets[hash_num])355{356hash->buckets[hash_num] = evas_object_list_remove(357hash->buckets[hash_num],358el);359hash->buckets[hash_num] = evas_object_list_prepend(360hash->buckets[hash_num],361el);362}363
364old_data = el->data;365el->data = (void *)data;366return old_data;367}368}369return 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 int385evas_hash_size(const Evas_Hash *hash)386{
387if (!hash)388return 0;389
390return 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 void418evas_hash_free(Evas_Hash *hash)419{
420int i, size;421
422if (!hash)423return;424
425size = evas_hash_size(hash);426for (i = 0; i < size; i++)427{428while (hash->buckets[i])429{430Evas_Hash_El *el;431
432el = (Evas_Hash_El *)hash->buckets[i];433hash->buckets[i] = evas_object_list_remove(hash->buckets[i], el);434free(el);435}436}437free(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 void474evas_hash_foreach(const Evas_Hash *hash, Evas_Bool (*func)(475const Evas_Hash *hash,476const char *key,477void *data,478void *fdata), const void *fdata)479{
480int i, size;481
482if (!hash)483return;484
485size = evas_hash_size(hash);486for (i = 0; i < size; i++)487{488Evas_Object_List *l, *next_l;489
490for (l = hash->buckets[i]; l; )491{492Evas_Hash_El *el;493
494next_l = l->next;495el = (Evas_Hash_El *)l;496if (!func(hash, el->key, el->data, (void *)fdata))497return;498
499l = 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 int533evas_hash_alloc_error(void)534{
535return _evas_hash_alloc_error;536}
537