EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_share_common.c
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
96 static const char EINA_MAGIC_SHARE_STR[] = "Eina Share";
97 static const char EINA_MAGIC_SHARE_HEAD_STR[] = "Eina Share Head";
98
99 static 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
121 typedef struct _Eina_Share_Common_Population Eina_Share_Common_Population;
122 #endif
123
124 typedef struct _Eina_Share_Common Eina_Share_Common;
125 typedef struct _Eina_Share_Common_Node Eina_Share_Common_Node;
126 typedef struct _Eina_Share_Common_Head Eina_Share_Common_Head;
127
128 struct _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
138 struct _Eina_Share_Common
139 {
140    Eina_Share_Common_Head *buckets[EINA_SHARE_COMMON_BUCKETS];
141
142    EINA_MAGIC
143 };
144
145 struct _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
156 struct _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
171 Eina_Bool _share_common_threads_activated = EINA_FALSE;
172
173 static Eina_Lock _mutex_big;
174
175 #ifdef EINA_SHARE_COMMON_USAGE
176 struct _Eina_Share_Common_Population
177 {
178    int count;
179    int max;
180 };
181
182 static Eina_Share_Common_Population population = { 0, 0 };
183
184 static Eina_Share_Common_Population population_group[4] =
185 {
186    { 0, 0 },
187    { 0, 0 },
188    { 0, 0 },
189    { 0, 0 }
190 };
191
192 static 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
207 static 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
226 static 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
250 void
251 eina_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
271 void
272 eina_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
283 static void
284 _eina_share_common_population_head_init(Eina_Share *share,
285                                         Eina_Share_Common_Head *head)
286 {
287    head->population = 1;
288 }
289
290 static 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
299 static 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
308 static void _eina_share_common_population_init(__UNUSED__ Eina_Share *share) {
309 }
310 static void _eina_share_common_population_shutdown(__UNUSED__ Eina_Share *share)
311 {
312 }
313 static void _eina_share_common_population_stats(__UNUSED__ Eina_Share *share) {
314 }
315 void eina_share_common_population_add(__UNUSED__ Eina_Share *share,
316                                       __UNUSED__ int slen) {
317 }
318 void eina_share_common_population_del(__UNUSED__ Eina_Share *share,
319                                       __UNUSED__ int slen) {
320 }
321 static void _eina_share_common_population_head_init(
322    __UNUSED__ Eina_Share *share,
323    __UNUSED__ Eina_Share_Common_Head *head) {
324 }
325 static void _eina_share_common_population_head_add(
326    __UNUSED__ Eina_Share *share,
327    __UNUSED__
328    Eina_Share_Common_Head *head) {
329 }
330 static void _eina_share_common_population_head_del(
331    __UNUSED__ Eina_Share *share,
332    __UNUSED__
333    Eina_Share_Common_Head *head) {
334 }
335 #endif
336
337 static 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
348 static 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
362 static 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
378 static 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
394 static 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
407 static 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
441 static 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
455 static 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
464 static 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
490 static 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
514 static 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
522 static 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
535 static 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
548 static Eina_Bool
549 eina_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  */
590 Eina_Bool
591 eina_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  */
636 Eina_Bool
637 eina_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  */
684 void
685 eina_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  */
699 void
700 eina_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
715 const char *
716 eina_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
783 const char *
784 eina_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
808 Eina_Bool
809 eina_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
863 on_error:
864    eina_lock_release(&_mutex_big);
865    /* possible segfault happened before here, but... */
866    return EINA_FALSE;
867 }
868
869 int
870 eina_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
882 void
883 eina_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  */