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