/* * list.h - useful list handling header * * Copyright © 2008 Julien Danjou * Copyright © 2006 Pierre Habouzit * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef AWESOME_COMMON_LIST_H #define AWESOME_COMMON_LIST_H #define DO_SLIST(type, prefix, dtor) \ static inline type *prefix##_list_next(type **list __attribute__ ((unused)), \ type *item) \ { \ return item->next; \ } \ \ static inline type *prefix##_list_pop(type **list) \ { \ if (*list) \ { \ type *res = *list; \ *list = res->next; \ if(res->next) \ res->next->prev = NULL; \ res->next = NULL; \ return res; \ } \ return NULL; \ } \ \ static inline void prefix##_list_push(type **list, type *item) \ { \ if(*list) \ (*list)->prev = item; \ item->next = *list; \ *list = item; \ } \ \ static inline type **prefix##_list_last(type **list) \ { \ while (*list && (*list)->next) \ list = &(*list)->next; \ return list; \ } \ \ static inline void prefix##_list_append(type **list, type *item) \ { \ if(*(list = prefix##_list_last(list))) \ { \ (*list)->next = item; \ item->prev = *list; \ } \ else \ (*list) = item; \ } \ \ static inline type *prefix##_list_rev(type *list) \ { \ type *l = NULL; \ while (list) \ prefix##_list_push(&l, prefix##_list_pop(&list)); \ return l; \ } \ \ static inline type **prefix##_list_init(type **list) \ { \ *list = NULL; \ return list; \ } \ \ static inline void prefix##_list_wipe(type **list) \ { \ while (*list) \ { \ type *item = prefix##_list_pop(list); \ dtor(&item); \ } \ } \ \ static inline type *prefix##_list_prev(type **list __attribute__ ((unused)), \ type *item) \ { \ return item->prev; \ } \ \ static inline void prefix##_list_swap(type **list, type *item1, type *item2) \ { \ if(!item1 || !item2) return; \ \ type *i1n = item1->next; \ type *i2n = item2->next; \ type *i1p = item1->prev; \ type *i2p = item2->prev; \ \ if(item1 == i2n) \ { \ item1->next = item2; \ item2->prev = item1; \ if((item1->prev = i2p)) \ i2p->next = item1; \ if((item2->next = i1n)) \ i1n->prev = item2; \ } \ else if(item2 == i1n) \ { \ item2->next = item1; \ item1->prev = item2; \ if((item2->prev = i1p)) \ i1p->next = item2; \ if((item1->next = i2n)) \ i2n->prev = item1; \ } \ else \ { \ if((item1->next = i2n)) \ item1->next->prev = item1; \ if((item1->prev = i2p)) \ item1->prev->next = item1; \ if((item2->prev = i1p)) \ item2->prev->next = item2; \ if((item2->next = i1n)) \ item2->next->prev = item2; \ } \ if(*list == item1) \ *list = item2; \ else if(*list == item2) \ *list = item1; \ } \ \ static inline type *prefix##_list_prev_cycle(type **list, type *item) \ { \ if(!item->prev) \ return *prefix##_list_last(list); \ return item->prev; \ } \ \ static inline type *prefix##_list_next_cycle(type **list, type *item) \ { \ if(item->next) \ return item->next; \ return *list; \ } \ \ static inline type *prefix##_list_detach(type **list, type *item) \ { \ if(item == *list) \ *list = item->next; \ else if(item->prev) \ item->prev->next = item->next; \ if(item->next) \ item->next->prev = item->prev; \ item->next = NULL; \ item->prev = NULL; \ return item; \ } \ static inline type *prefix##_list_attach_after(type *item1, type *item2) \ { \ item2->prev = item1; \ item2->next = item1->next; \ if(item1->next) \ item1->next->prev = item2; \ item1->next = item2; \ return item2; \ } #define DO_SLIST_UNREF(type, prefix, dtor) \ static inline void prefix##_list_unref(type **list) \ { \ type *next, *item = *list; \ while(item) \ { \ next = item->next; \ if(--(item->refcount) <= 0) \ { \ prefix##_list_detach(list, item); \ dtor(&item); \ } \ item = next; \ } \ } #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80