From: barbieri Date: Tue, 28 Oct 2008 12:23:12 +0000 (+0000) Subject: stringshare_del optimization. X-Git-Tag: 2.0_alpha~70^2~1147 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=23fd5812037e1cb713c4cf136c91f34fc21dbde8;p=framework%2Fuifw%2Feina.git 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. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@37268 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- diff --git a/src/lib/eina_stringshare.c b/src/lib/eina_stringshare.c index 93ab82b..ac4d3c7 100644 --- a/src/lib/eina_stringshare.c +++ b/src/lib/eina_stringshare.c @@ -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(); }