/*
 * list.h - Simple linked list.
 *
 * Authors Ghassan Almaless  (2008,2009,2010,2011,2012)
 *         Mohamed Lamine Karaoui (2015)
 *
 * Copyright (c) UPMC Sorbonne Universites
 *
 * This file is part of ALMOS-MKH     
 *
 * ALMOS-MKH is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2.0 of the License.
 *
 * ALMOS-MKH is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef _ALMOS_SLIST_H_
#define _ALMOS_SLIST_H_

#ifndef NULL
#define NULL (void *) 0
#endif


/***************************************************************************
 * This macro return an uint32_t that is the offset (number of bytes)
 * of a field in a structure.
 * @ type   : structure type
 * @ member : name of the field
 **************************************************************************/

#ifndef OFFSETOF
#define OFFSETOF( type , member ) ((unsigned int) & ((type *)0)->member)
#endif


////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//          Simple linked list functions & macros 
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

/***************************************************************************
 * This structure defines a simple linked list, managed as a stack.
 * Note : The list root is an extra list-entry, that is NOT part of the 
 *        set of linked elements.
 **************************************************************************/

typedef struct slist_entry_s
{
	struct slist_entry_s * next;
}
slist_entry_t;

/***************************************************************************
 * This macro returns a pointer on a structure containing an
 * embedded linked list (i.e. a list-entry or slist_entry field).
 * @ list_ptr       : pointer on the list_entry
 * @ container_type : type of the structure containing the list-entry
 * @ member_name    : name of the list_entry field
 * It can be used for both list_entry & slist_entry 
 **************************************************************************/

#define SLIST_ELEMENT( list_ptr , container_type , member_name)		\
	({const typeof(((container_type*)0)->member_name) *__member_ptr = (list_ptr); \
	(container_type *)( (char*)__member_ptr - offsetof(container_type,member_name));})

/***************************************************************************
 * This function initialises the root of a simple linked list.
 **************************************************************************/
static inline void slist_root_init( slist_entry_t * root )
{
	root->next = root;
}

/***************************************************************************
 * This function initialises an entry of a simple linked list.
 **************************************************************************/
static inline void slist_entry_init( slist_entry_t * entry )
{
	entry->next = NULL;
}

/***************************************************************************
 * This macro returns a pointer on the first element of a simple list.
 * @ root    : pointer on the list root
 * @ type    : type of the container
 * @ member  : name of the slist_entry field
 **************************************************************************/

#define SLIST_HEAD( root , type , member )		\
	SLIST_ELEMENT( root->next , type , member )

/***************************************************************************
 * This function push a new element in a simple linked list.
 * @ root    : pointer on the list root
 * @ entry   : entry to be inserted
 **************************************************************************/
static inline void slist_push( slist_entry_t * root,
                               slist_entry_t * entry )
{
	entry->next = root->next;
	root->next  = entry;	        \
}

/***************************************************************************
 * This function returns true if the list is empty.
 **************************************************************************/
static inline bool_t slist_empty( slist_entry_t * root )
{
    return ( root == root->next );
}

/***************************************************************************
 * This function pop anw element from a simple linked list.
 * It returns NULL if the list is empty.
 * @ root    : pointer on the list root
 **************************************************************************/
static inline slist_entry_t * list_pop( slist_entry_t * root )
{
	slist_entry_t * entry;
  
	if( slist_empty(root) ) return NULL;

	entry = root->next;
	root->next = entry->next;

	return entry;
}


#endif	/* _ALMOS_SLIST_H_ */
