2 * Copyright (C) 2001,2002 Paul Sheer
4 * This file is part of GnuTLS.
6 * GnuTLS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuTLS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 Academics always want to implement hash tables (i.e. dictionaries),
25 singly or doubly linked lists, and queues, because ... well ... they
28 These datatypes are nonsense for the following reasons:
29 hash tables: Hash tables are a mapping of some
30 string to some data, where that data is going to
31 be accessed COMPLETELY RANDOMLY. This is what it
32 is for. However it is extremely rare to have a
33 large number of data elements which really are
34 being accessed in a completely random way.
36 lists: appending and searching through lists is always
37 slow because these operations search all the way
40 queues: whats the difference between a queue and a list?
43 The system implemented here is a doubly linked list with previous
44 search index that can be appended or prepended with no overhead,
45 implemented entirely in macros. It is hence as versatile as a
46 doubly/singly linked list or queue and blazingly fast. Hence doing
47 sequential searches where the next search result is likely to be
48 closely indexed to the previous (usual case), is efficient.
50 Of course this doesn't mean you should use this as a hash table
51 where you REALLY need a hash table.
55 /********** example usage **********/
60 extern void free (void *x);
61 extern char *strdup (char *s);
63 // consider a list of elements containing an `int' and a `char *'
64 LIST_TYPE_DECLARE (names, char *s; int i;);
66 // for sorting, to compare elements
67 static int cm (names **a, names **b)
69 return strcmp ((*a)->s, (*b)->s);
72 // to free the contents of an element
73 static void free_item (names *a)
80 int main (int argc, char **argv)
82 // you can separate these into LIST_TYPE_DECLARE(), LIST_DECLARE() and linit() if needed.
83 LIST_DECLARE_INIT (l, names, free_item);
87 l.tail->s = strdup ("hello");
90 l.tail->s = strdup ("there");
93 l.tail->s = strdup ("my");
96 l.tail->s = strdup ("name");
99 l.tail->s = strdup ("is");
102 l.tail->s = strdup ("fred");
105 printf ("%ld\n\n", lcount (l));
106 lloopforward (l, j, printf ("%d %s\n", j->i, j->s));
110 lloopforward (l, j, printf ("%d %s\n", j->i, j->s));
112 lloopreverse (l, j, if (j->i <= 3) ldeleteinc (l, j););
115 lloopforward (l, j, printf ("%d %s\n", j->i, j->s));
120 lloopforward (l, j, printf ("%d %s\n", j->i, j->s));
130 /* the `search' member points to the last found.
131 this speeds up repeated searches on the same list-item,
132 the consecutive list-item, or the pre-consecutive list-item.
133 this obviates the need for a hash table for 99% of
134 cercumstances the time */
141 struct list_item
*next
;
142 struct list_item
*prev
;
144 } *head
, *tail
, *search
;
145 void (*free_func
) (struct list_item
*);
148 /* declare a list of type `x', also called `x' having members `typelist' */
150 #define LIST_TYPE_DECLARE(type,typelist) \
151 typedef struct type { \
157 #define LIST_DECLARE(l,type) \
161 type *head, *tail, *search; \
162 void (*free_func) (type *); \
165 #define LIST_DECLARE_INIT(l,type,free) \
169 type *head, *tail, *search; \
170 void (*free_func) (type *); \
171 } l = {0, sizeof (type), 0, 0, 0, (void (*) (type *)) free}
173 #define linit(l,type,free) \
175 memset (&(l), 0, sizeof (l)); \
176 (l).item_size = sizeof (type); \
177 (l).free_func = free; \
180 /* returns a pointer to the data of an item */
181 #define ldata(i) ((void *) &((i)->data[0]))
183 /* returns a pointer to the list head */
184 #define lhead(l) ((l).head)
186 /* returns a pointer to the list tail */
187 #define ltail(l) ((l).tail)
189 #define lnewsearch(l) \
192 /* adds to the beginning of the list */
193 #define lprepend(l) \
195 struct list_item *__t; \
196 __t = (struct list_item *) malloc ((l).item_size); \
197 memset (__t, 0, (l).item_size); \
198 __t->next = (l).head; \
200 __t->next->prev = __t; \
208 /* adds to the end of the list */
211 struct list_item *__t; \
212 __t = (struct list_item *) malloc ((l).item_size); \
213 memset (__t, 0, (l).item_size); \
214 __t->prev = (struct list_item *) (l).tail; \
216 __t->prev->next = __t; \
219 (l).head = (void *) __t; \
220 (l).tail = (void *) __t; \
224 /* you should free these manually */
225 #define lunlink(l,e) \
227 struct list_item *__t; \
230 if ((void *) (l).head == (void *) __t) \
231 (l).head = (l).head->next; \
232 if ((void *) (l).tail == (void *) __t) \
233 (l).tail = (l).tail->prev; \
235 __t->next->prev = __t->prev; \
237 __t->prev->next = __t->next; \
241 /* deletes list entry at point e, and increments e to the following list entry */
242 #define ldeleteinc(l,e) \
244 struct list_item *__t; \
247 if ((void *) (l).head == (void *) __t) \
248 (l).head = (l).head->next; \
249 if ((void *) (l).tail == (void *) __t) \
250 (l).tail = (l).tail->prev; \
252 __t->next->prev = __t->prev; \
254 __t->prev->next = __t->next; \
257 (*(l).free_func) ((void *) e); \
263 /* deletes list entry at point e, and deccrements e to the preceding list emtry */
264 #define ldeletedec(l,e) \
266 struct list_item *__t; \
269 if ((void *) (l).head == (void *) __t) \
270 (l).head = (l).head->next; \
271 if ((void *) (l).tail == (void *) __t) \
272 (l).tail = (l).tail->prev; \
274 __t->next->prev = __t->prev; \
276 __t->prev->next = __t->next; \
279 (*(l).free_func) ((void *) e); \
285 /* p and q must be consecutive and neither must be zero */
286 #define linsert(l,p,q) \
288 struct list_item *__t; \
289 __t = (struct list_item *) malloc ((l).item_size); \
290 memset (__t, 0, (l).item_size); \
291 __t->prev = (void *) p; \
292 __t->next = (void *) q; \
293 q->prev = (void *) __t; \
294 p->next = (void *) __t; \
298 /* p and q must be consecutive and neither must be zero */
299 #define ldeleteall(l) \
303 struct list_item *__p; \
304 __p = (struct list_item *) (l).head; \
307 (*(l).free_func) ((void *) __p); \
312 #define lloopstart(l,i) \
313 for (i = (void *) (l).head; i;) { \
314 struct list_item *__tl; \
315 __tl = (void *) i->next; \
317 #define lloopend(l,i) \
321 #define lloopforward(l,i,op) \
323 for (i = (void *) (l).head; i;) { \
324 struct list_item *__t; \
325 __t = (void *) i->next; \
331 #define lloopreverse(l,i,op) \
333 for (i = (void *) (l).tail; i;) { \
334 struct list_item *__t; \
335 __t = (void *) i->prev; \
341 #define lindex(l,i,n) \
344 for (__k = 0, i = (void *) (l).head; i && __k != n; i = i->next, __k++); \
347 #define lsearchforward(l,i,op) \
351 if ((i = (void *) (l).search)) { \
354 (l).search = (void *) i; \
357 if ((i = (void *) (l).search->next)) \
360 (l).search = (void *) i; \
363 if ((i = (void *) (l).search->prev)) \
366 (l).search = (void *) i; \
370 for (i = (void *) (l).head; i; i = i->next) \
373 (l).search = (void *) i; \
378 #define lsearchreverse(l,i,op) \
382 if ((i = (void *) (l).search)) { \
385 (l).search = (void *) i; \
388 if ((i = (void *) (l).search->prev)) \
391 (l).search = (void *) i; \
394 if ((i = (void *) (l).search->next)) \
397 (l).search = (void *) i; \
401 for (i = (void *) (l).tail; i; i = i->prev) \
404 (l).search = (void *) i; \
409 #define lcount(l) ((l).length)
411 /* sort with comparison function see qsort(3) */
412 #define larray(l,a) \
415 struct list_item *__p; \
416 a = (void *) malloc (((l).length + 1) * sizeof (void *)); \
417 for (__i = 0, __p = (void *) (l).head; __p; __p = __p->next, __i++) \
418 a[__i] = (void *) __p; \
422 /* sort with comparison function see qsort(3) */
425 struct list_item *__p; \
426 (l).head = (void *) a[0]; \
428 __p = (void *) a[0]; \
430 for (__j = 1; a[__j]; __j++, __p = __p->next) { \
431 __p->next = (void *) a[__j]; \
432 __p->next->prev = __p; \
434 (l).tail = (void *) __p; \
438 /* sort with comparison function see qsort(3) */
439 #define lsort(l,compare) \
444 qsort (__t, (l).length, sizeof (void *), (int (*) (const void *, const void *)) compare); \