You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
6.3 KiB

/***
* Copyright 2009-2017 by Gabriel Parmer. All rights reserved.
* Redistribution of this file is permitted under the BSD 2 clause license.
* Author: Gabriel Parmer, gparmer@gwu.edu, 2017
*
* History:
* - Initial implementation, ~2009
* - Adapted for parsec and relicensed, 2016
*/
/*
* API Conventions:
* - obj, new, and tmp are pointers of type T where T is the struct containing the linked list
* - head is a pointer to struct ps_list_head
* - l is the list field name within T
* - type is T without any ()
* - all ps_list_head_* functions should be applied to struct ps_list_head pointers
* - all ps_list_* functions should be passed items of type T, not struct ps_list_head
* - as with most macro-based APIs, please avoid passing in functions that cannot be multiply evaluated;
* generally passing only variables is a good move
*
* Example Usage:
*
* struct ps_list_head h;
* struct foo {
* struct ps_list l;
* void *d;
* } node, *i, *tmp;
*
* ps_list_head_init(&h);
* ps_list_init(&node);
* ps_list_head_add(&h, &node, l);
* ...
* for (i = ps_list_head_first(&h, struct foo, l) ;
* i != ps_list_head(&h, struct foo, l) ;
* i = ps_list_next(i, l)) { ... }
*
* for (ps_list_iter_init(&h, i, l) ; !ps_list_iter_term(&h, i, l) ; i = ps_list_next(i, l)) { ... }
*
* ps_list_foreach(&h, i, l) { ... }
*
* ps_list_foreach_del(&h, i, tmp, l) {
* ps_list_rem(i, l);
* ps_free(i);
* }
*
*/
#ifndef PS_LIST_H
#define PS_LIST_H
struct ps_list {
struct ps_list *n, *p;
};
/*
* This is a separate type to 1) provide guidance on how to use the
* API, and 2) to prevent developers from comparing pointers that
* should not be compared.
*/
struct ps_list_head {
struct ps_list l;
};
#define PS_LIST_DEF_NAME list
static inline void
ps_list_ll_init(struct ps_list *l)
{ l->n = l->p = l; }
static inline void
ps_list_head_init(struct ps_list_head *lh)
{ ps_list_ll_init(&lh->l); }
static inline int
ps_list_ll_empty(struct ps_list *l)
{ return l->n == l; }
static inline int
ps_list_head_empty(struct ps_list_head *lh)
{ return ps_list_ll_empty(&lh->l); }
static inline void
ps_list_ll_add(struct ps_list *l, struct ps_list *new)
{
new->n = l->n;
new->p = l;
l->n = new;
new->n->p = new;
}
static inline void
ps_list_ll_rem(struct ps_list *l)
{
l->n->p = l->p;
l->p->n = l->n;
l->p = l->n = l;
}
#define ps_offsetof(s, field) __builtin_offsetof(s, field)
//#define ps_offsetof(s, field) ((unsigned long)&(((s *)0)->field))
#define ps_container(intern, type, field) \
((type *)((char *)(intern) - ps_offsetof(type, field)))
/*
* Get a pointer to the object containing *l, of a type shared with
* *o. Importantly, "o" is not accessed here, and is _only_ used for
* its type. It will typically be the iterator/cursor working through
* a list. Do _not_ use this function. It is a utility used by the
* following functions.
*/
#define ps_list_obj_get(l, o, lname) \
ps_container(l, __typeof__(*(o)), lname)
//(typeof (*(o)) *)(((char*)(l)) - ps_offsetof(typeof(*(o)), lname))
/***
* The object API. These functions are called with pointers to your
* own (typed) structures.
*/
#define ps_list_is_head(lh, o, lname) (ps_list_obj_get((lh), (o), lname) == (o))
/* functions for if we don't use the default name for the list field */
#define ps_list_singleton(o, lname) ps_list_ll_empty(&(o)->lname)
#define ps_list_init(o, lname) ps_list_ll_init(&(o)->lname)
#define ps_list_next(o, lname) ps_list_obj_get((o)->lname.n, (o), lname)
#define ps_list_prev(o, lname) ps_list_obj_get((o)->lname.p, (o), lname)
#define ps_list_add(o, n, lname) ps_list_ll_add(&(o)->lname, &(n)->lname)
#define ps_list_append(o, n, lname) ps_list_add(ps_list_prev((o), lname), n, lname)
#define ps_list_rem(o, lname) ps_list_ll_rem(&(o)->lname)
#define ps_list_head_add(lh, o, lname) ps_list_ll_add((&(lh)->l), &(o)->lname)
#define ps_list_head_append(lh, o, lname) ps_list_ll_add(((&(lh)->l)->p), &(o)->lname)
/**
* Explicit type API: Pass in the types of the nodes in the list, and
* the name of the ps_list field in that type.
*/
#define ps_list_head_first(lh, type, lname) \
ps_container(((lh)->l.n), type, lname)
#define ps_list_head_last(lh, type, lname) \
ps_container(((lh)->l.p), type, lname)
/* If your struct named the list field "list" (as defined by PS_LIST_DEF_NAME */
#define ps_list_is_head_d(lh, o) ps_list_is_head(lh, o, PS_LIST_DEF_NAME)
#define ps_list_singleton_d(o) ps_list_singleton(o, PS_LIST_DEF_NAME)
#define ps_list_init_d(o) ps_list_init(o, PS_LIST_DEF_NAME)
#define ps_list_next_d(o) ps_list_next(o, PS_LIST_DEF_NAME)
#define ps_list_prev_d(o) ps_list_prev(o, PS_LIST_DEF_NAME)
#define ps_list_add_d(o, n) ps_list_add(o, n, PS_LIST_DEF_NAME)
#define ps_list_append_d(o, n) ps_list_append(o, n, PS_LIST_DEF_NAME)
#define ps_list_rem_d(o) ps_list_rem(o, PS_LIST_DEF_NAME)
#define ps_list_head_last_d(lh, o) ps_list_head_last(lh, o, PS_LIST_DEF_NAME)
#define ps_list_head_first_d(lh, type) ps_list_head_first(lh, type, PS_LIST_DEF_NAME)
#define ps_list_head_add_d(lh, o) ps_list_head_add(lh, o, PS_LIST_DEF_NAME)
#define ps_list_head_append_d(lh, o) ps_list_head_append(lh, o, PS_LIST_DEF_NAME)
/**
* Iteration API
*/
/* Iteration without mutating the list */
#define ps_list_foreach(head, iter, lname) \
for (iter = ps_list_head_first((head), __typeof__(*iter), lname) ; \
!ps_list_is_head((head), iter, lname) ; \
(iter) = ps_list_next(iter, lname))
#define ps_list_foreach_d(head, iter) ps_list_foreach(head, iter, PS_LIST_DEF_NAME)
/*
* Iteration where the current node can be ps_list_rem'ed.
* Notes:
* - typeof(iter) == typeof(tmp)
* - ps_list_add can be used on iter, but the added node will not be iterated over
*
* TODO: Add SMR/parallel version of this macro
*/
#define ps_list_foreach_del(head, iter, tmp, lname) \
for (iter = ps_list_head_first((head), __typeof__(*iter), lname), \
(tmp) = ps_list_next((iter), lname) ; \
!ps_list_is_head((head), iter, lname) ; \
(iter) = (tmp), (tmp) = ps_list_next((tmp), lname))
#define ps_list_foreach_del_d(head, iter, tmp) ps_list_foreach_del(head, iter, tmp, PS_LIST_DEF_NAME)
#endif /* PS_LIST_H */