/*-------------------------------------------------------------------------
 *
 * pg_list.h
 *	  interface for PostgreSQL generic linked list package
 *
 *
 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * $PostgreSQL: pgsql-server/src/include/nodes/pg_list.h,v 1.42 2003/11/29 22:41:06 pgsql Exp $
 *
 *-------------------------------------------------------------------------
 */
#ifndef PG_LIST_H
#define PG_LIST_H

#include "nodes/nodes.h"

/*----------------------
 *		List node
 *
 * We support three types of lists:
 *	lists of pointers (in practice always pointers to Nodes, but declare as
 *		"void *" to minimize casting annoyances)
 *	lists of integers
 *	lists of Oids
 *
 * (At this writing, ints and Oids are the same size, but they may not always
 * be so; try to be careful to maintain the distinction.)
 *
 * Lists must be homogeneous.
 *----------------------
 */
typedef struct ListCell
{
	union
	{
		void	*ptr_value;
		int		 int_value;
		Oid		 oid_value;
	} data;

	struct ListCell *next;
} ListCell;

typedef struct List
{
	NodeTag		 type;	/* T_List, T_IntList, or T_OidList */
	int			 length;
	ListCell	*head;
	ListCell	*tail;
} List;

/*
 * The *only* valid representation of an empty list is NIL; in other
 * words, a non-NIL list is guaranteed to have length >= 1 and
 * head/tail != NULL
 */
#define    NIL			((List *) NULL)

#define list_length(l)			((l) ? (l)->length : 0)
#define list_head(l)			((l) ? (l)->head : NULL)
#define list_tail(l)			((l) ? (l)->tail : NULL)

#define cell_next(lc)			((lc)->next)
#define cell_value(lc)			((lc)->data.ptr_value)
#define cell_value_int(lc)		((lc)->data.int_value)
#define cell_value_oid(lc)		((lc)->data.oid_value)

/*
 * foreach -
 *	  a convenience macro which loops through the list
 */
#define foreach(lc, l)	\
	for ((lc) = list_head(l); (lc) != NULL; (lc) = cell_next(lc))

extern List *list_append(List *list, void *datum);
extern List *list_append_int(List *list, int datum);
extern List *list_append_oid(List *list, Oid datum);

extern List *list_prepend(List *list, void *datum);
extern List *list_prepend_int(List *list, int datum);
extern List *list_prepend_oid(List *list, Oid datum);

extern List *list_conc(List *list1, List *list2);
extern void *list_nth(List *list, int n);
extern List *list_truncate(List *list, int new_size);

extern bool list_member(List *list, void *datum);
extern bool list_member_simple(List *list, void *datum);
extern bool list_member_int(List *list, int datum);
extern bool list_member_oid(List *list, Oid datum);

extern List *list_remove(List *list, void *datum);
extern List *list_remove_simple(List *list, void *datum);
extern List *list_remove_int(List *list, int datum);
extern List *list_remove_oid(List *list, Oid datum);

#define list_equal(l1, l2)						\
	list_equal_private(l1, l2, false)

#define list_equal_simple(l1, l2)				\
	list_equal_private(l1, l2, true)

#define list_set_union(l1, l2)					\
	list_set_union_private(l1, l2, false)
#define list_set_union_simple(l1, l2)			\
	list_set_union_private(l1, l2, true)

#define list_set_difference(l1, l2)				\
	list_set_difference_private(l1, l2, false)
#define list_set_difference_simple(l1, l2)		\
	list_set_difference_private(l1, l2, true)

#define list_copy(list)							\
	list_copy_private(list, false)
#define list_deep_copy(list)					\
	list_copy_private(list, true)

extern void list_free(List *list);

/*
 * Private API functions; callers should not invoke these
 * directly. Rather, one of the convenience macros above should be
 * used.
 */
extern bool list_equal_private(List *list1, List *list2,
							   bool simple);
extern List *list_set_union_private(List *list1, List *list2,
									bool simple);
extern List *list_set_difference_private(List *list1, List *list2,
										 bool simple);
extern List *list_copy_private(List *list, bool shallow);

#endif   /* PG_LIST_H */
