enable adding just part of a string.
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 6 May 2009 04:11:01 +0000 (04:11 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 6 May 2009 04:11:01 +0000 (04:11 +0000)
this allows us to add stringshare from a larger buffer that cannot be
modified.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@40516 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/include/eina_stringshare.h
src/lib/eina_stringshare.c

index f59844d..4670ad6 100644 (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);
index 529d0d8..04fcd86 100644 (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