76dcf69239ed1f92e490336ab2a05225671a2be6
[silc.git] / lib / silcutil / silclist.h
1 /*
2
3   silclist.h
4
5   Author: Timo Sirainen <tss@iki.fi>
6
7   Copyright (C) 2002 Timo Sirainen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20
21 /****h* silcutil/SILC List Interface
22  *
23  * DESCRIPTION
24  *
25  * Implementation of the SilcList interface.  This interface provides
26  * simple linked list.
27  *
28  ***/
29
30 #ifndef SILCLIST_H
31 #define SILCLIST_H
32
33 /****s* silcutil/SilcList/SilcList
34  *
35  * NAME
36  * 
37  *    typedef struct { ... } SilcList;
38  *
39  * DESCRIPTION
40  *
41  *    This is the SilcList context, and is initialized by calling the
42  *    function silc_list_init.
43  *
44  * EXAMPLE
45  *
46  *     SilcList list;
47  *     silc_list_init(list, struct SilcInternalEntryStruct, next);
48  *
49  ***/
50 typedef struct {
51   void *head, *tail;
52   void *current;
53   int offset;
54 } SilcList;
55
56 /****d* silcutil/SilcList/SILC_LIST_END
57  *
58  * NAME
59  * 
60  *    #define SILC_LIST_END ...
61  *
62  * DESCRIPTION
63  *
64  *    Functions return this when the list is invalid or when traversing
65  *    the list there is no more entires in the list.
66  *
67  * SOURCE
68  */
69 #define SILC_LIST_END NULL
70 /***/
71
72 /* Initializes SilcList object. Example:
73
74    SilcList list;
75
76    silc_list_init(list, struct SilcInternalEntryStruct, next);
77
78    Where `list' is the defined list, and second argument is the structure
79    of the entries in the list and last argument is the pointer in the entry
80    structure that is used as list member. SilcInternalEntry might be as 
81    follows:
82
83    struct SilcInternalEntryStruct {
84      char *dummy;
85      struct SilcInternalEntryStruct *next; // The list member pointer
86    };
87
88    The `next' pointer in the structure (or some other pointer for that matter)
89    is given for the silc_list_init as the last argument. This pointer is used
90    by the list routines to link the entries together in the list. Your code
91    should not touch the member pointer manually.
92 */
93
94 /****f* silcutil/SilcList/silc_list_init
95  *
96  * SYNOPSIS
97  *
98  *    #define silc_list_init(list, type, field) ...
99  *
100  * DESCRIPTION
101  *
102  *    This macro initializes the SilcList list.  The `list' is the defined
103  *    list, second argument is the structure of the entries in the list,
104  *    and last argument is the pointer in the entry structure that is used
105  *    as list member.  When using SilcList, you should not touch the
106  *    structure member pointer (the `next' for example) manually.
107  *
108  * EXAMPLE
109  *
110  *    struct SilcInternalEntryStruct {
111  *      char *dummy;
112  *      struct SilcInternalEntryStruct *next; // The list member pointer
113  *    };
114  *
115  *    SilcList list;
116  *    silc_list_init(list, struct SilcInternalEntryStruct, next);
117  *
118  ***/
119 #define silc_list_init(list, type, field) \
120   __silc_list_init(&(list), silc_offsetof(type, field))
121
122 static inline void __silc_list_init(SilcList *list, int offset)
123 {
124   list->head = list->tail = list->current = SILC_LIST_END;
125   list->offset = offset;
126 }
127
128 #define list_next(list, pos) ((void **) ((char *) (pos) + (list)->offset))
129
130 /****f* silcutil/SilcList/silc_list_count
131  *
132  * SYNOPSIS
133  *
134  *    #define silc_list_count(list) ...
135  *
136  * DESCRIPTION
137  *
138  *    Returns the number of entries in the list indicated by `list'.
139  *
140  ***/
141 #define silc_list_count(list) __silc_list_count(&(list))
142 static inline int __silc_list_count(SilcList *list)
143 {
144   int count = 0;
145   void *pos;
146
147   for (pos = list->head; pos != NULL; pos = *list_next(list, pos))
148     count++;
149
150   return count;
151 }
152
153 /****f* silcutil/SilcList/silc_list_start
154  *
155  * SYNOPSIS
156  *
157  *    #define silc_list_start(list) ...
158  *
159  * DESCRIPTION
160  *
161  *    Sets the start of the list.  This prepares the list for traversing
162  *    the entries from the start of the list.
163  *
164  ***/
165 #define silc_list_start(list) (list).current = (list).head;
166
167 /****f* silcutil/SilcList/silc_list_add
168  *
169  * SYNOPSIS
170  *
171  *    #define silc_list_add(list, entry) ...
172  *
173  * DESCRIPTION
174  *
175  *    Adds new entry indicated by `entry' to the end of the list indicated 
176  *    by `list'.
177  *
178  ***/
179 #define silc_list_add(list, entry) __silc_list_add(&(list), entry)
180 static inline void __silc_list_add(SilcList *list, void *data)
181 {
182   if (list->head == NULL)
183     list->head = data;
184   else
185     *list_next(list, list->tail) = data;
186
187   list->tail = data;
188   *list_next(list, data) = NULL;
189 }
190
191 /****f* silcutil/SilcList/silc_list_del
192  *
193  * SYNOPSIS
194  *
195  *    #define silc_list_del(list, entry) ...
196  *
197  * DESCRIPTION
198  *
199  *    Remove entry indicated by `entry' from the list indicated by `list'.
200  *
201  ***/
202 #define silc_list_del(list, data) __silc_list_del(&(list), data)
203 static inline void __silc_list_del(SilcList *list, void *data)
204 {
205   void **pos, *prev;
206
207   prev = NULL;
208   for (pos = &list->head; *pos != NULL; pos = list_next(list, *pos)) {
209     if (*pos == data) {
210       *pos = *list_next(list, data);
211       if (list->current == data)
212         list->current = *pos;
213       break;
214     }
215
216     prev = *pos;
217   }
218
219   if (data == list->tail)
220     list->tail = prev;
221 }
222
223 /****f* silcutil/SilcList/silc_list_get
224  *
225  * SYNOPSIS
226  *
227  *    #define silc_list_get(list, entry) ...
228  *
229  * DESCRIPTION
230  *
231  *    Returns the current entry from the list indicated by `list' and
232  *    moves the list pointer forward so that calling this next time will
233  *    return the next entry from the list.  This can be used to traverse
234  *    the list.  Returns SILC_LIST_END when the entire list has been
235  *    tarversed and no additional entries exist in the list. Later,
236  *    silc_list_start must be called again when re-starting the list
237  *    tarversing.
238  *
239  * EXAMPLE
240  *
241  *    // Traverse the list from the beginning to the end 
242  *    silc_list_start(list)
243  *    while ((entry = silc_list_get(list)) != SILC_LIST_END) {
244  *      ...
245  *    }
246  *
247  ***/
248 #define silc_list_get(x) __silc_list_get(&(x))
249
250 static inline
251 void *__silc_list_get(SilcList *list)
252 {
253   void *pos;
254
255   pos = list->current;
256   if (pos != NULL)
257     list->current = *list_next(list, pos);
258   return pos;
259 }
260
261 #endif