forked from enlightenment/efl
fix eina_array_remove to actually realloc down in size to remove bloat
eina_array_remove() didnt ever realloc down unless we went to 0 members. this wasn't very good as you'd expect the array to be reduced in size if enough items were removed. not only that the old code was stupid and ALWAYS malloc()ed a new array of the exact same size and copied items over in the most complex way possible, then freed the old one. this would have added overhead wherever used (evas_render) that should not have been there. this is based on the idea in a patch from Viacheslav Lvov <v.lvov@samsung.com>, but this is a re-do of it entirely, reducing the codebase massively even compared to the patch and making it much simpler to read, maintain, actually reduce memory and cut overhead.
This commit is contained in:
parent
403e97ecb0
commit
523d8607d1
|
@ -330,87 +330,46 @@ eina_array_remove(Eina_Array *array, Eina_Bool (*keep)(void *data,
|
||||||
void *gdata),
|
void *gdata),
|
||||||
void *gdata)
|
void *gdata)
|
||||||
{
|
{
|
||||||
void **tmp;
|
unsigned int i, j, size, count;
|
||||||
/* WARNING:
|
void *data, **tmp;
|
||||||
The algorithm does exit before using unitialized data. So compiler is
|
|
||||||
giving you a false positiv here too.
|
|
||||||
*/
|
|
||||||
void *data = NULL;
|
|
||||||
unsigned int total = 0;
|
|
||||||
unsigned int limit;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(array, EINA_FALSE);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(array, EINA_FALSE);
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(keep, EINA_FALSE);
|
EINA_SAFETY_ON_NULL_RETURN_VAL(keep, EINA_FALSE);
|
||||||
EINA_MAGIC_CHECK_ARRAY(array);
|
EINA_MAGIC_CHECK_ARRAY(array);
|
||||||
|
|
||||||
if (array->total == 0)
|
if (array->total == 0) return EINA_TRUE;
|
||||||
return EINA_TRUE;
|
// 1. walk through all items and shuffle down any items on top of
|
||||||
|
// previously removed item slots
|
||||||
for (i = 0; i < array->count; ++i)
|
for (count = array->count, tmp = array->data, j = 0, i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
data = eina_array_data_get(array, i);
|
data = tmp[i];
|
||||||
|
|
||||||
if (keep(data, gdata) == EINA_FALSE)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
limit = i;
|
|
||||||
if (i < array->count)
|
|
||||||
++i;
|
|
||||||
|
|
||||||
for (; i < array->count; ++i)
|
|
||||||
{
|
|
||||||
data = eina_array_data_get(array, i);
|
|
||||||
|
|
||||||
if (keep(data, gdata) == EINA_TRUE)
|
if (keep(data, gdata) == EINA_TRUE)
|
||||||
break;
|
{
|
||||||
|
// we keep it - store it (again) (and j will be <= i ALWAYS)
|
||||||
|
tmp[j] = data;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Special case all objects that need to stay are at the beginning of the array. */
|
array->count = j;
|
||||||
if (i == array->count)
|
// 2. if we reduced size by more than N (block size) then realloc back down
|
||||||
|
if ((array->total - array->count) >= array->step)
|
||||||
{
|
{
|
||||||
array->count = limit;
|
|
||||||
if (array->count == 0)
|
if (array->count == 0)
|
||||||
{
|
{
|
||||||
free(array->data);
|
free(array->data);
|
||||||
array->total = 0;
|
array->total = 0;
|
||||||
array->data = NULL;
|
array->data = NULL;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
return EINA_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = malloc(sizeof (void *) * array->total);
|
|
||||||
if (!tmp) return EINA_FALSE;
|
|
||||||
|
|
||||||
memcpy(tmp, array->data, limit * sizeof(void *));
|
|
||||||
total = limit;
|
|
||||||
|
|
||||||
if (i < array->count)
|
|
||||||
{
|
|
||||||
tmp[total] = data;
|
|
||||||
total++;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < array->count; ++i)
|
|
||||||
{
|
|
||||||
data = eina_array_data_get(array, i);
|
|
||||||
|
|
||||||
if (keep(data, gdata))
|
|
||||||
{
|
{
|
||||||
tmp[total] = data;
|
// realloc back down - rounding up to the nearest step size
|
||||||
total++;
|
size = (array->count + array->step - 1) % array->step;
|
||||||
|
tmp = realloc(array->data, sizeof(void *) * size);
|
||||||
|
if (!tmp) return EINA_FALSE;
|
||||||
|
array->total = size;
|
||||||
|
array->data = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(array->data);
|
|
||||||
|
|
||||||
/* If we do not keep any object in the array, we should have exited
|
|
||||||
earlier in test (i == array->count). */
|
|
||||||
assert(total != 0);
|
|
||||||
|
|
||||||
array->data = tmp;
|
|
||||||
array->count = total;
|
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue