aboutsummaryrefslogtreecommitdiff
path: root/src/include/nodes/pg_list.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/nodes/pg_list.h')
-rw-r--r--src/include/nodes/pg_list.h378
1 files changed, 281 insertions, 97 deletions
diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index 31566a29c9f..31c90de88c9 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/pg_list.h,v 1.43 2004/01/07 18:43:36 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/pg_list.h,v 1.44 2004/05/26 04:41:45 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,140 +16,324 @@
#include "nodes/nodes.h"
-/* ----------------------------------------------------------------
- * node definitions
- * ----------------------------------------------------------------
+/*
+ * As a temporary measure, enable the compatibility API unless the
+ * include site specifically disabled it. Once the rest of the source
+ * tree has been converted to the new API, this will be removed.
*/
+#ifndef DISABLE_LIST_COMPAT
+#define ENABLE_LIST_COMPAT
+#endif
-/*----------------------
- * List node
+/*
+ * This package implements singly-linked homogeneous lists. It is
+ * important to have constant-time length, append, and prepend
+ * operations. To achieve this, we deal with two distinct data
+ * structures:
+ *
+ * 1. A set of "list cells": each cell contains a data field and
+ * a link to the next cell in the list or NULL.
+ * 2. A single structure containing metadata about the list: the
+ * type of the list, pointers to the head and tail cells, and
+ * the length of the list.
*
* 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.)
- *----------------------
+ * T_List: lists of pointers
+ * (in practice usually pointers to Nodes, but not always;
+ * declared as "void *" to minimize casting annoyances)
+ * T_IntList: lists of integers
+ * T_OidList: lists of Oids
+ *
+ * (At the moment, ints and Oids are the same size, but they may not
+ * always be so; try to be careful to maintain the distinction.)
*/
-typedef struct List
+
+#define LIST_CELL_TYPE ListCell
+
+typedef struct ListCell ListCell;
+typedef struct List List;
+
+struct List
+{
+ NodeTag type; /* T_List, T_IntList, or T_OidList */
+ int length;
+ ListCell *head;
+ ListCell *tail;
+};
+
+struct ListCell
{
- NodeTag type;
union
{
- void *ptr_value;
- int int_value;
- Oid oid_value;
- } elem;
- struct List *next;
-} List;
+ void *ptr_value;
+ int int_value;
+ Oid oid_value;
+ } data;
+ ListCell *next;
+};
-#define NIL ((List *) NULL)
+/*
+ * 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)
-/* ----------------
- * accessor macros
- *
- * The general naming convention is that the base name xyz() is for the
- * pointer version, xyzi() is for integers, xyzo() is for Oids. We don't
- * bother with multiple names if the same routine can handle all cases.
- * ----------------
+/*
+ * These routines are used frequently. However, we can't implement
+ * them as macros, since we want to avoid double-evaluation of macro
+ * arguments. Therefore, we implement them using GCC inline functions,
+ * and as regular functions with non-GCC compilers.
+ */
+#ifdef __GNUC__
+
+static __inline__ ListCell *
+list_head(List *l)
+{
+ return l ? l->head : NULL;
+}
+
+static __inline__ ListCell *
+list_tail(List *l)
+{
+ return l ? l->tail : NULL;
+}
+
+static __inline__ int
+list_length(List *l)
+{
+ return l ? l->length : 0;
+}
+
+#else
+
+extern ListCell *list_head(List *l);
+extern ListCell *list_tail(List *l);
+extern int list_length(List *l);
+
+#endif /* __GNUC__ */
+
+/*
+ * NB: There is an unfortunate legacy from a previous incarnation of
+ * the List API: the macro lfirst() was used to mean "the data in this
+ * cons cell". To avoid changing every usage of lfirst(), that meaning
+ * has been kept. As a result, lfirst() takes a ListCell and returns
+ * the data it contains; to get the data in the _first_ cell of a
+ * List, use linitial(). Worse, lsecond() is more closely related to
+ * linitial() than lfirst(): given a List, lsecond() returns the data
+ * in the second cons cell.
*/
-#define lfirst(l) ((l)->elem.ptr_value)
-#define lfirsti(l) ((l)->elem.int_value)
-#define lfirsto(l) ((l)->elem.oid_value)
+#define lnext(lc) ((lc)->next)
+#define lfirst(lc) ((lc)->data.ptr_value)
+#define lfirst_int(lc) ((lc)->data.int_value)
+#define lfirst_oid(lc) ((lc)->data.oid_value)
-#define lnext(l) ((l)->next)
+#define linitial(l) lfirst(list_head(l))
+#define linitial_int(l) lfirst_int(list_head(l))
+#define linitial_oid(l) lfirst_oid(list_head(l))
-#define lsecond(l) lfirst(lnext(l))
+#define lsecond(l) lfirst(lnext(list_head(l)))
+#define lsecond_int(l) lfirst_int(lnext(list_head(l)))
+#define lsecond_oid(l) lfirst_oid(lnext(list_head(l)))
-#define lthird(l) lfirst(lnext(lnext(l)))
+#define lthird(l) lfirst(lnext(lnext(list_head(l))))
+#define lthird_int(l) lfirst_int(lnext(lnext(list_head(l))))
+#define lthird_oid(l) lfirst_oid(lnext(lnext(list_head(l))))
-#define lfourth(l) lfirst(lnext(lnext(lnext(l))))
+#define lfourth(l) lfirst(lnext(lnext(lnext(list_head(l)))))
+#define lfourth_int(l) lfirst_int(lnext(lnext(lnext(list_head(l)))))
+#define lfourth_oid(l) lfirst_oid(lnext(lnext(lnext(list_head(l)))))
+
+/*
+ * Convenience macros for building fixed-length lists
+ */
+#define list_make1(x1) lcons(x1, NIL)
+#define list_make2(x1,x2) lcons(x1, list_make1(x2))
+#define list_make3(x1,x2,x3) lcons(x1, list_make2(x2, x3))
+#define list_make4(x1,x2,x3,x4) lcons(x1, list_make3(x2, x3, x4))
+
+#define list_make1_int(x1) lcons_int(x1, NIL)
+#define list_make2_int(x1,x2) lcons_int(x1, list_make1_int(x2))
+#define list_make3_int(x1,x2,x3) lcons_int(x1, list_make2_int(x2, x3))
+#define list_make4_int(x1,x2,x3,x4) lcons_int(x1, list_make3_int(x2, x3, x4))
+
+#define list_make1_oid(x1) lcons_oid(x1, NIL)
+#define list_make2_oid(x1,x2) lcons_oid(x1, list_make1_oid(x2))
+#define list_make3_oid(x1,x2,x3) lcons_oid(x1, list_make2_oid(x2, x3))
+#define list_make4_oid(x1,x2,x3,x4) lcons_oid(x1, list_make3_oid(x2, x3, x4))
/*
* foreach -
* a convenience macro which loops through the list
*/
-#define foreach(_elt_,_list_) \
- for (_elt_ = (_list_); _elt_ != NIL; _elt_ = lnext(_elt_))
+#define foreach(cell, l) \
+ for ((cell) = list_head(l); (cell) != NULL; (cell) = lnext(cell))
/*
- * Convenience macros for building fixed-length lists
+ * for_each_cell -
+ * a convenience macro which loops through a list starting from a
+ * specified cell
*/
-#define makeList1(x1) lcons(x1, NIL)
-#define makeList2(x1,x2) lcons(x1, makeList1(x2))
-#define makeList3(x1,x2,x3) lcons(x1, makeList2(x2,x3))
-#define makeList4(x1,x2,x3,x4) lcons(x1, makeList3(x2,x3,x4))
+#define for_each_cell(cell, l) \
+ for ((cell) = (l); (cell) != NULL; (cell) = lnext(cell))
-#define makeListi1(x1) lconsi(x1, NIL)
-#define makeListi2(x1,x2) lconsi(x1, makeListi1(x2))
+/*
+ * forboth -
+ * a convenience macro for advancing through two linked lists
+ * simultaneously. This macro loops through both lists at the same
+ * time, stopping when either list runs out of elements. Depending
+ * on the requirements of the call site, it may also be wise to
+ * ensure that the lengths of the two lists are equal.
+ */
+#define forboth(cell1, list1, cell2, list2) \
+ for ((cell1) = list_head(list1), (cell2) = list_head(list2); \
+ (cell1) != NULL && (cell2) != NULL; \
+ (cell1) = lnext(cell1), (cell2) = lnext(cell2))
-#define makeListo1(x1) lconso(x1, NIL)
-#define makeListo2(x1,x2) lconso(x1, makeListo1(x2))
+extern List *lappend(List *list, void *datum);
+extern List *lappend_int(List *list, int datum);
+extern List *lappend_oid(List *list, Oid datum);
+
+extern ListCell *lappend_cell(List *list, ListCell *prev, void *datum);
+extern ListCell *lappend_cell_int(List *list, ListCell *prev, int datum);
+extern ListCell *lappend_cell_oid(List *list, ListCell *prev, Oid datum);
+
+extern List *lcons(void *datum, List *list);
+extern List *lcons_int(int datum, List *list);
+extern List *lcons_oid(Oid datum, List *list);
+
+extern List *list_concat(List *list1, List *list2);
+extern List *list_truncate(List *list, int new_size);
+
+extern void *list_nth(List *list, int n);
+extern int list_nth_int(List *list, int n);
+extern Oid list_nth_oid(List *list, int n);
+
+extern bool list_member(List *list, void *datum);
+extern bool list_member_ptr(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_delete(List *list, void *datum);
+extern List *list_delete_ptr(List *list, void *datum);
+extern List *list_delete_int(List *list, int datum);
+extern List *list_delete_oid(List *list, Oid datum);
+extern List *list_delete_first(List *list);
+extern List *list_delete_cell(List *list, ListCell *cell, ListCell *prev);
+
+extern List *list_union(List *list1, List *list2);
+extern List *list_union_ptr(List *list1, List *list2);
+extern List *list_union_int(List *list1, List *list2);
+extern List *list_union_oid(List *list1, List *list2);
+
+extern List *list_difference(List *list1, List *list2);
+extern List *list_difference_ptr(List *list1, List *list2);
+extern List *list_difference_int(List *list1, List *list2);
+extern List *list_difference_oid(List *list1, List *list2);
+
+extern void list_free(List *list);
+extern void list_free_deep(List *list);
+
+extern List *list_copy(List *list);
+extern List *list_copy_tail(List *list, int nskip);
/*
- * FastList is an optimization for building large lists. The conventional
- * way to build a list is repeated lappend() operations, but that is O(N^2)
- * in the number of list items, which gets tedious for large lists.
- *
- * Note: there are some hacks in gram.y that rely on the head pointer (the
- * value-as-list) being the first field.
+ * To ease migration to the new list API, a set of compatibility
+ * macros are provided that reduce the impact of the list API changes
+ * as far as possible. Until client code has been rewritten to use the
+ * new list API, the ENABLE_LIST_COMPAT symbol can be defined before
+ * including pg_list.h
+ */
+#ifdef ENABLE_LIST_COMPAT
+
+#define lfirsti(lc) lfirst_int(lc)
+#define lfirsto(lc) lfirst_oid(lc)
+
+#define llast(l) lfirst(list_tail(l))
+
+#define makeList1(x1) list_make1(x1)
+#define makeList2(x1, x2) list_make2(x1, x2)
+#define makeList3(x1, x2, x3) list_make3(x1, x2, x3)
+#define makeList4(x1, x2, x3, x4) list_make4(x1, x2, x3, x4)
+
+#define makeListi1(x1) list_make1_int(x1)
+#define makeListi2(x1, x2) list_make2_int(x1, x2)
+
+#define makeListo1(x1) list_make1_oid(x1)
+#define makeListo2(x1, x2) list_make2_oid(x1, x2)
+
+#define lconsi(datum, list) lcons_int(datum, list)
+#define lconso(datum, list) lcons_oid(datum, list)
+
+#define lappendi(list, datum) lappend_int(list, datum)
+#define lappendo(list, datum) lappend_oid(list, datum)
+
+#define nconc(l1, l2) list_concat(l1, l2)
+
+#define nth(n, list) list_nth(list, n)
+
+#define member(datum, list) list_member(list, datum)
+#define ptrMember(datum, list) list_member_ptr(list, datum)
+#define intMember(datum, list) list_member_int(list, datum)
+#define oidMember(datum, list) list_member_oid(list, datum)
+
+/*
+ * Note that the old lremove() determined equality via pointer
+ * comparison, whereas the new list_delete() uses equal(); in order to
+ * keep the same behavior, we therefore need to map lremove() calls to
+ * list_delete_ptr() rather than list_delete()
+ */
+#define lremove(elem, list) list_delete_ptr(list, elem)
+#define LispRemove(elem, list) list_delete(list, elem)
+#define lremovei(elem, list) list_delete_int(list, elem)
+#define lremoveo(elem, list) list_delete_oid(list, elem)
+
+#define ltruncate(n, list) list_truncate(list, n)
+
+#define set_union(l1, l2) list_union(l1, l2)
+#define set_uniono(l1, l2) list_union_oid(l1, l2)
+#define set_ptrUnion(l1, l2) list_union_ptr(l1, l2)
+
+#define set_difference(l1, l2) list_difference(l1, l2)
+#define set_differenceo(l1, l2) list_difference_oid(l1, l2)
+#define set_ptrDifference(l1, l2) list_difference_ptr(l1, l2)
+
+#define equali(l1, l2) equal(l1, l2)
+#define equalo(l1, l2) equal(l1, l2)
+
+#define freeList(list) list_free(list)
+
+#define listCopy(list) list_copy(list)
+
+extern int length(List *list);
+
+#endif
+
+/*
+ * Temporary hack: we define the FastList type whether the
+ * compatibility API is enabled or not, since this allows files that
+ * don't use the compatibility API to include headers that reference
+ * the FastList type without an error.
*/
typedef struct FastList
{
- List *head;
- List *tail;
+ List *list;
} FastList;
-#define FastListInit(fl) ( (fl)->head = (fl)->tail = NIL )
-#define FastListFromList(fl, l) \
- ( (fl)->head = (l), (fl)->tail = llastnode((fl)->head) )
-#define FastListValue(fl) ( (fl)->head )
+#ifdef ENABLE_LIST_COMPAT
-#define makeFastList1(fl, x1) \
- ( (fl)->head = (fl)->tail = makeList1(x1) )
-
-extern List *lcons(void *datum, List *list);
-extern List *lconsi(int datum, List *list);
-extern List *lconso(Oid datum, List *list);
-extern List *lappend(List *list, void *datum);
-extern List *lappendi(List *list, int datum);
-extern List *lappendo(List *list, Oid datum);
-extern List *nconc(List *list1, List *list2);
+extern void FastListInit(FastList *fl);
+extern void FastListFromList(FastList *fl, List *list);
+extern List *FastListValue(FastList *fl);
+extern void makeFastList1(FastList *fl, void *elem);
extern void FastAppend(FastList *fl, void *datum);
extern void FastAppendi(FastList *fl, int datum);
extern void FastAppendo(FastList *fl, Oid datum);
extern void FastConc(FastList *fl, List *cells);
-extern void FastConcFast(FastList *fl, FastList *fl2);
-extern void *nth(int n, List *l);
-extern int length(List *list);
-extern void *llast(List *list);
-extern List *llastnode(List *list);
-extern bool member(void *datum, List *list);
-extern bool ptrMember(void *datum, List *list);
-extern bool intMember(int datum, List *list);
-extern bool oidMember(Oid datum, List *list);
-extern List *lremove(void *elem, List *list);
-extern List *LispRemove(void *elem, List *list);
-extern List *lremovei(int elem, List *list);
-extern List *ltruncate(int n, List *list);
-
-extern List *set_union(List *list1, List *list2);
-extern List *set_uniono(List *list1, List *list2);
-extern List *set_ptrUnion(List *list1, List *list2);
-extern List *set_difference(List *list1, List *list2);
-extern List *set_differenceo(List *list1, List *list2);
-extern List *set_ptrDifference(List *list1, List *list2);
-
-extern bool equali(List *list1, List *list2);
-extern bool equalo(List *list1, List *list2);
-
-extern void freeList(List *list);
-
-/* in copyfuncs.c */
-extern List *listCopy(List *list);
+extern void FastConcFast(FastList *fl1, FastList *fl2);
+
+#endif
#endif /* PG_LIST_H */