/* 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 #include 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; }