Hi Vincent, I picked up your email from the archive as I didn't received it yet.
As you see, it's very easy with a simple #define to create simple code for simple cases and yet be powerful for more complex cases : #define grub_iterate_list_brk(list, func, context, it) \ {typeof(list) el = list; it = 0; \ while (el) {if (func(context, el)) {it = el; break;} el=el->next; }} that you can call with grub_iterate_list_brk(grub_devices, compare, dev, it); with the simpliest compare function between two devices, and you get in-line functions nearly as simpler as the one you wrote. But let's try this : item * grub_iterate_list_brk (item * start, void * (*fct) (void * a, void * b), void * search) { while (start && fct(search, (void *) start)) start = start->next; return start ? start : (item *) fct(search, NULL); } that you can call with : it = (dev *) grub_iterate_list_brk((item *) grub_devices, devcompare, device); You are not in-lining functions (that makes the code smaller) and this is a simple devcompare function to see how it works : void * devcompare (dev * a, dev * b) { if (b == NULL) return NULL; if (a == NULL) return NULL; return (void *) strcmp (a->name, b->name); } Which is 3 line long but still is readable ... and yet powerful : If (b == NULL) return NULL; You have ended the list and didn't find a match ? grub_iterate_list_brk let the compare function choose what it likes to return as a result : Can be NULL (not found) Can be a default value Can be the "best" item picked out of the iteration process that matches best the criteria; as you like :-) If (a == NULL) return NULL; What happens then ? if you call grub_iterate_list_brk with no criteria (device == NULL), than it assumes you want any item and returns the first item in the list. That's good behaviour and only a small overhead in devcompare. Return (void *) strcmp (a->name, b->name); Grub_iterate_list_brk return the item for which the compare function returns 0 (or NULL), so that you can easily write : Return (void *) ( a->id - b->id || a->magic - b-> magic || strcmp(a->name, b->name) ); Is that what you were looking for ? PS: Sorry folks for my previous emails sent in html : it sent lots of useless blank lines for nothing. ________________________________________ Eric Salomé Paris, France From: vincent guffens Subject: Re: RE : a simple list Date: Tue, 09 May 2006 10:08:24 +0100 User-agent: Debian Thunderbird 1.0.7 (X11/20051017) Thank you for this information. Adding the concept of context is indeed the right idea. I was doing it as follows void function (grub_device_t dev) { grub_device_t it; auto int look_for_dev (grub_device_t); int look_for_dev (grub_device_t grub_device_t other_dev) { return compare (dev, other_dev) } grub_iterate_list_brk (grub_devices, look_for_dev, it); } but it has to be compared with something like void function (grub_device_t dev) { grub_device_t it = grub_devices; while (it) { if ( compare (dev, it) ) break; } } which is obviously simpler. Maybe the only two functions that are really needed are add and del ? _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel