pipewire/spa/include/spa/utils/list.h
Wim Taymans 2de7f9cc03 list: add iteration with a cursor
Iterating a list with a cursor is heavier but is safe against removal
of any element in the list. Move the hook cursor iterator to list.
2018-08-15 11:24:40 +02:00

116 lines
3.6 KiB
C

/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_LIST_H__
#define __SPA_LIST_H__
#ifdef __cplusplus
extern "C" {
#endif
struct spa_list {
struct spa_list *next;
struct spa_list *prev;
};
#define SPA_LIST_INIT(list) (struct spa_list){ list, list };
static inline void spa_list_init(struct spa_list *list)
{
*list = SPA_LIST_INIT(list);
}
static inline void spa_list_insert(struct spa_list *list, struct spa_list *elem)
{
elem->prev = list;
elem->next = list->next;
list->next = elem;
elem->next->prev = elem;
}
static inline void spa_list_insert_list(struct spa_list *list, struct spa_list *other)
{
other->next->prev = list;
other->prev->next = list->next;
list->next->prev = other->prev;
list->next = other->next;
}
static inline void spa_list_remove(struct spa_list *elem)
{
elem->prev->next = elem->next;
elem->next->prev = elem->prev;
}
#define spa_list_is_empty(l) ((l)->next == (l))
#define spa_list_first(head, type, member) \
SPA_CONTAINER_OF((head)->next, type, member)
#define spa_list_last(head, type, member) \
SPA_CONTAINER_OF((head)->prev, type, member)
#define spa_list_append(list, item) \
spa_list_insert((list)->prev, item)
#define spa_list_prepend(list, item) \
spa_list_insert(list, item)
#define spa_list_is_end(pos, head, member) \
(&(pos)->member == (head))
#define spa_list_next(pos, member) \
SPA_CONTAINER_OF((pos)->member.next, __typeof__(*pos), member)
#define spa_list_for_each_next(pos, head, curr, member) \
for (pos = spa_list_first(curr, __typeof__(*pos), member); \
!spa_list_is_end(pos, head, member); \
pos = spa_list_next(pos, member))
#define spa_list_for_each(pos, head, member) \
spa_list_for_each_next(pos, head, head, member)
#define spa_list_for_each_safe_next(pos, tmp, head, curr, member) \
for (pos = spa_list_first(curr, __typeof__(*pos), member), \
tmp = spa_list_next(pos, member); \
!spa_list_is_end(pos, head, member); \
pos = tmp, \
tmp = spa_list_next(pos, member))
#define spa_list_for_each_safe(pos, tmp, head, member) \
spa_list_for_each_safe_next(pos, tmp, head, head, member)
#define spa_list_cursor_start(cursor, head, member) \
spa_list_prepend(head, &(cursor).member)
#define spa_list_for_each_cursor(pos, cursor, head, member) \
for(pos = spa_list_first(&(cursor).member, __typeof__(*(pos)), member); \
spa_list_remove(&(pos)->member), \
spa_list_append(&(cursor).member, &(pos)->member), \
!spa_list_is_end(pos, head, member); \
pos = spa_list_next(&cursor, member))
#define spa_list_cursor_end(cursor, member) \
spa_list_remove(&(cursor).member)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_LIST_H__ */