📄 list.c
字号:
prev = NULL; foreach(cell, list) { if (lfirst_int(cell) == datum) return list_delete_cell(list, cell, prev); prev = cell; } /* Didn't find a match: return the list unmodified */ return list;}/* As above, but for OIDs */List *list_delete_oid(List *list, Oid datum){ ListCell *cell; ListCell *prev; Assert(IsOidList(list)); check_list_invariants(list); prev = NULL; foreach(cell, list) { if (lfirst_oid(cell) == datum) return list_delete_cell(list, cell, prev); prev = cell; } /* Didn't find a match: return the list unmodified */ return list;}/* * Delete the first element of the list. * * This is useful to replace the Lisp-y code "list = lnext(list);" in cases * where the intent is to alter the list rather than just traverse it. * Beware that the removed cell is freed, whereas the lnext() coding leaves * the original list head intact if there's another pointer to it. */List *list_delete_first(List *list){ check_list_invariants(list); if (list == NIL) return NIL; /* would an error be better? */ return list_delete_cell(list, list_head(list), NULL);}/* * Generate the union of two lists. This is calculated by copying * list1 via list_copy(), then adding to it all the members of list2 * that aren't already in list1. * * Whether an element is already a member of the list is determined * via equal(). * * The returned list is newly-allocated, although the content of the * cells is the same (i.e. any pointed-to objects are not copied). * * NB: this function will NOT remove any duplicates that are present * in list1 (so it only performs a "union" if list1 is known unique to * start with). Also, if you are about to write "x = list_union(x, y)" * you probably want to use list_concat_unique() instead to avoid wasting * the list cells of the old x list. * * This function could probably be implemented a lot faster if it is a * performance bottleneck. */List *list_union(List *list1, List *list2){ List *result; ListCell *cell; Assert(IsPointerList(list1)); Assert(IsPointerList(list2)); result = list_copy(list1); foreach(cell, list2) { if (!list_member(result, lfirst(cell))) result = lappend(result, lfirst(cell)); } check_list_invariants(result); return result;}/* * This variant of list_union() determines duplicates via simple * pointer comparison. */List *list_union_ptr(List *list1, List *list2){ List *result; ListCell *cell; Assert(IsPointerList(list1)); Assert(IsPointerList(list2)); result = list_copy(list1); foreach(cell, list2) { if (!list_member_ptr(result, lfirst(cell))) result = lappend(result, lfirst(cell)); } check_list_invariants(result); return result;}/* * This variant of list_union() operates upon lists of integers. */List *list_union_int(List *list1, List *list2){ List *result; ListCell *cell; Assert(IsIntegerList(list1)); Assert(IsIntegerList(list2)); result = list_copy(list1); foreach(cell, list2) { if (!list_member_int(result, lfirst_int(cell))) result = lappend_int(result, lfirst_int(cell)); } check_list_invariants(result); return result;}/* * This variant of list_union() operates upon lists of OIDs. */List *list_union_oid(List *list1, List *list2){ List *result; ListCell *cell; Assert(IsOidList(list1)); Assert(IsOidList(list2)); result = list_copy(list1); foreach(cell, list2) { if (!list_member_oid(result, lfirst_oid(cell))) result = lappend_oid(result, lfirst_oid(cell)); } check_list_invariants(result); return result;}/* * Return a list that contains all the cells in list1 that are not in * list2. The returned list is freshly allocated via palloc(), but the * cells themselves point to the same objects as the cells of the * input lists. * * This variant works on lists of pointers, and determines list * membership via equal() */List *list_difference(List *list1, List *list2){ ListCell *cell; List *result = NIL; Assert(IsPointerList(list1)); Assert(IsPointerList(list2)); if (list2 == NIL) return list_copy(list1); foreach(cell, list1) { if (!list_member(list2, lfirst(cell))) result = lappend(result, lfirst(cell)); } check_list_invariants(result); return result;}/* * This variant of list_difference() determines list membership via * simple pointer equality. */List *list_difference_ptr(List *list1, List *list2){ ListCell *cell; List *result = NIL; Assert(IsPointerList(list1)); Assert(IsPointerList(list2)); if (list2 == NIL) return list_copy(list1); foreach(cell, list1) { if (!list_member_ptr(list2, lfirst(cell))) result = lappend(result, lfirst(cell)); } check_list_invariants(result); return result;}/* * This variant of list_difference() operates upon lists of integers. */List *list_difference_int(List *list1, List *list2){ ListCell *cell; List *result = NIL; Assert(IsIntegerList(list1)); Assert(IsIntegerList(list2)); if (list2 == NIL) return list_copy(list1); foreach(cell, list1) { if (!list_member_int(list2, lfirst_int(cell))) result = lappend_int(result, lfirst_int(cell)); } check_list_invariants(result); return result;}/* * This variant of list_difference() operates upon lists of OIDs. */List *list_difference_oid(List *list1, List *list2){ ListCell *cell; List *result = NIL; Assert(IsOidList(list1)); Assert(IsOidList(list2)); if (list2 == NIL) return list_copy(list1); foreach(cell, list1) { if (!list_member_oid(list2, lfirst_oid(cell))) result = lappend_oid(result, lfirst_oid(cell)); } check_list_invariants(result); return result;}/* * Append datum to list, but only if it isn't already in the list. * * Whether an element is already a member of the list is determined * via equal(). */List *list_append_unique(List *list, void *datum){ if (list_member(list, datum)) return list; else return lappend(list, datum);}/* * This variant of list_append_unique() determines list membership via * simple pointer equality. */List *list_append_unique_ptr(List *list, void *datum){ if (list_member_ptr(list, datum)) return list; else return lappend(list, datum);}/* * This variant of list_append_unique() operates upon lists of integers. */List *list_append_unique_int(List *list, int datum){ if (list_member_int(list, datum)) return list; else return lappend_int(list, datum);}/* * This variant of list_append_unique() operates upon lists of OIDs. */List *list_append_unique_oid(List *list, Oid datum){ if (list_member_oid(list, datum)) return list; else return lappend_oid(list, datum);}/* * Append to list1 each member of list2 that isn't already in list1. * * Whether an element is already a member of the list is determined * via equal(). * * This is almost the same functionality as list_union(), but list1 is * modified in-place rather than being copied. Note also that list2's cells * are not inserted in list1, so the analogy to list_concat() isn't perfect. */List *list_concat_unique(List *list1, List *list2){ ListCell *cell; Assert(IsPointerList(list1)); Assert(IsPointerList(list2)); foreach(cell, list2) { if (!list_member(list1, lfirst(cell))) list1 = lappend(list1, lfirst(cell)); } check_list_invariants(list1); return list1;}/* * This variant of list_concat_unique() determines list membership via * simple pointer equality. */List *list_concat_unique_ptr(List *list1, List *list2){ ListCell *cell; Assert(IsPointerList(list1)); Assert(IsPointerList(list2)); foreach(cell, list2) { if (!list_member_ptr(list1, lfirst(cell))) list1 = lappend(list1, lfirst(cell)); } check_list_invariants(list1); return list1;}/* * This variant of list_concat_unique() operates upon lists of integers. */List *list_concat_unique_int(List *list1, List *list2){ ListCell *cell; Assert(IsIntegerList(list1)); Assert(IsIntegerList(list2)); foreach(cell, list2) { if (!list_member_int(list1, lfirst_int(cell))) list1 = lappend_int(list1, lfirst_int(cell)); } check_list_invariants(list1); return list1;}/* * This variant of list_concat_unique() operates upon lists of OIDs. */List *list_concat_unique_oid(List *list1, List *list2){ ListCell *cell; Assert(IsOidList(list1)); Assert(IsOidList(list2)); foreach(cell, list2) { if (!list_member_oid(list1, lfirst_oid(cell))) list1 = lappend_oid(list1, lfirst_oid(cell)); } check_list_invariants(list1); return list1;}/* * Free all storage in a list, and optionally the pointed-to elements */static voidlist_free_private(List *list, bool deep){ ListCell *cell; check_list_invariants(list); cell = list_head(list); while (cell != NULL) { ListCell *tmp = cell; cell = lnext(cell); if (deep) pfree(lfirst(tmp)); pfree(tmp); } if (list) pfree(list);}/* * Free all the cells of the list, as well as the list itself. Any * objects that are pointed-to by the cells of the list are NOT * free'd. * * On return, the argument to this function has been freed, so the * caller would be wise to set it to NIL for safety's sake. */voidlist_free(List *list){ list_free_private(list, false);}/* * Free all the cells of the list, the list itself, and all the * objects pointed-to by the cells of the list (each element in the * list must contain a pointer to a palloc()'d region of memory!) * * On return, the argument to this function has been freed, so the * caller would be wise to set it to NIL for safety's sake. */voidlist_free_deep(List *list){ /* * A "deep" free operation only makes sense on a list of pointers. */ Assert(IsPointerList(list)); list_free_private(list, true);}/* * Return a shallow copy of the specified list. */List *list_copy(List *oldlist){ List *newlist; ListCell *newlist_prev; ListCell *oldlist_cur; if (oldlist == NIL) return NIL; newlist = new_list(oldlist->type); newlist->length = oldlist->length; /* * Copy over the data in the first cell; new_list() has already allocated * the head cell itself */ newlist->head->data = oldlist->head->data; newlist_prev = newlist->head; oldlist_cur = oldlist->head->next; while (oldlist_cur) { ListCell *newlist_cur; newlist_cur = (ListCell *) palloc(sizeof(*newlist_cur)); newlist_cur->data = oldlist_cur->data; newlist_prev->next = newlist_cur; newlist_prev = newlist_cur; oldlist_cur = oldlist_cur->next; } newlist_prev->next = NULL; newlist->tail = newlist_prev; check_list_invariants(newlist); return newlist;}/* * Return a shallow copy of the specified list, without the first N elements. */List *list_copy_tail(List *oldlist, int nskip){ List *newlist; ListCell *newlist_prev; ListCell *oldlist_cur; if (nskip < 0) nskip = 0; /* would it be better to elog? */ if (oldlist == NIL || nskip >= oldlist->length) return NIL; newlist = new_list(oldlist->type); newlist->length = oldlist->length - nskip; /* * Skip over the unwanted elements. */ oldlist_cur = oldlist->head; while (nskip-- > 0) oldlist_cur = oldlist_cur->next; /* * Copy over the data in the first remaining cell; new_list() has already * allocated the head cell itself */ newlist->head->data = oldlist_cur->data; newlist_prev = newlist->head; oldlist_cur = oldlist_cur->next; while (oldlist_cur) { ListCell *newlist_cur; newlist_cur = (ListCell *) palloc(sizeof(*newlist_cur)); newlist_cur->data = oldlist_cur->data; newlist_prev->next = newlist_cur; newlist_prev = newlist_cur; oldlist_cur = oldlist_cur->next; } newlist_prev->next = NULL; newlist->tail = newlist_prev; check_list_invariants(newlist); return newlist;}/* * When using non-GCC compilers, we can't define these as inline * functions in pg_list.h, so they are defined here. * * TODO: investigate supporting inlining for some non-GCC compilers. */#ifndef __GNUC__ListCell *list_head(List *l){ return l ? l->head : NULL;}ListCell *list_tail(List *l){ return l ? l->tail : NULL;}intlist_length(List *l){ return l ? l->length : 0;}#endif /* ! __GNUC__ *//* * Temporary compatibility functions * * In order to avoid warnings for these function definitions, we need * to include a prototype here as well as in pg_list.h. That's because * we don't enable list API compatibility in list.c, so we * don't see the prototypes for these functions. *//* * Given a list, return its length. This is merely defined for the * sake of backward compatibility: we can't afford to define a macro * called "length", so it must be a function. New code should use the * list_length() macro in order to avoid the overhead of a function * call. */int length(List *list);intlength(List *list){ return list_length(list);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -