b06ca7736e3d2f4f50638bdae2a08a96643636b1
[profile/ivi/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    ed->count++;
164    cnt = ed->count;
165    eina_lock_release(&ed->mutex);
166    return cnt;
167
168  on_error:
169    eina_lock_release(&ed->mutex);
170    return -1;
171 }
172
173 int
174 eet_dictionary_string_get_size(const Eet_Dictionary *ed,
175                                int                   idx)
176 {
177    int length = 0;
178
179    if (!ed) goto done;
180
181    if (idx < 0) goto done;
182
183    eina_lock_take((Eina_Lock*) &ed->mutex);
184
185    if (idx < ed->count)
186      length = ed->all[idx].len;
187
188    eina_lock_release((Eina_Lock*) &ed->mutex);
189
190  done:
191    return length;
192 }
193
194 EAPI int
195 eet_dictionary_count(const Eet_Dictionary *ed)
196 {
197   return ed->count;
198 }
199
200 int
201 eet_dictionary_string_get_hash(const Eet_Dictionary *ed,
202                                int                   idx)
203 {
204    int hash = -1;
205
206    if (!ed) goto done;
207
208    if (idx < 0) goto done;
209
210    eina_lock_take((Eina_Lock*) &ed->mutex);
211
212    if (idx < ed->count)
213      hash = ed->all[idx].hash;
214
215    eina_lock_release((Eina_Lock*) &ed->mutex);
216
217  done:
218    return hash;
219 }
220
221 const char *
222 eet_dictionary_string_get_char(const Eet_Dictionary *ed,
223                                int                   idx)
224 {
225    const char *s = NULL;
226
227    if (!ed) goto done;
228
229    if (idx < 0) goto done;
230
231    eina_lock_take((Eina_Lock*) &ed->mutex);
232
233    if (idx < ed->count)
234      {
235 #ifdef _WIN32
236         /* Windows file system could change the mmaped file when replacing a file. So we need to copy all string in memory to avoid bugs. */
237         if (!ed->all[idx].allocated)
238           {
239              ed->all[idx].str = eina_stringshare_add(ed->all[idx].str);
240              ed->all[idx].allocated = EINA_TRUE;
241           }
242 #endif /* ifdef _WIN32 */
243         s = ed->all[idx].str;
244      }
245
246    eina_lock_release((Eina_Lock*) &ed->mutex);
247
248  done:
249    return s;
250 }
251
252 static inline Eina_Bool
253 _eet_dictionary_string_get_me_cache(const char *s,
254                                     int         len,
255                                     int        *mantisse,
256                                     int        *exponent)
257 {
258    if ((len == 6) && (s[0] == '0') && (s[1] == 'x') && (s[3] == 'p'))
259      {
260         *mantisse = (s[2] >= 'a') ? (s[2] - 'a' + 10) : (s[2] - '0');
261         *exponent = (s[5] - '0');
262
263         return EINA_TRUE;
264      }
265
266    return EINA_FALSE;
267 }
268
269 static inline Eina_Bool
270 _eet_dictionary_string_get_float_cache(const char *s,
271                                        int         len,
272                                        float      *result)
273 {
274    int mantisse;
275    int exponent;
276
277    if (_eet_dictionary_string_get_me_cache(s, len, &mantisse, &exponent))
278      {
279         if (s[4] == '+')
280           *result = (float)(mantisse << exponent);
281         else
282           *result = (float)mantisse / (float)(1 << exponent);
283
284         return EINA_TRUE;
285      }
286
287    return EINA_FALSE;
288 }
289
290 static inline Eina_Bool
291 _eet_dictionary_string_get_double_cache(const char *s,
292                                         int         len,
293                                         double     *result)
294 {
295    int mantisse;
296    int exponent;
297
298    if (_eet_dictionary_string_get_me_cache(s, len, &mantisse, &exponent))
299      {
300         if (s[4] == '+')
301           *result = (double)(mantisse << exponent);
302         else
303           *result = (double)mantisse / (float)(1 << exponent);
304
305         return EINA_TRUE;
306      }
307
308    return EINA_FALSE;
309 }
310
311 static inline Eina_Bool
312 _eet_dictionary_test(const Eet_Dictionary *ed,
313                      int                   idx,
314                      void                 *result)
315 {
316    Eina_Bool limit = EINA_FALSE;
317
318    if (!result) goto done;
319
320    if (!ed) goto done;
321
322    if (idx < 0) goto done;
323
324    eina_lock_take((Eina_Lock*) &ed->mutex);
325
326    if (!(idx < ed->count)) goto unlock_done;
327
328    limit = EINA_TRUE;
329
330  unlock_done:
331    eina_lock_release((Eina_Lock*) &ed->mutex);
332
333  done:
334    return limit;
335 }
336
337 static Eet_Convert *
338 eet_dictionary_convert_get(const Eet_Dictionary *ed,
339                            int                   idx,
340                            const char          **str)
341 {
342    Eet_Convert *result;
343
344    eina_lock_take((Eina_Lock*) &ed->mutex);
345
346    *str = ed->all[idx].str;
347
348    if (!ed->converts)
349      {
350         ((Eet_Dictionary *)ed)->converts = eina_hash_int32_new(free);
351
352         goto add_convert;
353      }
354
355    result = eina_hash_find(ed->converts, &idx);
356    if (result) goto done;
357
358  add_convert:
359    result = calloc(1, sizeof (Eet_Convert));
360
361    eina_hash_add(ed->converts, &idx, result);
362
363  done:
364    eina_lock_release((Eina_Lock*) &ed->mutex);
365
366    return result;
367 }
368
369 Eina_Bool
370 eet_dictionary_string_get_float(const Eet_Dictionary *ed,
371                                 int                   idx,
372                                 float                *result)
373 {
374    Eet_Convert *convert;
375    const char *str;
376
377    if (!_eet_dictionary_test(ed, idx, result))
378      return EINA_FALSE;
379
380    convert = eet_dictionary_convert_get(ed, idx, &str);
381    if (!convert) return EINA_FALSE;
382
383    if (!(convert->type & EET_D_FLOAT))
384      {
385         eina_lock_take((Eina_Lock*) &ed->mutex);
386         if (!_eet_dictionary_string_get_float_cache(str, ed->all[idx].len,
387                                                     &convert->f))
388           {
389              long long mantisse = 0;
390              long exponent = 0;
391
392              if (eina_convert_atod(str, ed->all[idx].len, &mantisse,
393                                    &exponent) == EINA_FALSE)
394                {
395                   eina_lock_release((Eina_Lock*) &ed->mutex);
396                   return EINA_FALSE;
397                }
398
399              convert->f = ldexpf((float)mantisse, exponent);
400           }
401         eina_lock_release((Eina_Lock*) &ed->mutex);
402
403         convert->type |= EET_D_FLOAT;
404      }
405
406    *result = convert->f;
407    return EINA_TRUE;
408 }
409
410 Eina_Bool
411 eet_dictionary_string_get_double(const Eet_Dictionary *ed,
412                                  int                   idx,
413                                  double               *result)
414 {
415    Eet_Convert *convert;
416    const char *str;
417
418    if (!_eet_dictionary_test(ed, idx, result))
419      return EINA_FALSE;
420
421    convert = eet_dictionary_convert_get(ed, idx, &str);
422    if (!convert) return EINA_FALSE;
423
424    if (!(convert->type & EET_D_DOUBLE))
425      {
426         eina_lock_take((Eina_Lock*) &ed->mutex);
427
428         if (!_eet_dictionary_string_get_double_cache(str, ed->all[idx].len,
429                                                      &convert->d))
430           {
431              long long mantisse = 0;
432              long exponent = 0;
433
434              if (eina_convert_atod(str, ed->all[idx].len, &mantisse,
435                                    &exponent) == EINA_FALSE)
436                {
437                   eina_lock_release((Eina_Lock*) &ed->mutex);
438                   return EINA_FALSE;
439                }
440
441              convert->d = ldexp((double)mantisse, exponent);
442           }
443         eina_lock_release((Eina_Lock*) &ed->mutex);
444
445         convert->type |= EET_D_DOUBLE;
446      }
447
448    *result = convert->d;
449    return EINA_TRUE;
450 }
451
452 Eina_Bool
453 eet_dictionary_string_get_fp(const Eet_Dictionary *ed,
454                              int                   idx,
455                              Eina_F32p32          *result)
456 {
457    Eet_Convert *convert;
458    const char *str;
459
460    if (!_eet_dictionary_test(ed, idx, result))
461      return EINA_FALSE;
462
463    convert = eet_dictionary_convert_get(ed, idx, &str);
464    if (!convert) return EINA_FALSE;
465
466    if (!(convert->type & EET_D_FIXED_POINT))
467      {
468         Eina_F32p32 fp;
469
470         eina_lock_take((Eina_Lock*) &ed->mutex);
471         if (!eina_convert_atofp(str, ed->all[idx].len, &fp))
472           {
473              eina_lock_release((Eina_Lock*) &ed->mutex);
474              return EINA_FALSE;
475           }
476         eina_lock_release((Eina_Lock*) &ed->mutex);
477
478         convert->fp = fp;
479         convert->type |= EET_D_FIXED_POINT;
480      }
481
482    *result = convert->fp;
483    return EINA_TRUE;
484 }
485
486 EAPI int
487 eet_dictionary_string_check(Eet_Dictionary *ed,
488                             const char     *string)
489 {
490    int res = 0;
491    int i;
492
493    if ((!ed) || (!string))
494      return 0;
495
496    eina_lock_take(&ed->mutex);
497
498    if ((ed->start <= string) && (string < ed->end))
499      res = 1;
500
501    if (!res)
502      {
503         for (i = 0; i < ed->count; ++i)
504           if ((ed->all[i].allocated) && ed->all[i].str == string)
505             {
506                res = 1;
507                break;
508             }
509      }
510
511    eina_lock_release(&ed->mutex);
512
513    return res;
514 }
515