blob: 360429f4873755e758018a6915a591aaa6338e84 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#ifndef _LISTHELP_H
2#define _LISTHELP_H
3#include <linux/config.h>
4#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005
6/* Header to do more comprehensive job than linux/list.h; assume list
7 is first entry in structure. */
8
9/* Return pointer to first true entry, if any, or NULL. A macro
10 required to allow inlining of cmpfn. */
11#define LIST_FIND(head, cmpfn, type, args...) \
12({ \
13 const struct list_head *__i, *__j = NULL; \
14 \
15 ASSERT_READ_LOCK(head); \
16 list_for_each(__i, (head)) \
17 if (cmpfn((const type)__i , ## args)) { \
18 __j = __i; \
19 break; \
20 } \
21 (type)__j; \
22})
23
24#define LIST_FIND_W(head, cmpfn, type, args...) \
25({ \
26 const struct list_head *__i, *__j = NULL; \
27 \
28 ASSERT_WRITE_LOCK(head); \
29 list_for_each(__i, (head)) \
30 if (cmpfn((type)__i , ## args)) { \
31 __j = __i; \
32 break; \
33 } \
34 (type)__j; \
35})
36
37/* Just like LIST_FIND but we search backwards */
38#define LIST_FIND_B(head, cmpfn, type, args...) \
39({ \
40 const struct list_head *__i, *__j = NULL; \
41 \
42 ASSERT_READ_LOCK(head); \
43 list_for_each_prev(__i, (head)) \
44 if (cmpfn((const type)__i , ## args)) { \
45 __j = __i; \
46 break; \
47 } \
48 (type)__j; \
49})
50
51static inline int
52__list_cmp_same(const void *p1, const void *p2) { return p1 == p2; }
53
54/* Is this entry in the list? */
55static inline int
56list_inlist(struct list_head *head, const void *entry)
57{
58 return LIST_FIND(head, __list_cmp_same, void *, entry) != NULL;
59}
60
61/* Delete from list. */
62#ifdef CONFIG_NETFILTER_DEBUG
63#define LIST_DELETE(head, oldentry) \
64do { \
65 ASSERT_WRITE_LOCK(head); \
66 if (!list_inlist(head, oldentry)) \
67 printk("LIST_DELETE: %s:%u `%s'(%p) not in %s.\n", \
68 __FILE__, __LINE__, #oldentry, oldentry, #head); \
69 else list_del((struct list_head *)oldentry); \
70} while(0)
71#else
72#define LIST_DELETE(head, oldentry) list_del((struct list_head *)oldentry)
73#endif
74
75/* Append. */
76static inline void
77list_append(struct list_head *head, void *new)
78{
79 ASSERT_WRITE_LOCK(head);
80 list_add((new), (head)->prev);
81}
82
83/* Prepend. */
84static inline void
85list_prepend(struct list_head *head, void *new)
86{
87 ASSERT_WRITE_LOCK(head);
88 list_add(new, head);
89}
90
91/* Insert according to ordering function; insert before first true. */
92#define LIST_INSERT(head, new, cmpfn) \
93do { \
94 struct list_head *__i; \
95 ASSERT_WRITE_LOCK(head); \
96 list_for_each(__i, (head)) \
97 if ((new), (typeof (new))__i) \
98 break; \
99 list_add((struct list_head *)(new), __i->prev); \
100} while(0)
101
102/* If the field after the list_head is a nul-terminated string, you
103 can use these functions. */
104static inline int __list_cmp_name(const void *i, const char *name)
105{
106 return strcmp(name, i+sizeof(struct list_head)) == 0;
107}
108
109/* Returns false if same name already in list, otherwise does insert. */
110static inline int
111list_named_insert(struct list_head *head, void *new)
112{
113 if (LIST_FIND(head, __list_cmp_name, void *,
114 new + sizeof(struct list_head)))
115 return 0;
116 list_prepend(head, new);
117 return 1;
118}
119
120/* Find this named element in the list. */
121#define list_named_find(head, name) \
122LIST_FIND(head, __list_cmp_name, void *, name)
123
124#endif /*_LISTHELP_H*/