-
Notifications
You must be signed in to change notification settings - Fork 14
/
ps_list.h
189 lines (161 loc) · 6.31 KB
/
ps_list.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/***
* Copyright 2009-2017 by Gabriel Parmer. All rights reserved.
* Redistribution of this file is permitted under the BSD 2 clause license.
* Author: Gabriel Parmer, [email protected], 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 */