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 
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "eina_config.h"
34 #include "eina_private.h"
35 #include "eina_alloca.h"
36 #include "eina_log.h"
37 #include "eina_lock.h"
38 #include "eina_share_common.h"
39 
40 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
41 #include "eina_safety_checks.h"
42 #include "eina_stringshare.h"
43 
44 
45 #ifdef CRI
46 #undef CRI
47 #endif
48 #define CRI(...) EINA_LOG_DOM_CRIT(_eina_share_stringshare_log_dom, __VA_ARGS__)
49 
50 #ifdef ERR
51 #undef ERR
52 #endif
53 #define ERR(...) EINA_LOG_DOM_ERR(_eina_share_stringshare_log_dom, __VA_ARGS__)
54 
55 #ifdef DBG
56 #undef DBG
57 #endif
58 #define DBG(...) EINA_LOG_DOM_DBG(_eina_share_stringshare_log_dom, __VA_ARGS__)
59 
60 int _eina_share_stringshare_log_dom = -1;
61 
62 /* The actual share */
63 static Eina_Share *stringshare_share;
64 static const char EINA_MAGIC_STRINGSHARE_NODE_STR[] = "Eina Stringshare Node";
65 
66 extern Eina_Bool _share_common_threads_activated;
67 static Eina_Spinlock _mutex_small;
68 
69 /* Stringshare optimizations */
70 static const unsigned char _eina_stringshare_single[512] = {
71    0,0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,
72    16,0,17,0,18,0,19,0,20,0,21,0,22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,
73    31,0,32,0,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,
74    46,0,47,0,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0,57,0,58,0,59,0,60,0,
75    61,0,62,0,63,0,64,0,65,0,66,0,67,0,68,0,69,0,70,0,71,0,72,0,73,0,74,0,75,0,
76    76,0,77,0,78,0,79,0,80,0,81,0,82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,
77    91,0,92,0,93,0,94,0,95,0,96,0,97,0,98,0,99,0,100,0,101,0,102,0,103,0,104,0,
78    105,0,
79    106,0,107,0,108,0,109,0,110,0,111,0,112,0,113,0,114,0,115,0,116,0,117,0,118,
80    0,119,0,120,0,
81    121,0,122,0,123,0,124,0,125,0,126,0,127,0,128,0,129,0,130,0,131,0,132,0,133,
82    0,134,0,135,0,
83    136,0,137,0,138,0,139,0,140,0,141,0,142,0,143,0,144,0,145,0,146,0,147,0,148,
84    0,149,0,150,0,
85    151,0,152,0,153,0,154,0,155,0,156,0,157,0,158,0,159,0,160,0,161,0,162,0,163,
86    0,164,0,165,0,
87    166,0,167,0,168,0,169,0,170,0,171,0,172,0,173,0,174,0,175,0,176,0,177,0,178,
88    0,179,0,180,0,
89    181,0,182,0,183,0,184,0,185,0,186,0,187,0,188,0,189,0,190,0,191,0,192,0,193,
90    0,194,0,195,0,
91    196,0,197,0,198,0,199,0,200,0,201,0,202,0,203,0,204,0,205,0,206,0,207,0,208,
92    0,209,0,210,0,
93    211,0,212,0,213,0,214,0,215,0,216,0,217,0,218,0,219,0,220,0,221,0,222,0,223,
94    0,224,0,225,0,
95    226,0,227,0,228,0,229,0,230,0,231,0,232,0,233,0,234,0,235,0,236,0,237,0,238,
96    0,239,0,240,0,
97    241,0,242,0,243,0,244,0,245,0,246,0,247,0,248,0,249,0,250,0,251,0,252,0,253,
98    0,254,0,255,0
99 };
100 
101 typedef struct _Eina_Stringshare_Small Eina_Stringshare_Small;
102 typedef struct _Eina_Stringshare_Small_Bucket Eina_Stringshare_Small_Bucket;
103 
104 struct _Eina_Stringshare_Small_Bucket
105 {
106    /* separate arrays for faster lookups */
107    const char **strings;
108    unsigned char *lengths;
109    unsigned int *references;
110    int count;
111    int size;
112 };
113 
114 struct _Eina_Stringshare_Small
115 {
116    Eina_Stringshare_Small_Bucket *buckets[256];
117 };
118 
119 #define EINA_STRINGSHARE_SMALL_BUCKET_STEP 8
120 static Eina_Stringshare_Small _eina_small_share;
121 
122 static inline int
_eina_stringshare_small_cmp(const Eina_Stringshare_Small_Bucket * bucket,int i,const char * pstr,unsigned char plength)123 _eina_stringshare_small_cmp(const Eina_Stringshare_Small_Bucket *bucket,
124                             int i,
125                             const char *pstr,
126                             unsigned char plength)
127 {
128    /* pstr and plength are from second char and on, since the first is
129     * always the same.
130     *
131     * First string being always the same, size being between 2 and 3
132     * characters (there is a check for special case length==1 and then
133     * small stringshare is applied to strings < 4), we just need to
134     * compare 2 characters of both strings.
135     */
136    const unsigned char cur_plength = bucket->lengths[i] - 1;
137    const char *cur_pstr;
138 
139    if (cur_plength > plength)
140      return 1;
141    else if (cur_plength < plength)
142      return -1;
143 
144    cur_pstr = bucket->strings[i] + 1;
145 
146    if (cur_pstr[0] > pstr[0])
147      return 1;
148    else if (cur_pstr[0] < pstr[0])
149      return -1;
150 
151    if (plength == 1)
152      return 0;
153 
154    if (cur_pstr[1] > pstr[1])
155      return 1;
156    else if (cur_pstr[1] < pstr[1])
157      return -1;
158 
159    return 0;
160 }
161 
162 static const char *
_eina_stringshare_small_bucket_find(const Eina_Stringshare_Small_Bucket * bucket,const char * str,unsigned char length,int * idx)163 _eina_stringshare_small_bucket_find(const Eina_Stringshare_Small_Bucket *bucket,
164                                     const char *str,
165                                     unsigned char length,
166                                     int *idx)
167 {
168    const char *pstr = str + 1; /* skip first letter, it's always the same */
169    unsigned char plength = length - 1;
170    int i, low, high;
171 
172    if (bucket->count == 0)
173      {
174         *idx = 0;
175         return NULL;
176      }
177 
178    low = 0;
179    high = bucket->count;
180 
181    while (low < high)
182      {
183         int r;
184 
185         i = (low + high - 1) / 2;
186 
187         r = _eina_stringshare_small_cmp(bucket, i, pstr, plength);
188         if (r > 0)
189           high = i;
190         else if (r < 0)
191           low = i + 1;
192         else
193           {
194              *idx = i;
195              return bucket->strings[i];
196           }
197      }
198 
199    *idx = low;
200    return NULL;
201 }
202 
203 static Eina_Bool
_eina_stringshare_small_bucket_resize(Eina_Stringshare_Small_Bucket * bucket,int size)204 _eina_stringshare_small_bucket_resize(Eina_Stringshare_Small_Bucket *bucket,
205                                       int size)
206 {
207    void *tmp;
208 
209    tmp = realloc((void *)bucket->strings, size * sizeof(bucket->strings[0]));
210    if (!tmp) return 0;
211    bucket->strings = tmp;
212 
213    tmp = realloc(bucket->lengths, size * sizeof(bucket->lengths[0]));
214    if (!tmp) return 0;
215    bucket->lengths = tmp;
216 
217    tmp = realloc(bucket->references, size * sizeof(bucket->references[0]));
218    if (!tmp) return 0;
219    bucket->references = tmp;
220 
221    bucket->size = size;
222    return 1;
223 }
224 
225 static const char *
_eina_stringshare_small_bucket_insert_at(Eina_Stringshare_Small_Bucket ** p_bucket,const char * str,unsigned char length,int idx)226 _eina_stringshare_small_bucket_insert_at(
227    Eina_Stringshare_Small_Bucket **p_bucket,
228    const char *str,
229    unsigned char length,
230    int idx)
231 {
232    Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
233    int todo, off;
234    char *snew;
235 
236    if (!bucket)
237      {
238         *p_bucket = bucket = calloc(1, sizeof(*bucket));
239         if (!bucket) return NULL;
240      }
241 
242    if (bucket->count + 1 >= bucket->size)
243      {
244         int size = bucket->size + EINA_STRINGSHARE_SMALL_BUCKET_STEP;
245         if (!_eina_stringshare_small_bucket_resize(bucket, size))
246           return NULL;
247      }
248 
249    snew = malloc(length + 1);
250    if (!snew) return NULL;
251 
252    memcpy(snew, str, length);
253    snew[length] = '\0';
254 
255    off = idx + 1;
256    todo = bucket->count - idx;
257    if (todo > 0)
258      {
259         memmove((void *)(bucket->strings + off), bucket->strings + idx,
260                 todo * sizeof(bucket->strings[0]));
261         memmove(bucket->lengths + off,           bucket->lengths + idx,
262                 todo * sizeof(bucket->lengths[0]));
263         memmove(bucket->references + off,        bucket->references + idx,
264                 todo * sizeof(bucket->references[0]));
265      }
266 
267    bucket->strings[idx] = snew;
268    bucket->lengths[idx] = length;
269    bucket->references[idx] = 1;
270    bucket->count++;
271 
272    return snew;
273 }
274 
275 static void
_eina_stringshare_small_bucket_remove_at(Eina_Stringshare_Small_Bucket ** p_bucket,int idx)276 _eina_stringshare_small_bucket_remove_at(
277    Eina_Stringshare_Small_Bucket **p_bucket,
278    int idx)
279 {
280    Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
281    int todo, off;
282 
283    if (bucket->references[idx] > 1)
284      {
285         bucket->references[idx]--;
286         return;
287      }
288 
289    free((char *)bucket->strings[idx]);
290 
291    if (bucket->count == 1)
292      {
293         free((void *)bucket->strings);
294         free(bucket->lengths);
295         free(bucket->references);
296         free(bucket);
297         *p_bucket = NULL;
298         return;
299      }
300 
301    bucket->count--;
302    if (idx == bucket->count)
303      goto end;
304 
305    off = idx + 1;
306    todo = bucket->count - idx;
307 
308    memmove((void *)(bucket->strings + idx), bucket->strings + off,
309            todo * sizeof(bucket->strings[0]));
310    memmove(bucket->lengths + idx,           bucket->lengths + off,
311            todo * sizeof(bucket->lengths[0]));
312    memmove(bucket->references + idx,        bucket->references + off,
313            todo * sizeof(bucket->references[0]));
314 
315 end:
316    if (bucket->count + EINA_STRINGSHARE_SMALL_BUCKET_STEP < bucket->size)
317      {
318         int size = bucket->size - EINA_STRINGSHARE_SMALL_BUCKET_STEP;
319         _eina_stringshare_small_bucket_resize(bucket, size);
320      }
321 }
322 
323 static const char *
_eina_stringshare_small_add(const char * str,unsigned char length)324 _eina_stringshare_small_add(const char *str, unsigned char length)
325 {
326    Eina_Stringshare_Small_Bucket **bucket;
327    int i;
328 
329    bucket = _eina_small_share.buckets + (unsigned char)str[0];
330    if (!*bucket)
331      i = 0;
332    else
333      {
334         const char *ret;
335         ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i);
336         if (ret)
337           {
338              (*bucket)->references[i]++;
339              return ret;
340           }
341      }
342 
343    return _eina_stringshare_small_bucket_insert_at(bucket, str, length, i);
344 }
345 
346 static void
_eina_stringshare_small_del(const char * str,unsigned char length)347 _eina_stringshare_small_del(const char *str, unsigned char length)
348 {
349    Eina_Stringshare_Small_Bucket **bucket;
350    const char *ret;
351    int i;
352 
353    bucket = _eina_small_share.buckets + (unsigned char)str[0];
354    if (!*bucket)
355      goto error;
356 
357    ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i);
358    if (!ret)
359      goto error;
360 
361    _eina_stringshare_small_bucket_remove_at(bucket, i);
362    return;
363 
364 error:
365    CRI("EEEK trying to del non-shared stringshare \"%s\"", str);
366 }
367 
368 static void
_eina_stringshare_small_init(void)369 _eina_stringshare_small_init(void)
370 {
371    eina_spinlock_new(&_mutex_small);
372    memset(&_eina_small_share, 0, sizeof(_eina_small_share));
373 }
374 
375 static void
_eina_stringshare_small_shutdown(void)376 _eina_stringshare_small_shutdown(void)
377 {
378    Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end;
379 
380    p_bucket = _eina_small_share.buckets;
381    p_bucket_end = p_bucket + 256;
382 
383    for (; p_bucket < p_bucket_end; p_bucket++)
384      {
385         Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
386         char **s, **s_end;
387 
388         if (!bucket)
389           continue;
390 
391         s = (char **)bucket->strings;
392         s_end = s + bucket->count;
393         for (; s < s_end; s++)
394           free(*s);
395 
396         free((void *)bucket->strings);
397         free(bucket->lengths);
398         free(bucket->references);
399         free(bucket);
400         *p_bucket = NULL;
401      }
402 
403    eina_spinlock_free(&_mutex_small);
404 }
405 
406 static void
_eina_stringshare_small_bucket_dump(Eina_Stringshare_Small_Bucket * bucket,struct dumpinfo * di)407 _eina_stringshare_small_bucket_dump(Eina_Stringshare_Small_Bucket *bucket,
408                                     struct dumpinfo *di)
409 {
410    const char **s = bucket->strings;
411    unsigned char *l = bucket->lengths;
412    unsigned int *r = bucket->references;
413    int i;
414 
415    di->used += sizeof(*bucket);
416    di->used += bucket->count * sizeof(*s);
417    di->used += bucket->count * sizeof(*l);
418    di->used += bucket->count * sizeof(*r);
419    di->unique += bucket->count;
420 
421    for (i = 0; i < bucket->count; i++, s++, l++, r++)
422      {
423         int dups;
424 
425         printf("DDD: %5hhu %5u '%s'\n", *l, *r, *s);
426 
427         dups = (*r - 1);
428 
429         di->used += *l;
430         di->saved += *l * dups;
431         di->dups += dups;
432      }
433 }
434 
435 static void
_eina_stringshare_small_dump(struct dumpinfo * di)436 _eina_stringshare_small_dump(struct dumpinfo *di)
437 {
438    Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end;
439 
440    p_bucket = _eina_small_share.buckets;
441    p_bucket_end = p_bucket + 256;
442 
443    for (; p_bucket < p_bucket_end; p_bucket++)
444      {
445         Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
446 
447         if (!bucket)
448           continue;
449 
450         _eina_stringshare_small_bucket_dump(bucket, di);
451      }
452 }
453 
454 
455 /*============================================================================*
456  *                                 Global                                     *
457  *============================================================================*/
458 
459 /**
460  * @internal
461  * @brief Initialize the share_common module.
462  *
463  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
464  *
465  * This function sets up the share_common module of Eina. It is called by
466  * eina_init().
467  *
468  * @see eina_init()
469  */
470 Eina_Bool
eina_stringshare_init(void)471 eina_stringshare_init(void)
472 {
473    Eina_Bool ret;
474 
475    if (_eina_share_stringshare_log_dom < 0)
476      {
477         _eina_share_stringshare_log_dom = eina_log_domain_register
478            ("eina_stringshare", EINA_LOG_COLOR_DEFAULT);
479 
480         if (_eina_share_stringshare_log_dom < 0)
481           {
482              EINA_LOG_ERR("Could not register log domain: eina_stringshare");
483              return EINA_FALSE;
484           }
485      }
486 
487    ret = eina_share_common_init(&stringshare_share,
488                                 EINA_MAGIC_STRINGSHARE_NODE,
489                                 EINA_MAGIC_STRINGSHARE_NODE_STR);
490    if (ret)
491      _eina_stringshare_small_init();
492    else
493      {
494         eina_log_domain_unregister(_eina_share_stringshare_log_dom);
495         _eina_share_stringshare_log_dom = -1;
496      }
497 
498    return ret;
499 }
500 
501 /**
502  * @internal
503  * @brief Shut down the share_common module.
504  *
505  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
506  *
507  * This function shuts down the share_common module set up by
508  * eina_share_common_init(). It is called by eina_shutdown().
509  *
510  * @see eina_shutdown()
511  */
512 Eina_Bool
eina_stringshare_shutdown(void)513 eina_stringshare_shutdown(void)
514 {
515    Eina_Bool ret;
516    _eina_stringshare_small_shutdown();
517    ret = eina_share_common_shutdown(&stringshare_share);
518 
519    if (_eina_share_stringshare_log_dom >= 0)
520      {
521         eina_log_domain_unregister(_eina_share_stringshare_log_dom);
522         _eina_share_stringshare_log_dom = -1;
523      }
524 
525    return ret;
526 }
527 
528 /*============================================================================*
529  *                                   API                                      *
530  *============================================================================*/
531 
532 EAPI void
eina_stringshare_del(Eina_Stringshare * str)533 eina_stringshare_del(Eina_Stringshare *str)
534 {
535    int slen;
536 
537    if (!str)
538      return;
539 
540    /* special cases */
541    if (str[0] == '\0')
542      slen = 0;
543    else if (str[1] == '\0')
544      slen = 1;
545    else if (str[2] == '\0')
546      slen = 2;
547    else if (str[3] == '\0')
548      slen = 3;
549    else
550      slen = 4;  /* handled later */
551 
552    if (slen < 2)
553      {
554         eina_share_common_population_del(stringshare_share, slen);
555 
556         return;
557      }
558    else if (slen < 4)
559      {
560         eina_share_common_population_del(stringshare_share, slen);
561         eina_spinlock_take(&_mutex_small);
562         _eina_stringshare_small_del(str, slen);
563         eina_spinlock_release(&_mutex_small);
564 
565         return;
566      }
567 
568    if (!eina_share_common_del(stringshare_share, str))
569      CRI("EEEK trying to del non-shared stringshare \"%s\"", str);
570 }
571 
572 EAPI Eina_Stringshare *
eina_stringshare_add_length(const char * str,unsigned int slen)573 eina_stringshare_add_length(const char *str, unsigned int slen)
574 {
575    if (!str)
576      return NULL;
577    else if (slen == 0)
578      {
579         eina_share_common_population_add(stringshare_share, slen);
580 
581         return "";
582      }
583    else if (slen == 1)
584      {
585         eina_share_common_population_add(stringshare_share, slen);
586 
587         return (Eina_Stringshare *) _eina_stringshare_single + ((*str) << 1);
588      }
589    else if (slen < 4)
590      {
591         const char *s;
592 
593         eina_share_common_population_add(stringshare_share, slen);
594         eina_spinlock_take(&_mutex_small);
595         s = _eina_stringshare_small_add(str, slen);
596         eina_spinlock_release(&_mutex_small);
597 
598         return s;
599      }
600 
601    return eina_share_common_add_length(stringshare_share, str, slen *
602                                        sizeof(char), sizeof(char));
603 }
604 
605 EAPI Eina_Stringshare *
eina_stringshare_add(const char * str)606 eina_stringshare_add(const char *str)
607 {
608    if (!str) return NULL;
609    return eina_stringshare_add_length(str, strlen(str));
610 }
611 
612 EAPI Eina_Stringshare *
eina_stringshare_printf(const char * fmt,...)613 eina_stringshare_printf(const char *fmt, ...)
614 {
615    va_list args;
616    char *tmp = NULL;
617    const char *ret = "";
618    int len;
619 
620    if (!fmt)
621      return NULL;
622 
623    va_start(args, fmt);
624    len = vasprintf(&tmp, fmt, args);
625    va_end(args);
626 
627    if (len < 1) goto on_error;
628 
629    ret = eina_stringshare_add_length(tmp, len);
630 
631  on_error:
632    free(tmp);
633    return ret;
634 }
635 
636 EAPI Eina_Stringshare *
eina_stringshare_vprintf(const char * fmt,va_list args)637 eina_stringshare_vprintf(const char *fmt, va_list args)
638 {
639    char *tmp = NULL;
640    const char *ret = "";
641    int len;
642 
643    if (!fmt)
644      return NULL;
645 
646    len = vasprintf(&tmp, fmt, args);
647 
648    if (len < 1) goto on_error;
649 
650    ret = eina_stringshare_add_length(tmp, len);
651 
652  on_error:
653    free(tmp);
654    return ret;
655 }
656 
657 EAPI Eina_Stringshare *
eina_stringshare_nprintf(unsigned int len,const char * fmt,...)658 eina_stringshare_nprintf(unsigned int len, const char *fmt, ...)
659 {
660    va_list args;
661    char *tmp;
662    int size;
663 
664    if (!fmt)
665      return NULL;
666 
667    if (len == 0)
668      return "";
669 
670    tmp = alloca(sizeof(char) * (len + 1));
671 
672    va_start(args, fmt);
673    size = vsnprintf(tmp, len, fmt, args);
674    va_end(args);
675 
676    if (size < 1)
677      return "";
678    if ((unsigned int)size > len)
679      size = len;
680 
681    return eina_stringshare_add_length(tmp, size);
682 }
683 
684 EAPI Eina_Stringshare *
eina_stringshare_ref(Eina_Stringshare * str)685 eina_stringshare_ref(Eina_Stringshare *str)
686 {
687    int slen;
688 
689    if (!str)
690      return NULL;
691 
692    /* special cases */
693    if      (str[0] == '\0')
694      slen = 0;
695    else if (str[1] == '\0')
696      slen = 1;
697    else if (str[2] == '\0')
698      slen = 2;
699    else if (str[3] == '\0')
700      slen = 3;
701    else
702      slen = 3 + (int)strlen(str + 3);
703 
704    if (slen < 2)
705      {
706         eina_share_common_population_add(stringshare_share, slen);
707 
708         return str;
709      }
710    else if (slen < 4)
711      {
712         const char *s;
713 
714         eina_share_common_population_add(stringshare_share, slen);
715         eina_spinlock_take(&_mutex_small);
716         s = _eina_stringshare_small_add(str, slen);
717         eina_spinlock_release(&_mutex_small);
718 
719         return s;
720      }
721 
722    return eina_share_common_ref(stringshare_share, str);
723 }
724 
725 EAPI int
eina_stringshare_strlen(Eina_Stringshare * str)726 eina_stringshare_strlen(Eina_Stringshare *str)
727 {
728    int len;
729 
730    if (!str) return 0;
731 
732    /* special cases */
733    if (str[0] == '\0')
734      return 0;
735 
736    if (str[1] == '\0')
737      return 1;
738 
739    if (str[2] == '\0')
740      return 2;
741 
742    if (str[3] == '\0')
743      return 3;
744 
745    len = eina_share_common_length(stringshare_share, (Eina_Stringshare *) str);
746    len = (len > 0) ? len / (int)sizeof(char) : -1;
747    return len;
748 }
749 
750 EAPI void
eina_stringshare_dump(void)751 eina_stringshare_dump(void)
752 {
753    eina_share_common_dump(stringshare_share,
754                           _eina_stringshare_small_dump,
755                           sizeof(_eina_stringshare_single));
756 }
757