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