/* usb/dilist.h
 *
 * (c) 2002 Simtec Electronics
 *
 * Ben Dooks
 *
 * simple doubly linked list code indexed and sorted
 *
 * $Id: dilist.h,v 1.3 2003/08/07 13:06:57 ben Exp $
 *
 * This Library file is part of the Simtec Electronics USB stack development
 *   suite.
 * Specific licence is granted to use this file by third parties for the
 *   development of USB device drivers.
 *
*/

#ifndef __USB_DILIST_H
#define __USB_DILIST_H "$Id: dilist.h,v 1.3 2003/08/07 13:06:57 ben Exp $"

/** dlist item structure (to put in each item in the list)
 * @memo dlist item structure
*/
struct dilist_item {
  struct dlist_item   ent;

  union {
    unsigned long     un;
    long              si;
  } value;
};

/** dlist head structure
 * @memo head structure for dlist
*/

struct dilist_head {
  struct dlist_head   head;
  unsigned char       is_signed;
  unsigned char       reversed;
};


typedef struct dilist_head dilist_head_t;
typedef struct dilist_item dilist_item_t;

#define DILIST_INIT_HEAD { {  NULL , NULL , NULL, { 0 } } }

/** initialise the head structure for an dlist
 * @memo initialise the head structure for an dlist
 * @see dlist_head
*/

#define dilist_inithead(_dl) dlist_inithead(&(_dl)->head)

/** initialise an dlist item structure
 * @memo initialise an dlist item structure
 * @see dlist_item
*/

#define dilist_init(_entry,_item) do { (_entry)->ent.dl_data = (_item); } while(0)

#define dilist_get_front(_dl) dlist_get_front(&(_dl)->head)

/** Is an dlist empty
*/

#define dilist_empty(_dl) dlist_empty(&((_dl)->head))

/** dlist enumeration function.
 *
 * @param _dl the dlist head
 * @param _to the variable to take each item
 * @param _entry the entry field name within the item
 * @param _type type to cast _to to
 * @see dlist_head
 * @see dlist_item
*/
#define dilist_foreach(_dl,_to,_entry,_type) \
  for ((_to) = ((_dl)->head.first.dl_next != NULL) ? (_type)((_dl)->head.first.dl_next->dl_data) : NULL; \
       (_to) != NULL; \
       (_to) = (_type)((_to)->_entry.ent.dl_next == NULL ? NULL : ((_to)->_entry.ent.dl_next->dl_data)))

/** remove item from an dlist
 * @param head head of list
 * @param item item to remove
 * @see dlist_item
 * @see dlist_head
 */

#define dilist_remove(_head,_item) dlist_remove(&(_head)->head, &(_item)->ent)

extern void dilist_add(dilist_head_t *head, dilist_item_t *item);

extern void dilist_add_at(dilist_item_t *ptr, dilist_item_t *add);

extern dilist_item_t *dilist_find(dilist_head_t *head, unsigned long val);

#endif
