/****************************************************/
/* Gestion de listes doublement chainees            */
/* list.h                                           */
/*                                                  */
/* Ecrit par : Daniel Lacroix (all rights reserved) */
/*                                                  */
/****************************************************/

#ifndef __LIST_H__
#define __LIST_H__

#include <general.h>

/* pour les listes chainees */
typedef struct _List List;

struct _List {
  pointer data;
  List *next;
  List *prev;
};

/* Cree une nouvelle liste chainee. */
/* List *list_new()                 */
#define list_new() NULL

/* Rajoute en tete de la liste pList l'element data. */
/* Renvoie le nouveau point d'entree de la liste.    */
List *list_prepend(List *pList, pointer data);

/* Rajoute en queue de la liste pList l'element data. */
/* Renvoie le nouveau point d'entree de la liste.     */
List *list_append(List *pList, pointer data);

/* Rajoute un element apres l'element before. Si l'element before  */
/* n'est pas trouve alors le nouvel element sera rajoute a la fin. */
/* Renvoie ne nouveau point d'entree de la liste pList.            */
List *list_insert_after_item(List *pList, pointer before, pointer data);

/* Concatene la liste p2 a la liste p1 (p1 devant, p2 derriere)             */
/* Renvoie la nouvelle liste cree. p1 et p2 sont consideres comme detruites */
List *list_concat(List *p1, List *p2);

/* Empile data a la fin de la liste pList.              */
/* Renvoie le nouveau point d'entree de la liste pList. */
/* void list_push(List *pList, pointer data);           */
#define list_push(pList,data) list_append(pList,data)

/* Depile le dernier element de la liste pList.                  */
/* Le dernier est place dans data et est sorti de la liste       */
/* list_pop renvoie le nouveau point d'entree de la liste pList. */
List *list_pop(List *pList, pointer *data);

/* Renvoie une copie de la liste pList. Les pointeurs data sont copies */
/* pas le contenu pointe. Il s'agit d'une liste avec des "alias" sur   */
/* les elements de la premiere liste.                                  */
List *list_copy(List *pList);

/* Renvoie une copie de la liste pList. Les donnees contenu dans la liste sont copies */
/* avec la fonction copy_func. Elle recoit le pointeur de l'element d'origine et doit */
/* renvoyer un pointeur vers la copie.                                                */
List *list_copy_full(List *pList, pointer (* copy_func)(pointer data));

/* Libere la liste (pas les elements) */
void list_free(List *pList);

/* Libere la liste et appele la procedure free_func pour chaque elements */
void list_free_full(List *pList, void (* free_func)(pointer data));

/* Libere la liste et appele la procedure free (du C) pour chaque elements */
void list_free_full_simple(List *pList);

/* Libere un element de la liste (pas ce que l'element pointe si c'est un pointeur) */
/* Renvoie le nouveau point d'entree de la liste.                                   */
List *list_free_item(List *pList, pointer data);

/* Libere un element de la liste (pas ce que l'element pointe si c'est un pointeur) */
/* Si l'element a ete libere alors done == TRUE sinon FALSE.                        */
/* Renvoie le nouveau point d'entree de la liste.                                   */
List *list_free_item_with_check(List *pList, pointer data, boolean *done);

/* Libere un element de la liste pList (pas la donnee pointe par data) */
/* Renvoie le nouveau point d'entree de la liste.                      */
List *list_free_chunk(List *pList, List *pToFree);

/* Renvoi le nombre d'element contenue dans la liste */
/* Cette operation est realisee par comptage.        */
uint32 list_nb_item(List *pList);

/* Renvoie l'element a la position item_nb dans la liste pList */
/* Si l'element item_nb n'exite pas, la fonction renvoi NULL.  */
/* item_nb commence a 1.                                       */
pointer list_item(List *pList, uint32 item_nb);

/* Renvoie la donnee correspondant a l'element de liste pList */
/* pointer list_data(List *pList);                            */
#define list_data(pList) ((pList)?(pList)->data:NULL)

/* Renvoie l'element a la derniere position de la liste pList. */
/* Renvoie NULL si la liste est vide.                          */
/* List *list_last(List *pList);                               */
#define list_last(pList) ((pList)?(pList)->prev:NULL)

/* Renvoie TRUE si la liste pList est vide. Renvoie FALSE sinon. */
/* boolean list_is_empty(List *pList);                           */
#define list_is_empty(pList) (pList == NULL)

/* Renvoie TRUE si pCurrentList est au dela du dernier   */
/* element de la liste pList. Sinon renvoie FALSE        */
/* boolean list_is_end(List *pList, List *pCurrentList); */
#define list_is_end(pList,pCurrentList) (pCurrentList == NULL)

/* Renvoie TRUE si pCurrentList est le premier            */
/* element de la liste pList. Sinon renvoie FALSE         */
/* boolean list_is_first(List *pList, List *pCurrentList);*/
#define list_is_first(pList,pCurrentList) ((pCurrentList) == pList)

/* Renvoie TRUE si pCurrentList est le dernier            */
/* element de la liste pList. Sinon renvoie FALSE         */
/* boolean list_is_last(List *pList, List *pCurrentList); */
#define list_is_last(pList,pCurrentList)\
 ((pCurrentList != NULL) && (pList != NULL) && ((pCurrentList)->next == pList))

/* Renvoie l'element apres pCurrentList dans la liste pList.       */
/* Si on arrive au dela de la fin de la liste pList, renvoie NULL. */
/* List *list_next(List *pList, List *pCurrentList);               */
#define list_next(pList,pCurrentList)\
 (((pCurrentList)&&((pCurrentList)->next!=pList))?(pCurrentList)->next:NULL)

/* Renvoie l'element avant pCurrentList dans la liste pList.          */
/* Si l'element precedent est avant le premier element, renvoie NULL. */
/* List *list_prev(List *pList, List *pCurrentList);                  */
#define list_prev(pList,pCurrentList)\
 (((pCurrentList)&&((pCurrentList)!=pList))?(pCurrentList)->prev:NULL)

/* Deplace pCurrentList sur le prochain element de la liste pList */
/* Si on arrive a la fin pCurrentList devient NULL.               */
/* void list_move_next(List *pList, List *pCurrentList);          */
#define list_move_next(pList,pCurrentList) (pCurrentList = list_next(pList,pCurrentList))

/* Deplace pCurrentList sur l'element precedent de la liste pList         */
/* Si on arrive avant le premier element alors pCurrentList devient NULL. */
/* void list_move_prev(List *pList, List *pCurrentList);                  */
#define list_move_prev(pList,pCurrentList) (pCurrentList = list_prev(pList,pCurrentList))

/* Trie la liste pList. La fonction cmp_func est utilise pour  */
/* determine l'ordre. Elle doit renvoyer 0 si p1 pointe sur un */
/* element equivalent a p2. < 0 si p1 est inferieur a p2, >0   */
/* si p2 est superieur a p1.                                   */
/* Renvoie la liste triee.                                     */
List *list_sort(List *pList,int (* cmp_func)(pointer p1, pointer p2));

/* Insere l'element data dans la liste pList de maniere trie */
/* d'apres la fonction cmp_func. Elle doit renvoyer 0 si p1  */
/* pointe sur un element equivalent a p2. < 0 si p1 est      */
/* inferieur a p2, >0 si p2 est superieur a p1.              */
/* Renvoie le nouveau point d'entree de la liste.            */
List *list_insert_sorted(List *pList,int (* cmp_func)(pointer p1, pointer p2),
  pointer data);

/* Inverse l'ordre des elements de la liste pList          */
/* Renvoie le nouveau point d'entree de la liste           */
/* Cette operation peut ce faire pendant que l'on parcours */
/* (pas au sens multithreade du terme)                     */
/* la liste mais bien evidemment, le sens s'inverse.       */
List *list_invert(List *pList);

/* Recherche l'element de liste qui contient la premiere donnee data */
/* Renvoie l'element de liste si trouve, NULL sinon.                 */
List *list_find(List *pList, pointer data);

/* Recherche l'element de liste qui contient la premiere donnee pour laquelle la */
/* fonction find_func renvoie TRUE. La fonction find_func prend en parametre le  */
/* pointeur contenu dans la liste et le pointeur your_data qui est donne par     */
/* l'utilisateur (pour y stocker ce dont il a besoin pour la comparaison).       */
/* Renvoie l'element de liste si trouve, NULL sinon.                             */
List *list_find_full(List *pList, pointer your_data,
  boolean (* find_func)(pointer data, pointer your_data));

#endif /* __LIST_H__ */