summaryrefslogtreecommitdiffstats
path: root/include/linux/dlists.h
blob: f92485e40e464178aa7193674a95d4d156a0c972 (plain)
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
#ifndef DLISTS_H
#define DLISTS_H
/*
 * include/linux/dlists.h - macros for double linked lists
 *
 * Copyright (C) 1997, Thomas Schoebel-Theuer,
 * <schoebel@informatik.uni-stuttgart.de>.
 */

/* dlists are cyclic ringlists, so the last element cannot be tested
 * for NULL. Use the following construct for traversing cyclic lists:
 * ptr = anchor;
 * if(ptr) do {
 *      ...
 *      ptr = ptr->{something}_{next,prev};
 * } while(ptr != anchor);
 * The effort here is paid off with much simpler inserts/removes.
 * Examples for usage of these macros can be found in fs/ninode.c.
 * To access the last element in constant time, simply use
 * anchor->{something}_prev.
 */

#define DEF_GENERIC_INSERT(CHANGE,PREFIX,NAME,TYPE,NEXT,PREV) \
static inline void PREFIX##NAME(TYPE ** anchor, TYPE * elem)\
{\
	TYPE * oldfirst = *anchor;\
	if(!oldfirst) {\
		elem->NEXT = elem->PREV = *anchor = elem;\
	} else {\
		elem->PREV = oldfirst->PREV;\
		elem->NEXT = oldfirst;\
		oldfirst->PREV->NEXT = elem;\
		oldfirst->PREV = elem;\
		if(CHANGE)\
			*anchor = elem;\
	}\
}

/* insert_* is always at the first position */
#define DEF_INSERT(NAME,TYPE,NEXT,PREV) \
                   DEF_GENERIC_INSERT(1,insert_,NAME,TYPE,NEXT,PREV)

/* append_* is always at the tail  */
#define DEF_APPEND(NAME,TYPE,NEXT,PREV) \
                   DEF_GENERIC_INSERT(0,append_,NAME,TYPE,NEXT,PREV)

/* use this to insert _before_ oldelem somewhere in the middle of the list.
 * the list must not be empty, and oldelem must be already a member.*/
#define DEF_INSERT_MIDDLE(NAME,TYPE) \
static inline void insert_middle_##NAME(TYPE ** anchor, TYPE * oldelem, TYPE * elem)\
{\
	int status = (oldelem == *anchor);\
	insert_##NAME(&oldelem, elem);\
	if(status)\
		*anchor = oldelem;\
}

/* remove can be done with any element in the list */
#define DEF_REMOVE(NAME,TYPE,NEXT,PREV) \
static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
{\
	TYPE * next = elem->NEXT;\
	if(next == elem) {\
		*anchor = NULL;\
	} else {\
		TYPE * prev = elem->PREV;\
		prev->NEXT = next;\
		next->PREV = prev;\
		elem->NEXT = elem->PREV = NULL;/*leave this during debugging*/\
		if(*anchor == elem)\
			*anchor = next;\
	}\
}


/* According to ideas from David S. Miller, here is a slightly
 * more efficient plug-in compatible version using non-cyclic lists,
 * but allowing neither backward traversals nor constant time access
 * to the last element.
 * Note that although the interface is the same, the PPREV pointer must be
 * declared doubly indirect and the test for end-of-list is different. */

/* as above, this inserts always at the head */
#define DEF_LIN_INSERT(NAME,TYPE,NEXT,PPREV) \
static inline void insert_##NAME(TYPE ** anchor, TYPE * elem)\
{\
	TYPE * first;\
	if((elem->NEXT = first = *anchor))\
		first->PPREV = &elem->NEXT;\
	*anchor = elem;\
	elem->PPREV = anchor;\
}

/* as above, this works with any list element */
#define DEF_LIN_REMOVE(NAME,TYPE,NEXT,PPREV) \
static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
{\
	TYPE * pprev;\
	if((pprev = elem->PPREV)) {\
		TYPE * next;\
		if((next = elem->NEXT))\
			next->PPREV = pprev;\
		*pprev = next;\
		elem->PPREV = elem->NEXT = NULL; /*leave this for debugging*/\
	}\
}

#endif