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)
_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)
{
Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
int todo, off;
+ char *snew;
if (!bucket)
{
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]));
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
node->references = 1;
node->length = slen;
memcpy(node->str, str, slen);
+ node->str[slen] = '\0';
}
static Eina_Stringshare_Head *
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);
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);
* @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.
*
* 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)
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;
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)
{
}
node->references = 0;
- slen = node->length; /* already includes '\0' */
+ slen = node->length;
hash = eina_hash_superfast(str, slen);
hash_num = hash & 0xFF;
if (str[3] == '\0') return 3;
node = _eina_stringshare_node_from_str(str);
- return node->length - 1;
+ return node->length;
}
struct dumpinfo