#ifndef _TOOLS_LISTS_H_ /****************************************************************************************/
#define _TOOLS_LISTS_H_

/****************************************************************************************************************
 *
 * Doubly linked lists with header.
 *
 * Each list item contains pointers to next and previous items. The implementation uses a list header which
 * also contains next and prev pointers. On an empty list, the header points to itself. A list with items
 * is circular, with the header at the "top".
 *
 * Therefore, the list never contains NULL pointers and thus doesn't need special conditional cases for those.
 * In fact, an item with LH_NEXT and LH_PREV being zero is not considered part of a list.
 *
 * When traversing the list, either forward or backward, the loop termination condition is reached when the
 * loop pointer points to the list head.
 *
 ****************************************************************************************************************/

#ifdef ASSEMBLER

/* Minimal list header */
#define LH_NEXT		0			/* 4	Next item in list					*/
#define LH_PREV		4			/* 4	Previous item in list					*/
#define LH_SIZEOF	8

#endif

/****************************************************************************************************************/

#ifndef ASSEMBLER

#include <stddef.h>

// typedef'ing the passed type because some Qt Creator versions wrongly "spell-check" when type contains the struct keyword.
#define LIST_CAST(type, ptr, field) ({ typedef type _t; (_t *)(void *)((unsigned char *)(ptr) - offsetof(_t, field)); })
#define CONST_LIST_CAST(type, ptr, field) ({ typedef type _t; (const _t *)(const void *)((const unsigned char *)(ptr) - offsetof(_t, field)); })

typedef struct list_head {
  struct list_head *lh_next;
  struct list_head *lh_prev;
} list_head;

/****************************************************************************************************************/

// Init list head
static inline struct list_head *list_init(struct list_head *head);

static inline struct list_head *list_init(struct list_head *head) {
  head->lh_next = head;
  head->lh_prev = head;
  return head;
}

/****************************************************************************************************************/

// Insert item after another
static inline struct list_head *list_insert_after(struct list_head *prev, struct list_head *item) {
  item->lh_prev = prev;
  struct list_head *tmp = prev->lh_next;
  item->lh_next = tmp;
  tmp->lh_prev = item;
  prev->lh_next = item;
  return prev;
}

// Put item at top of list
static inline struct list_head *list_prepend(struct list_head *head, struct list_head *item) {
  return list_insert_after(head, item);
}

/****************************************************************************************************************/

// Insert item before another
static inline struct list_head *list_insert_before(struct list_head *next, struct list_head *item) {
  item->lh_next = next;
  struct list_head *tmp = next->lh_prev;
  item->lh_prev = tmp;
  tmp->lh_next = item;
  next->lh_prev = item;
  return next;
}

// Put item at end of list
static inline struct list_head *list_append(struct list_head *head, struct list_head *item) {
  return list_insert_before(head, item);
}

/****************************************************************************************************************/

// Remove item from list
static inline struct list_head *list_remove(struct list_head *item) {

  struct list_head *next = item->lh_next;
  if (!next) return item;

  struct list_head *prev = item->lh_prev;

  next->lh_prev = prev;
  prev->lh_next = next;

  item->lh_next = 0;
  item->lh_prev = 0;

  return item;
}

/****************************************************************************************************************/
#endif
#endif
