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
|