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.c977
1 files changed, 977 insertions, 0 deletions
diff --git a/libraries/eina/src/lib/eina_share_common.c b/libraries/eina/src/lib/eina_share_common.c
new file mode 100644
index 0000000..90e1868
--- /dev/null
+++ b/libraries/eina/src/lib/eina_share_common.c
@@ -0,0 +1,977 @@
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_log.h"
80#include "eina_lock.h"
81
82/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
83#include "eina_safety_checks.h"
84#include "eina_share_common.h"
85
86/*============================================================================*
87* Local *
88*============================================================================*/
89
90/**
91 * @cond LOCAL
92 */
93
94#define EINA_SHARE_COMMON_BUCKETS 256
95#define EINA_SHARE_COMMON_MASK 0xFF
96
97static const char EINA_MAGIC_SHARE_STR[] = "Eina Share";
98static const char EINA_MAGIC_SHARE_HEAD_STR[] = "Eina Share Head";
99
100static int _eina_share_common_count = 0;
101
102#define EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(d, unlock, ...) \
103 do { \
104 if (!EINA_MAGIC_CHECK((d), EINA_MAGIC_SHARE_HEAD)) \
105 { \
106 EINA_MAGIC_FAIL((d), EINA_MAGIC_SHARE_HEAD); \
107 unlock; \
108 return __VA_ARGS__; \
109 } \
110 } while (0)
111
112#define EINA_MAGIC_CHECK_SHARE_COMMON_NODE(d, _node_magic, unlock) \
113 do { \
114 if (!EINA_MAGIC_CHECK((d), _node_magic)) \
115 { \
116 EINA_MAGIC_FAIL((d), _node_magic); \
117 unlock; \
118 } \
119 } while (0)
120
121#ifdef EINA_SHARE_USAGE
122typedef struct _Eina_Share_Common_Population Eina_Share_Common_Population;
123#endif
124
125typedef struct _Eina_Share_Common Eina_Share_Common;
126typedef struct _Eina_Share_Common_Node Eina_Share_Common_Node;
127typedef struct _Eina_Share_Common_Head Eina_Share_Common_Head;
128
129int _eina_share_common_log_dom = -1;
130
131struct _Eina_Share
132{
133 Eina_Share_Common *share;
134 Eina_Magic node_magic;
135#ifdef EINA_SHARE_COMMON_USAGE
136 Eina_Share_Common_Population population;
137 int max_node_population;
138#endif
139};
140
141struct _Eina_Share_Common
142{
143 Eina_Share_Common_Head *buckets[EINA_SHARE_COMMON_BUCKETS];
144
145 EINA_MAGIC
146};
147
148struct _Eina_Share_Common_Node
149{
150 Eina_Share_Common_Node *next;
151
152 EINA_MAGIC
153
154 unsigned int length;
155 unsigned int references;
156 char str[];
157};
158
159struct _Eina_Share_Common_Head
160{
161 EINA_RBTREE;
162 EINA_MAGIC
163
164 int hash;
165
166#ifdef EINA_SHARE_COMMON_USAGE
167 int population;
168#endif
169
170 Eina_Share_Common_Node *head;
171 Eina_Share_Common_Node builtin_node;
172};
173
174Eina_Bool _share_common_threads_activated = EINA_FALSE;
175
176static Eina_Lock _mutex_big;
177
178#ifdef EINA_SHARE_COMMON_USAGE
179struct _Eina_Share_Common_Population
180{
181 int count;
182 int max;
183};
184
185static Eina_Share_Common_Population population = { 0, 0 };
186
187static Eina_Share_Common_Population population_group[4] =
188{
189 { 0, 0 },
190 { 0, 0 },
191 { 0, 0 },
192 { 0, 0 }
193};
194
195static void
196_eina_share_common_population_init(Eina_Share *share)
197{
198 unsigned int i;
199
200 for (i = 0;
201 i < sizeof (share->population_group) /
202 sizeof (share->population_group[0]);
203 ++i)
204 {
205 share->population_group[i].count = 0;
206 share->population_group[i].max = 0;
207 }
208}
209
210static void
211_eina_share_common_population_shutdown(Eina_Share *share)
212{
213 unsigned int i;
214
215 share->max_node_population = 0;
216 share->population.count = 0;
217 share->population.max = 0;
218
219 for (i = 0;
220 i < sizeof (share->population_group) /
221 sizeof (share->population_group[0]);
222 ++i)
223 {
224 share->population_group[i].count = 0;
225 share->population_group[i].max = 0;
226 }
227}
228
229static void
230_eina_share_common_population_stats(Eina_Share *share)
231{
232 unsigned int i;
233
234 fprintf(stderr, "eina share_common statistic:\n");
235 fprintf(stderr,
236 " * maximum shared strings : %i\n",
237 share->population.max);
238 fprintf(stderr,
239 " * maximum shared strings per node : %i\n",
240 share->max_node_population);
241
242 for (i = 0;
243 i < sizeof (share->population_group) /
244 sizeof (share->population_group[0]);
245 ++i)
246 fprintf(stderr,
247 "DDD: %i strings of length %i, max strings: %i\n",
248 share->population_group[i].count,
249 i,
250 share->population_group[i].max);
251}
252
253void
254eina_share_common_population_add(Eina_Share *share, int slen)
255{
256 eina_lock_take(&_mutex_big);
257
258 share->population.count++;
259 if (share->population.count > share->population.max)
260 share->population.max = share->population.count;
261
262 if (slen < 4)
263 {
264 share->population_group[slen].count++;
265 if (share->population_group[slen].count >
266 share->population_group[slen].max)
267 share->population_group[slen].max =
268 share->population_group[slen].count;
269 }
270
271 eina_lock_release(&_mutex_big);
272}
273
274void
275eina_share_common_population_del(Eina_Share *share, int slen)
276{
277 eina_lock_take(&_mutex_big);
278
279 share->population.count--;
280 if (slen < 4)
281 share->population_group[slen].count--;
282
283 eina_lock_release(&_mutex_big);
284}
285
286static void
287_eina_share_common_population_head_init(Eina_Share *share,
288 Eina_Share_Common_Head *head)
289{
290 head->population = 1;
291}
292
293static void
294_eina_share_common_population_head_add(Eina_Share *share,
295 Eina_Share_Common_Head *head)
296{
297 head->population++;
298 if (head->population > share->max_node_population)
299 share->max_node_population = head->population;
300}
301
302static void
303_eina_share_common_population_head_del(Eina_Share *share,
304 Eina_Share_Common_Head *head)
305{
306 head->population--;
307}
308
309#else /* EINA_SHARE_COMMON_USAGE undefined */
310
311static void _eina_share_common_population_init(__UNUSED__ Eina_Share *share) {
312}
313static void _eina_share_common_population_shutdown(__UNUSED__ Eina_Share *share)
314{
315}
316static void _eina_share_common_population_stats(__UNUSED__ Eina_Share *share) {
317}
318void eina_share_common_population_add(__UNUSED__ Eina_Share *share,
319 __UNUSED__ int slen) {
320}
321void eina_share_common_population_del(__UNUSED__ Eina_Share *share,
322 __UNUSED__ int slen) {
323}
324static void _eina_share_common_population_head_init(
325 __UNUSED__ Eina_Share *share,
326 __UNUSED__ Eina_Share_Common_Head *head) {
327}
328static void _eina_share_common_population_head_add(
329 __UNUSED__ Eina_Share *share,
330 __UNUSED__
331 Eina_Share_Common_Head *head) {
332}
333static void _eina_share_common_population_head_del(
334 __UNUSED__ Eina_Share *share,
335 __UNUSED__
336 Eina_Share_Common_Head *head) {
337}
338#endif
339
340static int
341_eina_share_common_cmp(const Eina_Share_Common_Head *ed,
342 const int *hash,
343 __UNUSED__ int length,
344 __UNUSED__ void *data)
345{
346 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, , 0);
347
348 return ed->hash - *hash;
349}
350
351static Eina_Rbtree_Direction
352_eina_share_common_node(const Eina_Share_Common_Head *left,
353 const Eina_Share_Common_Head *right,
354 __UNUSED__ void *data)
355{
356 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(left, , 0);
357 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(right, , 0);
358
359 if (left->hash - right->hash < 0)
360 return EINA_RBTREE_LEFT;
361
362 return EINA_RBTREE_RIGHT;
363}
364
365static void
366_eina_share_common_head_free(Eina_Share_Common_Head *ed, __UNUSED__ void *data)
367{
368 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, );
369
370 while (ed->head)
371 {
372 Eina_Share_Common_Node *el = ed->head;
373
374 ed->head = ed->head->next;
375 if (el != &ed->builtin_node)
376 MAGIC_FREE(el);
377 }
378 MAGIC_FREE(ed);
379}
380
381static void
382_eina_share_common_node_init(Eina_Share_Common_Node *node,
383 const char *str,
384 int slen,
385 unsigned int null_size,
386 Eina_Magic node_magic)
387{
388 EINA_MAGIC_SET(node, node_magic);
389 node->references = 1;
390 node->length = slen;
391 memcpy(node->str, str, slen);
392 memset(node->str + slen, 0, null_size); /* Nullify the null */
393
394 (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
395}
396
397static Eina_Share_Common_Head *
398_eina_share_common_head_alloc(int slen)
399{
400 Eina_Share_Common_Head *head;
401 const size_t head_size = offsetof(Eina_Share_Common_Head, builtin_node.str);
402
403 head = malloc(head_size + slen);
404 if (!head)
405 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
406
407 return head;
408}
409
410static const char *
411_eina_share_common_add_head(Eina_Share *share,
412 Eina_Share_Common_Head **p_bucket,
413 int hash,
414 const char *str,
415 unsigned int slen,
416 unsigned int null_size)
417{
418 Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
419 Eina_Share_Common_Head *head;
420
421 head = _eina_share_common_head_alloc(slen + null_size);
422 if (!head)
423 return NULL;
424
425 EINA_MAGIC_SET(head, EINA_MAGIC_SHARE_HEAD);
426 head->hash = hash;
427 head->head = &head->builtin_node;
428 _eina_share_common_node_init(head->head,
429 str,
430 slen,
431 null_size,
432 share->node_magic);
433 head->head->next = NULL;
434
435 _eina_share_common_population_head_init(share, head);
436
437 *p_tree = eina_rbtree_inline_insert
438 (*p_tree, EINA_RBTREE_GET(head),
439 EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
440
441 return head->head->str;
442}
443
444static void
445_eina_share_common_del_head(Eina_Share_Common_Head **p_bucket,
446 Eina_Share_Common_Head *head)
447{
448 Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
449
450 *p_tree = eina_rbtree_inline_remove
451 (*p_tree, EINA_RBTREE_GET(head),
452 EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
453
454 MAGIC_FREE(head);
455}
456
457
458static inline Eina_Bool
459_eina_share_common_node_eq(const Eina_Share_Common_Node *node,
460 const char *str,
461 unsigned int slen)
462{
463 return ((node->length == slen) &&
464 (memcmp(node->str, str, slen) == 0));
465}
466
467static Eina_Share_Common_Node *
468_eina_share_common_head_find(Eina_Share_Common_Head *head,
469 const char *str,
470 unsigned int slen)
471{
472 Eina_Share_Common_Node *node, *prev;
473
474 node = head->head;
475 if (_eina_share_common_node_eq(node, str, slen))
476 return node;
477
478 prev = node;
479 node = node->next;
480 for (; node; prev = node, node = node->next)
481 if (_eina_share_common_node_eq(node, str, slen))
482 {
483 /* promote node, make hot items be at the beginning */
484 prev->next = node->next;
485 node->next = head->head;
486 head->head = node;
487 return node;
488 }
489
490 return NULL;
491}
492
493static Eina_Bool
494_eina_share_common_head_remove_node(Eina_Share_Common_Head *head,
495 const Eina_Share_Common_Node *node)
496{
497 Eina_Share_Common_Node *cur, *prev;
498
499 if (head->head == node)
500 {
501 head->head = node->next;
502 return 1;
503 }
504
505 prev = head->head;
506 cur = head->head->next;
507 for (; cur; prev = cur, cur = cur->next)
508 if (cur == node)
509 {
510 prev->next = cur->next;
511 return 1;
512 }
513
514 return 0;
515}
516
517static Eina_Share_Common_Head *
518_eina_share_common_find_hash(Eina_Share_Common_Head *bucket, int hash)
519{
520 return (Eina_Share_Common_Head *)eina_rbtree_inline_lookup
521 (EINA_RBTREE_GET(bucket), &hash, 0,
522 EINA_RBTREE_CMP_KEY_CB(_eina_share_common_cmp), NULL);
523}
524
525static Eina_Share_Common_Node *
526_eina_share_common_node_alloc(unsigned int slen, unsigned int null_size)
527{
528 Eina_Share_Common_Node *node;
529 const size_t node_size = offsetof(Eina_Share_Common_Node, str);
530
531 node = malloc(node_size + slen + null_size);
532 if (!node)
533 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
534
535 return node;
536}
537
538static Eina_Share_Common_Node *
539_eina_share_common_node_from_str(const char *str, Eina_Magic node_magic)
540{
541 Eina_Share_Common_Node *node;
542 const size_t offset = offsetof(Eina_Share_Common_Node, str);
543
544 node = (Eina_Share_Common_Node *)(str - offset);
545 EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL);
546 return node;
547
548 (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
549}
550
551static Eina_Bool
552eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__,
553 Eina_Share_Common_Head *head,
554 struct dumpinfo *fdata)
555{
556 Eina_Share_Common_Node *node;
557
558 fdata->used += sizeof(Eina_Share_Common_Head);
559 for (node = head->head; node; node = node->next)
560 {
561 printf("DDD: %5i %5i ", node->length, node->references);
562 printf("'%.*s'\n", node->length, ((char *)node) + sizeof(Eina_Share_Common_Node));
563 fdata->used += sizeof(Eina_Share_Common_Node);
564 fdata->used += node->length;
565 fdata->saved += (node->references - 1) * node->length;
566 fdata->dups += node->references - 1;
567 fdata->unique++;
568 }
569
570 return EINA_TRUE;
571}
572
573/**
574 * @endcond
575 */
576
577
578/*============================================================================*
579* Global *
580*============================================================================*/
581
582/**
583 * @internal
584 * @brief Initialize the share_common module.
585 *
586 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
587 *
588 * This function sets up the share_common module of Eina. It is called by
589 * eina_init().
590 *
591 * @see eina_init()
592 */
593Eina_Bool
594eina_share_common_init(Eina_Share **_share,
595 Eina_Magic node_magic,
596 const char *node_magic_STR)
597{
598 Eina_Share *share;
599
600 share = *_share = calloc(sizeof(Eina_Share), 1);
601 if (!share) goto on_error;
602
603 if (_eina_share_common_log_dom < 0) /*Only register if not already */
604 _eina_share_common_log_dom = eina_log_domain_register(
605 "eina_share",
606 EINA_LOG_COLOR_DEFAULT);
607
608 if (_eina_share_common_log_dom < 0)
609 {
610 EINA_LOG_ERR("Could not register log domain: eina_share_common");
611 goto on_error;
612 }
613
614 share->share = calloc(1, sizeof(Eina_Share_Common));
615 if (!share->share)
616 {
617 if (_eina_share_common_log_dom > 0)
618 {
619 eina_log_domain_unregister(_eina_share_common_log_dom);
620 _eina_share_common_log_dom = -1;
621 }
622
623 goto on_error;
624 }
625
626 share->node_magic = node_magic;
627#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
628 EMS(EINA_MAGIC_SHARE);
629 EMS(EINA_MAGIC_SHARE_HEAD);
630 EMS(node_magic);
631#undef EMS
632 EINA_MAGIC_SET(share->share, EINA_MAGIC_SHARE);
633
634 _eina_share_common_population_init(share);
635
636 /* below is the common part among other all eina_share_common user */
637 if (_eina_share_common_count++ != 0)
638 return EINA_TRUE;
639
640 eina_lock_new(&_mutex_big);
641 return EINA_TRUE;
642
643 on_error:
644 _eina_share_common_count--;
645 return EINA_FALSE;
646}
647
648/**
649 * @internal
650 * @brief Shut down the share_common module.
651 *
652 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
653 *
654 * This function shuts down the share_common module set up by
655 * eina_share_common_init(). It is called by eina_shutdown().
656 *
657 * @see eina_shutdown()
658 */
659Eina_Bool
660eina_share_common_shutdown(Eina_Share **_share)
661{
662 unsigned int i;
663 Eina_Share *share = *_share;
664
665 eina_lock_take(&_mutex_big);
666
667 _eina_share_common_population_stats(share);
668
669 /* remove any string still in the table */
670 for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
671 {
672 eina_rbtree_delete(EINA_RBTREE_GET(
673 share->share->buckets[i]),
674 EINA_RBTREE_FREE_CB(
675 _eina_share_common_head_free), NULL);
676 share->share->buckets[i] = NULL;
677 }
678 MAGIC_FREE(share->share);
679
680 _eina_share_common_population_shutdown(share);
681 if (_eina_share_common_log_dom > 0) /* Only free if necessary */
682 {
683 eina_log_domain_unregister(_eina_share_common_log_dom);
684 _eina_share_common_log_dom = -1;
685 }
686
687 eina_lock_release(&_mutex_big);
688
689 free(*_share);
690 *_share = NULL;
691
692 /* below is the common part among other all eina_share_common user */
693 if (--_eina_share_common_count != 0)
694 return EINA_TRUE;
695
696 eina_lock_free(&_mutex_big);
697
698 return EINA_TRUE;
699}
700
701#ifdef EFL_HAVE_THREADS
702
703/**
704 * @internal
705 * @brief Activate the share_common mutexes.
706 *
707 * This function activate the mutexes in the eina share_common module. It is called by
708 * eina_threads_init().
709 *
710 * @see eina_threads_init()
711 */
712void
713eina_share_common_threads_init(void)
714{
715 _share_common_threads_activated = EINA_TRUE;
716}
717
718/**
719 * @internal
720 * @brief Shut down the share_common mutexes.
721 *
722 * This function shuts down the mutexes in the share_common module.
723 * It is called by eina_threads_shutdown().
724 *
725 * @see eina_threads_shutdown()
726 */
727void
728eina_share_common_threads_shutdown(void)
729{
730 _share_common_threads_activated = EINA_FALSE;
731}
732
733#endif
734
735/*============================================================================*
736* API *
737*============================================================================*/
738
739/**
740 * @cond LOCAL
741 */
742
743const char *
744eina_share_common_add_length(Eina_Share *share,
745 const char *str,
746 unsigned int slen,
747 unsigned int null_size)
748{
749 Eina_Share_Common_Head **p_bucket, *ed;
750 Eina_Share_Common_Node *el;
751 int hash_num, hash;
752
753 if (!str)
754 return NULL;
755
756 eina_share_common_population_add(share, slen);
757
758 if (slen <= 0)
759 return NULL;
760
761 hash = eina_hash_superfast(str, slen);
762 hash_num = hash & 0xFF;
763 hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
764
765 eina_lock_take(&_mutex_big);
766 p_bucket = share->share->buckets + hash_num;
767
768 ed = _eina_share_common_find_hash(*p_bucket, hash);
769 if (!ed)
770 {
771 const char *s = _eina_share_common_add_head(share,
772 p_bucket,
773 hash,
774 str,
775 slen,
776 null_size);
777 eina_lock_release(&_mutex_big);
778 return s;
779 }
780
781 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), NULL);
782
783 el = _eina_share_common_head_find(ed, str, slen);
784 if (el)
785 {
786 EINA_MAGIC_CHECK_SHARE_COMMON_NODE(el,
787 share->node_magic,
788 eina_lock_release(&_mutex_big));
789 el->references++;
790 eina_lock_release(&_mutex_big);
791 return el->str;
792 }
793
794 el = _eina_share_common_node_alloc(slen, null_size);
795 if (!el)
796 {
797 eina_lock_release(&_mutex_big);
798 return NULL;
799 }
800
801 _eina_share_common_node_init(el, str, slen, null_size, share->node_magic);
802 el->next = ed->head;
803 ed->head = el;
804 _eina_share_common_population_head_add(share, ed);
805
806 eina_lock_release(&_mutex_big);
807
808 return el->str;
809}
810
811const char *
812eina_share_common_ref(Eina_Share *share, const char *str)
813{
814 Eina_Share_Common_Node *node;
815
816 if (!str)
817 return NULL;
818
819 eina_lock_take(&_mutex_big);
820 node = _eina_share_common_node_from_str(str, share->node_magic);
821 if (!node)
822 {
823 eina_lock_release(&_mutex_big);
824 return str;
825 }
826 node->references++;
827
828 eina_lock_release(&_mutex_big);
829
830 eina_share_common_population_add(share, node->length);
831
832 return str;
833}
834
835
836void
837eina_share_common_del(Eina_Share *share, const char *str)
838{
839 unsigned int slen;
840 Eina_Share_Common_Head *ed;
841 Eina_Share_Common_Head **p_bucket;
842 Eina_Share_Common_Node *node;
843 int hash_num, hash;
844
845 if (!str)
846 return;
847
848 eina_lock_take(&_mutex_big);
849
850 node = _eina_share_common_node_from_str(str, share->node_magic);
851 if (!node)
852 goto on_error;
853
854 slen = node->length;
855 eina_share_common_population_del(share, slen);
856 if (node->references > 1)
857 {
858 node->references--;
859 eina_lock_release(&_mutex_big);
860 return;
861 }
862
863 node->references = 0;
864
865 hash = eina_hash_superfast(str, slen);
866 hash_num = hash & 0xFF;
867 hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
868
869 p_bucket = share->share->buckets + hash_num;
870 ed = _eina_share_common_find_hash(*p_bucket, hash);
871 if (!ed)
872 goto on_error;
873
874 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big));
875
876 if (!_eina_share_common_head_remove_node(ed, node))
877 goto on_error;
878
879 if (node != &ed->builtin_node)
880 MAGIC_FREE(node);
881
882 if (!ed->head)
883 _eina_share_common_del_head(p_bucket, ed);
884 else
885 _eina_share_common_population_head_del(share, ed);
886
887 eina_lock_release(&_mutex_big);
888
889 return;
890
891on_error:
892 eina_lock_release(&_mutex_big);
893 /* possible segfault happened before here, but... */
894 CRITICAL("EEEK trying to del non-shared share_common \"%s\"", str);
895}
896
897int
898eina_share_common_length(__UNUSED__ Eina_Share *share, const char *str)
899{
900 const Eina_Share_Common_Node *node;
901
902 if (!str)
903 return -1;
904
905 node = _eina_share_common_node_from_str(str, share->node_magic);
906 if (!node) return 0;
907 return node->length;
908}
909
910void
911eina_share_common_dump(Eina_Share *share, void (*additional_dump)(
912 struct dumpinfo *), int used)
913{
914 Eina_Iterator *it;
915 unsigned int i;
916 struct dumpinfo di;
917
918 if (!share)
919 return;
920
921 di.used = used;
922 di.saved = 0;
923 di.dups = 0;
924 di.unique = 0;
925 printf("DDD: len ref string\n");
926 printf("DDD:-------------------\n");
927
928 eina_lock_take(&_mutex_big);
929 for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
930 {
931 if (!share->share->buckets[i])
932 {
933 continue; // printf("DDD: BUCKET # %i (HEAD=%i, NODE=%i)\n", i,
934
935 }
936
937// sizeof(Eina_Share_Common_Head), sizeof(Eina_Share_Common_Node));
938 it = eina_rbtree_iterator_prefix(
939 (Eina_Rbtree *)share->share->buckets[i]);
940 eina_iterator_foreach(it, EINA_EACH_CB(eina_iterator_array_check), &di);
941 eina_iterator_free(it);
942 }
943 if (additional_dump)
944 additional_dump(&di);
945
946#ifdef EINA_SHARE_COMMON_USAGE
947 /* One character strings are not counted in the hash. */
948 di.saved += share->population_group[0].count * sizeof(char);
949 di.saved += share->population_group[1].count * sizeof(char) * 2;
950#endif
951 printf("DDD:-------------------\n");
952 printf("DDD: usage (bytes) = %i, saved = %i (%3.0f%%)\n",
953 di.used, di.saved, di.used ? (di.saved * 100.0 / di.used) : 0.0);
954 printf("DDD: unique: %d, duplicates: %d (%3.0f%%)\n",
955 di.unique, di.dups, di.unique ? (di.dups * 100.0 / di.unique) : 0.0);
956
957#ifdef EINA_SHARE_COMMON_USAGE
958 printf("DDD: Allocated strings: %i\n", share->population.count);
959 printf("DDD: Max allocated strings: %i\n", share->population.max);
960
961 for (i = 0;
962 i < sizeof (share->population_group) /
963 sizeof (share->population_group[0]);
964 ++i)
965 fprintf(stderr,
966 "DDD: %i strings of length %i, max strings: %i\n",
967 share->population_group[i].count,
968 i,
969 share->population_group[i].max);
970#endif
971
972 eina_lock_release(&_mutex_big);
973}
974
975/**
976 * @endcond
977 */