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