[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE : a simple list

From: Eric Salomé
Subject: RE : a simple list
Date: Tue, 9 May 2006 01:51:41 +0200


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)}

#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) ……




      if (*ctxt == NULL) {

           /* First iteration : Do any initialization */

           *ctxt = malloc (sizeof (my_struct)); ….



/* Do the iteration stuff */





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 : address@hidden [mailto:address@hidden De la part de Guffens, Vincent
Envoyé : lundi 8 mai 2006 01:14
À : address@hidden
Objet : a simple list



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)) )
  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;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]