Added examples to headers.
[silc.git] / lib / silcutil / silcdlist.h
1 /*
2
3   silcdlist.h
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2000 - 2007 Pekka Riikonen
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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #ifndef SILDCLIST_H
21 #define SILDCLIST_H
22
23 #include "silclist.h"
24
25 /****h* silcutil/SILC Dynamic List Interface
26  *
27  * DESCRIPTION
28  *
29  * SILC Dynamic List API can be used to add opaque contexts to list that
30  * will automatically allocate list entries.  Normal SILC List API cannot
31  * be used for this purpose because in that case the context passed to the
32  * list must be defined as list structure already.  This is not the case in
33  * SilcDList.  But SilcDList is a bit slower than SilcList because it
34  * requires memory allocation when adding new entries to the list.
35  *
36  * SILC Dynamic List is not thread-safe.  If the same list context must be
37  * used in multithreaded environment concurrency control must be employed.
38  *
39  * EXAMPLE
40  *
41  * SilcDList list = silc_dlist_init();
42  *
43  * silc_dlist_add(list, entry1);
44  * silc_dlist_add(list, entry2);
45  *
46  * // Traverse the list from the beginning to the end
47  * silc_dlist_start(list)
48  * while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
49  *      ...
50  * }
51  *
52  * silc_dlist_uninit(list);
53  *
54  ***/
55
56 /****s* silcutil/SilcDListAPI/SilcDList
57  *
58  * NAME
59  *
60  *    typedef struct { ... } *SilcDList;
61  *
62  * DESCRIPTION
63  *
64  *    This is the actual SilcDList object that is used by application.
65  *    Application defines this object and adds contexts to this list with
66  *    Dynamic List Interface functions.
67  *
68  ***/
69 typedef struct SilcDListStruct {
70   SilcStack stack;
71   SilcList list;
72   void *current;
73   void *prev;
74 } *SilcDList;
75
76 /* SilcDListEntry structure, one entry in the list. This MUST NOT be used
77    directly by the application. */
78 typedef struct SilcDListEntryStruct {
79   void *context;
80   struct SilcDListEntryStruct *next;
81   struct SilcDListEntryStruct *prev;
82 } *SilcDListEntry;
83
84 /****f* silcutil/SilcDListAPI/silc_dlist_init
85  *
86  * SYNOPSIS
87  *
88  *    static inline
89  *    SilcDList silc_dlist_init(void);
90  *
91  * DESCRIPTION
92  *
93  *    Initializes SilcDList.  Returns the SilcDList context or NULL on error.
94  *
95  ***/
96
97 static inline
98 SilcDList silc_dlist_init(void)
99 {
100   SilcDList list;
101
102   list = (SilcDList)silc_malloc(sizeof(*list));
103   if (!list)
104     return NULL;
105   list->stack = list->current = list->prev = NULL;
106   silc_list_init_prev(list->list, struct SilcDListEntryStruct, next, prev);
107
108   return list;
109 }
110
111 /****f* silcutil/SilcDListAPI/silc_dlist_sinit
112  *
113  * SYNOPSIS
114  *
115  *    static inline
116  *    SilcDList silc_dlist_sinit(SilcStack stack);
117  *
118  * DESCRIPTION
119  *
120  *    Initializes SilcDList.  Returns the SilcDList context or NULL on error.
121  *    This is same as silc_dlist_init but allocates the memory from `stack'
122  *    if `stack' is non-NULL.
123  *
124  ***/
125
126 static inline
127 SilcDList silc_dlist_sinit(SilcStack stack)
128 {
129   SilcDList list;
130
131   if (stack)
132     stack = silc_stack_alloc(0, stack);
133   list = (SilcDList)silc_smalloc(stack, sizeof(*list));
134   if (!list) {
135     silc_stack_free(stack);
136     return NULL;
137   }
138   list->stack = stack;
139   list->current = list->prev = NULL;
140   silc_list_init_prev(list->list, struct SilcDListEntryStruct, next, prev);
141
142   return list;
143 }
144
145 /****f* silcutil/SilcDListAPI/silc_dlist_uninit
146  *
147  * SYNOPSIS
148  *
149  *    static inline
150  *    void silc_dlist_uninit(SilcDList list);
151  *
152  * DESCRIPTION
153  *
154  *    Uninits and frees all memory. Must be called to free memory. Does NOT
155  *    free the contexts saved by caller.  If the silc_dlist_sinit was used
156  *    with SilcStack this will release all memory allocated by the SilcDList
157  *    back to the SilcStack.
158  *
159  ***/
160
161 static inline
162 void silc_dlist_uninit(SilcDList list)
163 {
164   if (list) {
165     SilcDListEntry e;
166     SilcStack stack = list->stack;
167     silc_list_start(list->list);
168     while ((e = (SilcDListEntry)silc_list_get(list->list)) != SILC_LIST_END) {
169       silc_list_del(list->list, e);
170       silc_sfree(stack, e);
171     }
172     silc_sfree(stack, list);
173     silc_stack_free(stack);
174   }
175 }
176
177 /****f* silcutil/SilcDListAPI/silc_dlist_count
178  *
179  * SYNOPSIS
180  *
181  *    static inline
182  *    int silc_dlist_count(SilcDList list);
183  *
184  * DESCRIPTION
185  *
186  * Return the number of entries in the list.
187  *
188  ***/
189
190 static inline
191 int silc_dlist_count(SilcDList list)
192 {
193   return silc_list_count(list->list);
194 }
195
196 /****f* silcutil/SilcDListAPI/silc_dlist_start
197  *
198  * SYNOPSIS
199  *
200  *    static inline
201  *    void silc_dlist_start(SilcDList list);
202  *
203  * DESCRIPTION
204  *
205  *    Set the start of the list. This prepares the list for traversing entries
206  *    from the start of the list towards end of the list.
207  *
208  ***/
209
210 static inline
211 void silc_dlist_start(SilcDList list)
212 {
213   silc_list_start(list->list);
214   list->current = list->prev = NULL;
215 }
216
217 /****f* silcutil/SilcDListAPI/silc_dlist_end
218  *
219  * SYNOPSIS
220  *
221  *    static inline
222  *    void silc_dlist_end(SilcDList list);
223  *
224  * DESCRIPTION
225  *
226  *    Set the end of the list. This prepares the list for traversing entries
227  *    from the end of the list towards start of the list.
228  *
229  ***/
230
231 static inline
232 void silc_dlist_end(SilcDList list)
233 {
234   silc_list_end(list->list);
235   list->current = list->prev = NULL;
236 }
237
238 /****f* silcutil/SilcDListAPI/silc_dlist_add
239  *
240  * SYNOPSIS
241  *
242  *    static inline
243  *    SilcBool silc_dlist_add(SilcDList list, void *context);
244  *
245  * DESCRIPTION
246  *
247  *    Adds new entry to the list. This is the default function to add new
248  *    entries to the list.
249  *
250  ***/
251
252 static inline
253 SilcBool silc_dlist_add(SilcDList list, void *context)
254 {
255   SilcDListEntry e = (SilcDListEntry)silc_smalloc(list->stack, sizeof(*e));
256   if (silc_unlikely(!e))
257     return FALSE;
258   e->context = context;
259   silc_list_add(list->list, e);
260   return TRUE;
261 }
262
263 /****f* silcutil/SilcDList/silc_dlist_insert
264  *
265  * SYNOPSIS
266  *
267  *    static inline
268  *    SilcBool silc_dlist_insert(SilcDList list, void *context);
269  *
270  * DESCRIPTION
271  *
272  *    Insert new entry to the list between current and previous entry.
273  *    If list is at the start this adds the entry at head of the list.
274  *    Use silc_dlist_add to add at the end of the list.
275  *
276  ***/
277
278 static inline
279 SilcBool silc_dlist_insert(SilcDList list, void *context)
280 {
281   SilcDListEntry e = (SilcDListEntry)silc_smalloc(list->stack, sizeof(*e));
282   if (silc_unlikely(!e))
283     return FALSE;
284   e->context = context;
285   silc_list_insert(list->list, list->prev, e);
286   return TRUE;
287 }
288
289 /****f* silcutil/SilcDListAPI/silc_dlist_del
290  *
291  * SYNOPSIS
292  *
293  *    static inline
294  *    void silc_dlist_del(SilcDList list, void *entry);
295  *
296  * DESCRIPTION
297  *
298  *    Remove entry from the list.
299  *
300  ***/
301
302 static inline
303 void silc_dlist_del(SilcDList list, void *entry)
304 {
305   SilcDListEntry e;
306
307   silc_list_start(list->list);
308   while ((e = (SilcDListEntry)silc_list_get(list->list)) != SILC_LIST_END) {
309     if (e->context == entry) {
310       silc_list_del(list->list, e);
311 #if defined(SILC_DEBUG)
312       memset(e, 'F', sizeof(*e));
313 #endif
314       if (list->current == e)
315         list->current = NULL;
316       if (list->prev == e)
317         list->prev = NULL;
318       silc_sfree(list->stack, e);
319       break;
320     }
321   }
322 }
323
324 /****f* silcutil/SilcDListAPI/silc_dlist_get
325  *
326  * SYNOPSIS
327  *
328  *    static inline
329  *    void *silc_dlist_get(SilcDList list);
330  *
331  * DESCRIPTION
332  *
333  *    Returns current entry from the list and moves the list pointer forward
334  *    so that calling this next time returns the next entry from the list.
335  *    This can be used to traverse the list. Return SILC_LIST_END when the
336  *    entire list has been traversed. Later, silc_list_start (or
337  *    silc_dlist_end) must be called again when re-starting list traversing.
338  *
339  * EXAMPLE
340  *
341  *    // Traverse the list from the beginning to the end
342  *    silc_dlist_start(list)
343  *    while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
344  *      ...
345  *    }
346  *
347  ***/
348
349 static inline
350 void *silc_dlist_get(SilcDList list)
351 {
352   SilcDListEntry e;
353   list->prev = list->current;
354   list->current = e = (SilcDListEntry)silc_list_get(list->list);
355   if (e != SILC_LIST_END)
356     return e->context;
357   return SILC_LIST_END;
358 }
359
360 #endif