Added SILC Thread Queue API
[silc.git] / lib / silcutil / silclist.h
index 60e1bcc4f31e3ef32b44564ad5ebca45a77a62b8..66efd22fa7dd8667df1280a8ccff30a06e0464bc 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silclist.h 
+  silclist.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 - 2003 Pekka Riikonen
+  Copyright (C) 2002 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
  *
  * DESCRIPTION
  *
- * Implementation of the SilcList interface.  This interface provides
- * simple linked list.
+ * Generic list interface that can turn any structure with list pointers
+ * into a SilcList.  The interface can provide both singly and doubly linked
+ * lists.  The interface does not allocate any memory.
+ *
+ * SILC List is not thread-safe.  If the same list context must be used
+ * in multithreaded environment concurrency control must be employed.
+ *
+ * EXAMPLE
+ *
+ * struct EntryStruct {
+ *   char *dummy;
+ *   struct EntryStruct *next;        // The list member pointer
+ * };
+ *
+ * SilcList list;
+ *
+ * // Initialize list
+ * silc_list_init(list, struct EntryStruct, next);
  *
  ***/
 
@@ -32,7 +48,7 @@
 /****s* silcutil/SilcList/SilcList
  *
  * NAME
- * 
+ *
  *    typedef struct { ... } SilcList;
  *
  * DESCRIPTION
  *    function silc_list_init.
  *
  ***/
-typedef struct {
+typedef struct SilcListStruct {
   void *head;                       /* Start of the list */
   void *tail;                       /* End of the list */
   void *current;                    /* Current pointer in list */
-  unsigned int next_offset : 16;     /* Offset to 'next' pointer */
-  unsigned int prev_offset : 16;     /* Offset to 'prev' pointer */
+  SilcUInt16 next_offset;           /* Offset to 'next' pointer */
+  SilcUInt16 prev_offset;           /* Offset to 'prev' pointer */
   unsigned int prev_set    : 1;             /* Set if 'prev' exists */
   unsigned int end_set     : 1;             /* Set if silc_list_end was called */
   unsigned int count       : 30;     /* Number of entries in the list */
@@ -55,7 +71,7 @@ typedef struct {
 /****d* silcutil/SilcList/SILC_LIST_END
  *
  * NAME
- * 
+ *
  *    #define SILC_LIST_END ...
  *
  * DESCRIPTION
@@ -101,6 +117,7 @@ do {                                                        \
   (list).next_offset = silc_offsetof(type, nextfield); \
   (list).prev_set = 0;                                 \
   (list).prev_offset = 0;                              \
+  (list).end_set = 0;                                  \
   (list).head = (list).tail = (list).current = NULL;   \
 } while(0)
 
@@ -131,7 +148,7 @@ do {                                                        \
  *    };
  *
  *    SilcList list;
- *    silc_list_init(list, struct SilcInternalEntryStruct, next, prev);
+ *    silc_list_init_prev(list, struct SilcInternalEntryStruct, next, prev);
  *
  ***/
 #define silc_list_init_prev(list, type, nextfield, prevfield)  \
@@ -140,6 +157,7 @@ do {                                                                \
   (list).next_offset = silc_offsetof(type, nextfield);         \
   (list).prev_offset = silc_offsetof(type, prevfield);         \
   (list).prev_set = 1;                                         \
+  (list).end_set = 0;                                          \
   (list).head = (list).tail = (list).current = NULL;           \
 } while(0)
 
@@ -205,7 +223,7 @@ do {                                                                \
  *
  * DESCRIPTION
  *
- *    Adds new entry indicated by `entry' to the end of the list indicated 
+ *    Adds new entry indicated by `entry' to the end of the list indicated
  *    by `list'.
  *
  ***/
@@ -222,6 +240,48 @@ do {                                                       \
   (list).count++;                                      \
 } while(0)
 
+/****f* silcutil/SilcList/silc_list_insert
+ *
+ * SYNOPSIS
+ *
+ *    #define silc_list_insert(list, current, entry) ...
+ *
+ * DESCRIPTION
+ *
+ *    Insert new entry indicated by `entry' after the entry `current'
+ *    to the list indicated by `list'.  If `current' is NULL, then the
+ *    `entry' is added at the head of the list.  Use the silc_list_add
+ *    to add at the end of the list.
+ *
+ ***/
+#define silc_list_insert(list, current, entry)                          \
+do {                                                                    \
+  if (!(current)) {                                                     \
+    if ((list).head)                                                    \
+      *__silc_list_next(list, entry) = (list).head;                     \
+    else                                                                \
+      *__silc_list_next(list, entry) = NULL;                            \
+    if ((list).prev_set && (list).head)                                         \
+      *__silc_list_prev(list, (list).head) = entry;                     \
+    if (!(list).tail)                                                   \
+      (list).tail = (entry);                                            \
+    (list).head = (entry);                                              \
+    if ((list).prev_set)                                                \
+      *__silc_list_prev(list, entry) = NULL;                            \
+  } else {                                                              \
+    *__silc_list_next(list, entry) = *__silc_list_next(list, current);  \
+    *__silc_list_next(list, current) = entry;                           \
+    if ((list).prev_set) {                                              \
+      *__silc_list_prev(list, entry) = current;                                 \
+      if (*__silc_list_next(list, entry))                               \
+        *__silc_list_prev(list, *__silc_list_next(list, entry)) = entry; \
+    }                                                                   \
+    if ((list).tail == (current))                                       \
+      (list).tail = (entry);                                            \
+  }                                                                     \
+  (list).count++;                                                       \
+} while(0)
+
 /****f* silcutil/SilcList/silc_list_del
  *
  * SYNOPSIS
@@ -271,7 +331,7 @@ do {                                                                        \
  *
  * EXAMPLE
  *
- *    // Traverse the list from the beginning to the end 
+ *    // Traverse the list from the beginning to the end
  *    silc_list_start(list);
  *    while ((entry = silc_list_get(list)) != SILC_LIST_END) {
  *      ...