aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/lib/eina_share_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/lib/eina_share_common.c')
-rw-r--r--libraries/eina/src/lib/eina_share_common.c949
1 files changed, 0 insertions, 949 deletions
diff --git a/libraries/eina/src/lib/eina_share_common.c b/libraries/eina/src/lib/eina_share_common.c
deleted file mode 100644
index 776e429..0000000
--- a/libraries/eina/src/lib/eina_share_common.c
+++ /dev/null
@@ -1,949 +0,0 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2010
3 * Carsten Haitzler,
4 * Jorge Luis Zapata Muga,
5 * Cedric Bail,
6 * Gustavo Sverzut Barbieri
7 * Tom Hacohen
8 * Brett Nash
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library;
22 * if not, see <http://www.gnu.org/licenses/>.
23 *
24 * This file incorporates work covered by the following copyright and
25 * permission notice:
26 *
27 * Copyright (C) 2008 Peter Wehrfritz
28 *
29 * Permission is hereby granted, free of charge, to any person obtaining a copy
30 * of this software and associated documentation files (the "Software"), to
31 * deal in the Software without restriction, including without limitation the
32 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
33 * sell copies of the Software, and to permit persons to whom the Software is
34 * furnished to do so, subject to the following conditions:
35 *
36 * The above copyright notice and this permission notice shall be included in
37 * all copies of the Software and its Copyright notices. In addition publicly
38 * documented acknowledgment must be given that this software has been used if no
39 * source code of this software is made available publicly. This includes
40 * acknowledgments in either Copyright notices, Manuals, Publicity and Marketing
41 * documents or any documentation provided with any product containing this
42 * software. This License does not apply to any software that links to the
43 * libraries provided by this software (statically or dynamically), but only to
44 * the software provided.
45 *
46 * Please see the OLD-COPYING.PLAIN for a plain-english explanation of this notice
47 * and it's intent.
48 *
49 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
52 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
53 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
54 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
55 */
56
57#ifdef HAVE_CONFIG_H
58# include "config.h"
59#endif
60
61#include <stdlib.h>
62#include <stdio.h>
63#include <string.h>
64#include <stddef.h>
65
66#ifdef EFL_HAVE_POSIX_THREADS
67# include <pthread.h>
68#endif
69
70#ifdef HAVE_EVIL
71# include <Evil.h>
72#endif
73
74#include "eina_config.h"
75#include "eina_private.h"
76#include "eina_hash.h"
77#include "eina_rbtree.h"
78#include "eina_error.h"
79#include "eina_lock.h"
80
81/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
82#include "eina_safety_checks.h"
83#include "eina_share_common.h"
84
85/*============================================================================*
86* Local *
87*============================================================================*/
88
89/**
90 * @cond LOCAL
91 */
92
93#define EINA_SHARE_COMMON_BUCKETS 256
94#define EINA_SHARE_COMMON_MASK 0xFF
95
96static const char EINA_MAGIC_SHARE_STR[] = "Eina Share";
97static const char EINA_MAGIC_SHARE_HEAD_STR[] = "Eina Share Head";
98
99static int _eina_share_common_count = 0;
100
101#define EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(d, unlock, ...) \
102 do { \
103 if (!EINA_MAGIC_CHECK((d), EINA_MAGIC_SHARE_HEAD)) \
104 { \
105 EINA_MAGIC_FAIL((d), EINA_MAGIC_SHARE_HEAD); \
106 unlock; \
107 return __VA_ARGS__; \
108 } \
109 } while (0)
110
111#define EINA_MAGIC_CHECK_SHARE_COMMON_NODE(d, _node_magic, unlock) \
112 do { \
113 if (!EINA_MAGIC_CHECK((d), _node_magic)) \
114 { \
115 EINA_MAGIC_FAIL((d), _node_magic); \
116 unlock; \
117 } \
118 } while (0)
119
120#ifdef EINA_SHARE_USAGE
121typedef struct _Eina_Share_Common_Population Eina_Share_Common_Population;
122#endif
123
124typedef struct _Eina_Share_Common Eina_Share_Common;
125typedef struct _Eina_Share_Common_Node Eina_Share_Common_Node;
126typedef struct _Eina_Share_Common_Head Eina_Share_Common_Head;
127
128struct _Eina_Share
129{
130 Eina_Share_Common *share;
131 Eina_Magic node_magic;
132#ifdef EINA_SHARE_COMMON_USAGE
133 Eina_Share_Common_Population population;
134 int max_node_population;
135#endif
136};
137
138struct _Eina_Share_Common
139{
140 Eina_Share_Common_Head *buckets[EINA_SHARE_COMMON_BUCKETS];
141
142 EINA_MAGIC
143};
144
145struct _Eina_Share_Common_Node
146{
147 Eina_Share_Common_Node *next;
148
149 EINA_MAGIC
150
151 unsigned int length;
152 unsigned int references;
153 char str[];
154};
155
156struct _Eina_Share_Common_Head
157{
158 EINA_RBTREE;
159 EINA_MAGIC
160
161 int hash;
162
163#ifdef EINA_SHARE_COMMON_USAGE
164 int population;
165#endif
166
167 Eina_Share_Common_Node *head;
168 Eina_Share_Common_Node builtin_node;
169};
170
171Eina_Bool _share_common_threads_activated = EINA_FALSE;
172
173static Eina_Lock _mutex_big;
174
175#ifdef EINA_SHARE_COMMON_USAGE
176struct _Eina_Share_Common_Population
177{
178 int count;
179 int max;
180};
181
182static Eina_Share_Common_Population population = { 0, 0 };
183
184static Eina_Share_Common_Population population_group[4] =
185{
186 { 0, 0 },
187 { 0, 0 },
188 { 0, 0 },
189 { 0, 0 }
190};
191
192static void
193_eina_share_common_population_init(Eina_Share *share)
194{
195 unsigned int i;
196
197 for (i = 0;
198 i < sizeof (share->population_group) /
199 sizeof (share->population_group[0]);
200 ++i)
201 {
202 share->population_group[i].count = 0;
203 share->population_group[i].max = 0;
204 }
205}
206
207static void
208_eina_share_common_population_shutdown(Eina_Share *share)
209{
210 unsigned int i;
211
212 share->max_node_population = 0;
213 share->population.count = 0;
214 share->population.max = 0;
215
216 for (i = 0;
217 i < sizeof (share->population_group) /
218 sizeof (share->population_group[0]);
219 ++i)
220 {
221 share->population_group[i].count = 0;
222 share->population_group[i].max = 0;
223 }
224}
225
226static void
227_eina_share_common_population_stats(Eina_Share *share)
228{
229 unsigned int i;
230
231 fprintf(stderr, "eina share_common statistic:\n");
232 fprintf(stderr,
233 " * maximum shared strings : %i\n",
234 share->population.max);
235 fprintf(stderr,
236 " * maximum shared strings per node : %i\n",
237 share->max_node_population);
238
239 for (i = 0;
240 i < sizeof (share->population_group) /
241 sizeof (share->population_group[0]);
242 ++i)
243 fprintf(stderr,
244 "DDD: %i strings of length %i, max strings: %i\n",
245 share->population_group[i].count,
246 i,
247 share->population_group[i].max);
248}
249
250void
251eina_share_common_population_add(Eina_Share *share, int slen)
252{
253 eina_lock_take(&_mutex_big);
254
255 share->population.count++;
256 if (share->population.count > share->population.max)
257 share->population.max = share->population.count;
258
259 if (slen < 4)
260 {
261 share->population_group[slen].count++;
262 if (share->population_group[slen].count >
263 share->population_group[slen].max)
264 share->population_group[slen].max =
265 share->population_group[slen].count;
266 }
267
268 eina_lock_release(&_mutex_big);
269}
270
271void
272eina_share_common_population_del(Eina_Share *share, int slen)
273{
274 eina_lock_take(&_mutex_big);
275
276 share->population.count--;
277 if (slen < 4)
278 share->population_group[slen].count--;
279
280 eina_lock_release(&_mutex_big);
281}
282
283static void
284_eina_share_common_population_head_init(Eina_Share *share,
285 Eina_Share_Common_Head *head)
286{
287 head->population = 1;
288}
289
290static void
291_eina_share_common_population_head_add(Eina_Share *share,
292 Eina_Share_Common_Head *head)
293{
294 head->population++;
295 if (head->population > share->max_node_population)
296 share->max_node_population = head->population;
297}
298
299static void
300_eina_share_common_population_head_del(Eina_Share *share,
301 Eina_Share_Common_Head *head)
302{
303 head->population--;
304}
305
306#else /* EINA_SHARE_COMMON_USAGE undefined */
307
308static void _eina_share_common_population_init(__UNUSED__ Eina_Share *share) {
309}
310static void _eina_share_common_population_shutdown(__UNUSED__ Eina_Share *share)
311{
312}
313static void _eina_share_common_population_stats(__UNUSED__ Eina_Share *share) {
314}
315void eina_share_common_population_add(__UNUSED__ Eina_Share *share,
316 __UNUSED__ int slen) {
317}
318void eina_share_common_population_del(__UNUSED__ Eina_Share *share,
319 __UNUSED__ int slen) {
320}
321static void _eina_share_common_population_head_init(
322 __UNUSED__ Eina_Share *share,
323 __UNUSED__ Eina_Share_Common_Head *head) {
324}
325static void _eina_share_common_population_head_add(
326 __UNUSED__ Eina_Share *share,
327 __UNUSED__
328 Eina_Share_Common_Head *head) {
329}
330static void _eina_share_common_population_head_del(
331 __UNUSED__ Eina_Share *share,
332 __UNUSED__
333 Eina_Share_Common_Head *head) {
334}
335#endif
336
337static int
338_eina_share_common_cmp(const Eina_Share_Common_Head *ed,
339 const int *hash,
340 __UNUSED__ int length,
341 __UNUSED__ void *data)
342{
343 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, , 0);
344
345 return ed->hash - *hash;
346}
347
348static Eina_Rbtree_Direction
349_eina_share_common_node(const Eina_Share_Common_Head *left,
350 const Eina_Share_Common_Head *right,
351 __UNUSED__ void *data)
352{
353 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(left, , 0);
354 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(right, , 0);
355
356 if (left->hash - right->hash < 0)
357 return EINA_RBTREE_LEFT;
358
359 return EINA_RBTREE_RIGHT;
360}
361
362static void
363_eina_share_common_head_free(Eina_Share_Common_Head *ed, __UNUSED__ void *data)
364{
365 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, );
366
367 while (ed->head)
368 {
369 Eina_Share_Common_Node *el = ed->head;
370
371 ed->head = ed->head->next;
372 if (el != &ed->builtin_node)
373 MAGIC_FREE(el);
374 }
375 MAGIC_FREE(ed);
376}
377
378static void
379_eina_share_common_node_init(Eina_Share_Common_Node *node,
380 const char *str,
381 int slen,
382 unsigned int null_size,
383 Eina_Magic node_magic)
384{
385 EINA_MAGIC_SET(node, node_magic);
386 node->references = 1;
387 node->length = slen;
388 memcpy(node->str, str, slen);
389 memset(node->str + slen, 0, null_size); /* Nullify the null */
390
391 (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
392}
393
394static Eina_Share_Common_Head *
395_eina_share_common_head_alloc(int slen)
396{
397 Eina_Share_Common_Head *head;
398 const size_t head_size = offsetof(Eina_Share_Common_Head, builtin_node.str);
399
400 head = malloc(head_size + slen);
401 if (!head)
402 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
403
404 return head;
405}
406
407static const char *
408_eina_share_common_add_head(Eina_Share *share,
409 Eina_Share_Common_Head **p_bucket,
410 int hash,
411 const char *str,
412 unsigned int slen,
413 unsigned int null_size)
414{
415 Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
416 Eina_Share_Common_Head *head;
417
418 head = _eina_share_common_head_alloc(slen + null_size);
419 if (!head)
420 return NULL;
421
422 EINA_MAGIC_SET(head, EINA_MAGIC_SHARE_HEAD);
423 head->hash = hash;
424 head->head = &head->builtin_node;
425 _eina_share_common_node_init(head->head,
426 str,
427 slen,
428 null_size,
429 share->node_magic);
430 head->head->next = NULL;
431
432 _eina_share_common_population_head_init(share, head);
433
434 *p_tree = eina_rbtree_inline_insert
435 (*p_tree, EINA_RBTREE_GET(head),
436 EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
437
438 return head->head->str;
439}
440
441static void
442_eina_share_common_del_head(Eina_Share_Common_Head **p_bucket,
443 Eina_Share_Common_Head *head)
444{
445 Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
446
447 *p_tree = eina_rbtree_inline_remove
448 (*p_tree, EINA_RBTREE_GET(head),
449 EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
450
451 MAGIC_FREE(head);
452}
453
454
455static inline Eina_Bool
456_eina_share_common_node_eq(const Eina_Share_Common_Node *node,
457 const char *str,
458 unsigned int slen)
459{
460 return ((node->length == slen) &&
461 (memcmp(node->str, str, slen) == 0));
462}
463
464static Eina_Share_Common_Node *
465_eina_share_common_head_find(Eina_Share_Common_Head *head,
466 const char *str,
467 unsigned int slen)
468{
469 Eina_Share_Common_Node *node, *prev;
470
471 node = head->head;
472 if (_eina_share_common_node_eq(node, str, slen))
473 return node;
474
475 prev = node;
476 node = node->next;
477 for (; node; prev = node, node = node->next)
478 if (_eina_share_common_node_eq(node, str, slen))
479 {
480 /* promote node, make hot items be at the beginning */
481 prev->next = node->next;
482 node->next = head->head;
483 head->head = node;
484 return node;
485 }
486
487 return NULL;
488}
489
490static Eina_Bool
491_eina_share_common_head_remove_node(Eina_Share_Common_Head *head,
492 const Eina_Share_Common_Node *node)
493{
494 Eina_Share_Common_Node *cur, *prev;
495
496 if (head->head == node)
497 {
498 head->head = node->next;
499 return 1;
500 }
501
502 prev = head->head;
503 cur = head->head->next;
504 for (; cur; prev = cur, cur = cur->next)
505 if (cur == node)
506 {
507 prev->next = cur->next;
508 return 1;
509 }
510
511 return 0;
512}
513
514static Eina_Share_Common_Head *
515_eina_share_common_find_hash(Eina_Share_Common_Head *bucket, int hash)
516{
517 return (Eina_Share_Common_Head *)eina_rbtree_inline_lookup
518 (EINA_RBTREE_GET(bucket), &hash, 0,
519 EINA_RBTREE_CMP_KEY_CB(_eina_share_common_cmp), NULL);
520}
521
522static Eina_Share_Common_Node *
523_eina_share_common_node_alloc(unsigned int slen, unsigned int null_size)
524{
525 Eina_Share_Common_Node *node;
526 const size_t node_size = offsetof(Eina_Share_Common_Node, str);
527
528 node = malloc(node_size + slen + null_size);
529 if (!node)
530 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
531
532 return node;
533}
534
535static Eina_Share_Common_Node *
536_eina_share_common_node_from_str(const char *str, Eina_Magic node_magic)
537{
538 Eina_Share_Common_Node *node;
539 const size_t offset = offsetof(Eina_Share_Common_Node, str);
540
541 node = (Eina_Share_Common_Node *)(str - offset);
542 EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL);
543 return node;
544
545 (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
546}
547
548static Eina_Bool
549eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__,
550 Eina_Share_Common_Head *head,
551 struct dumpinfo *fdata)
552{
553 Eina_Share_Common_Node *node;
554
555 fdata->used += sizeof(Eina_Share_Common_Head);
556 for (node = head->head; node; node = node->next)
557 {
558 printf("DDD: %5i %5i ", node->length, node->references);
559 printf("'%.*s'\n", node->length, ((char *)node) + sizeof(Eina_Share_Common_Node));
560 fdata->used += sizeof(Eina_Share_Common_Node);
561 fdata->used += node->length;
562 fdata->saved += (node->references - 1) * node->length;
563 fdata->dups += node->references - 1;
564 fdata->unique++;
565 }
566
567 return EINA_TRUE;
568}
569
570/**
571 * @endcond
572 */
573
574
575/*============================================================================*
576* Global *
577*============================================================================*/
578
579/**
580 * @internal
581 * @brief Initialize the share_common module.
582 *
583 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
584 *
585 * This function sets up the share_common module of Eina. It is called by
586 * eina_init().
587 *
588 * @see eina_init()
589 */
590Eina_Bool
591eina_share_common_init(Eina_Share **_share,
592 Eina_Magic node_magic,
593 const char *node_magic_STR)
594{
595 Eina_Share *share;
596
597 share = *_share = calloc(sizeof(Eina_Share), 1);
598 if (!share) goto on_error;
599
600 share->share = calloc(1, sizeof(Eina_Share_Common));
601 if (!share->share) goto on_error;
602
603 share->node_magic = node_magic;
604#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
605 EMS(EINA_MAGIC_SHARE);
606 EMS(EINA_MAGIC_SHARE_HEAD);
607 EMS(node_magic);
608#undef EMS
609 EINA_MAGIC_SET(share->share, EINA_MAGIC_SHARE);
610
611 _eina_share_common_population_init(share);
612
613 /* below is the common part among other all eina_share_common user */
614 if (_eina_share_common_count++ != 0)
615 return EINA_TRUE;
616
617 eina_lock_new(&_mutex_big);
618 return EINA_TRUE;
619
620 on_error:
621 _eina_share_common_count--;
622 return EINA_FALSE;
623}
624
625/**
626 * @internal
627 * @brief Shut down the share_common module.
628 *
629 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
630 *
631 * This function shuts down the share_common module set up by
632 * eina_share_common_init(). It is called by eina_shutdown().
633 *
634 * @see eina_shutdown()
635 */
636Eina_Bool
637eina_share_common_shutdown(Eina_Share **_share)
638{
639 unsigned int i;
640 Eina_Share *share = *_share;
641
642 eina_lock_take(&_mutex_big);
643
644 _eina_share_common_population_stats(share);
645
646 /* remove any string still in the table */
647 for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
648 {
649 eina_rbtree_delete(EINA_RBTREE_GET(
650 share->share->buckets[i]),
651 EINA_RBTREE_FREE_CB(
652 _eina_share_common_head_free), NULL);
653 share->share->buckets[i] = NULL;
654 }
655 MAGIC_FREE(share->share);
656
657 _eina_share_common_population_shutdown(share);
658
659 eina_lock_release(&_mutex_big);
660
661 free(*_share);
662 *_share = NULL;
663
664 /* below is the common part among other all eina_share_common user */
665 if (--_eina_share_common_count != 0)
666 return EINA_TRUE;
667
668 eina_lock_free(&_mutex_big);
669
670 return EINA_TRUE;
671}
672
673#ifdef EFL_HAVE_THREADS
674
675/**
676 * @internal
677 * @brief Activate the share_common mutexes.
678 *
679 * This function activate the mutexes in the eina share_common module. It is called by
680 * eina_threads_init().
681 *
682 * @see eina_threads_init()
683 */
684void
685eina_share_common_threads_init(void)
686{
687 _share_common_threads_activated = EINA_TRUE;
688}
689
690/**
691 * @internal
692 * @brief Shut down the share_common mutexes.
693 *
694 * This function shuts down the mutexes in the share_common module.
695 * It is called by eina_threads_shutdown().
696 *
697 * @see eina_threads_shutdown()
698 */
699void
700eina_share_common_threads_shutdown(void)
701{
702 _share_common_threads_activated = EINA_FALSE;
703}
704
705#endif
706
707/*============================================================================*
708* API *
709*============================================================================*/
710
711/**
712 * @cond LOCAL
713 */
714
715const char *
716eina_share_common_add_length(Eina_Share *share,
717 const char *str,
718 unsigned int slen,
719 unsigned int null_size)
720{
721 Eina_Share_Common_Head **p_bucket, *ed;
722 Eina_Share_Common_Node *el;
723 int hash_num, hash;
724
725 if (!str)
726 return NULL;
727
728 eina_share_common_population_add(share, slen);
729
730 if (slen <= 0)
731 return NULL;
732
733 hash = eina_hash_superfast(str, slen);
734 hash_num = hash & 0xFF;
735 hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
736
737 eina_lock_take(&_mutex_big);
738 p_bucket = share->share->buckets + hash_num;
739
740 ed = _eina_share_common_find_hash(*p_bucket, hash);
741 if (!ed)
742 {
743 const char *s = _eina_share_common_add_head(share,
744 p_bucket,
745 hash,
746 str,
747 slen,
748 null_size);
749 eina_lock_release(&_mutex_big);
750 return s;
751 }
752
753 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), NULL);
754
755 el = _eina_share_common_head_find(ed, str, slen);
756 if (el)
757 {
758 EINA_MAGIC_CHECK_SHARE_COMMON_NODE(el,
759 share->node_magic,
760 eina_lock_release(&_mutex_big));
761 el->references++;
762 eina_lock_release(&_mutex_big);
763 return el->str;
764 }
765
766 el = _eina_share_common_node_alloc(slen, null_size);
767 if (!el)
768 {
769 eina_lock_release(&_mutex_big);
770 return NULL;
771 }
772
773 _eina_share_common_node_init(el, str, slen, null_size, share->node_magic);
774 el->next = ed->head;
775 ed->head = el;
776 _eina_share_common_population_head_add(share, ed);
777
778 eina_lock_release(&_mutex_big);
779
780 return el->str;
781}
782
783const char *
784eina_share_common_ref(Eina_Share *share, const char *str)
785{
786 Eina_Share_Common_Node *node;
787
788 if (!str)
789 return NULL;
790
791 eina_lock_take(&_mutex_big);
792 node = _eina_share_common_node_from_str(str, share->node_magic);
793 if (!node)
794 {
795 eina_lock_release(&_mutex_big);
796 return str;
797 }
798 node->references++;
799
800 eina_lock_release(&_mutex_big);
801
802 eina_share_common_population_add(share, node->length);
803
804 return str;
805}
806
807
808Eina_Bool
809eina_share_common_del(Eina_Share *share, const char *str)
810{
811 unsigned int slen;
812 Eina_Share_Common_Head *ed;
813 Eina_Share_Common_Head **p_bucket;
814 Eina_Share_Common_Node *node;
815 int hash_num, hash;
816
817 if (!str)
818 return EINA_TRUE;
819
820 eina_lock_take(&_mutex_big);
821
822 node = _eina_share_common_node_from_str(str, share->node_magic);
823 if (!node)
824 goto on_error;
825
826 slen = node->length;
827 eina_share_common_population_del(share, slen);
828 if (node->references > 1)
829 {
830 node->references--;
831 eina_lock_release(&_mutex_big);
832 return EINA_TRUE;
833 }
834
835 node->references = 0;
836
837 hash = eina_hash_superfast(str, slen);
838 hash_num = hash & 0xFF;
839 hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
840
841 p_bucket = share->share->buckets + hash_num;
842 ed = _eina_share_common_find_hash(*p_bucket, hash);
843 if (!ed)
844 goto on_error;
845
846 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), EINA_FALSE);
847
848 if (!_eina_share_common_head_remove_node(ed, node))
849 goto on_error;
850
851 if (node != &ed->builtin_node)
852 MAGIC_FREE(node);
853
854 if (!ed->head)
855 _eina_share_common_del_head(p_bucket, ed);
856 else
857 _eina_share_common_population_head_del(share, ed);
858
859 eina_lock_release(&_mutex_big);
860
861 return EINA_TRUE;
862
863on_error:
864 eina_lock_release(&_mutex_big);
865 /* possible segfault happened before here, but... */
866 return EINA_FALSE;
867}
868
869int
870eina_share_common_length(__UNUSED__ Eina_Share *share, const char *str)
871{
872 const Eina_Share_Common_Node *node;
873
874 if (!str)
875 return -1;
876
877 node = _eina_share_common_node_from_str(str, share->node_magic);
878 if (!node) return 0;
879 return node->length;
880}
881
882void
883eina_share_common_dump(Eina_Share *share, void (*additional_dump)(
884 struct dumpinfo *), int used)
885{
886 Eina_Iterator *it;
887 unsigned int i;
888 struct dumpinfo di;
889
890 if (!share)
891 return;
892
893 di.used = used;
894 di.saved = 0;
895 di.dups = 0;
896 di.unique = 0;
897 printf("DDD: len ref string\n");
898 printf("DDD:-------------------\n");
899
900 eina_lock_take(&_mutex_big);
901 for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
902 {
903 if (!share->share->buckets[i])
904 {
905 continue; // printf("DDD: BUCKET # %i (HEAD=%i, NODE=%i)\n", i,
906
907 }
908
909// sizeof(Eina_Share_Common_Head), sizeof(Eina_Share_Common_Node));
910 it = eina_rbtree_iterator_prefix(
911 (Eina_Rbtree *)share->share->buckets[i]);
912 eina_iterator_foreach(it, EINA_EACH_CB(eina_iterator_array_check), &di);
913 eina_iterator_free(it);
914 }
915 if (additional_dump)
916 additional_dump(&di);
917
918#ifdef EINA_SHARE_COMMON_USAGE
919 /* One character strings are not counted in the hash. */
920 di.saved += share->population_group[0].count * sizeof(char);
921 di.saved += share->population_group[1].count * sizeof(char) * 2;
922#endif
923 printf("DDD:-------------------\n");
924 printf("DDD: usage (bytes) = %i, saved = %i (%3.0f%%)\n",
925 di.used, di.saved, di.used ? (di.saved * 100.0 / di.used) : 0.0);
926 printf("DDD: unique: %d, duplicates: %d (%3.0f%%)\n",
927 di.unique, di.dups, di.unique ? (di.dups * 100.0 / di.unique) : 0.0);
928
929#ifdef EINA_SHARE_COMMON_USAGE
930 printf("DDD: Allocated strings: %i\n", share->population.count);
931 printf("DDD: Max allocated strings: %i\n", share->population.max);
932
933 for (i = 0;
934 i < sizeof (share->population_group) /
935 sizeof (share->population_group[0]);
936 ++i)
937 fprintf(stderr,
938 "DDD: %i strings of length %i, max strings: %i\n",
939 share->population_group[i].count,
940 i,
941 share->population_group[i].max);
942#endif
943
944 eina_lock_release(&_mutex_big);
945}
946
947/**
948 * @endcond
949 */