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 ?
Also, I found out yesterday that
the compiler throws out warning about strict aliasing when using the
iterate function. I had to add -fno-strict-aliasing to get rid of them.
Eric Salomé wrote:
Hi,
I didn’t take a good look at current iterate functions in Grub 2, yet.
Most iterations needs a “init” (before treatment of first item) and a
“fini” (after treatment of last item).
Further more, one might want to make iteration functions “re-entrant”
(or recursive), or call-back other functions in a generic way.
One way to get to such behavior easily cost a bit more than the example
you provided :
you may just add an argument (let’s call it the context object) to the
call of the iterate function :
#define grub_iterate_list(list, func, context) \
{typeof(list) el = list; while (el) {func(context, el); el=el-next;}
func(context, NULL)}
or
#define grub_iterate_list(list, func) \
{void * context = NULL; typeof(list) el = list; while (el)
{func(context, el); el=el-next;} func(context, NULL)}
but I prefer the first define as it allows transmission of a full
context to the iteration function.
my_struct * my_ctxt;
my_ctxt = NULL; grub_iterate_list(list, my_func, my_ctxt);
void my_func (my_struct ** ctxt, my_item * item) {
if (item == NULL) {
/* End of iteration : Do any cleanup */
if (*ctxt == NULL) return;
free (*ctxt) ……
…..
return;
}
if (*ctxt == NULL) {
/* First iteration : Do any initialization */
*ctxt = malloc (sizeof (my_struct)); ….
…..
}
/* Do the iteration stuff */
…..
return;
}
In grub_iterate_list_brk, you can use context to send a patern or model
object to compare each item of the list with.
The draw back is it makes iteration function a bit less readable, but a
lot more powerful.
_
Eric Salomé – Paris, France
-Message d'origine-
De : [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] De la part de
Guffens, Vincent
Envoyé : lundi 8 mai 2006 01:14
À : grub-devel@gnu.org
Objet : a simple list
Hi,
I need to use a simple list to register the pci devices, drivers and so
on. I notice that there are lists like that already in the code so what
would you think about having a list.h file like that ?
/* A very simple list.
*
* If you want a list of struct myitem
* you do
*
* struct myitem *item_list;
*
* where myitem MUST have its next pointer as the FIRST field
*
* and you can then add, delete the EL item,
* grub_add_list (item_list, el);
* grub_del_list (item_list, el);
*
* or call HOOK(item) for each element of the list
* grub_iterate_list (item_list, hook);
*
* This brk version will point el to the list item for which
* HOOK(EL) returns a non-null value
* grub_iterate_list_brk (item_list, hook, el);
*
*/
struct obj {
struct obj *next; /* MUST BE FIRST */
};
#define grub_del_list(list, el) _grub_del_list((struct obj**) list,
(struct obj*) el)
#define grub_add_list(list, el) _grub_add_list((struct obj**) list,
(struct obj*) el)
#define grub_find_list(list, el) \
(typeof(list)) _grub_find_list((struct obj*) list, (struct obj*) el)
#define grub_iterate_list(list, func) \
{typeof(list) el = list; while (el) {func(el); el=el-next;}}
#define grub_iterate_list_brk(list, func, it) \
{typeof(list) el = list; it = 0; \
while (el) {if (func(el)) {it = el; break;} el=el-next; }}
static inline struct obj* _grub_find_list (struct obj *list, struct obj
*el)
{
struct obj *it = list;
for (it = list; it; it=it-next)
{
if (it == el) return el;
}
return 0;
};
static inline void _grub_add_list (struct obj **list, struct obj *el)
{
if ( (!el) || (_grub_find_list (*list, el)) )
return;
el-next = *list;
*list = el;
};
static inline void _grub_del_list (struct obj **list, struct obj *el)
{
struct obj **p;
struct obj *q;
for (p = list, q = *p; q; p = (q-next), q = q-next)
if (q == el)
{
*p = q-next;
break;
}
};