/* -*- c-file-style: "GNU" -*- */
/*
 * Copyright (C) CNRS, INRIA, Universite Bordeaux 1, Telecom SudParis
 * See COPYING in top-level directory.
 */

#ifndef EZTRACE_LIST_H
#define EZTRACE_LIST_H

#include <stdlib.h>

struct ezt_list_t;

struct ezt_list_token_t {
  /* pointer to the user data */
  void* data;
  /* pointer to the list */
  struct ezt_list_t* list;
  /* pointer to the next token in the list */
  struct ezt_list_token_t* next;
  /* pointer to the previous token in the list */
  struct ezt_list_token_t* prev;
};

struct ezt_list_t {
  struct ezt_list_token_t* head;
  struct ezt_list_token_t* tail;
  int nb_item;
};

/* return true if the list is empty */
#define ezt_list_empty(l) ((l)->head == NULL)

/* iterate over the list */
#define ezt_list_foreach(l, t) for (t = (l)->head; t != NULL; t = (t)->next)

/* same as list_foreach, but supports list modifications
 * for each iteration, t is the current value (that can be removed from the list)
 * n is the next value (that should not be modified!)
 */
#define ezt_list_foreach_safe(l, t, n) for (t = (l)->head, (n) = ((l)->head ? t->next : NULL); \
                                            t != NULL;                                         \
                                            t = n, (n) = t ? (t)->next : NULL)

/* return the first token of the list */
#define ezt_list_get_head(l) ((l)->head)

/* return the last token of the list */
#define ezt_list_get_tail(l) ((l)->tail)

/* initialize a list */
static inline void ezt_list_new(struct ezt_list_t* l) {
  l->head = NULL;
  l->tail = NULL;
  l->nb_item = 0;
}

/* add a new token at the list tail */
static inline void ezt_list_add(struct ezt_list_t* l,
                                struct ezt_list_token_t* n) {
  /* initialize the new token */
  n->list = l;
  n->next = NULL;
  n->prev = l->tail;

  if (ezt_list_empty(l)) {
    l->head = n;
  } else {
    l->tail->next = n;
  }
  l->tail = n;
  l->nb_item++;
}

void eztrace_abort();
/* remove a token from the list */
static inline void ezt_list_remove(struct ezt_list_token_t* t) {
  if (t->prev)
    t->prev->next = t->next;
  else
    t->list->head = t->next;

  if (t->next)
    t->next->prev = t->prev;
  else
    t->list->tail = t->prev;

  if (t->list->head && !t->list->tail)
    eztrace_abort();

  t->list->nb_item--;
}

#endif /* EZTRACE_LIST_H */
