| /* 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. |
| */ |
| #ifndef _ANDROID_GRAPHICS_REFLIST_H |
| #define _ANDROID_GRAPHICS_REFLIST_H |
| |
| #include <inttypes.h> |
| |
| #include "android/utils/compiler.h" |
| #include <android/utils/system.h> |
| |
| ANDROID_BEGIN_HEADER |
| |
| /* Definitions for a smart list of references to generic objects. |
| * supports safe deletion and addition while they are being iterated |
| * with AREFLIST_FOREACH() macro. |
| * |
| * note that you cannot add NULL to an ARefList. |
| */ |
| |
| /* Clients should ignore these implementation details, which |
| * we're going to explain there: |
| * - 'count' is the number of items in the list |
| * - 'size' is the number of slots in the list's array. It is |
| * always >= 'count'. Some slots correspond to deleted items |
| * and will hold a NULL value. |
| * - 'max' is the size of the slots array |
| * - 'u.item0' is used when 'max' is 1 |
| * - 'u.items' is the slot array if 'max > 1' |
| * - 'u.next' is only used for free-list storage. |
| */ |
| typedef struct ARefList { |
| /* XXX: should we use uint32_t instead ? */ |
| uint16_t count, size, max; |
| uint16_t iteration; |
| union { |
| void* item0; |
| void** items; |
| } u; |
| } ARefList; |
| |
| /* Initialize an empty ARefList */ |
| AINLINED void |
| areflist_init(ARefList* l) |
| { |
| l->count = 0; |
| l->size = 0; |
| l->max = 1; |
| l->iteration = 0; |
| } |
| |
| /* Return the number of items in a list */ |
| AINLINED int |
| areflist_getCount(const ARefList* l) |
| { |
| return l->count; |
| } |
| |
| /* Clear an ARefList */ |
| void areflist_setEmpty(ARefList* l); |
| |
| /* Finalize, i.e. clear, an ARefList */ |
| AINLINED void |
| areflist_done(ARefList* l) |
| { |
| areflist_setEmpty(l); |
| } |
| |
| /* Return TRUE iff an ARefList has no item */ |
| AINLINED ABool |
| areflist_isEmpty(const ARefList* l) |
| { |
| return (areflist_getCount(l) == 0); |
| } |
| |
| /* Return the index of 'item' in the ARefList, or -1. |
| * This returns -1 if 'item' is NULL. |
| */ |
| int areflist_indexOf(const ARefList* l, void* item); |
| |
| /* Return TRUE iff an ARefList contains 'item' */ |
| AINLINED ABool |
| areflist_has(const ARefList* l, void* item) |
| { |
| return areflist_indexOf(l, item) >= 0; |
| } |
| |
| /* Append 'item' to a list. An item can be added several |
| * times to the same list. Do nothing if 'item' is NULL. */ |
| void areflist_add(ARefList* l, void* item); |
| |
| /* Remove first instance of 'item' from an ARefList. |
| * Returns TRUE iff the item was found in the list. */ |
| ABool areflist_delFirst(ARefList* l, void* item); |
| |
| /* Remove all instances of 'item' from an ARefList. |
| * returns TRUE iff the item was found in the list */ |
| ABool areflist_delAll(ARefList* l, void* item); |
| |
| /* Same as areflist_add() */ |
| AINLINED void |
| areflist_push(ARefList* l, void* item) |
| { |
| areflist_add(l, item); |
| } |
| |
| /* Remove last item from an ARefList and return it. |
| * NULL is returned if the list is empty */ |
| void* areflist_popLast(ARefList* l); |
| |
| /* Return the n-th array entry, or NULL in case of invalid index */ |
| void* areflist_get(const ARefList* l, int n); |
| |
| AINLINED int |
| areflist_count(ARefList* l) |
| { |
| return l->count; |
| } |
| |
| void areflist_append(ARefList* l, const ARefList* src); |
| |
| /* used internally */ |
| void _areflist_remove_deferred(ARefList* l); |
| |
| void** _areflist_at(const ARefList* l, int n); |
| |
| #define AREFLIST_LOOP(list_,itemvar_) \ |
| do { \ |
| ARefList* _reflist_loop = (list_); \ |
| int _reflist_loop_i = 0; \ |
| int _reflist_loop_n = _reflist_loop->size; \ |
| _reflist_loop->iteration += 2; \ |
| for ( ; _reflist_loop_i < _reflist_loop_n; _reflist_loop_i++ ) { \ |
| void** _reflist_loop_at = _areflist_at(_reflist_loop, _reflist_loop_i); \ |
| (itemvar_) = *(_reflist_loop_at); \ |
| if ((itemvar_) != NULL) { |
| |
| #define AREFLIST_LOOP_END \ |
| } \ |
| } \ |
| if (_reflist_loop->iteration & 1) \ |
| _areflist_remove_deferred(_reflist_loop); \ |
| } while (0); |
| |
| #define AREFLIST_LOOP_CONST(list_,itemvar_) \ |
| do { \ |
| const ARefList* _reflist_loop = (list_); \ |
| int _reflist_loop_i = 0; \ |
| int _reflist_loop_n = _reflist_loop->size; \ |
| for ( ; _reflist_loop_i < _reflist_loop_n; _reflist_loop_i++ ) { \ |
| void** _reflist_loop_at = _areflist_at(_reflist_loop, _reflist_loop_i); \ |
| (itemvar_) = *(_reflist_loop_at); \ |
| if ((itemvar_) != NULL) { |
| |
| #define AREFLIST_LOOP_DEL() \ |
| (_reflist_loop->iteration |= 1, *_reflist_loop_at = NULL) |
| |
| #define AREFLIST_LOOP_SET(val) \ |
| (_reflist_loop->iteration |= 1, *_reflist_loop_at = (val)) |
| |
| |
| #define AREFLIST_FOREACH(list_,item_,statement_) \ |
| ({ ARefList* _reflist = (list_); \ |
| int _reflist_i = 0; \ |
| int _reflist_n = _reflist->size; \ |
| _reflist->iteration += 2; \ |
| for ( ; _reflist_i < _reflist_n; _reflist_i++ ) { \ |
| void** __reflist_at = _areflist_at(_reflist, _reflist_i); \ |
| void* item_ = *__reflist_at; \ |
| if (item_ != NULL) { \ |
| statement_; \ |
| } \ |
| } \ |
| _reflist->iteration -= 2; \ |
| if (_reflist->iteration == 1) \ |
| _areflist_remove_deferred(_reflist); \ |
| }) |
| |
| #define AREFLIST_FOREACH_CONST(list_,item_,statement_) \ |
| ({ const ARefList* _reflist = (list_); \ |
| int _reflist_i = 0; \ |
| int _reflist_n = _reflist->size; \ |
| for ( ; _reflist_i < _reflist_n; _reflist_i++ ) { \ |
| void** __reflist_at = _areflist_at(_reflist, _reflist_i); \ |
| void* item_ = *__reflist_at; \ |
| if (item_ != NULL) { \ |
| statement_; \ |
| } \ |
| } \ |
| }) |
| |
| /* use this to delete the currently iterated element */ |
| #define AREFLIST_DEL_ITERATED() \ |
| ({ *__reflist_at = NULL; \ |
| _reflist->iteration |= 1; }) |
| |
| /* use this to replace the currently iterated element */ |
| #define AREFLIST_SET_ITERATED(item) \ |
| ({ *__reflist_at = (item); \ |
| if (item == NULL) _reflist->iteration |= 1; }) |
| |
| void areflist_copy(ARefList* dst, const ARefList* src); |
| |
| ANDROID_END_HEADER |
| |
| #endif /* _ANDROID_GRAPHICS_REFLIST_H */ |