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