Added silc_list_pop
[runtime.git] / lib / silcutil / silclist.h
index 50213491f0b361239d015a5cd08606752499b777..52454c30d7f1dd2b2ec1ab575d6d46a7b7520a2e 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 - 2005 Pekka Riikonen
+  Copyright (C) 2002 - 2008 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
 
 */
 
-/****h* silcutil/SILC List Interface
+/****h* silcutil/List Interface
  *
  * 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);
  *
  ***/
 
 #ifndef SILCLIST_H
 #define SILCLIST_H
 
-/****s* silcutil/SilcList/SilcList
+/****s* silcutil/SilcList
  *
  * NAME
  *
  *    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 */
 } SilcList;
 
-/****d* silcutil/SilcList/SILC_LIST_END
+/****d* silcutil/SILC_LIST_END
  *
  * NAME
  *
- *    #define SILC_LIST_END ...
+ *    #define SILC_LIST_END NULL
  *
  * DESCRIPTION
  *
@@ -68,7 +84,7 @@ typedef struct {
 #define SILC_LIST_END NULL
 /***/
 
-/****f* silcutil/SilcList/silc_list_init
+/****f* silcutil/silc_list_init
  *
  * SYNOPSIS
  *
@@ -101,10 +117,11 @@ 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)
 
-/****f* silcutil/SilcList/silc_list_init_prev
+/****f* silcutil/silc_list_init_prev
  *
  * SYNOPSIS
  *
@@ -140,14 +157,15 @@ 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)
 
-/****f* silcutil/SilcList/silc_list_count
+/****f* silcutil/silc_list_count
  *
  * SYNOPSIS
  *
- *    #define silc_list_count(list) ...
+ *    SilcUInt32 silc_list_count(SilcList list);
  *
  * DESCRIPTION
  *
@@ -156,11 +174,11 @@ do {                                                              \
  ***/
 #define silc_list_count(list) (list).count
 
-/****f* silcutil/SilcList/silc_list_start
+/****f* silcutil/silc_list_start
  *
  * SYNOPSIS
  *
- *    #define silc_list_start(list) ...
+ *    void silc_list_start(SilcList list);
  *
  * DESCRIPTION
  *
@@ -171,11 +189,11 @@ do {                                                              \
 #define silc_list_start(list)                          \
   ((list).current = (list).head, (list).end_set = 0)
 
-/****f* silcutil/SilcList/silc_list_end
+/****f* silcutil/silc_list_end
  *
  * SYNOPSIS
  *
- *    #define silc_list_end(list) ...
+ *    void silc_list_end(SilcList list);
  *
  * DESCRIPTION
  *
@@ -197,11 +215,11 @@ do {                                                              \
 #define __silc_list_prev(list, pos)                            \
   ((void **)((unsigned char *)(pos) + (list).prev_offset))
 
-/****f* silcutil/SilcList/silc_list_add
+/****f* silcutil/silc_list_add
  *
  * SYNOPSIS
  *
- *    #define silc_list_add(list, entry) ...
+ *    void silc_list_add(SilcList list, void *entry);
  *
  * DESCRIPTION
  *
@@ -222,11 +240,11 @@ do {                                                      \
   (list).count++;                                      \
 } while(0)
 
-/****f* silcutil/SilcList/silc_list_insert
+/****f* silcutil/silc_list_insert
  *
  * SYNOPSIS
  *
- *    #define silc_list_insert(list, current, entry) ...
+ *    void silc_list_insert(SilcList list, void *current, void *entry);
  *
  * DESCRIPTION
  *
@@ -264,11 +282,11 @@ do {                                                                       \
   (list).count++;                                                       \
 } while(0)
 
-/****f* silcutil/SilcList/silc_list_del
+/****f* silcutil/silc_list_del
  *
  * SYNOPSIS
  *
- *    #define silc_list_del(list, entry) ...
+ *    void silc_list_del(SilcListlist, void *entry);
  *
  * DESCRIPTION
  *
@@ -282,7 +300,7 @@ do {                                                                        \
   for (p = &(list).head; *p; p = __silc_list_next(list, *p)) {         \
     if (*p == (entry)) {                                               \
       *p = *__silc_list_next(list, entry);                             \
-      if (*p && (list).prev_set)                                       \
+      if ((list).prev_set && *p)                                       \
         *__silc_list_prev(list, *p) = *__silc_list_prev(list, entry);  \
       if ((list).current == (entry))                                   \
         (list).current = *p;                                           \
@@ -295,11 +313,11 @@ do {                                                                      \
     (list).tail = prev;                                                        \
 } while(0)
 
-/****f* silcutil/SilcList/silc_list_get
+/****f* silcutil/silc_list_get
  *
  * SYNOPSIS
  *
- *    #define silc_list_get(list) ...
+ *    void *silc_list_get(SilcList list);
  *
  * DESCRIPTION
  *
@@ -337,4 +355,43 @@ void *__silc_list_get(SilcList *list)
   return pos;
 }
 
-#endif
+/****f* silcutil/silc_list_pop
+ *
+ * SYNOPSIS
+ *
+ *    void *silc_list_pop(SilcList list);
+ *
+ * DESCRIPTION
+ *
+ *    Pops the head of the list.  Removes the head of the list and returns
+ *    the removed head.  This will always remove the head of the list even
+ *    if silc_list_end was called.  Calling silc_list_start is not necessary.
+ *    Returns SILC_LIST_END if the list is empty.
+ *
+ ***/
+#define silc_list_pop(x) __silc_list_pop(&(x))
+static inline
+void *__silc_list_pop(SilcList *list)
+{
+  void *head, **p;
+
+  if (!list->head)
+    return NULL;
+
+  head = list->head;
+  p = &list->head;
+  *p = *__silc_list_next(*list, head);
+  if (list->prev_set && *p)
+    *__silc_list_prev(*list, *p) = *__silc_list_prev(*list, head);
+
+  if (list->current == head)
+    list->current = *p;
+  if (head == list->tail)
+    list->tail = NULL;
+
+  list->count--;
+
+  return head;
+}
+
+#endif /* SILCLIST_H */