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_init(void);
EAPI int eina_stringshare_shutdown(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_add(const char *str) EINA_WARN_UNUSED_RESULT;
EAPI const char *eina_stringshare_ref(const char *str); EAPI const char *eina_stringshare_ref(const char *str);
EAPI void eina_stringshare_del(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 static inline int
_eina_stringshare_small_cmp(const Eina_Stringshare_Small_Bucket *bucket, int i, const char *pstr, unsigned char plength) _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; const char *cur_pstr;
if (cur_plength > plength) 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) _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 */ 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; int i, low, high;
if (bucket->count == 0) 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; Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
int todo, off; int todo, off;
char *snew;
if (!bucket) if (!bucket)
{ {
@ -474,18 +475,20 @@ _eina_stringshare_small_bucket_insert_at(Eina_Stringshare_Small_Bucket **p_bucke
return NULL; return NULL;
} }
str = strdup(str); snew = malloc(length + 1);
if (!str) if (!snew)
{ {
eina_error_set(EINA_ERROR_OUT_OF_MEMORY); eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return NULL; return NULL;
} }
memcpy(snew, str, length);
snew[length] = '\0';
off = index + 1; off = index + 1;
todo = bucket->count - index; todo = bucket->count - index;
if (todo > 0) if (todo > 0)
{ {
memmove((void *)(bucket->strings + off), bucket->strings + index, memmove((void *)(bucket->strings + off), bucket->strings + index,
todo * sizeof(bucket->strings[0])); todo * sizeof(bucket->strings[0]));
memmove(bucket->lengths + off, bucket->lengths + index, memmove(bucket->lengths + off, bucket->lengths + index,
todo * sizeof(bucket->lengths[0])); 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])); todo * sizeof(bucket->references[0]));
} }
bucket->strings[index] = str; bucket->strings[index] = snew;
bucket->lengths[index] = length; bucket->lengths[index] = length;
bucket->references[index] = 1; bucket->references[index] = 1;
bucket->count++; bucket->count++;
return str; return snew;
} }
static void static void
@ -635,6 +638,7 @@ _eina_stringshare_node_init(Eina_Stringshare_Node *node, const char *str, int sl
node->references = 1; node->references = 1;
node->length = slen; node->length = slen;
memcpy(node->str, str, slen); memcpy(node->str, str, slen);
node->str[slen] = '\0';
} }
static Eina_Stringshare_Head * static Eina_Stringshare_Head *
@ -643,7 +647,7 @@ _eina_stringshare_head_alloc(int slen)
Eina_Stringshare_Head *head, t; Eina_Stringshare_Head *head, t;
const size_t head_size = (char *)&(t.builtin_node.str) - (char *)&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) if (!head)
eina_error_set(EINA_ERROR_OUT_OF_MEMORY); eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
@ -756,7 +760,7 @@ _eina_stringshare_node_alloc(int slen)
Eina_Stringshare_Node *node, t; Eina_Stringshare_Node *node, t;
const size_t node_size = (char *)&(t.str) - (char *)&t; const size_t node_size = (char *)&(t.str) - (char *)&t;
node = malloc(node_size + slen); node = malloc(node_size + slen + 1);
if (!node) if (!node)
eina_error_set(EINA_ERROR_OUT_OF_MEMORY); 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. * @brief Retrieve an instance of a string for use in a program.
* *
* @param str The string to retrieve an instance of. * @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. * @return A pointer to an instance of the string on success.
* @c NULL on failure. * @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 * it is added to the strings to be searched and a duplicated string
* of @p str is returned. * 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 * @note it's not possible to have more than 65k references or strings
* bigger than 65k since we use 'unsigned short' to save space. * bigger than 65k since we use 'unsigned short' to save space.
*
* @see eina_stringshare_add()
*/ */
EAPI const char * 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_Head **p_bucket, *ed;
Eina_Stringshare_Node *el; Eina_Stringshare_Node *el;
int hash_num, slen, hash; int hash_num, hash;
if (!str) return NULL; 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); _eina_stringshare_population_add(slen);
if (slen == 0) if (slen == 0)
@ -921,8 +926,6 @@ eina_stringshare_add(const char *str)
else if (slen < 4) else if (slen < 4)
return _eina_stringshare_small_add(str, slen); return _eina_stringshare_small_add(str, slen);
slen++; /* everything else need to account '\0' */
hash = eina_hash_superfast(str, slen); hash = eina_hash_superfast(str, slen);
hash_num = hash & 0xFF; hash_num = hash & 0xFF;
hash = (hash >> 8) & EINA_STRINGSHARE_MASK; hash = (hash >> 8) & EINA_STRINGSHARE_MASK;
@ -954,6 +957,44 @@ eina_stringshare_add(const char *str)
return el->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 * static Eina_Stringshare_Node *
_eina_stringshare_node_from_str(const char *str) _eina_stringshare_node_from_str(const char *str)
{ {
@ -1058,7 +1099,7 @@ eina_stringshare_del(const char *str)
} }
node->references = 0; node->references = 0;
slen = node->length; /* already includes '\0' */ slen = node->length;
hash = eina_hash_superfast(str, slen); hash = eina_hash_superfast(str, slen);
hash_num = hash & 0xFF; hash_num = hash & 0xFF;
@ -1116,7 +1157,7 @@ eina_stringshare_strlen(const char *str)
if (str[3] == '\0') return 3; if (str[3] == '\0') return 3;
node = _eina_stringshare_node_from_str(str); node = _eina_stringshare_node_from_str(str);
return node->length - 1; return node->length;
} }
struct dumpinfo struct dumpinfo