/*
 * Copyright (c) 2014-2019 Satlab Aps <satlab@satlab.com>
 * All rights reserved. Do not distribute without permission.
 */

#ifndef _SL_LIST_H_
#define _SL_LIST_H_

struct sl_list {
	struct sl_list *prev;
	struct sl_list *next;
};

#define sl_container_of(ptr, sample, member)				\
	(void *)((char *)(ptr) -				        \
	        ((char *)&(sample)->member - (char *)(sample)))

#define SL_LIST_INIT(name) { &(name), &(name) }
#define SL_LIST(name) struct sl_list name = SL_LIST_INIT(name)

#define sl_list_for_each(pos, head, member)				\
	for (pos = sl_container_of((head)->next, pos, member);		\
	     &pos->member != (head);					\
	     pos = sl_container_of(pos->member.next, pos, member))

#define sl_list_for_each_safe(pos, tmp, head, member)			\
	for (pos = sl_container_of((head)->next, pos, member),		\
	     tmp = sl_container_of((pos)->member.next, tmp, member);	\
	     &pos->member != (head);					\
	     pos = tmp,							\
	     tmp = sl_container_of(pos->member.next, tmp, member))

#define sl_list_for_each_reverse(pos, head, member)			\
	for (pos = sl_container_of((head)->prev, pos, member);		\
	     &pos->member != (head);					\
	     pos = sl_container_of(pos->member.prev, pos, member))

#define sl_list_for_each_reverse_safe(pos, tmp, head, member)		\
	for (pos = sl_container_of((head)->prev, pos, member),		\
	     tmp = sl_container_of((pos)->member.prev, tmp, member);	\
	     &pos->member != (head);					\
	     pos = tmp,							\
	     tmp = sl_container_of(pos->member.prev, tmp, member))

void sl_list_init(struct sl_list *list);

void sl_list_insert(struct sl_list *elm, struct sl_list *list);

void sl_list_insert_tail(struct sl_list *list, struct sl_list *elm);

void sl_list_remove(struct sl_list *elm);

int sl_list_length(struct sl_list *list);

int sl_list_empty(struct sl_list *list);

int sl_list_head(struct sl_list *list, struct sl_list *cur);

#endif /* _SL_LIST_H_ */
