* eet: Reduce convertion to FP, float and double with a little overhead.
[framework/uifw/eet.git] / src / lib / eet_dictionary.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <math.h>
12
13 #include <Eina.h>
14
15 #include "Eet.h"
16 #include "Eet_private.h"
17
18 Eet_Dictionary *
19 eet_dictionary_add(void)
20 {
21    Eet_Dictionary       *new;
22
23    new = calloc(1, sizeof (Eet_Dictionary));
24    if (!new)
25      return NULL;
26
27    memset(new->hash, -1, sizeof (int) * 256);
28
29    return new;
30 }
31
32 void
33 eet_dictionary_free(Eet_Dictionary *ed)
34 {
35    if (ed)
36      {
37         int     i;
38
39         for (i = 0; i < ed->count; ++i)
40           if (ed->all[i].str)
41             free(ed->all[i].str);
42         if (ed->all) free(ed->all);
43         free(ed);
44      }
45 }
46
47 static int
48 _eet_dictionary_lookup(Eet_Dictionary *ed, const char *string, int hash)
49 {
50    int  prev = -1;
51    int  current;
52
53    current = ed->hash[hash];
54
55    while (current != -1)
56      {
57         if (ed->all[current].str)
58           {
59              if (strcmp(ed->all[current].str, string) >= 0)
60                break ;
61           }
62         if (ed->all[current].mmap)
63           {
64              if (strcmp(ed->all[current].mmap, string) >= 0)
65                break ;
66           }
67
68         prev = current;
69         current = ed->all[current].next;
70      }
71
72    if (current == -1)
73      return prev;
74
75    return current;
76 }
77
78 int
79 eet_dictionary_string_add(Eet_Dictionary *ed, const char *string)
80 {
81    Eet_String   *current;
82    char         *str;
83    int           hash;
84    int           index;
85    int           len;
86
87    if (!ed)
88      return -1;
89
90    hash = _eet_hash_gen(string, 8);
91
92    index = _eet_dictionary_lookup(ed, string, hash);
93
94    if (index != -1)
95      {
96         if (ed->all[index].str)
97           {
98              if (strcmp(ed->all[index].str, string) == 0)
99                return index;
100           }
101         if (ed->all[index].mmap)
102           {
103              if (strcmp(ed->all[index].mmap, string) == 0)
104                return index;
105           }
106      }
107
108    if (ed->total == ed->count)
109      {
110         Eet_String      *new;
111         int              total;
112
113         total = ed->total + 8;
114
115         new = realloc(ed->all, sizeof (Eet_String) * total);
116         if (new == NULL)
117           return -1;
118
119         ed->all = new;
120         ed->total = total;
121      }
122
123    len = strlen(string) + 1;
124    str = strdup(string);
125    if (str == NULL)
126      return -1;
127
128    current = ed->all + ed->count;
129
130    current->type = EET_D_NOT_CONVERTED;
131
132    current->hash = hash;
133
134    current->str = str;
135    current->len = len;
136    current->mmap = NULL;
137
138    if (index == -1)
139      {
140         current->next = ed->hash[hash];
141         current->prev = -1;
142         ed->hash[hash] = ed->count;
143      }
144    else
145      {
146         current->next = index;
147         current->prev = ed->all[index].prev;
148
149         if (current->next != -1)
150           ed->all[current->next].prev = ed->count;
151         if (current->prev != -1)
152           ed->all[current->prev].next = ed->count;
153         else
154           ed->hash[hash] = ed->count;
155      }
156
157    return ed->count++;
158 }
159
160 int
161 eet_dictionary_string_get_size(const Eet_Dictionary *ed, int index)
162 {
163    if (!ed) return 0;
164    if (index < 0) return 0;
165    if (index < ed->count)
166      return ed->all[index].len;
167    return 0;
168 }
169
170 int
171 eet_dictionary_string_get_hash(const Eet_Dictionary *ed, int index)
172 {
173    if (!ed) return -1;
174    if (index < 0) return -1;
175    if (index < ed->count)
176      return ed->all[index].hash;
177    return -1;
178 }
179
180 const char *
181 eet_dictionary_string_get_char(const Eet_Dictionary *ed, int index)
182 {
183    if (!ed) return NULL;
184    if (index < 0) return NULL;
185    if (index < ed->count)
186      {
187 #ifdef _WIN32
188         /* Windows file system could change the mmaped file when replacing a file. So we need to copy all string in memory to avoid bugs. */
189         if (ed->all[index].str == NULL)
190           {
191              ed->all[index].str = strdup(ed->all[index].mmap);
192              ed->all[index].mmap = NULL;
193           }
194 #else
195         if (ed->all[index].mmap)
196           return ed->all[index].mmap;
197 #endif
198         return ed->all[index].str;
199      }
200    return NULL;
201 }
202
203 static inline Eina_Bool
204 _eet_dictionary_string_get_me_cache(const char *s, int len, int *mantisse, int *exponent)
205 {
206    if ((len == 6) && (s[0] == '0') && (s[1] == 'x') && (s[3] == 'p'))
207      {
208         *mantisse = (s[2] >= 'a') ? (s[2] - 'a' + 10) : (s[2] - '0');
209         *exponent = (s[5] - '0');
210
211         return EINA_TRUE;
212      }
213    return EINA_FALSE;
214 }
215
216 static inline Eina_Bool
217 _eet_dictionary_string_get_float_cache(const char *s, int len, float *result)
218 {
219    int  mantisse;
220    int  exponent;
221
222    if (_eet_dictionary_string_get_me_cache(s, len, &mantisse, &exponent))
223      {
224         if (s[4] == '+')        *result = (float) (mantisse << exponent);
225         else                    *result = (float) mantisse / (float) (1 << exponent);
226
227         return EINA_TRUE;
228      }
229    return EINA_FALSE;
230 }
231
232 static inline Eina_Bool
233 _eet_dictionary_string_get_double_cache(const char *s, int len, double *result)
234 {
235    int  mantisse;
236    int  exponent;
237
238    if (_eet_dictionary_string_get_me_cache(s, len, &mantisse, &exponent))
239      {
240         if (s[4] == '+')        *result = (double) (mantisse << exponent);
241         else                    *result = (double) mantisse / (float) (1 << exponent);
242
243         return EINA_TRUE;
244      }
245    return EINA_FALSE;
246 }
247
248 static inline Eina_Bool
249 _eet_dictionary_test(const Eet_Dictionary *ed, int index, void *result)
250 {
251    if (!result) return EINA_FALSE;
252    if (!ed) return EINA_FALSE;
253    if (index < 0) return EINA_FALSE;
254    if (!(index < ed->count)) return EINA_FALSE;
255    return EINA_TRUE;
256 }
257
258 Eina_Bool
259 eet_dictionary_string_get_float(const Eet_Dictionary *ed, int index, float *result)
260 {
261    if (!_eet_dictionary_test(ed, index, result)) return EINA_FALSE;
262
263    if (!(ed->all[index].type & EET_D_FLOAT))
264      {
265         const char      *str;
266
267         str = ed->all[index].str ? ed->all[index].str : ed->all[index].mmap;
268
269         if (!_eet_dictionary_string_get_float_cache(str, ed->all[index].len, &ed->all[index].f))
270           {
271              long long    mantisse = 0;
272              long         exponent = 0;
273
274              if (eina_convert_atod(str, ed->all[index].len, &mantisse, &exponent) == EINA_FALSE)
275                return EINA_FALSE;
276
277              ed->all[index].f = ldexpf((float) mantisse, exponent);
278           }
279
280         ed->all[index].type |= EET_D_FLOAT;
281      }
282
283    *result = ed->all[index].f;
284    return EINA_TRUE;
285 }
286
287 Eina_Bool
288 eet_dictionary_string_get_double(const Eet_Dictionary *ed, int index, double *result)
289 {
290    if (!_eet_dictionary_test(ed, index, result)) return EINA_FALSE;
291
292    if (!(ed->all[index].type & EET_D_DOUBLE))
293      {
294         const char      *str;
295
296         str = ed->all[index].str ? ed->all[index].str : ed->all[index].mmap;
297
298         if (!_eet_dictionary_string_get_double_cache(str, ed->all[index].len, &ed->all[index].d))
299           {
300              long long    mantisse = 0;
301              long         exponent = 0;
302
303              if (eina_convert_atod(str, ed->all[index].len, &mantisse, &exponent) == EINA_FALSE)
304                return EINA_FALSE;
305
306              ed->all[index].d = ldexp((double) mantisse, exponent);
307           }
308
309         ed->all[index].type |= EET_D_DOUBLE;
310      }
311
312    *result = ed->all[index].d;
313    return EINA_TRUE;
314 }
315
316 Eina_Bool
317 eet_dictionary_string_get_fp(const Eet_Dictionary *ed, int index, Eina_F32p32 *result)
318 {
319    if (!_eet_dictionary_test(ed, index, result)) return EINA_FALSE;
320
321    if (!(ed->all[index].type & EET_D_FIXED_POINT))
322      {
323         const char *str;
324         Eina_F32p32 fp;
325
326         str = ed->all[index].str ? ed->all[index].str : ed->all[index].mmap;
327
328         if (!eina_convert_atofp(str,  ed->all[index].len, &fp))
329           return EINA_FALSE;
330
331         ed->all[index].fp = fp;
332         ed->all[index].type |= EET_D_FIXED_POINT;
333      }
334
335    *result = ed->all[index].fp;
336    return EINA_TRUE;
337 }
338
339 EAPI int
340 eet_dictionary_string_check(Eet_Dictionary *ed, const char *string)
341 {
342    int  i;
343
344    if (ed == NULL
345        || string == NULL)
346      return 0;
347
348    if (ed->start <= string
349        && string < ed->end)
350      return 1;
351
352    for (i = 0; i < ed->count; ++i)
353      if (ed->all[i].str == string)
354        return 1;
355
356    return 0;
357 }