forked from enlightenment/efl
stringshare_del optimization.
trade off safety by speed, we will always assume str was previously shared, like evas_stringshare_del() did and we can know with zero-cost the number of references and can avoid strlen() too. When references drop to zero we still have to do the hash, access the bucket and then lookup the Red-Black tree, then walk the list of nodes, but avoiding so would use more memory, unacceptable at this point. SVN revision: 37268
This commit is contained in:
parent
9a0b7ebd18
commit
3cd98b547a
|
@ -814,6 +814,9 @@ eina_stringshare_add(const char *str)
|
|||
* if it exists. If that counter reaches 0, the memory associated to
|
||||
* @p str is freed. If @p str is NULL, the function returns
|
||||
* immediatly.
|
||||
*
|
||||
* Note that if the given pointer is not shared or NULL, bad things
|
||||
* will happen, likely a segmentation fault.
|
||||
*/
|
||||
EAPI void
|
||||
eina_stringshare_del(const char *str)
|
||||
|
@ -821,31 +824,43 @@ eina_stringshare_del(const char *str)
|
|||
Eina_Stringshare_Head *ed;
|
||||
Eina_Stringshare_Node *el;
|
||||
Eina_Stringshare_Node *prev;
|
||||
Eina_Stringshare_Node *node;
|
||||
int hash_num, slen, hash;
|
||||
|
||||
if (!str) return;
|
||||
|
||||
slen = strlen(str) + 1;
|
||||
/* special cases */
|
||||
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 = 4; /* handled later */
|
||||
|
||||
#ifdef EINA_STRINGSHARE_USAGE
|
||||
population.count--;
|
||||
if (slen <= 5)
|
||||
population_group[slen - 1].count--;
|
||||
if (slen < 4)
|
||||
population_group[slen].count--;
|
||||
#endif
|
||||
|
||||
switch (slen)
|
||||
if (slen < 2)
|
||||
return;
|
||||
else if (slen < 4)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
return ;
|
||||
case 3:
|
||||
case 4:
|
||||
_eina_stringshare_small_del(str, slen - 1);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
_eina_stringshare_small_del(str, slen);
|
||||
return;
|
||||
}
|
||||
|
||||
node = (void *)(str - sizeof(Eina_Stringshare_Node));
|
||||
EINA_MAGIC_CHECK_STRINGSHARE_NODE(node);
|
||||
if (node->references > 1)
|
||||
{
|
||||
node->references--;
|
||||
return;
|
||||
}
|
||||
|
||||
node->references = 0;
|
||||
slen = node->length; /* already includes '\0' */
|
||||
|
||||
hash = eina_hash_superfast(str, slen);
|
||||
hash_num = hash & 0xFF;
|
||||
hash = (hash >> 8) & EINA_STRINGSHARE_MASK;
|
||||
|
@ -857,39 +872,32 @@ eina_stringshare_del(const char *str)
|
|||
|
||||
EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed);
|
||||
|
||||
for (prev = NULL, el = ed->head;
|
||||
el && (const char*) (el + 1) != str;
|
||||
prev = el, el = el->next)
|
||||
for (prev = NULL, el = ed->head; el && el != node; prev = el, el = el->next)
|
||||
;
|
||||
|
||||
if (!el) goto on_error;
|
||||
|
||||
EINA_MAGIC_CHECK_STRINGSHARE_NODE(el);
|
||||
|
||||
el->references--;
|
||||
if (el->references == 0)
|
||||
{
|
||||
if (prev) prev->next = el->next;
|
||||
else ed->head = el->next;
|
||||
if (el->begin == EINA_FALSE)
|
||||
MAGIC_FREE(el);
|
||||
if (prev) prev->next = el->next;
|
||||
else ed->head = el->next;
|
||||
if (el->begin == EINA_FALSE)
|
||||
MAGIC_FREE(el);
|
||||
|
||||
#ifdef EINA_STRINGSHARE_USAGE
|
||||
ed->population--;
|
||||
ed->population--;
|
||||
#endif
|
||||
|
||||
if (ed->head == NULL)
|
||||
{
|
||||
share->buckets[hash_num] = (Eina_Stringshare_Head*) eina_rbtree_inline_remove(EINA_RBTREE_GET(share->buckets[hash_num]),
|
||||
EINA_RBTREE_GET(ed),
|
||||
EINA_RBTREE_CMP_NODE_CB(_eina_stringshare_node),
|
||||
NULL);
|
||||
MAGIC_FREE(ed);
|
||||
}
|
||||
if (ed->head == NULL)
|
||||
{
|
||||
share->buckets[hash_num] = (Eina_Stringshare_Head*) eina_rbtree_inline_remove(EINA_RBTREE_GET(share->buckets[hash_num]),
|
||||
EINA_RBTREE_GET(ed),
|
||||
EINA_RBTREE_CMP_NODE_CB(_eina_stringshare_node),
|
||||
NULL);
|
||||
MAGIC_FREE(ed);
|
||||
}
|
||||
return ;
|
||||
|
||||
on_error:
|
||||
/* possible segfault happened before here, but... */
|
||||
EINA_ERROR_PWARN("EEEK trying to del non-shared stringshare \"%s\"\n", str);
|
||||
if (getenv("EINA_ERROR_ABORT")) abort();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue