1 /*
2
3 silcdlist.h
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2000 - 2007 Pekka Riikonen
8
9 The contents of this file are subject to one of the Licenses specified
10 in the COPYING file; You may not use this file except in compliance
11 with the License.
12
13 The software distributed under the License is distributed on an "AS IS"
14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15 KIND, either expressed or implied. See the COPYING file for more
16 information.
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
silc_dlist_init(void)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
silc_dlist_uninit(SilcDList list)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
silc_dlist_count(SilcDList list)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
silc_dlist_start(SilcDList list)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
silc_dlist_end(SilcDList list)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
silc_dlist_add(SilcDList list,void * context)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
silc_dlist_insert(SilcDList list,void * context)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
silc_dlist_del(SilcDList list,void * entry)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
silc_dlist_get(SilcDList list)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
307