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