|
|
@@ -0,0 +1,193 @@
|
|
|
+#ifndef LINKLIST_H_INCLUDED
|
|
|
+#define LINKLIST_H_INCLUDED
|
|
|
+
|
|
|
+#include "inline.h"
|
|
|
+
|
|
|
+struct list_head {
|
|
|
+/*----------------------------------------------------------------------------
|
|
|
+ This is a header for an element of a doubly linked list, or an anchor
|
|
|
+ for such a list.
|
|
|
+
|
|
|
+ itemP == NULL means it's an anchor; otherwise it's a header.
|
|
|
+
|
|
|
+ Initialize a list header with list_init_header(). You don't have to
|
|
|
+ do anything to terminate a list header.
|
|
|
+
|
|
|
+ Initialize an anchor with list_make_emtpy(). You don't have to do anything
|
|
|
+ to terminate a list header.
|
|
|
+-----------------------------------------------------------------------------*/
|
|
|
+ struct list_head * nextP;
|
|
|
+ /* For a header, this is the address of the list header for
|
|
|
+ the next element in the list. If there is no next element,
|
|
|
+ it points to the anchor. If the header is not in a list at
|
|
|
+ all, it is NULL.
|
|
|
+
|
|
|
+ For an anchor, it is the address of the list header of the
|
|
|
+ first element. If the list is empty, it points to the
|
|
|
+ anchor itself.
|
|
|
+ */
|
|
|
+ struct list_head * prevP;
|
|
|
+ /* For a header, this is the address of the list header for
|
|
|
+ the previous element in the list. If there is no previous element,
|
|
|
+ it points to the anchor. If the header is not in a list at
|
|
|
+ all, it is NULL.
|
|
|
+
|
|
|
+ For an anchor, it is the address of the list header of the
|
|
|
+ last element. If the list is empty, it points to the
|
|
|
+ anchor itself.
|
|
|
+ */
|
|
|
+ void * itemP;
|
|
|
+ /* For a header, this is the address of the list element to which it
|
|
|
+ belongs. For an anchor, this is NULL.
|
|
|
+ */
|
|
|
+};
|
|
|
+
|
|
|
+static __inline__ void
|
|
|
+list_init_header(struct list_head * const headerP,
|
|
|
+ void * const itemP) {
|
|
|
+
|
|
|
+ headerP->prevP = NULL;
|
|
|
+ headerP->nextP = NULL;
|
|
|
+ headerP->itemP = itemP;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ int
|
|
|
+list_is_linked(struct list_head * headerP) {
|
|
|
+ return headerP->prevP != NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ int
|
|
|
+list_is_empty(struct list_head * const anchorP) {
|
|
|
+ return anchorP->nextP == anchorP;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ unsigned int
|
|
|
+list_count(struct list_head * const anchorP) {
|
|
|
+ unsigned int count;
|
|
|
+
|
|
|
+ struct list_head * p;
|
|
|
+
|
|
|
+ for (p = anchorP->nextP, count = 0;
|
|
|
+ p != anchorP;
|
|
|
+ p = p->nextP, ++count);
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ void
|
|
|
+list_make_empty(struct list_head * const anchorP) {
|
|
|
+ anchorP->prevP = anchorP;
|
|
|
+ anchorP->nextP = anchorP;
|
|
|
+ anchorP->itemP = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static __inline__ void
|
|
|
+list_insert_after(struct list_head * const beforeHeaderP,
|
|
|
+ struct list_head * const newHeaderP) {
|
|
|
+ newHeaderP->prevP = beforeHeaderP;
|
|
|
+ newHeaderP->nextP = beforeHeaderP->nextP;
|
|
|
+
|
|
|
+ beforeHeaderP->nextP = newHeaderP;
|
|
|
+ newHeaderP->nextP->prevP = newHeaderP;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ void
|
|
|
+list_add_tail(struct list_head * const anchorP,
|
|
|
+ struct list_head * const headerP) {
|
|
|
+ list_insert_after(anchorP->prevP, headerP);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ void
|
|
|
+list_add_head(struct list_head * const anchorP,
|
|
|
+ struct list_head * const headerP) {
|
|
|
+ list_insert_after(anchorP, headerP);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ void
|
|
|
+list_remove(struct list_head * const headerP) {
|
|
|
+ headerP->prevP->nextP = headerP->nextP;
|
|
|
+ headerP->nextP->prevP = headerP->prevP;
|
|
|
+ headerP->prevP = NULL;
|
|
|
+ headerP->nextP = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ struct list_head *
|
|
|
+list_remove_head(struct list_head * const anchorP) {
|
|
|
+ struct list_head * retval;
|
|
|
+
|
|
|
+ if (list_is_empty(anchorP))
|
|
|
+ retval = NULL;
|
|
|
+ else {
|
|
|
+ retval = anchorP->nextP;
|
|
|
+ list_remove(retval);
|
|
|
+ }
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ struct list_head *
|
|
|
+list_remove_tail(struct list_head * const anchorP) {
|
|
|
+ struct list_head * retval;
|
|
|
+
|
|
|
+ if (list_is_empty(anchorP))
|
|
|
+ retval = NULL;
|
|
|
+ else {
|
|
|
+ retval = anchorP->prevP;
|
|
|
+ list_remove(retval);
|
|
|
+ }
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ void *
|
|
|
+list_foreach(struct list_head * const anchorP,
|
|
|
+ void * functionP(struct list_head *, void *),
|
|
|
+ void * const context) {
|
|
|
+
|
|
|
+ struct list_head * p;
|
|
|
+ struct list_head * nextP;
|
|
|
+ void * result;
|
|
|
+
|
|
|
+ for (p = anchorP->nextP, nextP = p->nextP, result=NULL;
|
|
|
+ p != anchorP && result == NULL;
|
|
|
+ p = nextP, nextP = p->nextP)
|
|
|
+ result = (*functionP)(p, context);
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static __inline__ void
|
|
|
+list_append(struct list_head * const newAnchorP,
|
|
|
+ struct list_head * const baseAnchorP) {
|
|
|
+
|
|
|
+ if (!list_is_empty(newAnchorP)) {
|
|
|
+ baseAnchorP->prevP->nextP = newAnchorP->nextP;
|
|
|
+ newAnchorP->nextP->prevP = baseAnchorP->prevP;
|
|
|
+ newAnchorP->prevP->nextP = baseAnchorP;
|
|
|
+ baseAnchorP->prevP = newAnchorP->prevP;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+
|