summaryrefslogtreecommitdiff
path: root/pfinet/linux-src/include/linux/dlists.h
diff options
context:
space:
mode:
Diffstat (limited to 'pfinet/linux-src/include/linux/dlists.h')
-rw-r--r--pfinet/linux-src/include/linux/dlists.h108
1 files changed, 108 insertions, 0 deletions
diff --git a/pfinet/linux-src/include/linux/dlists.h b/pfinet/linux-src/include/linux/dlists.h
new file mode 100644
index 00000000..f92485e4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/dlists.h
@@ -0,0 +1,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