#ifndef MEGASR_CLIST_H
#define MEGASR_CLIST_H
/**
 *----------------------------------------------------------------------------
 *	LSI Corporation
 *	1621 Barber Lane
 *	Milpitas, California 95035
 *----------------------------------------------------------------------------
 * Copyright © 2004-2006, LSI Corporation All Rights Reserved.
 * 
 * LSI's source code is an unpublished work and the use of copyright
 * notice does not imply otherwise. This source code contains confidential,
 * trade secret material of LSI Corporation. Any attempt or
 * participation in deciphering, decoding, reverse engineering or
 * in any way altering the source code is strictly prohibited, unless the
 * prior written consent of LSI Corporation.
 *---------------------------------------------------------------------------- 
 **/
// generic implementation of doubly linked list
struct megasr_clist {
	struct megasr_clist *next;
	struct megasr_clist *prev;
};

static void megasr_clist_setup(struct megasr_clist *list)
{
	list->next = list;
	list->prev = list;
}

#define megasr_clist_is_empty(list) ((list)->next == list && (list)->prev == list)

static INLINE void megasr_clist_append(struct megasr_clist *lnode, struct megasr_clist *list)
{
	lnode->next = list;
	lnode->prev = list->prev;
	list->prev->next = lnode;
	list->prev = lnode;
}

static INLINE void megasr_clist_prepend(struct megasr_clist *lnode, struct megasr_clist *list)
{
	lnode->prev = list;
	lnode->next = list->next;
	list->next->prev = lnode;
	list->next = lnode;
}

static INLINE void megasr_clist_detach(struct megasr_clist *lnode)
{
	lnode->prev->next = lnode->next;
	lnode->next->prev = lnode->prev;
	megasr_clist_setup(lnode);
}

static INLINE void megasr_clist_move_append(struct megasr_clist *lnode, struct megasr_clist *list)
{
	megasr_clist_detach(lnode);
	megasr_clist_append(lnode, list);
}

static INLINE void megasr_clist_move_prepend(struct megasr_clist *lnode, struct megasr_clist *list)
{
	megasr_clist_detach(lnode);
	megasr_clist_prepend(lnode, list);
}

static INLINE void megasr_clist_merge(struct megasr_clist *removed_list, struct megasr_clist *target_list)
{
	target_list->prev->next = removed_list->next;
	removed_list->next->prev = target_list->prev;
	removed_list->prev->next = target_list;
	target_list->prev = removed_list->prev;

	//clean up removed_list
	megasr_clist_setup(removed_list);
}

#define megasr_clist_first_object(CLIST, STYPE, NODE_NAME)	((STYPE *)((uint8_t *)(CLIST) - offsetof(STYPE, NODE_NAME)))

#define megasr_clist_last_object(CLIST, STYPE, NODE_NAME)	(((CLIST)->next != CLIST) ? megasr_clist_first_object((CLIST)->prev, STYPE, NODE_NAME) : NULL)

/**
 * Traverse linked list. The current node can be removed while this traversal
 *
 * @param clist			: pointer to the list itself
 * @param ret_obj		: we return pointer to the requested object here for the caller
 * @param aux_obj		: caller provided auxillary pointer for pointer backup
 * @param stype			: object type
 * @param node_member	: name of the member
 **/
#define megasr_clist_traverse_each(ret_obj, aux_obj, head, stype, node_member)			\
	ret_obj = megasr_clist_first_object((head)->next, stype, node_member);				\
	aux_obj = megasr_clist_first_object(ret_obj->node_member.next, stype, node_member);	\
	for (;&ret_obj->node_member != head; 												\
			ret_obj = aux_obj,															\
			aux_obj = megasr_clist_first_object(aux_obj->node_member.next, stype, node_member))

#endif //MEGASR_CLIST_H
