From ebeabe37353b118a51bd4398617f6a8290cf4ede Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Wed, 6 May 2009 04:11:01 +0000 Subject: [PATCH] enable adding just part of a string. this allows us to add stringshare from a larger buffer that cannot be modified. SVN revision: 40516 --- legacy/eina/src/include/eina_stringshare.h | 1 + legacy/eina/src/lib/eina_stringshare.c | 83 ++++++++++++++++------ 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/legacy/eina/src/include/eina_stringshare.h b/legacy/eina/src/include/eina_stringshare.h index f59844dd0d..4670ad6404 100644 --- a/legacy/eina/src/include/eina_stringshare.h +++ b/legacy/eina/src/include/eina_stringshare.h @@ -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); diff --git a/legacy/eina/src/lib/eina_stringshare.c b/legacy/eina/src/lib/eina_stringshare.c index 529d0d8fc1..04fcd86bdb 100644 --- a/legacy/eina/src/lib/eina_stringshare.c +++ b/legacy/eina/src/lib/eina_stringshare.c @@ -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