eet: unborking !
[framework/uifw/eet.git] / src / lib / eet_dictionary.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif /* ifdef HAVE_CONFIG_H */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <math.h>
8
9 #include <Eina.h>
10
11 #include "Eet.h"
12 #include "Eet_private.h"
13
14 Eet_Dictionary *
15 eet_dictionary_add(void)
16 {
17    Eet_Dictionary *new;
18
19    new = eet_dictionary_calloc(1);
20    if (!new)
21      return NULL;
22
23    memset(new->hash, -1, sizeof (int) * 256);
24    eina_lock_new(&new->mutex);
25
26    return new;
27 }
28
29 void
30 eet_dictionary_free(Eet_Dictionary *ed)
31 {
32    int i;
33
34    if (!ed) return;
35
36    eina_lock_free(&ed->mutex);
37
38    for (i = 0; i < ed->count; ++i)
39      if (ed->all[i].allocated)
40        eina_stringshare_del(ed->all[i].str);
41
42    if (ed->all)
43      free(ed->all);
44
45    if (ed->converts) eina_hash_free(ed->converts);
46
47    eet_dictionary_mp_free(ed);
48 }
49
50 static int
51 _eet_dictionary_lookup(Eet_Dictionary *ed,
52                        const char     *string,
53                        int             len,
54                        int             hash)
55 {
56    Eina_Bool found = EINA_FALSE;
57    int prev = -1;
58    int current;
59
60    current = ed->hash[hash];
61
62    while (current != -1)
63      {
64         if (ed->all[current].len == len)
65           {
66              if (ed->all[current].str &&
67                  ((ed->all[current].str == string) ||
68                      (!strcmp(ed->all[current].str, string))))
69                {
70                   found = EINA_TRUE;
71                   break;
72                }
73           }
74
75         prev = current;
76         current = ed->all[current].next;
77      }
78
79    if ((current == -1) && found)
80      return prev;
81
82    return current;
83 }
84
85 int
86 eet_dictionary_string_add(Eet_Dictionary *ed,
87                           const char     *string)
88 {
89    Eet_String *current;
90    const char *str;
91    int hash;
92    int idx;
93    int len;
94    int cnt;
95
96    if (!ed)
97      return -1;
98
99    hash = _eet_hash_gen(string, 8);
100    len = strlen(string) + 1;
101
102    eina_lock_take(&ed->mutex);
103
104    idx = _eet_dictionary_lookup(ed, string, len, hash);
105
106    if (idx != -1)
107      {
108         if (ed->all[idx].str && 
109             ((ed->all[idx].str == string) ||
110                 (!strcmp(ed->all[idx].str, string))))
111           {
112             eina_lock_release(&ed->mutex);
113             return idx;
114           }
115      }
116
117    if (ed->total == ed->count)
118      {
119         Eet_String *new;
120         int total;
121
122         total = ed->total + 8;
123
124         new = realloc(ed->all, total * sizeof(Eet_String));
125         if (!new) goto on_error;
126
127         ed->all = new;
128         ed->total = total;
129      }
130
131    str = eina_stringshare_add(string);
132    if (!str) goto on_error;
133
134    current = ed->all + ed->count;
135
136    current->allocated = EINA_TRUE;
137
138    current->hash = hash;
139
140    current->str = str;
141    current->len = len;
142
143    if (idx == -1)
144      {
145         current->next = ed->hash[hash];
146         current->prev = -1;
147         ed->hash[hash] = ed->count;
148      }
149    else
150      {
151         current->next = idx;
152         current->prev = ed->all[idx].prev;
153
154         if (current->next != -1)
155           ed->all[current->next].prev = ed->count;
156
157         if (current->prev != -1)
158           ed->all[current->prev].next = ed->count;
159         else
160           ed->hash[hash] = ed->count;
161      }
162
163    cnt = ed->count++;
164    eina_lock_release(&ed->mutex);
165    return cnt;
166
167  on_error:
168    eina_lock_release(&ed->mutex);
169    return -1;
170 }
171
172 int
173 eet_dictionary_string_get_size(const Eet_Dictionary *ed,
174                                int                   idx)
175 {
176    int length = 0;
177
178    if (!ed) goto done;
179
180    if (idx < 0) goto done;
181
182    eina_lock_take((Eina_Lock*) &ed->mutex);
183
184    if (idx < ed->count)
185      length = ed->all[idx].len;
186
187    eina_lock_release((Eina_Lock*) &ed->mutex);
188
189  done:
190    return length;
191 }
192
193 EAPI int
194 eet_dictionary_count(const Eet_Dictionary *ed)
195 {
196   return ed->count;
197 }
198
199 int
200 eet_dictionary_string_get_hash(const Eet_Dictionary *ed,
201                                int                   idx)
202 {
203    int hash = -1;
204
205    if (!ed) goto done;
206
207    if (idx < 0) goto done;
208
209    eina_lock_take((Eina_Lock*) &ed->mutex);
210
211    if (idx < ed->count)
212      hash = ed->all[idx].hash;
213
214    eina_lock_release((Eina_Lock*) &ed->mutex);
215
216  done:
217    return hash;
218 }
219
220 const char *
221 eet_dictionary_string_get_char(const Eet_Dictionary *ed,
222                                int                   idx)
223 {
224    const char *s = NULL;
225
226    if (!ed) goto done;
227
228    if (idx < 0) goto done;
229
230    eina_lock_take((Eina_Lock*) &ed->mutex);
231
232    if (idx < ed->count)
233      {
234 #ifdef _WIN32
235         /* Windows file system could change the mmaped file when replacing a file. So we need to copy all string in memory to avoid bugs. */
236         if (!ed->all[idx].allocated)
237           {
238              ed->all[idx].str = eina_stringshare_add(ed->all[idx].str);
239              ed->all[idx].allocated = EINA_TRUE;
240           }
241 #endif /* ifdef _WIN32 */
242         s = ed->all[idx].str;
243      }
244
245    eina_lock_release((Eina_Lock*) &ed->mutex);
246
247  done:
248    return s;
249 }
250
251 static inline Eina_Bool
252 _eet_dictionary_string_get_me_cache(const char *s,
253                                     int         len,
254                                     int        *mantisse,
255                                     int        *exponent)
256 {
257    if ((len == 6) && (s[0] == '0') && (s[1] == 'x') && (s[3] == 'p'))
258      {
259         *mantisse = (s[2] >= 'a') ? (s[2] - 'a' + 10) : (s[2] - '0');
260         *exponent = (s[5] - '0');
261
262         return EINA_TRUE;
263      }
264
265    return EINA_FALSE;
266 }
267
268 static inline Eina_Bool
269 _eet_dictionary_string_get_float_cache(const char *s,
270                                        int         len,
271                                        float      *result)
272 {
273    int mantisse;
274    int exponent;
275
276    if (_eet_dictionary_string_get_me_cache(s, len, &mantisse, &exponent))
277      {
278         if (s[4] == '+')
279           *result = (float)(mantisse << exponent);
280         else
281           *result = (float)mantisse / (float)(1 << exponent);
282
283         return EINA_TRUE;
284      }
285
286    return EINA_FALSE;
287 }
288
289 static inline Eina_Bool
290 _eet_dictionary_string_get_double_cache(const char *s,
291                                         int         len,
292                                         double     *result)
293 {
294    int mantisse;
295    int exponent;
296
297    if (_eet_dictionary_string_get_me_cache(s, len, &mantisse, &exponent))
298      {
299         if (s[4] == '+')
300           *result = (double)(mantisse << exponent);
301         else
302           *result = (double)mantisse / (float)(1 << exponent);
303
304         return EINA_TRUE;
305      }
306
307    return EINA_FALSE;
308 }
309
310 static inline Eina_Bool
311 _eet_dictionary_test(const Eet_Dictionary *ed,
312                      int                   idx,
313                      void                 *result)
314 {
315    Eina_Bool limit = EINA_FALSE;
316
317    if (!result) goto done;
318
319    if (!ed) goto done;
320
321    if (idx < 0) goto done;
322
323    eina_lock_take((Eina_Lock*) &ed->mutex);
324
325    if (!(idx < ed->count)) goto unlock_done;
326
327    limit = EINA_TRUE;
328
329  unlock_done:
330    eina_lock_release((Eina_Lock*) &ed->mutex);
331
332  done:
333    return limit;
334 }
335
336 static Eet_Convert *
337 eet_dictionary_convert_get(const Eet_Dictionary *ed,
338                            int                   idx,
339                            const char          **str)
340 {
341    Eet_Convert *result;
342
343    eina_lock_take((Eina_Lock*) &ed->mutex);
344
345    *str = ed->all[idx].str;
346
347    if (!ed->converts)
348      {
349         ((Eet_Dictionary *)ed)->converts = eina_hash_int32_new(free);
350
351         goto add_convert;
352      }
353
354    result = eina_hash_find(ed->converts, &idx);
355    if (result) goto done;
356
357  add_convert:
358    result = calloc(1, sizeof (Eet_Convert));
359
360    eina_hash_add(ed->converts, &idx, result);
361
362  done:
363    eina_lock_release((Eina_Lock*) &ed->mutex);
364
365    return result;
366 }
367
368 Eina_Bool
369 eet_dictionary_string_get_float(const Eet_Dictionary *ed,
370                                 int                   idx,
371                                 float                *result)
372 {
373    Eet_Convert *convert;
374    const char *str;
375
376    if (!_eet_dictionary_test(ed, idx, result))
377      return EINA_FALSE;
378
379    convert = eet_dictionary_convert_get(ed, idx, &str);
380    if (!convert) return EINA_FALSE;
381
382    if (!(convert->type & EET_D_FLOAT))
383      {
384         eina_lock_take((Eina_Lock*) &ed->mutex);
385         if (!_eet_dictionary_string_get_float_cache(str, ed->all[idx].len,
386                                                     &convert->f))
387           {
388              long long mantisse = 0;
389              long exponent = 0;
390
391              if (eina_convert_atod(str, ed->all[idx].len, &mantisse,
392                                    &exponent) == EINA_FALSE)
393                {
394                   eina_lock_release((Eina_Lock*) &ed->mutex);
395                   return EINA_FALSE;
396                }
397
398              convert->f = ldexpf((float)mantisse, exponent);
399           }
400         eina_lock_release((Eina_Lock*) &ed->mutex);
401
402         convert->type |= EET_D_FLOAT;
403      }
404
405    *result = convert->f;
406    return EINA_TRUE;
407 }
408
409 Eina_Bool
410 eet_dictionary_string_get_double(const Eet_Dictionary *ed,
411                                  int                   idx,
412                                  double               *result)
413 {
414    Eet_Convert *convert;
415    const char *str;
416
417    if (!_eet_dictionary_test(ed, idx, result))
418      return EINA_FALSE;
419
420    convert = eet_dictionary_convert_get(ed, idx, &str);
421    if (!convert) return EINA_FALSE;
422
423    if (!(convert->type & EET_D_DOUBLE))
424      {
425         eina_lock_take((Eina_Lock*) &ed->mutex);
426
427         if (!_eet_dictionary_string_get_double_cache(str, ed->all[idx].len,
428                                                      &convert->d))
429           {
430              long long mantisse = 0;
431              long exponent = 0;
432
433              if (eina_convert_atod(str, ed->all[idx].len, &mantisse,
434                                    &exponent) == EINA_FALSE)
435                {
436                   eina_lock_release((Eina_Lock*) &ed->mutex);
437                   return EINA_FALSE;
438                }
439
440              convert->d = ldexp((double)mantisse, exponent);
441           }
442         eina_lock_release((Eina_Lock*) &ed->mutex);
443
444         convert->type |= EET_D_DOUBLE;
445      }
446
447    *result = convert->d;
448    return EINA_TRUE;
449 }
450
451 Eina_Bool
452 eet_dictionary_string_get_fp(const Eet_Dictionary *ed,
453                              int                   idx,
454                              Eina_F32p32          *result)
455 {
456    Eet_Convert *convert;
457    const char *str;
458
459    if (!_eet_dictionary_test(ed, idx, result))
460      return EINA_FALSE;
461
462    convert = eet_dictionary_convert_get(ed, idx, &str);
463    if (!convert) return EINA_FALSE;
464
465    if (!(convert->type & EET_D_FIXED_POINT))
466      {
467         Eina_F32p32 fp;
468
469         eina_lock_take((Eina_Lock*) &ed->mutex);
470         if (!eina_convert_atofp(str, ed->all[idx].len, &fp))
471           {
472              eina_lock_release((Eina_Lock*) &ed->mutex);
473              return EINA_FALSE;
474           }
475         eina_lock_release((Eina_Lock*) &ed->mutex);
476
477         convert->fp = fp;
478         convert->type |= EET_D_FIXED_POINT;
479      }
480
481    *result = convert->fp;
482    return EINA_TRUE;
483 }
484
485 EAPI int
486 eet_dictionary_string_check(Eet_Dictionary *ed,
487                             const char     *string)
488 {
489    int res = 0;
490    int i;
491
492    if ((!ed) || (!string))
493      return 0;
494
495    eina_lock_take(&ed->mutex);
496
497    if ((ed->start <= string) && (string < ed->end))
498      res = 1;
499
500    if (!res)
501      {
502         for (i = 0; i < ed->count; ++i)
503           if ((ed->all[i].allocated) && ed->all[i].str == string)
504             {
505                res = 1;
506                break;
507             }
508      }
509
510    eina_lock_release(&ed->mutex);
511
512    return res;
513 }
514