efl/src/lib/eina/eina_stringshare.c

757 lines
18 KiB
C
Raw Normal View History

/* EINA - EFL data type library
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2010
* Carsten Haitzler,
* Jorge Luis Zapata Muga,
* Cedric Bail,
* Gustavo Sverzut Barbieri
* Tom Hacohen
* Brett Nash
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
2010-07-27 19:37:05 -07:00
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "eina_config.h"
#include "eina_private.h"
#include "eina_alloca.h"
#include "eina_log.h"
#include "eina_lock.h"
#include "eina_share_common.h"
/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
#include "eina_safety_checks.h"
#include "eina_stringshare.h"
#ifdef CRI
#undef CRI
#endif
#define CRI(...) EINA_LOG_DOM_CRIT(_eina_share_stringshare_log_dom, __VA_ARGS__)
#ifdef ERR
#undef ERR
#endif
#define ERR(...) EINA_LOG_DOM_ERR(_eina_share_stringshare_log_dom, __VA_ARGS__)
#ifdef DBG
#undef DBG
#endif
#define DBG(...) EINA_LOG_DOM_DBG(_eina_share_stringshare_log_dom, __VA_ARGS__)
int _eina_share_stringshare_log_dom = -1;
/* The actual share */
static Eina_Share *stringshare_share;
static const char EINA_MAGIC_STRINGSHARE_NODE_STR[] = "Eina Stringshare Node";
extern Eina_Bool _share_common_threads_activated;
static Eina_Spinlock _mutex_small;
/* Stringshare optimizations */
static const unsigned char _eina_stringshare_single[512] = {
2010-07-27 19:37:05 -07:00
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,
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,
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,
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,
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,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,
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,
105,0,
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,
0,119,0,120,0,
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,
0,134,0,135,0,
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,
0,149,0,150,0,
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,
0,164,0,165,0,
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,
0,179,0,180,0,
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,
0,194,0,195,0,
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,
0,209,0,210,0,
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,
0,224,0,225,0,
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,
0,239,0,240,0,
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,
0,254,0,255,0
};
2010-07-27 19:37:05 -07:00
typedef struct _Eina_Stringshare_Small Eina_Stringshare_Small;
typedef struct _Eina_Stringshare_Small_Bucket Eina_Stringshare_Small_Bucket;
struct _Eina_Stringshare_Small_Bucket
{
/* separate arrays for faster lookups */
2010-07-27 19:37:05 -07:00
const char **strings;
unsigned char *lengths;
unsigned int *references;
int count;
int size;
};
struct _Eina_Stringshare_Small
{
Eina_Stringshare_Small_Bucket *buckets[256];
};
#define EINA_STRINGSHARE_SMALL_BUCKET_STEP 8
static Eina_Stringshare_Small _eina_small_share;
static inline int
2010-07-27 19:37:05 -07:00
_eina_stringshare_small_cmp(const Eina_Stringshare_Small_Bucket *bucket,
int i,
const char *pstr,
unsigned char plength)
{
/* pstr and plength are from second char and on, since the first is
* always the same.
*
* First string being always the same, size being between 2 and 3
* characters (there is a check for special case length==1 and then
* small stringshare is applied to strings < 4), we just need to
* compare 2 characters of both strings.
*/
const unsigned char cur_plength = bucket->lengths[i] - 1;
const char *cur_pstr;
if (cur_plength > plength)
return 1;
else if (cur_plength < plength)
return -1;
cur_pstr = bucket->strings[i] + 1;
if (cur_pstr[0] > pstr[0])
return 1;
else if (cur_pstr[0] < pstr[0])
return -1;
if (plength == 1)
return 0;
if (cur_pstr[1] > pstr[1])
return 1;
else if (cur_pstr[1] < pstr[1])
return -1;
return 0;
}
static const char *
2010-07-27 19:37:05 -07:00
_eina_stringshare_small_bucket_find(const Eina_Stringshare_Small_Bucket *bucket,
const char *str,
unsigned char length,
int *idx)
{
const char *pstr = str + 1; /* skip first letter, it's always the same */
unsigned char plength = length - 1;
int i, low, high;
if (bucket->count == 0)
{
2010-07-27 19:37:05 -07:00
*idx = 0;
return NULL;
}
low = 0;
high = bucket->count;
while (low < high)
{
2010-07-27 19:37:05 -07:00
int r;
i = (low + high - 1) / 2;
r = _eina_stringshare_small_cmp(bucket, i, pstr, plength);
if (r > 0)
high = i;
2010-07-27 19:37:05 -07:00
else if (r < 0)
low = i + 1;
2010-07-27 19:37:05 -07:00
else
{
*idx = i;
return bucket->strings[i];
}
}
*idx = low;
return NULL;
}
static Eina_Bool
2010-07-27 19:37:05 -07:00
_eina_stringshare_small_bucket_resize(Eina_Stringshare_Small_Bucket *bucket,
int size)
{
void *tmp;
2010-07-27 19:37:05 -07:00
tmp = realloc((void *)bucket->strings, size * sizeof(bucket->strings[0]));
if (!tmp) return 0;
bucket->strings = tmp;
tmp = realloc(bucket->lengths, size * sizeof(bucket->lengths[0]));
if (!tmp) return 0;
bucket->lengths = tmp;
tmp = realloc(bucket->references, size * sizeof(bucket->references[0]));
if (!tmp) return 0;
bucket->references = tmp;
bucket->size = size;
return 1;
}
static const char *
2010-07-27 19:37:05 -07:00
_eina_stringshare_small_bucket_insert_at(
Eina_Stringshare_Small_Bucket **p_bucket,
const char *str,
unsigned char length,
int idx)
{
Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
int todo, off;
char *snew;
if (!bucket)
{
2010-07-27 19:37:05 -07:00
*p_bucket = bucket = calloc(1, sizeof(*bucket));
if (!bucket) return NULL;
}
if (bucket->count + 1 >= bucket->size)
{
2010-07-27 19:37:05 -07:00
int size = bucket->size + EINA_STRINGSHARE_SMALL_BUCKET_STEP;
if (!_eina_stringshare_small_bucket_resize(bucket, size))
return NULL;
}
snew = malloc(length + 1);
if (!snew) return NULL;
2010-07-27 19:37:05 -07:00
memcpy(snew, str, length);
snew[length] = '\0';
off = idx + 1;
todo = bucket->count - idx;
if (todo > 0)
{
2010-07-27 19:37:05 -07:00
memmove((void *)(bucket->strings + off), bucket->strings + idx,
todo * sizeof(bucket->strings[0]));
memmove(bucket->lengths + off, bucket->lengths + idx,
todo * sizeof(bucket->lengths[0]));
memmove(bucket->references + off, bucket->references + idx,
todo * sizeof(bucket->references[0]));
}
bucket->strings[idx] = snew;
bucket->lengths[idx] = length;
bucket->references[idx] = 1;
bucket->count++;
return snew;
}
static void
2010-07-27 19:37:05 -07:00
_eina_stringshare_small_bucket_remove_at(
Eina_Stringshare_Small_Bucket **p_bucket,
int idx)
{
Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
int todo, off;
if (bucket->references[idx] > 1)
{
2010-07-27 19:37:05 -07:00
bucket->references[idx]--;
return;
}
free((char *)bucket->strings[idx]);
if (bucket->count == 1)
{
2010-07-27 19:37:05 -07:00
free((void *)bucket->strings);
free(bucket->lengths);
free(bucket->references);
free(bucket);
*p_bucket = NULL;
return;
}
bucket->count--;
if (idx == bucket->count)
goto end;
off = idx + 1;
todo = bucket->count - idx;
memmove((void *)(bucket->strings + idx), bucket->strings + off,
2010-07-27 19:37:05 -07:00
todo * sizeof(bucket->strings[0]));
memmove(bucket->lengths + idx, bucket->lengths + off,
todo * sizeof(bucket->lengths[0]));
memmove(bucket->references + idx, bucket->references + off,
todo * sizeof(bucket->references[0]));
2010-07-27 19:37:05 -07:00
end:
if (bucket->count + EINA_STRINGSHARE_SMALL_BUCKET_STEP < bucket->size)
{
2010-07-27 19:37:05 -07:00
int size = bucket->size - EINA_STRINGSHARE_SMALL_BUCKET_STEP;
_eina_stringshare_small_bucket_resize(bucket, size);
}
}
static const char *
_eina_stringshare_small_add(const char *str, unsigned char length)
{
Eina_Stringshare_Small_Bucket **bucket;
int i;
bucket = _eina_small_share.buckets + (unsigned char)str[0];
if (!*bucket)
i = 0;
else
{
2010-07-27 19:37:05 -07:00
const char *ret;
ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i);
if (ret)
{
(*bucket)->references[i]++;
return ret;
}
}
return _eina_stringshare_small_bucket_insert_at(bucket, str, length, i);
}
static void
_eina_stringshare_small_del(const char *str, unsigned char length)
{
Eina_Stringshare_Small_Bucket **bucket;
const char *ret;
int i;
bucket = _eina_small_share.buckets + (unsigned char)str[0];
if (!*bucket)
goto error;
ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i);
if (!ret)
goto error;
_eina_stringshare_small_bucket_remove_at(bucket, i);
return;
2010-07-27 19:37:05 -07:00
error:
CRI("EEEK trying to del non-shared stringshare \"%s\"", str);
}
static void
_eina_stringshare_small_init(void)
{
eina_spinlock_new(&_mutex_small);
memset(&_eina_small_share, 0, sizeof(_eina_small_share));
}
static void
_eina_stringshare_small_shutdown(void)
{
Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end;
p_bucket = _eina_small_share.buckets;
p_bucket_end = p_bucket + 256;
for (; p_bucket < p_bucket_end; p_bucket++)
{
2010-07-27 19:37:05 -07:00
Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
char **s, **s_end;
if (!bucket)
continue;
2010-07-27 19:37:05 -07:00
s = (char **)bucket->strings;
s_end = s + bucket->count;
for (; s < s_end; s++)
free(*s);
2010-07-27 19:37:05 -07:00
free((void *)bucket->strings);
free(bucket->lengths);
free(bucket->references);
free(bucket);
2010-07-27 19:37:05 -07:00
*p_bucket = NULL;
}
eina_spinlock_free(&_mutex_small);
}
static void
2010-07-27 19:37:05 -07:00
_eina_stringshare_small_bucket_dump(Eina_Stringshare_Small_Bucket *bucket,
struct dumpinfo *di)
{
const char **s = bucket->strings;
unsigned char *l = bucket->lengths;
unsigned int *r = bucket->references;
int i;
di->used += sizeof(*bucket);
di->used += bucket->count * sizeof(*s);
di->used += bucket->count * sizeof(*l);
di->used += bucket->count * sizeof(*r);
di->unique += bucket->count;
for (i = 0; i < bucket->count; i++, s++, l++, r++)
{
2010-07-27 19:37:05 -07:00
int dups;
printf("DDD: %5hhu %5u '%s'\n", *l, *r, *s);
2010-07-27 19:37:05 -07:00
dups = (*r - 1);
2010-07-27 19:37:05 -07:00
di->used += *l;
di->saved += *l * dups;
di->dups += dups;
}
}
static void
_eina_stringshare_small_dump(struct dumpinfo *di)
{
Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end;
p_bucket = _eina_small_share.buckets;
p_bucket_end = p_bucket + 256;
for (; p_bucket < p_bucket_end; p_bucket++)
{
2010-07-27 19:37:05 -07:00
Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
2010-07-27 19:37:05 -07:00
if (!bucket)
continue;
2010-07-27 19:37:05 -07:00
_eina_stringshare_small_bucket_dump(bucket, di);
}
}
/*============================================================================*
* Global *
*============================================================================*/
/**
* @internal
* @brief Initialize the share_common module.
*
* @return #EINA_TRUE on success, #EINA_FALSE on failure.
*
* This function sets up the share_common module of Eina. It is called by
* eina_init().
*
* @see eina_init()
*/
Eina_Bool
eina_stringshare_init(void)
{
Eina_Bool ret;
if (_eina_share_stringshare_log_dom < 0)
{
_eina_share_stringshare_log_dom = eina_log_domain_register
("eina_stringshare", EINA_LOG_COLOR_DEFAULT);
if (_eina_share_stringshare_log_dom < 0)
{
EINA_LOG_ERR("Could not register log domain: eina_stringshare");
return EINA_FALSE;
}
}
2010-07-27 19:37:05 -07:00
ret = eina_share_common_init(&stringshare_share,
EINA_MAGIC_STRINGSHARE_NODE,
EINA_MAGIC_STRINGSHARE_NODE_STR);
if (ret)
_eina_stringshare_small_init();
else
{
eina_log_domain_unregister(_eina_share_stringshare_log_dom);
_eina_share_stringshare_log_dom = -1;
}
2010-07-27 19:37:05 -07:00
return ret;
}
/**
* @internal
* @brief Shut down the share_common module.
*
* @return #EINA_TRUE on success, #EINA_FALSE on failure.
*
* This function shuts down the share_common module set up by
* eina_share_common_init(). It is called by eina_shutdown().
*
* @see eina_shutdown()
*/
Eina_Bool
eina_stringshare_shutdown(void)
{
Eina_Bool ret;
_eina_stringshare_small_shutdown();
ret = eina_share_common_shutdown(&stringshare_share);
if (_eina_share_stringshare_log_dom >= 0)
{
eina_log_domain_unregister(_eina_share_stringshare_log_dom);
_eina_share_stringshare_log_dom = -1;
}
return ret;
}
/*============================================================================*
* API *
*============================================================================*/
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API void
eina_stringshare_del(Eina_Stringshare *str)
{
int slen;
if (!str)
return;
2010-07-27 19:37:05 -07:00
/* special cases */
if (str[0] == '\0')
slen = 0;
2010-07-27 19:37:05 -07:00
else if (str[1] == '\0')
slen = 1;
2010-07-27 19:37:05 -07:00
else if (str[2] == '\0')
slen = 2;
2010-07-27 19:37:05 -07:00
else if (str[3] == '\0')
slen = 3;
2010-07-27 19:37:05 -07:00
else
slen = 4; /* handled later */
if (slen < 2)
{
eina_share_common_population_del(stringshare_share, slen);
return;
}
else if (slen < 4)
{
eina_share_common_population_del(stringshare_share, slen);
eina_spinlock_take(&_mutex_small);
_eina_stringshare_small_del(str, slen);
eina_spinlock_release(&_mutex_small);
return;
}
2010-07-27 19:37:05 -07:00
if (!eina_share_common_del(stringshare_share, str))
CRI("EEEK trying to del non-shared stringshare \"%s\"", str);
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Stringshare *
eina_stringshare_add_length(const char *str, unsigned int slen)
{
if (!str)
return NULL;
else if (slen == 0)
{
eina_share_common_population_add(stringshare_share, slen);
return "";
}
else if (slen == 1)
{
eina_share_common_population_add(stringshare_share, slen);
return (Eina_Stringshare *) _eina_stringshare_single + ((*str) << 1);
}
else if (slen < 4)
{
const char *s;
eina_share_common_population_add(stringshare_share, slen);
eina_spinlock_take(&_mutex_small);
s = _eina_stringshare_small_add(str, slen);
eina_spinlock_release(&_mutex_small);
return s;
}
2010-07-27 19:37:05 -07:00
return eina_share_common_add_length(stringshare_share, str, slen *
sizeof(char), sizeof(char));
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Stringshare *
eina_stringshare_add(const char *str)
{
if (!str) return NULL;
return eina_stringshare_add_length(str, strlen(str));
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Stringshare *
eina_stringshare_printf(const char *fmt, ...)
{
va_list args;
char *tmp = NULL;
const char *ret = "";
int len;
2010-07-27 19:37:05 -07:00
if (!fmt)
return NULL;
va_start(args, fmt);
len = vasprintf(&tmp, fmt, args);
va_end(args);
if (len < 1) goto on_error;
ret = eina_stringshare_add_length(tmp, len);
on_error:
free(tmp);
return ret;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Stringshare *
eina_stringshare_vprintf(const char *fmt, va_list args)
{
char *tmp = NULL;
const char *ret = "";
int len;
2010-07-27 19:37:05 -07:00
if (!fmt)
return NULL;
len = vasprintf(&tmp, fmt, args);
if (len < 1) goto on_error;
ret = eina_stringshare_add_length(tmp, len);
on_error:
free(tmp);
return ret;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Stringshare *
eina_stringshare_nprintf(unsigned int len, const char *fmt, ...)
{
va_list args;
char *tmp;
int size;
2010-07-27 19:37:05 -07:00
if (!fmt)
return NULL;
2010-07-27 19:37:05 -07:00
if (len == 0)
return "";
tmp = alloca(sizeof(char) * (len + 1));
va_start(args, fmt);
size = vsnprintf(tmp, len, fmt, args);
va_end(args);
if (size < 1)
return "";
if ((unsigned int)size > len)
size = len;
2013-11-12 02:01:10 -08:00
return eina_stringshare_add_length(tmp, size);
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Stringshare *
eina_stringshare_ref(Eina_Stringshare *str)
{
int slen;
2010-07-27 19:37:05 -07:00
if (!str)
return NULL;
/* special cases */
2010-07-27 19:37:05 -07:00
if (str[0] == '\0')
slen = 0;
2010-07-27 19:37:05 -07:00
else if (str[1] == '\0')
slen = 1;
2010-07-27 19:37:05 -07:00
else if (str[2] == '\0')
slen = 2;
2010-07-27 19:37:05 -07:00
else if (str[3] == '\0')
slen = 3;
2010-07-27 19:37:05 -07:00
else
slen = 3 + (int)strlen(str + 3);
if (slen < 2)
{
2010-07-27 19:37:05 -07:00
eina_share_common_population_add(stringshare_share, slen);
2010-07-27 19:37:05 -07:00
return str;
}
else if (slen < 4)
{
2010-07-27 19:37:05 -07:00
const char *s;
eina_share_common_population_add(stringshare_share, slen);
eina_spinlock_take(&_mutex_small);
2010-07-27 19:37:05 -07:00
s = _eina_stringshare_small_add(str, slen);
eina_spinlock_release(&_mutex_small);
2010-07-27 19:37:05 -07:00
return s;
}
return eina_share_common_ref(stringshare_share, str);
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API int
eina_stringshare_strlen(Eina_Stringshare *str)
{
int len;
if (!str) return 0;
/* special cases */
2010-07-27 19:37:05 -07:00
if (str[0] == '\0')
return 0;
2010-07-27 19:37:05 -07:00
if (str[1] == '\0')
return 1;
2010-07-27 19:37:05 -07:00
if (str[2] == '\0')
return 2;
2010-07-27 19:37:05 -07:00
if (str[3] == '\0')
return 3;
len = eina_share_common_length(stringshare_share, (Eina_Stringshare *) str);
2010-07-27 19:37:05 -07:00
len = (len > 0) ? len / (int)sizeof(char) : -1;
return len;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API void
eina_stringshare_dump(void)
{
2010-07-27 19:37:05 -07:00
eina_share_common_dump(stringshare_share,
_eina_stringshare_small_dump,
sizeof(_eina_stringshare_single));
}