From: Enlightenment S. <no-...@en...> - 2008-10-27 19:26:20
|
Log: stringshare: special case for small (2-3 letters). This should reduce overhead and give a bit speedup as well, let's test with e17 real data and see how it goes. Author: barbieri Date: 2008-10-27 12:26:14 -0700 (Mon, 27 Oct 2008) New Revision: 37250 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-27 15:16:06 UTC (rev 37249) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-27 19:26:14 UTC (rev 37250) @@ -2,7 +2,10 @@ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 */ /* EINA - EFL data type library - * Copyright (C) 2002-2008 Carsten Haitzler, Jorge Luis Zapata Muga, Cedric Bail + * Copyright (C) 2002-2008 Carsten Haitzler, + * Jorge Luis Zapata Muga, + * Cedric Bail, + * Gustavo Sverzut Barbieri * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -160,6 +163,27 @@ 241,0,242,0,243,0,244,0,245,0,246,0,247,0,248,0,249,0,250,0,251,0,252,0,253,0,254,0,255,0 }; +typedef struct _Eina_Stringshare_Small Eina_Stringshare_Small; +typedef struct _Eina_Stringshare_Small_Bucket Eina_Stringshare_Small_Bucket; + +struct _Eina_Stringshare_Small_Bucket +{ + /* separate arrays for faster lookups */ + const char **strings; + unsigned char *lengths; + unsigned short *references; + int count; + int size; +}; + +struct _Eina_Stringshare_Small +{ + Eina_Stringshare_Small_Bucket *buckets[256]; +}; +#define EINA_STRINGSHARE_SMALL_BUCKET_STEP 8 +static Eina_Stringshare_Small _eina_small_share; + + #ifdef EINA_STRINGSHARE_USAGE typedef struct _Eina_Stringshare_Population Eina_Stringshare_Population; struct _Eina_Stringshare_Population @@ -222,6 +246,268 @@ */ +static Eina_Stringshare_Small _eina_small_share; + +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; + int i, low, high; + + if (bucket->count == 0) + { + *index = 0; + return NULL; + } + + low = 0; + high = bucket->count; + + while (low < high) + { + unsigned char cur_length; + + i = (low + high - 1) / 2; + cur_length = bucket->lengths[i]; + + if (cur_length > length) + high = i; + else if (cur_length < length) + low = i + 1; + else + { + const char *cur_pstr = bucket->strings[i] + 1; + int r; + + r = memcmp(cur_pstr, pstr, plength); + if (r > 0) + high = i; + else if (r < 0) + low = i + 1; + else + { + *index = i; + return bucket->strings[i]; + } + } + } + + *index = low; + return NULL; +} + +static Eina_Bool +_eina_stringshare_small_bucket_resize(Eina_Stringshare_Small_Bucket *bucket, int size) +{ + void *tmp; + + tmp = realloc(bucket->strings, size * sizeof(bucket->strings[0])); + if (!tmp) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return 0; + } + bucket->strings = tmp; + + tmp = realloc(bucket->lengths, size * sizeof(bucket->lengths[0])); + if (!tmp) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return 0; + } + bucket->lengths = tmp; + + tmp = realloc(bucket->references, size * sizeof(bucket->references[0])); + if (!tmp) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return 0; + } + bucket->references = tmp; + + bucket->size = size; + return 1; +} + +static const char * +_eina_stringshare_small_bucket_insert_at(Eina_Stringshare_Small_Bucket **p_bucket, const char *str, unsigned char length, int index) +{ + Eina_Stringshare_Small_Bucket *bucket = *p_bucket; + int todo, off; + + if (!bucket) + { + *p_bucket = bucket = calloc(1, sizeof(*bucket)); + if (!bucket) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return NULL; + } + } + + if (bucket->count + 1 >= bucket->size) + { + int size = bucket->size + EINA_STRINGSHARE_SMALL_BUCKET_STEP; + if (!_eina_stringshare_small_bucket_resize(bucket, size)) + return NULL; + } + + str = strdup(str); + if (!str) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return NULL; + } + + off = index + 1; + todo = bucket->count - index; + if (todo > 0) + { + memmove(bucket->strings + off, bucket->strings + index, + todo * sizeof(bucket->strings[0])); + memmove(bucket->lengths + off, bucket->lengths + index, + todo * sizeof(bucket->lengths[0])); + memmove(bucket->references + off, bucket->references + index, + todo * sizeof(bucket->references[0])); + } + + bucket->strings[index] = str; + bucket->lengths[index] = length; + bucket->references[index] = 1; + bucket->count++; + + return str; +} + +static void +_eina_stringshare_small_bucket_remove_at(Eina_Stringshare_Small_Bucket **p_bucket, int index) +{ + Eina_Stringshare_Small_Bucket *bucket = *p_bucket; + int todo, off; + + if (bucket->references[index] > 1) + { + bucket->references[index]--; + return; + } + + free((char *)bucket->strings[index]); + + if (bucket->count == 1) + { + free(bucket->strings); + free(bucket->lengths); + free(bucket->references); + free(bucket); + *p_bucket = NULL; + return; + } + + bucket->count--; + if (index == bucket->count) + goto end; + + off = index + 1; + todo = bucket->count - index; + + memmove(bucket->strings + index, bucket->strings + off, + todo * sizeof(bucket->strings[0])); + memmove(bucket->lengths + index, bucket->lengths + off, + todo * sizeof(bucket->lengths[0])); + memmove(bucket->references + index, bucket->references + off, + todo * sizeof(bucket->references[0])); + + end: + if (bucket->count + EINA_STRINGSHARE_SMALL_BUCKET_STEP < bucket->size) + { + int size = bucket->size - EINA_STRINGSHARE_SMALL_BUCKET_STEP; + _eina_stringshare_small_bucket_resize(bucket, size); + } +} + +static const char * +_eina_stringshare_small_add(const char *str, unsigned char length) +{ + Eina_Stringshare_Small_Bucket **bucket; + int i; + + bucket = _eina_small_share.buckets + (unsigned char)str[0]; + if (!*bucket) + i = 0; + else + { + const char *ret; + ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i); + if (ret) + { + (*bucket)->references[i]++; + return ret; + } + } + + return _eina_stringshare_small_bucket_insert_at(bucket, str, length, i); +} + +static void +_eina_stringshare_small_del(const char *str, unsigned char length) +{ + Eina_Stringshare_Small_Bucket **bucket; + const char *ret; + int i; + + bucket = _eina_small_share.buckets + (unsigned char)str[0]; + if (!*bucket) + goto error; + + ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i); + if (!ret) + goto error; + + _eina_stringshare_small_bucket_remove_at(bucket, i); + return; + + error: + EINA_ERROR_PWARN("EEEK trying to del non-shared stringshare \"%s\"\n", str); + if (getenv("EINA_ERROR_ABORT")) abort(); +} + +static void +_eina_stringshare_small_init(void) +{ + memset(&_eina_small_share, 0, sizeof(_eina_small_share)); +} + +static void +_eina_stringshare_small_shutdown(void) +{ + Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end; + + p_bucket = _eina_small_share.buckets; + p_bucket_end = p_bucket + 256; + + for (; p_bucket < p_bucket_end; p_bucket++) + { + Eina_Stringshare_Small_Bucket *bucket = *p_bucket; + char **s, **s_end; + + if (!bucket) + continue; + + s = (char **)bucket->strings; + s_end = s + bucket->count; + for (; s < s_end; s++) + free(*s); + + free(bucket->strings); + free(bucket->lengths); + free(bucket->references); + free(bucket); + *p_bucket = NULL; + } +} + + /*============================================================================* * Global * *============================================================================*/ @@ -279,8 +565,6 @@ */ if (!_eina_stringshare_init_count) { - unsigned int i; - share = calloc(1, sizeof(Eina_Stringshare)); if (!share) return 0; @@ -296,7 +580,11 @@ "Eina Stringshare Node"); EINA_MAGIC_SET(share, EINA_MAGIC_STRINGSHARE); + _eina_stringshare_small_init(); + #ifdef EINA_STRINGSHARE_USAGE + unsigned int i; + for (i = 0; i < sizeof (population_group) / sizeof (population_group[0]); ++i) { population_group[i].count = 0; @@ -356,6 +644,7 @@ } #endif + _eina_stringshare_small_shutdown(); eina_magic_string_shutdown(); eina_error_shutdown(); } @@ -410,6 +699,7 @@ return &(_eina_stringshare_single[(*str) << 1]); case 3: case 4: + return _eina_stringshare_small_add(str, slen - 1); default: break; } @@ -525,6 +815,8 @@ return ; case 3: case 4: + _eina_stringshare_small_del(str, slen - 1); + return; default: break; } @@ -582,6 +874,52 @@ int used, saved, dups, unique; }; +static void +_eina_stringshare_small_bucket_dump(Eina_Stringshare_Small_Bucket *bucket, struct dumpinfo *di) +{ + const char **s = bucket->strings; + unsigned char *l = bucket->lengths; + unsigned short *r = bucket->references; + int i; + + di->used += sizeof(*bucket); + di->used += bucket->count * sizeof(*s); + di->used += bucket->count * sizeof(*l); + di->used += bucket->count * sizeof(*r); + di->unique += bucket->count; + + for (i = 0; i < bucket->count; i++, s++, l++, r++) + { + int dups; + printf("DDD: %5hhu %5hu '%s'\n", *l, *r, *s); + + dups = (*r - 1); + + di->used += *l; + di->saved += *l * dups; + di->dups += dups; + } +} + +static void +_eina_stringshare_small_dump(struct dumpinfo *di) +{ + Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end; + + p_bucket = _eina_small_share.buckets; + p_bucket_end = p_bucket + 256; + + for (; p_bucket < p_bucket_end; p_bucket++) + { + Eina_Stringshare_Small_Bucket *bucket = *p_bucket; + + if (!bucket) + continue; + + _eina_stringshare_small_bucket_dump(bucket, di); + } +} + static Eina_Bool eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__, Eina_Stringshare_Head *head, struct dumpinfo *fdata) { @@ -621,6 +959,7 @@ di.unique = 0; printf("DDD: len ref string\n"); printf("DDD:-------------------\n"); + _eina_stringshare_small_dump(&di); for (i = 0; i < EINA_STRINGSHARE_BUCKETS; i++) { if (!share->buckets[i]) continue; |
From: Enlightenment S. <no-...@en...> - 2008-10-27 20:16:56
|
Log: better optimize small stringshare comparison Author: barbieri Date: 2008-10-27 13:16:52 -0700 (Mon, 27 Oct 2008) New Revision: 37251 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-27 19:26:14 UTC (rev 37250) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-27 20:16:52 UTC (rev 37251) @@ -248,6 +248,35 @@ 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 char *cur_pstr; + + if (cur_plength > plength) + return 1; + else if (cur_plength < plength) + return -1; + + cur_pstr = bucket->strings[i] + 1; + + if (cur_pstr[0] > pstr[0]) + return 1; + else if (cur_pstr[0] < pstr[0]) + return -1; + + if (plength == 1) + return 0; + + if (cur_pstr[1] > pstr[1]) + return 1; + else if (cur_pstr[1] < pstr[1]) + return -1; + + return 0; +} + static const char * _eina_stringshare_small_bucket_find(const Eina_Stringshare_Small_Bucket *bucket, const char *str, unsigned char length, int *index) { @@ -266,30 +295,23 @@ while (low < high) { - unsigned char cur_length; + int r; i = (low + high - 1) / 2; - cur_length = bucket->lengths[i]; - if (cur_length > length) - high = i; - else if (cur_length < length) - low = i + 1; + r = _eina_stringshare_small_cmp(bucket, i, pstr, plength); + if (r > 0) + { + high = i; + } + else if (r < 0) + { + low = i + 1; + } else { - const char *cur_pstr = bucket->strings[i] + 1; - int r; - - r = memcmp(cur_pstr, pstr, plength); - if (r > 0) - high = i; - else if (r < 0) - low = i + 1; - else - { - *index = i; - return bucket->strings[i]; - } + *index = i; + return bucket->strings[i]; } } |
From: Enlightenment S. <no-...@en...> - 2008-10-27 20:35:36
|
Log: dump show percentages. not that useful, but I like it. Author: barbieri Date: 2008-10-27 13:35:28 -0700 (Mon, 27 Oct 2008) New Revision: 37253 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-27 20:24:12 UTC (rev 37252) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-27 20:35:28 UTC (rev 37253) @@ -997,8 +997,11 @@ di.saved += population_group[1].count * sizeof(char) * 2; #endif printf("DDD:-------------------\n"); - printf("DDD: usage (bytes) = %i, saved = %i (%i duplicates, %i unique)\n", - di.used, di.saved, di.dups, di.unique); + printf("DDD: usage (bytes) = %i, saved = %i (%3.0f%%)\n", + di.used, di.saved, di.used ? (di.saved * 100.0 / di.used) : 0.0); + printf("DDD: unique: %d, duplicates: %d (%3.0f%%)\n", + di.unique, di.dups, di.unique ? (di.dups * 100.0 / di.unique) : 0.0); + #ifdef EINA_STRINGSHARE_USAGE printf("DDD: Allocated strings: %i\n", population.count); printf("DDD: Max allocated strings: %i\n", population.max); |
From: Enlightenment S. <no-...@en...> - 2008-10-28 00:18:42
|
Log: define function as void as in prototype. Author: barbieri Date: 2008-10-27 17:18:31 -0700 (Mon, 27 Oct 2008) New Revision: 37256 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-27 22:52:49 UTC (rev 37255) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-28 00:18:31 UTC (rev 37256) @@ -579,7 +579,7 @@ * returns the number of times it has already been called. */ EAPI int -eina_stringshare_init() +eina_stringshare_init(void) { /* * No strings have been loaded at this point, so create the hash @@ -630,7 +630,7 @@ * times than eina_stringshare_init(). */ EAPI int -eina_stringshare_shutdown() +eina_stringshare_shutdown(void) { unsigned int i; |
From: Enlightenment S. <no-...@en...> - 2008-10-28 00:42:48
|
Log: Save 4 bytes per big string shared. Author: barbieri Date: 2008-10-27 17:42:35 -0700 (Mon, 27 Oct 2008) New Revision: 37258 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-28 00:31:09 UTC (rev 37257) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-28 00:42:35 UTC (rev 37258) @@ -135,8 +135,8 @@ Eina_Stringshare_Node *next; - int length; - int references; + unsigned short length; + unsigned short references; Eina_Bool begin : 1; }; @@ -686,6 +686,9 @@ * 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. + * + * @note it's not possible to have more than 65k references or strings + * bigger than 65k since we use 'unsigned short' to save space. */ EAPI const char * eina_stringshare_add(const char *str) |
From: Enlightenment S. <no-...@en...> - 2008-10-28 12:23:18
|
Log: 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. Author: barbieri Date: 2008-10-28 05:23:12 -0700 (Tue, 28 Oct 2008) New Revision: 37268 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-28 08:59:12 UTC (rev 37267) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-28 12:23:12 UTC (rev 37268) @@ -814,6 +814,9 @@ * 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_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_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); + if (prev) prev->next = el->next; + else ed->head = el->next; + if (el->begin == EINA_FALSE) + MAGIC_FREE(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); - #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(); } |
From: Enlightenment S. <no-...@en...> - 2008-10-28 13:35:47
|
Log: save a byte per stringshare node. we don't need to use 'begin' flag (that takes a byte) just to see if we're in the same memory block as the head, just do a pointer math. Author: barbieri Date: 2008-10-28 05:34:58 -0700 (Tue, 28 Oct 2008) New Revision: 37270 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-28 12:26:05 UTC (rev 37269) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-28 12:34:58 UTC (rev 37270) @@ -137,8 +137,6 @@ unsigned short length; unsigned short references; - - Eina_Bool begin : 1; }; static Eina_Stringshare *share = NULL; @@ -228,13 +226,14 @@ _eina_stringshare_head_free(Eina_Stringshare_Head *ed, __UNUSED__ void *data) { EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed); + Eina_Stringshare_Node *first_node = (Eina_Stringshare_Node *)(ed + 1); while (ed->head) { Eina_Stringshare_Node *el = ed->head; ed->head = ed->head->next; - if (el->begin == EINA_FALSE) + if (el != first_node) MAGIC_FREE(el); } MAGIC_FREE(ed); @@ -754,8 +753,6 @@ nel = (Eina_Stringshare_Node*) (ed + 1); EINA_MAGIC_SET(nel, EINA_MAGIC_STRINGSHARE_NODE); - - nel->begin = EINA_TRUE; } EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed); @@ -783,8 +780,6 @@ nel = malloc(sizeof (Eina_Stringshare_Node) + slen); if (!nel) return NULL; EINA_MAGIC_SET(nel, EINA_MAGIC_STRINGSHARE_NODE); - - nel->begin = EINA_FALSE; } nel->references = 1; @@ -878,7 +873,7 @@ if (prev) prev->next = el->next; else ed->head = el->next; - if (el->begin == EINA_FALSE) + if (el != (Eina_Stringshare_Node *)(ed + 1)) MAGIC_FREE(el); #ifdef EINA_STRINGSHARE_USAGE |
From: Enlightenment S. <no-...@en...> - 2008-10-28 14:25:51
|
Log: reduce the popuplation_group size. we just have special case for up to 3 letters, everything else is regular population. Author: barbieri Date: 2008-10-28 05:26:05 -0700 (Tue, 28 Oct 2008) New Revision: 37269 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-28 12:23:12 UTC (rev 37268) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-28 12:26:05 UTC (rev 37269) @@ -194,13 +194,12 @@ static Eina_Stringshare_Population population = { 0, 0 }; -static Eina_Stringshare_Population population_group[5] = +static Eina_Stringshare_Population population_group[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0, 0 } }; static int max_node_population = 0; @@ -708,7 +707,7 @@ population.count++; if (population.count > population.max) population.max = population.count; - if (slen <= 5) + if (slen <= 4) { population_group[slen - 1].count++; if (population_group[slen - 1].count > population_group[slen - 1].max) |
From: Enlightenment S. <no-...@en...> - 2008-10-28 17:15:12
|
Log: Code refactor and cleanup of eina_stringshare_add(). Cases are now handled in separate, doing less useless steps and easier to understand since 3 cases are now distinct. Author: barbieri Date: 2008-10-28 10:15:07 -0700 (Tue, 28 Oct 2008) New Revision: 37278 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-28 16:40:34 UTC (rev 37277) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-28 17:15:07 UTC (rev 37278) @@ -115,6 +115,17 @@ EINA_MAGIC; }; +struct _Eina_Stringshare_Node +{ + EINA_MAGIC; + + Eina_Stringshare_Node *next; + + unsigned short length; + unsigned short references; + char str[]; +}; + struct _Eina_Stringshare_Head { EINA_RBTREE; @@ -127,18 +138,9 @@ #endif Eina_Stringshare_Node *head; + Eina_Stringshare_Node builtin_node; }; -struct _Eina_Stringshare_Node -{ - EINA_MAGIC; - - Eina_Stringshare_Node *next; - - unsigned short length; - unsigned short references; -}; - static Eina_Stringshare *share = NULL; static int _eina_stringshare_init_count = 0; static const char _eina_stringshare_single[512] = { @@ -226,14 +228,13 @@ _eina_stringshare_head_free(Eina_Stringshare_Head *ed, __UNUSED__ void *data) { EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed); - Eina_Stringshare_Node *first_node = (Eina_Stringshare_Node *)(ed + 1); while (ed->head) { Eina_Stringshare_Node *el = ed->head; ed->head = ed->head->next; - if (el != first_node) + if (el != &ed->builtin_node) MAGIC_FREE(el); } MAGIC_FREE(ed); @@ -672,6 +673,76 @@ return _eina_stringshare_init_count; } +static void +_eina_stringshare_node_init(Eina_Stringshare_Node *node, const char *str, int slen) +{ + EINA_MAGIC_SET(node, EINA_MAGIC_STRINGSHARE_NODE); + node->references = 1; + node->length = slen; + memcpy(node->str, str, slen); +} + +static const char * +_eina_stringshare_add_head(Eina_Stringshare_Head **p_bucket, int hash, const char *str, int slen) +{ + Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket; + Eina_Stringshare_Head *head; + + head = malloc(sizeof(Eina_Stringshare_Head) + slen); + if (!head) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return NULL; + } + + EINA_MAGIC_SET(head, EINA_MAGIC_STRINGSHARE_HEAD); + head->hash = hash; + head->head = &head->builtin_node; + _eina_stringshare_node_init(head->head, str, slen); + head->head->next = NULL; + +#ifdef EINA_STRINGSHARE_USAGE + head->population = 1; +#endif + + *p_tree = eina_rbtree_inline_insert + (*p_tree, EINA_RBTREE_GET(head), + EINA_RBTREE_CMP_NODE_CB(_eina_stringshare_node), NULL); + + return head->head->str; +} + +static inline Eina_Bool +_eina_stringshare_node_eq(const Eina_Stringshare_Node *node, const char *str, int slen) +{ + return ((node->length == slen) && + (memcmp(node->str, str, slen) == 0)); +} + +static Eina_Stringshare_Node * +_eina_stringshare_head_find(Eina_Stringshare_Head *head, const char *str, int slen) +{ + Eina_Stringshare_Node *node, *prev; + + node = head->head; + if (_eina_stringshare_node_eq(node, str, slen)) + return node; + + prev = node; + node = node->next; + for (; node != NULL; prev = node, node = node->next) + if (_eina_stringshare_node_eq(node, str, slen)) + { + /* promote node, make hot items be at the beginning */ + prev->next = node->next; + node->next = head->head; + head->head = node; + return node; + } + + return NULL; +} + /** * @brief Retrieve an instance of a string for use in a program. * @@ -691,11 +762,8 @@ EAPI const char * eina_stringshare_add(const char *str) { - Eina_Stringshare_Node *nel = NULL; - Eina_Stringshare_Node *tmp; - Eina_Stringshare_Head *ed; + Eina_Stringshare_Head **p_bucket, *ed; Eina_Stringshare_Node *el; - char *el_str; int hash_num, slen, hash; if (!str) return NULL; @@ -731,72 +799,40 @@ hash_num = hash & 0xFF; hash = (hash >> 8) & EINA_STRINGSHARE_MASK; - ed = (Eina_Stringshare_Head*) eina_rbtree_inline_lookup((Eina_Rbtree*) share->buckets[hash_num], - &hash, 0, - EINA_RBTREE_CMP_KEY_CB(_eina_stringshare_cmp), NULL); + p_bucket = share->buckets + hash_num; + ed = (Eina_Stringshare_Head*) eina_rbtree_inline_lookup + (EINA_RBTREE_GET(*p_bucket), &hash, 0, + EINA_RBTREE_CMP_KEY_CB(_eina_stringshare_cmp), NULL); + if (!ed) - { - ed = malloc(sizeof (Eina_Stringshare_Head) + sizeof (Eina_Stringshare_Node) + slen); - if (!ed) return NULL; - EINA_MAGIC_SET(ed, EINA_MAGIC_STRINGSHARE_HEAD); + return _eina_stringshare_add_head(p_bucket, hash, str, slen); - ed->hash = hash; - ed->head = NULL; - -#ifdef EINA_STRINGSHARE_USAGE - ed->population = 0; -#endif - - share->buckets[hash_num] = (Eina_Stringshare_Head*) eina_rbtree_inline_insert((Eina_Rbtree*) share->buckets[hash_num], - EINA_RBTREE_GET(ed), - EINA_RBTREE_CMP_NODE_CB(_eina_stringshare_node), NULL); - - nel = (Eina_Stringshare_Node*) (ed + 1); - EINA_MAGIC_SET(nel, EINA_MAGIC_STRINGSHARE_NODE); - } - EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed); - for (el = ed->head, tmp = NULL; - el && (slen != el->length || memcmp(str, (const char*) (el + 1), slen) != 0); - tmp = el, el = el->next) - ; - + el = _eina_stringshare_head_find(ed, str, slen); if (el) { - if (tmp) - { - tmp->next = el->next; - el->next = ed->head; - ed->head = el; - } - el->references++; - return (const char*) (el + 1); + return el->str; } - if (!nel) + el = malloc(sizeof(Eina_Stringshare_Node) + slen); + if (!el) { - nel = malloc(sizeof (Eina_Stringshare_Node) + slen); - if (!nel) return NULL; - EINA_MAGIC_SET(nel, EINA_MAGIC_STRINGSHARE_NODE); + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return NULL; } - nel->references = 1; - nel->length = slen; + _eina_stringshare_node_init(el, str, slen); + el->next = ed->head; + ed->head = el; - el_str = (char*) (nel + 1); - memcpy(el_str, str, slen); - - nel->next = ed->head; - ed->head = nel; - #ifdef EINA_STRINGSHARE_USAGE ed->population++; if (ed->population > max_node_population) max_node_population = ed->population; #endif - return el_str; + return el->str; } /** @@ -873,7 +909,7 @@ if (prev) prev->next = el->next; else ed->head = el->next; - if (el != (Eina_Stringshare_Node *)(ed + 1)) + if (el != &ed->builtin_node) MAGIC_FREE(el); #ifdef EINA_STRINGSHARE_USAGE |
From: Enlightenment S. <no-...@en...> - 2008-10-28 17:16:51
|
Log: Add missing magic check for existing node. Author: barbieri Date: 2008-10-28 10:16:42 -0700 (Tue, 28 Oct 2008) New Revision: 37279 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-28 17:15:07 UTC (rev 37278) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-28 17:16:42 UTC (rev 37279) @@ -812,6 +812,7 @@ el = _eina_stringshare_head_find(ed, str, slen); if (el) { + EINA_MAGIC_CHECK_STRINGSHARE_NODE(el); el->references++; return el->str; } |
From: Enlightenment S. <no-...@en...> - 2008-10-28 17:48:10
|
Log: improve readability: avoid macros inside our code mixing #ifdef'ed blocks inside code is bad, can lead to warnings if some variables are not used and it's a pain to read. instead, just define functions and always call them, choose their implementation based on the ifdef macros. I opted to have 2 declarations, but one can go like other parts and #ifdef around the function contents as well. Author: barbieri Date: 2008-10-28 10:47:59 -0700 (Tue, 28 Oct 2008) New Revision: 37281 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-28 17:19:02 UTC (rev 37280) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-28 17:47:59 UTC (rev 37281) @@ -203,6 +203,102 @@ }; static int max_node_population = 0; + + +static void +_eina_stringshare_population_init(void) +{ + unsigned int i; + + for (i = 0; i < sizeof (population_group) / sizeof (population_group[0]); ++i) + { + population_group[i].count = 0; + population_group[i].max = 0; + } +} + +static void +_eina_stringshare_population_shutdown(void) +{ + unsigned int i; + + max_node_population = 0; + population.count = 0; + population.max = 0; + + for (i = 0; i < sizeof (population_group) / sizeof (population_group[0]); ++i) + { + population_group[i].count = 0; + population_group[i].max = 0; + } +} + +static void +_eina_stringshare_population_stats(void) +{ + unsigned int i; + + fprintf(stderr, "eina stringshare statistic:\n"); + fprintf(stderr, " * maximum shared strings : %i\n", population.max); + fprintf(stderr, " * maximum shared strings per node : %i\n", max_node_population); + + for (i = 0; i < sizeof (population_group) / sizeof (population_group[0]); ++i) + fprintf(stderr, "DDD: %i strings of length %i, max strings: %i\n", population_group[i].count, i, population_group[i].max); +} + +static void +_eina_stringshare_population_add(int slen) +{ + population.count++; + if (population.count > population.max) + population.max = population.count; + + if (slen < 4) + { + population_group[slen].count++; + if (population_group[slen].count > population_group[slen].max) + population_group[slen].max = population_group[slen].count; + } +} + +static void +_eina_stringshare_population_del(int slen) +{ + population.count--; + if (slen < 4) + population_group[slen].count--; +} + +static void +_eina_stringshare_population_head_init(Eina_Stringshare_Head *head) +{ + head->population = 1; +} + +static void +_eina_stringshare_population_head_add(Eina_Stringshare_Head *head) +{ + head->population++; + if (head->population > max_node_population) + max_node_population = head->population; +} + +static void +_eina_stringshare_population_head_del(Eina_Stringshare_Head *head) +{ + head->population--; +} + +#else /* EINA_STRINGSHARE_USAGE undefined */ + +static void _eina_stringshare_population_init(void) {} +static void _eina_stringshare_population_shutdown(void) {} +static void _eina_stringshare_population_stats(void) {} +static void _eina_stringshare_population_add(int slen) {} +static void _eina_stringshare_population_del(int slen) {} +static void _eina_stringshare_population_head_init(Eina_Stringshare_Head *head) {} +static void _eina_stringshare_population_head_add(Eina_Stringshare_Head *head) {} +static void _eina_stringshare_population_head_del(Eina_Stringshare_Head *head) {} #endif static int @@ -602,16 +698,7 @@ EINA_MAGIC_SET(share, EINA_MAGIC_STRINGSHARE); _eina_stringshare_small_init(); - -#ifdef EINA_STRINGSHARE_USAGE - unsigned int i; - - for (i = 0; i < sizeof (population_group) / sizeof (population_group[0]); ++i) - { - population_group[i].count = 0; - population_group[i].max = 0; - } -#endif + _eina_stringshare_population_init(); } return ++_eina_stringshare_init_count; @@ -633,15 +720,8 @@ { unsigned int i; -#ifdef EINA_STRINGSHARE_USAGE - fprintf(stderr, "eina stringshare statistic:\n"); - fprintf(stderr, " * maximum shared strings : %i\n", population.max); - fprintf(stderr, " * maximum shared strings per node : %i\n", max_node_population); + _eina_stringshare_population_stats(); - for (i = 0; i < sizeof (population_group) / sizeof (population_group[0]); ++i) - fprintf(stderr, "DDD: %i strings of length %i, max strings: %i\n", population_group[i].count, i, population_group[i].max); -#endif - --_eina_stringshare_init_count; if (!_eina_stringshare_init_count) { @@ -653,18 +733,7 @@ } MAGIC_FREE(share); -#ifdef EINA_STRINGSHARE_USAGE - max_node_population = 0; - population.count = 0; - population.max = 0; - - for (i = 0; i < sizeof (population_group) / sizeof (population_group[0]); ++i) - { - population_group[i].count = 0; - population_group[i].max = 0; - } -#endif - + _eina_stringshare_population_shutdown(); _eina_stringshare_small_shutdown(); eina_magic_string_shutdown(); eina_error_shutdown(); @@ -701,9 +770,7 @@ _eina_stringshare_node_init(head->head, str, slen); head->head->next = NULL; -#ifdef EINA_STRINGSHARE_USAGE - head->population = 1; -#endif + _eina_stringshare_population_head_init(head); *p_tree = eina_rbtree_inline_insert (*p_tree, EINA_RBTREE_GET(head), @@ -768,32 +835,22 @@ if (!str) return NULL; - slen = strlen(str) + 1; + 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 + strlen(str + 3); -#ifdef EINA_STRINGSHARE_USAGE - population.count++; - if (population.count > population.max) population.max = population.count; + _eina_stringshare_population_add(slen); - if (slen <= 4) - { - population_group[slen - 1].count++; - if (population_group[slen - 1].count > population_group[slen - 1].max) - population_group[slen - 1].max = population_group[slen - 1].count; - } -#endif + if (slen == 0) + return ""; + else if (slen == 1) + return _eina_stringshare_single + ((*str) << 1); + else if (slen < 4) + return _eina_stringshare_small_add(str, slen); - switch (slen) - { - case 1: - return ""; - case 2: - return &(_eina_stringshare_single[(*str) << 1]); - case 3: - case 4: - return _eina_stringshare_small_add(str, slen - 1); - default: - break; - } + slen++; /* everything else need to account '\0' */ hash = eina_hash_superfast(str, slen); hash_num = hash & 0xFF; @@ -827,12 +884,8 @@ _eina_stringshare_node_init(el, str, slen); el->next = ed->head; ed->head = el; + _eina_stringshare_population_head_add(ed); -#ifdef EINA_STRINGSHARE_USAGE - ed->population++; - if (ed->population > max_node_population) max_node_population = ed->population; -#endif - return el->str; } @@ -867,11 +920,7 @@ else if (str[3] == '\0') slen = 3; else slen = 4; /* handled later */ -#ifdef EINA_STRINGSHARE_USAGE - population.count--; - if (slen < 4) - population_group[slen].count--; -#endif + _eina_stringshare_population_del(slen); if (slen < 2) return; @@ -913,9 +962,7 @@ if (el != &ed->builtin_node) MAGIC_FREE(el); -#ifdef EINA_STRINGSHARE_USAGE - ed->population--; -#endif + _eina_stringshare_population_head_del(ed); if (ed->head == NULL) { |
From: Enlightenment S. <no-...@en...> - 2008-10-28 18:12:14
|
Log: refactor eina_stringshare_del() to make it easier to read. Author: barbieri Date: 2008-10-28 11:12:10 -0700 (Tue, 28 Oct 2008) New Revision: 37282 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-28 17:47:59 UTC (rev 37281) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-28 18:12:10 UTC (rev 37282) @@ -779,6 +779,19 @@ return head->head->str; } +static void +_eina_stringshare_del_head(Eina_Stringshare_Head **p_bucket, Eina_Stringshare_Head *head) +{ + Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket; + + *p_tree = eina_rbtree_inline_remove + (*p_tree, EINA_RBTREE_GET(head), + EINA_RBTREE_CMP_NODE_CB(_eina_stringshare_node), NULL); + + MAGIC_FREE(head); +} + + static inline Eina_Bool _eina_stringshare_node_eq(const Eina_Stringshare_Node *node, const char *str, int slen) { @@ -810,6 +823,37 @@ return NULL; } +static Eina_Bool +_eina_stringshare_head_remove_node(Eina_Stringshare_Head *head, const Eina_Stringshare_Node *node) +{ + Eina_Stringshare_Node *cur, *prev; + + if (head->head == node) + { + head->head = node->next; + return 1; + } + + prev = head->head; + cur = head->head->next; + for (; cur != NULL; prev = cur, cur = cur->next) + if (cur == node) + { + prev = cur->next; + return 1; + } + + return 0; +} + +static Eina_Stringshare_Head * +_eina_stringshare_find_hash(Eina_Stringshare_Head *bucket, int hash) +{ + return (Eina_Stringshare_Head*) eina_rbtree_inline_lookup + (EINA_RBTREE_GET(bucket), &hash, 0, + EINA_RBTREE_CMP_KEY_CB(_eina_stringshare_cmp), NULL); +} + /** * @brief Retrieve an instance of a string for use in a program. * @@ -857,10 +901,7 @@ hash = (hash >> 8) & EINA_STRINGSHARE_MASK; p_bucket = share->buckets + hash_num; - ed = (Eina_Stringshare_Head*) eina_rbtree_inline_lookup - (EINA_RBTREE_GET(*p_bucket), &hash, 0, - EINA_RBTREE_CMP_KEY_CB(_eina_stringshare_cmp), NULL); - + ed = _eina_stringshare_find_hash(*p_bucket, hash); if (!ed) return _eina_stringshare_add_head(p_bucket, hash, str, slen); @@ -906,8 +947,7 @@ eina_stringshare_del(const char *str) { Eina_Stringshare_Head *ed; - Eina_Stringshare_Node *el; - Eina_Stringshare_Node *prev; + Eina_Stringshare_Head **p_bucket; Eina_Stringshare_Node *node; int hash_num, slen, hash; @@ -945,35 +985,26 @@ hash_num = hash & 0xFF; hash = (hash >> 8) & EINA_STRINGSHARE_MASK; - ed = (Eina_Stringshare_Head*) eina_rbtree_inline_lookup(EINA_RBTREE_GET(share->buckets[hash_num]), - &hash, 0, - EINA_RBTREE_CMP_KEY_CB(_eina_stringshare_cmp), NULL); - if (!ed) goto on_error; + p_bucket = share->buckets + hash_num; + ed = _eina_stringshare_find_hash(*p_bucket, hash); + if (!ed) + goto on_error; EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed); - for (prev = NULL, el = ed->head; el && el != node; prev = el, el = el->next) - ; + if (!_eina_stringshare_head_remove_node(ed, node)) + goto on_error; - if (!el) goto on_error; + if (node != &ed->builtin_node) + MAGIC_FREE(node); - if (prev) prev->next = el->next; - else ed->head = el->next; - if (el != &ed->builtin_node) - MAGIC_FREE(el); + if (!ed->head) + _eina_stringshare_del_head(p_bucket, ed); + else + _eina_stringshare_population_head_del(ed); - _eina_stringshare_population_head_del(ed); + return; - 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); |
From: Enlightenment S. <no-...@en...> - 2008-10-29 14:18:38
|
Log: Fix stringshare on 64bits platforms. sizeof(Eina_Stringshare_Node) is now 24 bytes on 64bits platforms, but str[] was pointing to before that, to the 20th byte, causing out of bounds access. Adding the padding will cause str[] to use the correct position. It wastes 4 more bytes, like pre-optimizations, but it's just on big machines. Author: barbieri Date: 2008-10-29 07:18:29 -0700 (Wed, 29 Oct 2008) New Revision: 37305 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-29 11:26:00 UTC (rev 37304) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-29 14:18:29 UTC (rev 37305) @@ -123,6 +123,11 @@ unsigned short length; unsigned short references; + +#if __WORDSIZE == 64 + unsigned int __padding; +#endif + char str[]; }; |
From: Enlightenment S. <no-...@en...> - 2008-10-29 14:51:21
|
Log: Remove unused attribute warnings. Author: barbieri Date: 2008-10-29 07:51:18 -0700 (Wed, 29 Oct 2008) New Revision: 37307 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-29 14:35:22 UTC (rev 37306) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-29 14:51:18 UTC (rev 37307) @@ -299,11 +299,11 @@ static void _eina_stringshare_population_init(void) {} static void _eina_stringshare_population_shutdown(void) {} static void _eina_stringshare_population_stats(void) {} -static void _eina_stringshare_population_add(int slen) {} -static void _eina_stringshare_population_del(int slen) {} -static void _eina_stringshare_population_head_init(Eina_Stringshare_Head *head) {} -static void _eina_stringshare_population_head_add(Eina_Stringshare_Head *head) {} -static void _eina_stringshare_population_head_del(Eina_Stringshare_Head *head) {} +static void _eina_stringshare_population_add(__UNUSED__ int slen) {} +static void _eina_stringshare_population_del(__UNUSED__ int slen) {} +static void _eina_stringshare_population_head_init(__UNUSED__ Eina_Stringshare_Head *head) {} +static void _eina_stringshare_population_head_add(__UNUSED__ Eina_Stringshare_Head *head) {} +static void _eina_stringshare_population_head_del(__UNUSED__ Eina_Stringshare_Head *head) {} #endif static int |
From: Enlightenment S. <no-...@en...> - 2008-10-29 23:33:28
|
Log: Do not pad node on 64bits. Instead of padding node we should always refer to offset of str[] inside node, that way we save some bytes and work properly. Author: barbieri Date: 2008-10-29 16:33:24 -0700 (Wed, 29 Oct 2008) New Revision: 37322 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-29 23:12:56 UTC (rev 37321) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-29 23:33:24 UTC (rev 37322) @@ -123,11 +123,6 @@ unsigned short length; unsigned short references; - -#if __WORDSIZE == 64 - unsigned int __padding; -#endif - char str[]; }; @@ -756,18 +751,28 @@ memcpy(node->str, str, slen); } +static Eina_Stringshare_Head * +_eina_stringshare_head_alloc(int slen) +{ + Eina_Stringshare_Head *head; + const unsigned int head_size = (char *)head->builtin_node.str - (char *)head; + + head = malloc(head_size + slen); + if (!head) + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + + return head; +} + static const char * _eina_stringshare_add_head(Eina_Stringshare_Head **p_bucket, int hash, const char *str, int slen) { Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket; Eina_Stringshare_Head *head; - head = malloc(sizeof(Eina_Stringshare_Head) + slen); + head = _eina_stringshare_head_alloc(slen); if (!head) - { - eina_error_set(EINA_ERROR_OUT_OF_MEMORY); - return NULL; - } + return NULL; EINA_MAGIC_SET(head, EINA_MAGIC_STRINGSHARE_HEAD); head->hash = hash; @@ -859,6 +864,19 @@ EINA_RBTREE_CMP_KEY_CB(_eina_stringshare_cmp), NULL); } +static Eina_Stringshare_Node * +_eina_stringshare_node_alloc(int slen) +{ + Eina_Stringshare_Node *node; + const unsigned int node_size = (char *)node->str - (char *)node; + + node = malloc(node_size + slen); + if (!node) + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + + return node; +} + /** * @brief Retrieve an instance of a string for use in a program. * @@ -920,12 +938,9 @@ return el->str; } - el = malloc(sizeof(Eina_Stringshare_Node) + slen); + el = _eina_stringshare_node_alloc(slen); if (!el) - { - eina_error_set(EINA_ERROR_OUT_OF_MEMORY); - return NULL; - } + return NULL; _eina_stringshare_node_init(el, str, slen); el->next = ed->head; @@ -935,6 +950,17 @@ return el->str; } +static Eina_Stringshare_Node * +_eina_stringshare_node_from_str(const char *str) +{ + Eina_Stringshare_Node *node; + const unsigned int offset = (char *)node->str - (char *)node; + + node = (Eina_Stringshare_Node *)(str - offset); + EINA_MAGIC_CHECK_STRINGSHARE_NODE(node); + return node; +} + /** * @brief Note that the given string has lost an instance. * @@ -975,8 +1001,7 @@ return; } - node = (void *)(str - sizeof(Eina_Stringshare_Node)); - EINA_MAGIC_CHECK_STRINGSHARE_NODE(node); + node = _eina_stringshare_node_from_str(str); if (node->references > 1) { node->references--; @@ -1041,8 +1066,7 @@ if (str[2] == '\0') return 2; if (str[3] == '\0') return 3; - node = (void *)(str - sizeof(Eina_Stringshare_Node)); - EINA_MAGIC_CHECK_STRINGSHARE_NODE(node); + node = _eina_stringshare_node_from_str(str); return node->length; } |
From: Enlightenment S. <no-...@en...> - 2008-10-29 23:50:34
|
Log: Pack a hole when magic is in use. Author: barbieri Date: 2008-10-29 16:50:24 -0700 (Wed, 29 Oct 2008) New Revision: 37324 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-10-29 23:41:55 UTC (rev 37323) +++ trunk/eina/src/lib/eina_stringshare.c 2008-10-29 23:50:24 UTC (rev 37324) @@ -117,10 +117,10 @@ struct _Eina_Stringshare_Node { + Eina_Stringshare_Node *next; + EINA_MAGIC; - Eina_Stringshare_Node *next; - unsigned short length; unsigned short references; char str[]; |
From: Enlightenment S. <no-...@en...> - 2008-12-06 03:02:33
|
Log: shut up gcc warning, with comment. Author: barbieri Date: 2008-12-05 19:02:30 -0800 (Fri, 05 Dec 2008) New Revision: 37953 Modified: trunk/eina/src/lib/eina_hash.c Modified: trunk/eina/src/lib/eina_hash.c =================================================================== --- trunk/eina/src/lib/eina_hash.c 2008-12-06 03:01:59 UTC (rev 37952) +++ trunk/eina/src/lib/eina_hash.c 2008-12-06 03:02:30 UTC (rev 37953) @@ -821,7 +821,7 @@ eina_hash_del(Eina_Hash *hash, const void *key, const void *data) { int key_length = 0; - int hash_num; + int hash_num = 0; /* XXX: shut up GCC, not really required */ if (!hash) return EINA_FALSE; if (key) |
From: Enlightenment S. <no-...@en...> - 2008-12-21 06:45:12
|
Log: oops, eina_stringshare_strlen() should never account '\0'. Author: barbieri Date: 2008-12-20 22:45:09 -0800 (Sat, 20 Dec 2008) New Revision: 38260 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-12-21 05:48:20 UTC (rev 38259) +++ trunk/eina/src/lib/eina_stringshare.c 2008-12-21 06:45:09 UTC (rev 38260) @@ -1112,7 +1112,7 @@ if (str[3] == '\0') return 3; node = _eina_stringshare_node_from_str(str); - return node->length; + return node->length - 1; } struct dumpinfo |
From: Enlightenment S. <no-...@en...> - 2008-12-23 19:18:00
|
Log: remove dead stores and reduce some variable scope. from clang report. Author: barbieri Date: 2008-12-23 11:17:55 -0800 (Tue, 23 Dec 2008) New Revision: 38294 Modified: trunk/eina/src/lib/eina_accessor.c trunk/eina/src/lib/eina_rbtree.c trunk/eina/src/lib/eina_rectangle.c Modified: trunk/eina/src/lib/eina_accessor.c =================================================================== --- trunk/eina/src/lib/eina_accessor.c 2008-12-23 18:14:16 UTC (rev 38293) +++ trunk/eina/src/lib/eina_accessor.c 2008-12-23 19:17:55 UTC (rev 38294) @@ -158,7 +158,7 @@ { void *container; void *data; - unsigned int i = start; + unsigned int i; EINA_MAGIC_CHECK_ACCESSOR(accessor); Modified: trunk/eina/src/lib/eina_rbtree.c =================================================================== --- trunk/eina/src/lib/eina_rbtree.c 2008-12-23 18:14:16 UTC (rev 38293) +++ trunk/eina/src/lib/eina_rbtree.c 2008-12-23 19:17:55 UTC (rev 38294) @@ -324,7 +324,7 @@ eina_rbtree_inline_remove(Eina_Rbtree *root, Eina_Rbtree *node, Eina_Rbtree_Cmp_Node_Cb cmp, const void *data) { Eina_Rbtree head; - Eina_Rbtree *q, *p, *g; + Eina_Rbtree *q, *p; Eina_Rbtree *f = NULL; Eina_Rbtree_Direction dir; @@ -334,13 +334,14 @@ dir = EINA_RBTREE_RIGHT; q = &head; - g = p = NULL; + p = NULL; q->son[EINA_RBTREE_RIGHT] = root; /* Search and push a red down */ while (q->son[dir] != NULL) { Eina_Rbtree_Direction last = dir; + Eina_Rbtree *g; /* Update helpers */ g = p; p = q; Modified: trunk/eina/src/lib/eina_rectangle.c =================================================================== --- trunk/eina/src/lib/eina_rectangle.c 2008-12-23 18:14:16 UTC (rev 38293) +++ trunk/eina/src/lib/eina_rectangle.c 2008-12-23 19:17:55 UTC (rev 38294) @@ -102,7 +102,6 @@ Eina_Bool t2 = EINA_TRUE; Eina_Bool t3 = EINA_TRUE; Eina_Bool t4 = EINA_TRUE; - Eina_Bool intersects; if ((rect->x + rect->w + w) > poolw) t1 = EINA_FALSE; if ((rect->y + h) > poolh) t1 = EINA_FALSE; @@ -113,9 +112,9 @@ if ((rect->x + w) > poolw) t4 = EINA_FALSE; if ((rect->y - h) < 0) t4 = EINA_FALSE; - intersects = EINA_FALSE; if (t1) { + Eina_Bool intersects; /* 1. try here: * +----++--+ * |AAAA||??| @@ -128,9 +127,9 @@ if (!intersects) goto on_intersect; } - intersects = EINA_FALSE; if (t2) { + Eina_Bool intersects; /* 2. try here: * +----+ * |AAAA| @@ -146,9 +145,9 @@ if (!intersects) goto on_intersect; } - intersects = EINA_FALSE; if (t3) { + Eina_Bool intersects; /* 3. try here: * +--++----+ * |??||AAAA| @@ -161,9 +160,9 @@ if (!intersects) goto on_intersect; } - intersects = EINA_FALSE; if (t4) { + Eina_Bool intersects; /* 2. try here: * +--+ * |??| |
From: Enlightenment S. <no-...@en...> - 2008-12-23 20:05:48
|
Log: fix possible errors with pointer/offset calculation. it works on gcc, but maybe it would break in other compilers, so make it safe. Author: barbieri Date: 2008-12-23 12:05:44 -0800 (Tue, 23 Dec 2008) New Revision: 38302 Modified: trunk/eina/src/lib/eina_stringshare.c Modified: trunk/eina/src/lib/eina_stringshare.c =================================================================== --- trunk/eina/src/lib/eina_stringshare.c 2008-12-23 19:55:52 UTC (rev 38301) +++ trunk/eina/src/lib/eina_stringshare.c 2008-12-23 20:05:44 UTC (rev 38302) @@ -636,8 +636,8 @@ static Eina_Stringshare_Head * _eina_stringshare_head_alloc(int slen) { - Eina_Stringshare_Head *head; - const unsigned int head_size = (char *)head->builtin_node.str - (char *)head; + Eina_Stringshare_Head *head, t; + const unsigned int head_size = (char *)&(t.builtin_node.str) - (char *)&t; head = malloc(head_size + slen); if (!head) @@ -749,8 +749,8 @@ static Eina_Stringshare_Node * _eina_stringshare_node_alloc(int slen) { - Eina_Stringshare_Node *node; - const unsigned int node_size = (char *)node->str - (char *)node; + Eina_Stringshare_Node *node, t; + const unsigned int node_size = (char *)&(t.str) - (char *)&t; node = malloc(node_size + slen); if (!node) @@ -953,8 +953,8 @@ static Eina_Stringshare_Node * _eina_stringshare_node_from_str(const char *str) { - Eina_Stringshare_Node *node; - const unsigned int offset = (char *)node->str - (char *)node; + Eina_Stringshare_Node *node, t; + const unsigned int offset = (char *)&(t.str) - (char *)&t; node = (Eina_Stringshare_Node *)(str - offset); EINA_MAGIC_CHECK_STRINGSHARE_NODE(node); |
From: Enlightenment S. <no-...@en...> - 2009-06-06 22:54:00
|
Log: do not leak module if user do not want it. Author: barbieri Date: 2009-06-06 15:53:03 -0700 (Sat, 06 Jun 2009) New Revision: 40924 Modified: trunk/eina/src/lib/eina_module.c Modified: trunk/eina/src/lib/eina_module.c =================================================================== --- trunk/eina/src/lib/eina_module.c 2009-06-06 22:31:34 UTC (rev 40923) +++ trunk/eina/src/lib/eina_module.c 2009-06-06 22:53:03 UTC (rev 40924) @@ -139,7 +139,8 @@ if (!m) return; /* call the user provided cb on this module */ - cb_data->cb(m, cb_data->data); + if (!cb_data->cb(m, cb_data->data)) + eina_module_delete(m); } } static int _eina_module_count = 0; |
From: Enlightenment S. <no-...@en...> - 2009-06-16 14:59:12
|
Log: better error setting and reporting in module loading. * just set error codes if we know the error. * debug dlopen() error using EINA_ERROR_PDBG() Author: barbieri Date: 2009-06-16 07:59:09 -0700 (Tue, 16 Jun 2009) New Revision: 41057 Modified: trunk/eina/src/lib/eina_module.c Modified: trunk/eina/src/lib/eina_module.c =================================================================== --- trunk/eina/src/lib/eina_module.c 2009-06-16 13:34:08 UTC (rev 41056) +++ trunk/eina/src/lib/eina_module.c 2009-06-16 14:59:09 UTC (rev 41057) @@ -210,19 +210,22 @@ if (m->handle) goto loaded; - eina_error_set(EINA_ERROR_WRONG_MODULE); - dl_handle = dlopen(m->file, RTLD_NOW); - if (!dl_handle) return EINA_FALSE; + if (!dl_handle) + { + EINA_ERROR_PDBG("could not dlopen(\"%s\", RTLD_NOW): %s\n", + m->file, dlerror()); + eina_error_set(EINA_ERROR_WRONG_MODULE); + return EINA_FALSE; + } - eina_error_set(EINA_ERROR_MODULE_INIT_FAILED); - initcall = dlsym(dl_handle, EINA_MODULE_SYMBOL_INIT); if ((!initcall) || (!(*initcall))) goto ok; if ((*initcall)() == EINA_TRUE) goto ok; + eina_error_set(EINA_ERROR_MODULE_INIT_FAILED); dlclose(dl_handle); return EINA_FALSE; ok: |
From: Enlightenment S. <no-...@en...> - 2009-06-20 16:31:20
|
Log: and rename static linkage as well. Author: barbieri Date: 2009-06-20 09:31:15 -0700 (Sat, 20 Jun 2009) New Revision: 41131 Modified: trunk/eina/src/lib/Makefile.am Modified: trunk/eina/src/lib/Makefile.am =================================================================== --- trunk/eina/src/lib/Makefile.am 2009-06-20 16:18:17 UTC (rev 41130) +++ trunk/eina/src/lib/Makefile.am 2009-06-20 16:31:15 UTC (rev 41131) @@ -59,7 +59,7 @@ if EINA_STATIC_BUILD_PASS_THROUGH -libeina_la_SOURCES += $(top_srcdir)/src/modules/mp/pass_through/pass_through.c +libeina_la_SOURCES += $(top_srcdir)/src/modules/mp/pass_through/eina_pass_through.c endif |
From: Enlightenment S. <no-...@en...> - 2009-07-14 14:01:07
|
Log: one more safety check: do not remove element if it's not in any list. This is the best we can do, but what should be done is to check if element is really from that list. Author: barbieri Date: 2009-07-14 07:00:59 -0700 (Tue, 14 Jul 2009) New Revision: 41326 Modified: trunk/eina/src/lib/eina_inlist.c Modified: trunk/eina/src/lib/eina_inlist.c =================================================================== --- trunk/eina/src/lib/eina_inlist.c 2009-07-14 12:02:31 UTC (rev 41325) +++ trunk/eina/src/lib/eina_inlist.c 2009-07-14 14:00:59 UTC (rev 41326) @@ -251,6 +251,8 @@ /* checkme */ EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(item, list); + EINA_SAFETY_ON_TRUE_RETURN_VAL + ((item != list) && (item->prev == NULL) && (item->next == NULL), list); if (item->next) item->next->prev = item->prev; |
From: Enlightenment S. <no-...@en...> - 2009-07-14 15:32:29
|
Log: inlist: docs, docs docs Author: barbieri Date: 2009-07-14 08:32:21 -0700 (Tue, 14 Jul 2009) New Revision: 41328 Modified: trunk/eina/src/lib/eina_inlist.c Modified: trunk/eina/src/lib/eina_inlist.c =================================================================== --- trunk/eina/src/lib/eina_inlist.c 2009-07-14 15:32:01 UTC (rev 41327) +++ trunk/eina/src/lib/eina_inlist.c 2009-07-14 15:32:21 UTC (rev 41328) @@ -148,9 +148,91 @@ * * @brief These functions provide inline list management. * + * Inline lists mean its nodes pointers are part of same memory as + * data. This has the benefit of framenting memory less and avoiding + * @c node->data indirection, but has the drawback of elements only + * being able to be part of one single inlist at same time. But it is + * possible to have inlist nodes to be part of regular lists created + * with eina_list_append() or eina_list_prepend(). + * + * Inline lists have its purposes, but if you don't know them go with + * regular lists instead. + * + * @code + * #include <Eina.h> + * #include <stdio.h> + * + * int + * main(void) + * { + * struct my_struct { + * EINA_INLIST; + * int a, b; + * } *d, *cur; + * Eina_Inlist *list, *itr; + * + * eina_init(); + * + * d = malloc(sizeof(*d)); + * d->a = 1; + * d->b = 10; + * list = eina_inlist_append(NULL, EINA_INLIST_GET(d)); + * + * d = malloc(sizeof(*d)); + * d->a = 2; + * d->b = 20; + * list = eina_inlist_append(list, EINA_INLIST_GET(d)); + * + * d = malloc(sizeof(*d)); + * d->a = 3; + * d->b = 30; + * list = eina_inlist_prepend(list, EINA_INLIST_GET(d)); + * + * printf("list=%p\n", list); + * EINA_INLIST_FOREACH(list, cur) + * printf("\ta=%d, b=%d\n", cur->a, cur->b); + * + * list = eina_inlist_remove(list, EINA_INLIST_GET(d)); + * free(d); + * printf("list=%p\n", list); + * for (itr = list; itr != NULL; itr = itr->next) + * { + * cur = EINA_INLIST_CONTAINER_GET(itr, struct my_struct); + * printf("\ta=%d, b=%d\n", cur->a, cur->b); + * } + * + * while (list) + * { + * Eina_Inlist *aux = list; + * list = eina_inlist_remove(list, list); + * free(aux); + * } + * + * eina_shutdown(); + * + * return 0; + * } + * @endcode + * * @{ */ +/** + * Add a new node to end of list. + * + * @note this code is meant to be fast, appends are O(1) and do not + * walk @a list anyhow. + * + * @note @a new_l is considered to be in no list. If it was in another + * list before, please eina_inlist_remove() it before adding. No + * check of @a new_l prev and next pointers is done, so it' safe + * to have them uninitialized. + * + * @param list existing list head or NULL to create a new list. + * @param new_l new list node, must not be NULL. + * + * @return the new list head. Use it and not given @a list anymore. + */ EAPI Eina_Inlist * eina_inlist_append(Eina_Inlist *list, Eina_Inlist *new_l) { @@ -175,6 +257,22 @@ return list; } +/** + * Add a new node to beginning of list. + * + * @note this code is meant to be fast, prepends are O(1) and do not + * walk @a list anyhow. + * + * @note @a new_l is considered to be in no list. If it was in another + * list before, please eina_inlist_remove() it before adding. No + * check of @a new_l prev and next pointers is done, so it' safe + * to have them uninitialized. + * + * @param list existing list head or NULL to create a new list. + * @param new_l new list node, must not be NULL. + * + * @return the new list head. Use it and not given @a list anymore. + */ EAPI Eina_Inlist * eina_inlist_prepend(Eina_Inlist *list, Eina_Inlist *new_l) { @@ -193,6 +291,28 @@ return new_l; } +/** + * Add a new node after the given relative item in list. + * + * @note this code is meant to be fast, appends are O(1) and do not + * walk @a list anyhow. + * + * @note @a new_l is considered to be in no list. If it was in another + * list before, please eina_inlist_remove() it before adding. No + * check of @a new_l prev and next pointers is done, so it' safe + * to have them uninitialized. + * + * @note @a relative is considered to be inside @a list, no checks are + * done to confirm that and giving nodes from different lists + * will lead to problems. Giving NULL @a relative is the same as + * eina_list_append(). + * + * @param list existing list head or NULL to create a new list. + * @param new_l new list node, must not be NULL. + * @param relative reference node, @a new_l will be added after it. + * + * @return the new list head. Use it and not given @a list anymore. + */ EAPI Eina_Inlist * eina_inlist_append_relative(Eina_Inlist *list, Eina_Inlist *new_l, @@ -215,6 +335,28 @@ return eina_inlist_append(list, new_l); } +/** + * Add a new node before the given relative item in list. + * + * @note this code is meant to be fast, prepends are O(1) and do not + * walk @a list anyhow. + * + * @note @a new_l is considered to be in no list. If it was in another + * list before, please eina_inlist_remove() it before adding. No + * check of @a new_l prev and next pointers is done, so it' safe + * to have them uninitialized. + * + * @note @a relative is considered to be inside @a list, no checks are + * done to confirm that and giving nodes from different lists + * will lead to problems. Giving NULL @a relative is the same as + * eina_list_prepend(). + * + * @param list existing list head or NULL to create a new list. + * @param new_l new list node, must not be NULL. + * @param relative reference node, @a new_l will be added before it. + * + * @return the new list head. Use it and not given @a list anymore. + */ EAPI Eina_Inlist * eina_inlist_prepend_relative(Eina_Inlist *list, Eina_Inlist *new_l, @@ -243,6 +385,23 @@ return eina_inlist_prepend(list, new_l); } +/** + * Remove node from list. + * + * @note this code is meant to be fast, removals are O(1) and do not + * walk @a list anyhow. + * + * @note @a item is considered to be inside @a list, no checks are + * done to confirm that and giving nodes from different lists + * will lead to problems, specially if @a item is the head since + * it will be different from @a list and the wrong new head will + * be returned. + * + * @param list existing list head, must not be NULL. + * @param item existing list node, must not be NULL. + * + * @return the new list head. Use it and not given @a list anymore. + */ EAPI Eina_Inlist * eina_inlist_remove(Eina_Inlist *list, Eina_Inlist *item) { @@ -272,6 +431,21 @@ return return_l; } +/** + * Move existing node to beginning of list. + * + * @note this code is meant to be fast, promotion is O(1) and do not + * walk @a list anyhow. + * + * @note @a item is considered to be inside @a list, no checks are + * done to confirm that and giving nodes from different lists + * will lead to problems. + * + * @param list existing list head or NULL to create a new list. + * @param item list node to move to beginning (head), must not be NULL. + * + * @return the new list head. Use it and not given @a list anymore. + */ EAPI Eina_Inlist * eina_inlist_promote(Eina_Inlist *list, Eina_Inlist *item) { @@ -297,6 +471,21 @@ return item; } +/** + * Move existing node to end of list. + * + * @note this code is meant to be fast, demoting is O(1) and do not + * walk @a list anyhow. + * + * @note @a item is considered to be inside @a list, no checks are + * done to confirm that and giving nodes from different lists + * will lead to problems. + * + * @param list existing list head or NULL to create a new list. + * @param item list node to move to end (tail), must not be NULL. + * + * @return the new list head. Use it and not given @a list anymore. + */ EAPI Eina_Inlist * eina_inlist_demote(Eina_Inlist *list, Eina_Inlist *item) { @@ -329,6 +518,17 @@ return l; } +/** + * Find given node in list, returns itself if found, NULL if not. + * + * @warning this is an expensive call and have O(n) cost, possibly + * walking the whole list. + * + * @param list existing list to search @a item in, must not be NULL. + * @param item what to search for, must not be NULL. + * + * @return @a item if found, NULL if not. + */ EAPI Eina_Inlist * eina_inlist_find(Eina_Inlist *list, Eina_Inlist *item) { @@ -366,6 +566,26 @@ return i; } +/** + * @brief Returned a new iterator asociated to a list. + * + * @param list The list. + * @return A new iterator. + * + * This function returns a newly allocated iterator associated to @p + * list. If @p list is @c NULL or the count member of @p list is less + * or equal than 0, this function still returns a valid iterator that + * will always return false on eina_iterator_next(), thus keeping API + * sane. + * + * If the memory can not be allocated, NULL is returned and + * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is + * returned. + * + * @warning if the list structure changes then the iterator becomes + * invalid! That is, if you add or remove nodes this iterator + * behavior is undefined and your program may crash! + */ EAPI Eina_Iterator * eina_inlist_iterator_new(const Eina_Inlist *list) { @@ -390,6 +610,18 @@ return &it->iterator; } +/** + * @brief Returned a new accessor asociated to a list. + * + * @param list The list. + * @return A new accessor. + * + * This function returns a newly allocated accessor associated to + * @p list. If @p list is @c NULL or the count member of @p list is + * less or equal than 0, this function returns NULL. If the memory can + * not be allocated, NULL is returned and #EINA_ERROR_OUT_OF_MEMORY is + * set. Otherwise, a valid accessor is returned. + */ EAPI Eina_Accessor * eina_inlist_accessor_new(const Eina_Inlist *list) { |