Merged silc_1_1_branch to trunk.
[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  ***/
40
41 /****s* silcutil/SilcDListAPI/SilcDList
42  *
43  * NAME
44  *
45  *    typedef struct { ... } *SilcDList;
46  *
47  * DESCRIPTION
48  *
49  *    This is the actual SilcDList object that is used by application.
50  *    Application defines this object and adds contexts to this list with
51  *    Dynamic List Interface functions.
52  *
53  ***/
54 typedef struct SilcDListStruct {
55   SilcList list;
56   void *current;
57   void *prev;
58 } *SilcDList;
59
60 /* SilcDListEntry structure, one entry in the list. This MUST NOT be used
61    directly by the application. */
62 typedef struct SilcDListEntryStruct {
63   void *context;
64   struct SilcDListEntryStruct *next;
65   struct SilcDListEntryStruct *prev;
66 } *SilcDListEntry;
67
68 /****f* silcutil/SilcDListAPI/silc_dlist_init
69  *
70  * SYNOPSIS
71  *
72  *    static inline
73  *    SilcDList silc_dlist_init(void);
74  *
75  * DESCRIPTION
76  *
77  *    Initializes SilcDList.
78  *
79  ***/
80
81 static inline
82 SilcDList silc_dlist_init(void)
83 {
84   SilcDList list;
85
86   list = (SilcDList)silc_malloc(sizeof(*list));
87   if (!list)
88     return NULL;
89   list->current = list->prev = NULL;
90   silc_list_init_prev(list->list, struct SilcDListEntryStruct, next, prev);
91
92   return list;
93 }
94
95 /****f* silcutil/SilcDListAPI/silc_dlist_uninit
96  *
97  * SYNOPSIS
98  *
99  *    static inline
100  *    void silc_dlist_uninit(SilcDList list);
101  *
102  * DESCRIPTION
103  *
104  *    Uninits and frees all memory. Must be called to free memory. Does NOT
105  *    free the contexts saved by caller.
106  *
107  ***/
108
109 static inline
110 void silc_dlist_uninit(SilcDList list)
111 {
112   if (list) {
113     SilcDListEntry e;
114     silc_list_start(list->list);
115     while ((e = (SilcDListEntry)silc_list_get(list->list)) != SILC_LIST_END) {
116       silc_list_del(list->list, e);
117       silc_free(e);
118     }
119     silc_free(list);
120   }
121 }
122
123 /****f* silcutil/SilcDListAPI/silc_dlist_count
124  *
125  * SYNOPSIS
126  *
127  *    static inline
128  *    int silc_dlist_count(SilcDList list);
129  *
130  * DESCRIPTION
131  *
132  * Return the number of entries in the list.
133  *
134  ***/
135
136 static inline
137 int silc_dlist_count(SilcDList list)
138 {
139   return silc_list_count(list->list);
140 }
141
142 /****f* silcutil/SilcDListAPI/silc_dlist_start
143  *
144  * SYNOPSIS
145  *
146  *    static inline
147  *    void silc_dlist_start(SilcDList list);
148  *
149  * DESCRIPTION
150  *
151  *    Set the start of the list. This prepares the list for traversing entries
152  *    from the start of the list towards end of the list.
153  *
154  ***/
155
156 static inline
157 void silc_dlist_start(SilcDList list)
158 {
159   silc_list_start(list->list);
160   list->current = list->prev = NULL;
161 }
162
163 /****f* silcutil/SilcDListAPI/silc_dlist_end
164  *
165  * SYNOPSIS
166  *
167  *    static inline
168  *    void silc_dlist_end(SilcDList list);
169  *
170  * DESCRIPTION
171  *
172  *    Set the end of the list. This prepares the list for traversing entries
173  *    from the end of the list towards start of the list.
174  *
175  ***/
176
177 static inline
178 void silc_dlist_end(SilcDList list)
179 {
180   silc_list_end(list->list);
181   list->current = list->prev = NULL;
182 }
183
184 /****f* silcutil/SilcDListAPI/silc_dlist_add
185  *
186  * SYNOPSIS
187  *
188  *    static inline
189  *    SilcBool silc_dlist_add(SilcDList list, void *context);
190  *
191  * DESCRIPTION
192  *
193  *    Adds new entry to the list. This is the default function to add new
194  *    entries to the list.
195  *
196  ***/
197
198 static inline
199 SilcBool silc_dlist_add(SilcDList list, void *context)
200 {
201   SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
202   if (silc_unlikely(!e))
203     return FALSE;
204   e->context = context;
205   silc_list_add(list->list, e);
206   return TRUE;
207 }
208
209 /****f* silcutil/SilcDList/silc_dlist_insert
210  *
211  * SYNOPSIS
212  *
213  *    static inline
214  *    SilcBool silc_dlist_insert(SilcDList list, void *context);
215  *
216  * DESCRIPTION
217  *
218  *    Insert new entry to the list between current and previous entry.
219  *    If list is at the start this adds the entry at head of the list.
220  *    Use silc_dlist_add to add at the end of the list.
221  *
222  ***/
223
224 static inline
225 SilcBool silc_dlist_insert(SilcDList list, void *context)
226 {
227   SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
228   if (silc_unlikely(!e))
229     return FALSE;
230   e->context = context;
231   silc_list_insert(list->list, list->prev, e);
232   return TRUE;
233 }
234
235 /****f* silcutil/SilcDListAPI/silc_dlist_del
236  *
237  * SYNOPSIS
238  *
239  *    static inline
240  *    void silc_dlist_del(SilcDList list, void *entry);
241  *
242  * DESCRIPTION
243  *
244  *    Remove entry from the list.
245  *
246  ***/
247
248 static inline
249 void silc_dlist_del(SilcDList list, void *entry)
250 {
251   SilcDListEntry e;
252
253   silc_list_start(list->list);
254   while ((e = (SilcDListEntry)silc_list_get(list->list)) != SILC_LIST_END) {
255     if (e->context == entry) {
256       silc_list_del(list->list, e);
257 #if defined(SILC_DEBUG)
258       memset(e, 'F', sizeof(*e));
259 #endif
260       if (list->current == e)
261         list->current = NULL;
262       if (list->prev == e)
263         list->prev = NULL;
264       silc_free(e);
265       break;
266     }
267   }
268 }
269
270 /****f* silcutil/SilcDListAPI/silc_dlist_get
271  *
272  * SYNOPSIS
273  *
274  *    static inline
275  *    void *silc_dlist_get(SilcDList list);
276  *
277  * DESCRIPTION
278  *
279  *    Returns current entry from the list and moves the list pointer forward
280  *    so that calling this next time returns the next entry from the list.
281  *    This can be used to traverse the list. Return SILC_LIST_END when the
282  *    entire list has been traversed. Later, silc_list_start (or
283  *    silc_dlist_end) must be called again when re-starting list traversing.
284  *
285  * EXAMPLE
286  *
287  *    // Traverse the list from the beginning to the end
288  *    silc_dlist_start(list)
289  *    while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
290  *      ...
291  *    }
292  *
293  ***/
294
295 static inline
296 void *silc_dlist_get(SilcDList list)
297 {
298   SilcDListEntry e;
299   list->prev = list->current;
300   list->current = e = (SilcDListEntry)silc_list_get(list->list);
301   if (e != SILC_LIST_END)
302     return e->context;
303   return SILC_LIST_END;
304 }
305
306 #endif