enable adding just part of a string.

this allows us to add stringshare from a larger buffer that cannot be
modified.


SVN revision: 40516
This commit is contained in:
Gustavo Sverzut Barbieri 2009-05-06 04:11:01 +00:00
parent 48c7e28b20
commit ebeabe3735
2 changed files with 63 additions and 21 deletions

View File

@ -67,6 +67,7 @@
EAPI int eina_stringshare_init(void);
EAPI int eina_stringshare_shutdown(void);
EAPI const char *eina_stringshare_add_length(const char *str, unsigned int slen) EINA_WARN_UNUSED_RESULT;
EAPI const char *eina_stringshare_add(const char *str) EINA_WARN_UNUSED_RESULT;
EAPI const char *eina_stringshare_ref(const char *str);
EAPI void eina_stringshare_del(const char *str);

View File

@ -350,7 +350,7 @@ static Eina_Stringshare_Small _eina_small_share;
static inline int
_eina_stringshare_small_cmp(const Eina_Stringshare_Small_Bucket *bucket, int i, const char *pstr, unsigned char plength)
{
const unsigned char cur_plength = bucket->lengths[i] - 1;
const unsigned char cur_plength = bucket->lengths[i];
const char *cur_pstr;
if (cur_plength > plength)
@ -380,7 +380,7 @@ static const char *
_eina_stringshare_small_bucket_find(const Eina_Stringshare_Small_Bucket *bucket, const char *str, unsigned char length, int *index)
{
const char *pstr = str + 1; /* skip first letter, it's always the same */
unsigned char plength = length - 1;
unsigned char plength = length;
int i, low, high;
if (bucket->count == 0)
@ -456,6 +456,7 @@ _eina_stringshare_small_bucket_insert_at(Eina_Stringshare_Small_Bucket **p_bucke
{
Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
int todo, off;
char *snew;
if (!bucket)
{
@ -474,18 +475,20 @@ _eina_stringshare_small_bucket_insert_at(Eina_Stringshare_Small_Bucket **p_bucke
return NULL;
}
str = strdup(str);
if (!str)
snew = malloc(length + 1);
if (!snew)
{
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return NULL;
}
memcpy(snew, str, length);
snew[length] = '\0';
off = index + 1;
todo = bucket->count - index;
if (todo > 0)
{
memmove((void *)(bucket->strings + off), bucket->strings + index,
memmove((void *)(bucket->strings + off), bucket->strings + index,
todo * sizeof(bucket->strings[0]));
memmove(bucket->lengths + off, bucket->lengths + index,
todo * sizeof(bucket->lengths[0]));
@ -493,12 +496,12 @@ _eina_stringshare_small_bucket_insert_at(Eina_Stringshare_Small_Bucket **p_bucke
todo * sizeof(bucket->references[0]));
}
bucket->strings[index] = str;
bucket->strings[index] = snew;
bucket->lengths[index] = length;
bucket->references[index] = 1;
bucket->count++;
return str;
return snew;
}
static void
@ -635,6 +638,7 @@ _eina_stringshare_node_init(Eina_Stringshare_Node *node, const char *str, int sl
node->references = 1;
node->length = slen;
memcpy(node->str, str, slen);
node->str[slen] = '\0';
}
static Eina_Stringshare_Head *
@ -643,7 +647,7 @@ _eina_stringshare_head_alloc(int slen)
Eina_Stringshare_Head *head, t;
const size_t head_size = (char *)&(t.builtin_node.str) - (char *)&t;
head = malloc(head_size + slen);
head = malloc(head_size + slen + 1);
if (!head)
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
@ -756,7 +760,7 @@ _eina_stringshare_node_alloc(int slen)
Eina_Stringshare_Node *node, t;
const size_t node_size = (char *)&(t.str) - (char *)&t;
node = malloc(node_size + slen);
node = malloc(node_size + slen + 1);
if (!node)
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
@ -885,6 +889,7 @@ eina_stringshare_shutdown(void)
* @brief Retrieve an instance of a string for use in a program.
*
* @param str The string to retrieve an instance of.
* @param slen The string size (<= strlen(str)).
* @return A pointer to an instance of the string on success.
* @c NULL on failure.
*
@ -894,24 +899,24 @@ eina_stringshare_shutdown(void)
* it is added to the strings to be searched and a duplicated string
* of @p str is returned.
*
* This function does not check string size, but uses the give the
* exact given size. This can be used to stringshare part of a larger
* buffer or substring.
*
* @note it's not possible to have more than 65k references or strings
* bigger than 65k since we use 'unsigned short' to save space.
*
* @see eina_stringshare_add()
*/
EAPI const char *
eina_stringshare_add(const char *str)
eina_stringshare_add_length(const char *str, unsigned int slen)
{
Eina_Stringshare_Head **p_bucket, *ed;
Eina_Stringshare_Node *el;
int hash_num, slen, hash;
int hash_num, hash;
if (!str) return NULL;
if (str[0] == '\0') slen = 0;
else if (str[1] == '\0') slen = 1;
else if (str[2] == '\0') slen = 2;
else if (str[3] == '\0') slen = 3;
else slen = 3 + (int)strlen(str + 3);
_eina_stringshare_population_add(slen);
if (slen == 0)
@ -921,8 +926,6 @@ eina_stringshare_add(const char *str)
else if (slen < 4)
return _eina_stringshare_small_add(str, slen);
slen++; /* everything else need to account '\0' */
hash = eina_hash_superfast(str, slen);
hash_num = hash & 0xFF;
hash = (hash >> 8) & EINA_STRINGSHARE_MASK;
@ -954,6 +957,44 @@ eina_stringshare_add(const char *str)
return el->str;
}
/**
* @brief Retrieve an instance of a string for use in a program.
*
* @param str The NULL terminated string to retrieve an instance of.
* @return A pointer to an instance of the string on success.
* @c NULL on failure.
*
* This function retrieves an instance of @p str. If @p str is
* @c NULL, then @c NULL is returned. If @p str is already stored, it
* is just returned and its reference counter is increased. Otherwise
* it is added to the strings to be searched and a duplicated string
* of @p str is returned.
*
* The string @a str must be NULL terminated ('\0') and its full
* length will be used. To use part of the string or non-null
* terminated, use eina_stringshare_add_length() instead.
*
* @note it's not possible to have more than 65k references or strings
* bigger than 65k since we use 'unsigned short' to save space.
*
* @see eina_stringshare_add_length()
*/
EAPI const char *
eina_stringshare_add(const char *str)
{
int slen;
if (!str) return NULL;
if (str[0] == '\0') slen = 0;
else if (str[1] == '\0') slen = 1;
else if (str[2] == '\0') slen = 2;
else if (str[3] == '\0') slen = 3;
else slen = 3 + (int)strlen(str + 3);
return eina_stringshare_add_length(str, slen);
}
static Eina_Stringshare_Node *
_eina_stringshare_node_from_str(const char *str)
{
@ -1058,7 +1099,7 @@ eina_stringshare_del(const char *str)
}
node->references = 0;
slen = node->length; /* already includes '\0' */
slen = node->length;
hash = eina_hash_superfast(str, slen);
hash_num = hash & 0xFF;
@ -1116,7 +1157,7 @@ eina_stringshare_strlen(const char *str)
if (str[3] == '\0') return 3;
node = _eina_stringshare_node_from_str(str);
return node->length - 1;
return node->length;
}
struct dumpinfo