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