blob: f4399747f87233ee681a76acf5ac93318143b2b2 [file] [log] [blame]
/* Copyright (C) 2007-2008 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
*/
#include "android/utils/reflist.h"
#include "android/utils/system.h"
#include "android/utils/assert.h"
#include <stdlib.h>
#include <string.h>
static void** _areflist_items(const ARefList* l)
{
if (l->max == 1)
return (void**)&l->u.item0;
else
return l->u.items;
}
static void
_areflist_checkSize0(ARefList* l)
{
if (l->size == 0 && l->max > 1) {
AFREE(l->u.items);
l->max = 1;
l->u.item0 = NULL;
}
}
void
areflist_setEmpty(ARefList* l)
{
if (l->iteration > 0) {
/* deferred empty, set all items to NULL
* to stop iterations */
void** items = _areflist_items(l);
AARRAY_ZERO(items, l->count);
l->iteration |= 1;
} else {
/* direct empty */
l->size = 0;
_areflist_checkSize0(l);
}
l->count = 0;
}
int
areflist_indexOf(const ARefList* l, void* item)
{
if (item) {
void** items = _areflist_items(l);
void** end = items + l->count;
void** ii = items;
for ( ; ii < end; ii += 1 )
if (*ii == item)
return (ii - items);
}
return -1;
}
static void
areflist_grow(ARefList* l, int count)
{
int newcount = l->size + count;
if (newcount > l->max) {
int oldmax = l->max;
int newmax;
void** items;
if (oldmax == 1) {
oldmax = 0;
items = NULL;
} else {
items = l->u.items;
}
newmax = oldmax;
while (newmax < newcount)
newmax += (newmax >> 1) + 4;
AARRAY_RENEW(items, newmax);
if (l->max == 1)
items[0] = l->u.item0;
l->u.items = items;
l->max = (uint16_t) newmax;
}
}
void
areflist_add(ARefList* l, void* item)
{
if (item) {
void** items;
if (l->size >= l->max) {
areflist_grow(l, 1);
}
items = _areflist_items(l);
items[l->size] = item;
l->size += 1;
l->count += 1;
}
}
void
areflist_append(ARefList* l, const ARefList* l2)
{
AREFLIST_FOREACH_CONST(l2, item, {
areflist_add(l, item);
});
}
void*
areflist_popLast(ARefList* l)
{
void* item = NULL;
void** items = _areflist_items(l);
int nn;
if (l->count == 0)
return NULL;
for (nn = l->size; nn > 0; nn--) {
item = items[nn-1];
if (item != NULL)
goto FOUND_LAST;
}
return NULL;
FOUND_LAST:
/* we found the last non-NULL item in the array */
l->count -= 1;
items[nn-1] = NULL;
if (l->iteration == 0) {
l->size = nn;
_areflist_checkSize0(l);
}
return item;
}
ABool
areflist_delFirst(ARefList* l, void* item)
{
if (item == NULL)
return 0;
int index = areflist_indexOf(l, item);
if (index < 0)
return 0;
void** items = _areflist_items(l);
if (l->iteration > 0) {
/* deferred deletion */
items[index] = NULL;
l->iteration |= 1;
l->count -= 1;
} else {
/* direct deletion */
if (l->max > 1) {
AARRAY_MOVE(items + index, items + index + 1, l->size - index - 1);
l->size -= 1;
l->count -= 1;
_areflist_checkSize0(l);
} else {
l->u.item0 = NULL;
l->size = 0;
l->count = 0;
}
}
return 1;
}
ABool
areflist_delAll(ARefList* l, void* item)
{
ABool result = 0;
if (item == NULL)
return 0;
void** items = _areflist_items(l);
int readPos = 0;
int writePos = 0;
/* don't modify the list until we find the item
* or an EMPTY slot */
for ( ; readPos < l->size; readPos++ ) {
if (items[readPos] == NULL || items[readPos] == item)
goto COPY_LIST;
}
return 0;
COPY_LIST:
writePos = readPos;
for ( ; readPos < l->size; readPos++ ) {
if (items[readPos] == NULL) {
continue;
}
if (items[readPos] == item) {
result = 1;
continue;
}
items[writePos] = items[readPos];
writePos++;
}
l->count = l->size = (uint16_t) writePos;
_areflist_checkSize0(l);
return result;
}
void
_areflist_remove_deferred(ARefList* l)
{
if (l->iteration & 1) {
/* remove all NULL elements from the array */
void** items = _areflist_items(l);
int rr = 0;
int ww = 0;
for ( ; rr < l->size; rr++ ) {
if (items[rr] != NULL)
items[ww++] = items[rr];
}
l->count = l->size = (uint16_t) ww;
_areflist_checkSize0(l);
}
l->iteration = 0;
}
void
areflist_copy(ARefList* dst, const ARefList* src)
{
dst[0] = src[0];
if (src->max > 1) {
dst->max = dst->count;
AARRAY_NEW(dst->u.items, dst->max);
void** ritems = src->u.items;
void** witems = _areflist_items(dst);
int rr = 0;
int ww = 0;
for ( ; rr < src->size; rr++ ) {
if (ritems[rr] != NULL) {
witems[ww++] = ritems[rr];
}
}
dst->size = ww;
AASSERT_TRUE(ww == dst->count);
_areflist_checkSize0(dst);
}
}
void*
areflist_get(const ARefList* l, int n)
{
if ((unsigned)n >= (unsigned)l->count)
return NULL;
if (l->max == 1)
return l->u.item0;
return l->u.items[n];
}
void**
_areflist_at(const ARefList* l, int n)
{
void** items;
if ((unsigned)n >= (unsigned)l->size)
return NULL;
items = _areflist_items(l);
return items + n;
}