blob: 8c3783fc2141b4f7b86dd263f28d4b7698bd0fae [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.
*/
#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 */