Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * list.c
4 : : * implementation for PostgreSQL generic list package
5 : : *
6 : : * See comments in pg_list.h.
7 : : *
8 : : *
9 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
10 : : * Portions Copyright (c) 1994, Regents of the University of California
11 : : *
12 : : *
13 : : * IDENTIFICATION
14 : : * src/backend/nodes/list.c
15 : : *
16 : : *-------------------------------------------------------------------------
17 : : */
18 : : #include "postgres.h"
19 : :
20 : : #include "common/int.h"
21 : : #include "nodes/pg_list.h"
22 : : #include "port/pg_bitutils.h"
23 : : #include "utils/memdebug.h"
24 : : #include "utils/memutils.h"
25 : :
26 : :
27 : : /*
28 : : * The previous List implementation, since it used a separate palloc chunk
29 : : * for each cons cell, had the property that adding or deleting list cells
30 : : * did not move the storage of other existing cells in the list. Quite a
31 : : * bit of existing code depended on that, by retaining ListCell pointers
32 : : * across such operations on a list. There is no such guarantee in this
33 : : * implementation, so instead we have debugging support that is meant to
34 : : * help flush out now-broken assumptions. Defining DEBUG_LIST_MEMORY_USAGE
35 : : * while building this file causes the List operations to forcibly move
36 : : * all cells in a list whenever a cell is added or deleted. In combination
37 : : * with MEMORY_CONTEXT_CHECKING and/or Valgrind, this can usually expose
38 : : * broken code. It's a bit expensive though, as there's many more palloc
39 : : * cycles and a lot more data-copying than in a default build.
40 : : *
41 : : * By default, we enable this when building for Valgrind.
42 : : */
43 : : #ifdef USE_VALGRIND
44 : : #define DEBUG_LIST_MEMORY_USAGE
45 : : #endif
46 : :
47 : : /* Overhead for the fixed part of a List header, measured in ListCells */
48 : : #define LIST_HEADER_OVERHEAD \
49 : : ((int) ((offsetof(List, initial_elements) - 1) / sizeof(ListCell) + 1))
50 : :
51 : : /*
52 : : * Macros to simplify writing assertions about the type of a list; a
53 : : * NIL list is considered to be an empty list of any type.
54 : : */
55 : : #define IsPointerList(l) ((l) == NIL || IsA((l), List))
56 : : #define IsIntegerList(l) ((l) == NIL || IsA((l), IntList))
57 : : #define IsOidList(l) ((l) == NIL || IsA((l), OidList))
58 : : #define IsXidList(l) ((l) == NIL || IsA((l), XidList))
59 : :
60 : : #ifdef USE_ASSERT_CHECKING
61 : : /*
62 : : * Check that the specified List is valid (so far as we can tell).
63 : : */
64 : : static void
65 : : check_list_invariants(const List *list)
66 : : {
67 : : if (list == NIL)
68 : : return;
69 : :
70 : : Assert(list->length > 0);
71 : : Assert(list->length <= list->max_length);
72 : : Assert(list->elements != NULL);
73 : :
74 : : Assert(list->type == T_List ||
75 : : list->type == T_IntList ||
76 : : list->type == T_OidList ||
77 : : list->type == T_XidList);
78 : : }
79 : : #else
80 : : #define check_list_invariants(l) ((void) 0)
81 : : #endif /* USE_ASSERT_CHECKING */
82 : :
83 : : /*
84 : : * Return a freshly allocated List with room for at least min_size cells.
85 : : *
86 : : * Since empty non-NIL lists are invalid, new_list() sets the initial length
87 : : * to min_size, effectively marking that number of cells as valid; the caller
88 : : * is responsible for filling in their data.
89 : : */
90 : : static List *
91 : 84942797 : new_list(NodeTag type, int min_size)
92 : : {
93 : : List *newlist;
94 : : int max_size;
95 : :
96 : : Assert(min_size > 0);
97 : :
98 : : /*
99 : : * We allocate all the requested cells, and possibly some more, as part of
100 : : * the same palloc request as the List header. This is a big win for the
101 : : * typical case of short fixed-length lists. It can lose if we allocate a
102 : : * moderately long list and then it gets extended; we'll be wasting more
103 : : * initial_elements[] space than if we'd made the header small. However,
104 : : * rounding up the request as we do in the normal code path provides some
105 : : * defense against small extensions.
106 : : */
107 : :
108 : : #ifndef DEBUG_LIST_MEMORY_USAGE
109 : :
110 : : /*
111 : : * Normally, we set up a list with some extra cells, to allow it to grow
112 : : * without a repalloc. Prefer cell counts chosen to make the total
113 : : * allocation a power-of-2, since palloc would round it up to that anyway.
114 : : * (That stops being true for very large allocations, but very long lists
115 : : * are infrequent, so it doesn't seem worth special logic for such cases.)
116 : : *
117 : : * The minimum allocation is 8 ListCell units, providing either 4 or 5
118 : : * available ListCells depending on the machine's word width. Counting
119 : : * palloc's overhead, this uses the same amount of space as a one-cell
120 : : * list did in the old implementation, and less space for any longer list.
121 : : *
122 : : * We needn't worry about integer overflow; no caller passes min_size
123 : : * that's more than twice the size of an existing list, so the size limits
124 : : * within palloc will ensure that we don't overflow here.
125 : : */
126 : 84942797 : max_size = pg_nextpower2_32(Max(8, min_size + LIST_HEADER_OVERHEAD));
127 : 84942797 : max_size -= LIST_HEADER_OVERHEAD;
128 : : #else
129 : :
130 : : /*
131 : : * For debugging, don't allow any extra space. This forces any cell
132 : : * addition to go through enlarge_list() and thus move the existing data.
133 : : */
134 : : max_size = min_size;
135 : : #endif
136 : :
137 : 84942797 : newlist = (List *) palloc(offsetof(List, initial_elements) +
138 : : max_size * sizeof(ListCell));
139 : 84942797 : newlist->type = type;
140 : 84942797 : newlist->length = min_size;
141 : 84942797 : newlist->max_length = max_size;
142 : 84942797 : newlist->elements = newlist->initial_elements;
143 : :
144 : 84942797 : return newlist;
145 : : }
146 : :
147 : : /*
148 : : * Enlarge an existing non-NIL List to have room for at least min_size cells.
149 : : *
150 : : * This does *not* update list->length, as some callers would find that
151 : : * inconvenient. (list->length had better be the correct number of existing
152 : : * valid cells, though.)
153 : : */
154 : : static void
155 : 4079404 : enlarge_list(List *list, int min_size)
156 : : {
157 : : int new_max_len;
158 : :
159 : : Assert(min_size > list->max_length); /* else we shouldn't be here */
160 : :
161 : : #ifndef DEBUG_LIST_MEMORY_USAGE
162 : :
163 : : /*
164 : : * As above, we prefer power-of-two total allocations; but here we need
165 : : * not account for list header overhead.
166 : : */
167 : :
168 : : /* clamp the minimum value to 16, a semi-arbitrary small power of 2 */
169 : 4079404 : new_max_len = pg_nextpower2_32(Max(16, min_size));
170 : :
171 : : #else
172 : : /* As above, don't allocate anything extra */
173 : : new_max_len = min_size;
174 : : #endif
175 : :
176 [ + + ]: 4079404 : if (list->elements == list->initial_elements)
177 : : {
178 : : /*
179 : : * Replace original in-line allocation with a separate palloc block.
180 : : * Ensure it is in the same memory context as the List header. (The
181 : : * previous List implementation did not offer any guarantees about
182 : : * keeping all list cells in the same context, but it seems reasonable
183 : : * to create such a guarantee now.)
184 : : */
185 : 2565997 : list->elements = (ListCell *)
186 : 2565997 : MemoryContextAlloc(GetMemoryChunkContext(list),
187 : : new_max_len * sizeof(ListCell));
188 : 2565997 : memcpy(list->elements, list->initial_elements,
189 : 2565997 : list->length * sizeof(ListCell));
190 : :
191 : : /*
192 : : * We must not move the list header, so it's unsafe to try to reclaim
193 : : * the initial_elements[] space via repalloc. In debugging builds,
194 : : * however, we can clear that space and/or mark it inaccessible.
195 : : * (wipe_mem includes VALGRIND_MAKE_MEM_NOACCESS.)
196 : : */
197 : : #ifdef CLOBBER_FREED_MEMORY
198 : : wipe_mem(list->initial_elements,
199 : : list->max_length * sizeof(ListCell));
200 : : #else
201 : : VALGRIND_MAKE_MEM_NOACCESS(list->initial_elements,
202 : : list->max_length * sizeof(ListCell));
203 : : #endif
204 : : }
205 : : else
206 : : {
207 : : #ifndef DEBUG_LIST_MEMORY_USAGE
208 : : /* Normally, let repalloc deal with enlargement */
209 : 1513407 : list->elements = repalloc_array(list->elements, ListCell, new_max_len);
210 : : #else
211 : : /*
212 : : * repalloc() might enlarge the space in-place, which we don't want
213 : : * for debugging purposes, so forcibly move the data somewhere else.
214 : : */
215 : : ListCell *newelements;
216 : :
217 : : newelements = (ListCell *)
218 : : MemoryContextAlloc(GetMemoryChunkContext(list),
219 : : new_max_len * sizeof(ListCell));
220 : : memcpy(newelements, list->elements,
221 : : list->length * sizeof(ListCell));
222 : : pfree(list->elements);
223 : : list->elements = newelements;
224 : : #endif
225 : : }
226 : :
227 : 4079404 : list->max_length = new_max_len;
228 : 4079404 : }
229 : :
230 : : /*
231 : : * Convenience functions to construct short Lists from given values.
232 : : * (These are normally invoked via the list_makeN macros.)
233 : : */
234 : : List *
235 : 9571207 : list_make1_impl(NodeTag t, ListCell datum1)
236 : : {
237 : 9571207 : List *list = new_list(t, 1);
238 : :
239 : 9571207 : list->elements[0] = datum1;
240 : : check_list_invariants(list);
241 : 9571207 : return list;
242 : : }
243 : :
244 : : List *
245 : 1165707 : list_make2_impl(NodeTag t, ListCell datum1, ListCell datum2)
246 : : {
247 : 1165707 : List *list = new_list(t, 2);
248 : :
249 : 1165707 : list->elements[0] = datum1;
250 : 1165707 : list->elements[1] = datum2;
251 : : check_list_invariants(list);
252 : 1165707 : return list;
253 : : }
254 : :
255 : : List *
256 : 5009 : list_make3_impl(NodeTag t, ListCell datum1, ListCell datum2,
257 : : ListCell datum3)
258 : : {
259 : 5009 : List *list = new_list(t, 3);
260 : :
261 : 5009 : list->elements[0] = datum1;
262 : 5009 : list->elements[1] = datum2;
263 : 5009 : list->elements[2] = datum3;
264 : : check_list_invariants(list);
265 : 5009 : return list;
266 : : }
267 : :
268 : : List *
269 : 131 : list_make4_impl(NodeTag t, ListCell datum1, ListCell datum2,
270 : : ListCell datum3, ListCell datum4)
271 : : {
272 : 131 : List *list = new_list(t, 4);
273 : :
274 : 131 : list->elements[0] = datum1;
275 : 131 : list->elements[1] = datum2;
276 : 131 : list->elements[2] = datum3;
277 : 131 : list->elements[3] = datum4;
278 : : check_list_invariants(list);
279 : 131 : return list;
280 : : }
281 : :
282 : : List *
283 : 171 : list_make5_impl(NodeTag t, ListCell datum1, ListCell datum2,
284 : : ListCell datum3, ListCell datum4, ListCell datum5)
285 : : {
286 : 171 : List *list = new_list(t, 5);
287 : :
288 : 171 : list->elements[0] = datum1;
289 : 171 : list->elements[1] = datum2;
290 : 171 : list->elements[2] = datum3;
291 : 171 : list->elements[3] = datum4;
292 : 171 : list->elements[4] = datum5;
293 : : check_list_invariants(list);
294 : 171 : return list;
295 : : }
296 : :
297 : : /*
298 : : * Make room for a new head cell in the given (non-NIL) list.
299 : : *
300 : : * The data in the new head cell is undefined; the caller should be
301 : : * sure to fill it in
302 : : */
303 : : static void
304 : 2263889 : new_head_cell(List *list)
305 : : {
306 : : /* Enlarge array if necessary */
307 [ + + ]: 2263889 : if (list->length >= list->max_length)
308 : 39871 : enlarge_list(list, list->length + 1);
309 : : /* Now shove the existing data over */
310 : 2263889 : memmove(&list->elements[1], &list->elements[0],
311 : 2263889 : list->length * sizeof(ListCell));
312 : 2263889 : list->length++;
313 : 2263889 : }
314 : :
315 : : /*
316 : : * Make room for a new tail cell in the given (non-NIL) list.
317 : : *
318 : : * The data in the new tail cell is undefined; the caller should be
319 : : * sure to fill it in
320 : : */
321 : : static void
322 : 67948057 : new_tail_cell(List *list)
323 : : {
324 : : /* Enlarge array if necessary */
325 [ + + ]: 67948057 : if (list->length >= list->max_length)
326 : 4019158 : enlarge_list(list, list->length + 1);
327 : 67948057 : list->length++;
328 : 67948057 : }
329 : :
330 : : /*
331 : : * Append a pointer to the list. A pointer to the modified list is
332 : : * returned. Note that this function may or may not destructively
333 : : * modify the list; callers should always use this function's return
334 : : * value, rather than continuing to use the pointer passed as the
335 : : * first argument.
336 : : */
337 : : List *
338 : 104332206 : lappend(List *list, void *datum)
339 : : {
340 : : Assert(IsPointerList(list));
341 : :
342 [ + + ]: 104332206 : if (list == NIL)
343 : 43648241 : list = new_list(T_List, 1);
344 : : else
345 : 60683965 : new_tail_cell(list);
346 : :
347 : 104332206 : llast(list) = datum;
348 : : check_list_invariants(list);
349 : 104332206 : return list;
350 : : }
351 : :
352 : : /*
353 : : * Append an integer to the specified list. See lappend()
354 : : */
355 : : List *
356 : 6910848 : lappend_int(List *list, int datum)
357 : : {
358 : : Assert(IsIntegerList(list));
359 : :
360 [ + + ]: 6910848 : if (list == NIL)
361 : 1248403 : list = new_list(T_IntList, 1);
362 : : else
363 : 5662445 : new_tail_cell(list);
364 : :
365 : 6910848 : llast_int(list) = datum;
366 : : check_list_invariants(list);
367 : 6910848 : return list;
368 : : }
369 : :
370 : : /*
371 : : * Append an OID to the specified list. See lappend()
372 : : */
373 : : List *
374 : 5435009 : lappend_oid(List *list, Oid datum)
375 : : {
376 : : Assert(IsOidList(list));
377 : :
378 [ + + ]: 5435009 : if (list == NIL)
379 : 3833392 : list = new_list(T_OidList, 1);
380 : : else
381 : 1601617 : new_tail_cell(list);
382 : :
383 : 5435009 : llast_oid(list) = datum;
384 : : check_list_invariants(list);
385 : 5435009 : return list;
386 : : }
387 : :
388 : : /*
389 : : * Append a TransactionId to the specified list. See lappend()
390 : : */
391 : : List *
392 : 87 : lappend_xid(List *list, TransactionId datum)
393 : : {
394 : : Assert(IsXidList(list));
395 : :
396 [ + + ]: 87 : if (list == NIL)
397 : 57 : list = new_list(T_XidList, 1);
398 : : else
399 : 30 : new_tail_cell(list);
400 : :
401 : 87 : llast_xid(list) = datum;
402 : : check_list_invariants(list);
403 : 87 : return list;
404 : : }
405 : :
406 : : /*
407 : : * Make room for a new cell at position 'pos' (measured from 0).
408 : : * The data in the cell is left undefined, and must be filled in by the
409 : : * caller. 'list' is assumed to be non-NIL, and 'pos' must be a valid
410 : : * list position, ie, 0 <= pos <= list's length.
411 : : * Returns address of the new cell.
412 : : */
413 : : static ListCell *
414 : 744214 : insert_new_cell(List *list, int pos)
415 : : {
416 : : Assert(pos >= 0 && pos <= list->length);
417 : :
418 : : /* Enlarge array if necessary */
419 [ + + ]: 744214 : if (list->length >= list->max_length)
420 : 1323 : enlarge_list(list, list->length + 1);
421 : : /* Now shove the existing data over */
422 [ + + ]: 744214 : if (pos < list->length)
423 : 321857 : memmove(&list->elements[pos + 1], &list->elements[pos],
424 : 321857 : (list->length - pos) * sizeof(ListCell));
425 : 744214 : list->length++;
426 : :
427 : 744214 : return &list->elements[pos];
428 : : }
429 : :
430 : : /*
431 : : * Insert the given datum at position 'pos' (measured from 0) in the list.
432 : : * 'pos' must be valid, ie, 0 <= pos <= list's length.
433 : : *
434 : : * Note that this takes time proportional to the distance to the end of the
435 : : * list, since the following entries must be moved.
436 : : */
437 : : List *
438 : 2426048 : list_insert_nth(List *list, int pos, void *datum)
439 : : {
440 [ + + ]: 2426048 : if (list == NIL)
441 : : {
442 : : Assert(pos == 0);
443 : 1681834 : return list_make1(datum);
444 : : }
445 : : Assert(IsPointerList(list));
446 : 744214 : lfirst(insert_new_cell(list, pos)) = datum;
447 : : check_list_invariants(list);
448 : 744214 : return list;
449 : : }
450 : :
451 : : List *
452 : 0 : list_insert_nth_int(List *list, int pos, int datum)
453 : : {
454 [ # # ]: 0 : if (list == NIL)
455 : : {
456 : : Assert(pos == 0);
457 : 0 : return list_make1_int(datum);
458 : : }
459 : : Assert(IsIntegerList(list));
460 : 0 : lfirst_int(insert_new_cell(list, pos)) = datum;
461 : : check_list_invariants(list);
462 : 0 : return list;
463 : : }
464 : :
465 : : List *
466 : 0 : list_insert_nth_oid(List *list, int pos, Oid datum)
467 : : {
468 [ # # ]: 0 : if (list == NIL)
469 : : {
470 : : Assert(pos == 0);
471 : 0 : return list_make1_oid(datum);
472 : : }
473 : : Assert(IsOidList(list));
474 : 0 : lfirst_oid(insert_new_cell(list, pos)) = datum;
475 : : check_list_invariants(list);
476 : 0 : return list;
477 : : }
478 : :
479 : : /*
480 : : * Prepend a new element to the list. A pointer to the modified list
481 : : * is returned. Note that this function may or may not destructively
482 : : * modify the list; callers should always use this function's return
483 : : * value, rather than continuing to use the pointer passed as the
484 : : * second argument.
485 : : *
486 : : * Note that this takes time proportional to the length of the list,
487 : : * since the existing entries must be moved.
488 : : *
489 : : * Caution: before Postgres 8.0, the original List was unmodified and
490 : : * could be considered to retain its separate identity. This is no longer
491 : : * the case.
492 : : */
493 : : List *
494 : 5405311 : lcons(void *datum, List *list)
495 : : {
496 : : Assert(IsPointerList(list));
497 : :
498 [ + + ]: 5405311 : if (list == NIL)
499 : 3178671 : list = new_list(T_List, 1);
500 : : else
501 : 2226640 : new_head_cell(list);
502 : :
503 : 5405311 : linitial(list) = datum;
504 : : check_list_invariants(list);
505 : 5405311 : return list;
506 : : }
507 : :
508 : : /*
509 : : * Prepend an integer to the list. See lcons()
510 : : */
511 : : List *
512 : 17234 : lcons_int(int datum, List *list)
513 : : {
514 : : Assert(IsIntegerList(list));
515 : :
516 [ + + ]: 17234 : if (list == NIL)
517 : 7805 : list = new_list(T_IntList, 1);
518 : : else
519 : 9429 : new_head_cell(list);
520 : :
521 : 17234 : linitial_int(list) = datum;
522 : : check_list_invariants(list);
523 : 17234 : return list;
524 : : }
525 : :
526 : : /*
527 : : * Prepend an OID to the list. See lcons()
528 : : */
529 : : List *
530 : 29991 : lcons_oid(Oid datum, List *list)
531 : : {
532 : : Assert(IsOidList(list));
533 : :
534 [ + + ]: 29991 : if (list == NIL)
535 : 2171 : list = new_list(T_OidList, 1);
536 : : else
537 : 27820 : new_head_cell(list);
538 : :
539 : 29991 : linitial_oid(list) = datum;
540 : : check_list_invariants(list);
541 : 29991 : return list;
542 : : }
543 : :
544 : : /*
545 : : * Concatenate list2 to the end of list1, and return list1.
546 : : *
547 : : * This is equivalent to lappend'ing each element of list2, in order, to list1.
548 : : * list1 is destructively changed, list2 is not. (However, in the case of
549 : : * pointer lists, list1 and list2 will point to the same structures.)
550 : : *
551 : : * Callers should be sure to use the return value as the new pointer to the
552 : : * concatenated list: the 'list1' input pointer may or may not be the same
553 : : * as the returned pointer.
554 : : *
555 : : * Note that this takes at least time proportional to the length of list2.
556 : : * It'd typically be the case that we have to enlarge list1's storage,
557 : : * probably adding time proportional to the length of list1.
558 : : */
559 : : List *
560 : 5219053 : list_concat(List *list1, const List *list2)
561 : : {
562 : : int new_len;
563 : :
564 [ + + ]: 5219053 : if (list1 == NIL)
565 : 3697172 : return list_copy(list2);
566 [ + + ]: 1521881 : if (list2 == NIL)
567 : 891316 : return list1;
568 : :
569 : : Assert(list1->type == list2->type);
570 : :
571 : 630565 : new_len = list1->length + list2->length;
572 : : /* Enlarge array if necessary */
573 [ + + ]: 630565 : if (new_len > list1->max_length)
574 : 19052 : enlarge_list(list1, new_len);
575 : :
576 : : /* Even if list1 == list2, using memcpy should be safe here */
577 : 630565 : memcpy(&list1->elements[list1->length], &list2->elements[0],
578 : 630565 : list2->length * sizeof(ListCell));
579 : 630565 : list1->length = new_len;
580 : :
581 : : check_list_invariants(list1);
582 : 630565 : return list1;
583 : : }
584 : :
585 : : /*
586 : : * Form a new list by concatenating the elements of list1 and list2.
587 : : *
588 : : * Neither input list is modified. (However, if they are pointer lists,
589 : : * the output list will point to the same structures.)
590 : : *
591 : : * This is equivalent to, but more efficient than,
592 : : * list_concat(list_copy(list1), list2).
593 : : * Note that some pre-v13 code might list_copy list2 as well, but that's
594 : : * pointless now.
595 : : */
596 : : List *
597 : 871535 : list_concat_copy(const List *list1, const List *list2)
598 : : {
599 : : List *result;
600 : : int new_len;
601 : :
602 [ + + ]: 871535 : if (list1 == NIL)
603 : 374880 : return list_copy(list2);
604 [ + + ]: 496655 : if (list2 == NIL)
605 : 415626 : return list_copy(list1);
606 : :
607 : : Assert(list1->type == list2->type);
608 : :
609 : 81029 : new_len = list1->length + list2->length;
610 : 81029 : result = new_list(list1->type, new_len);
611 : 81029 : memcpy(result->elements, list1->elements,
612 : 81029 : list1->length * sizeof(ListCell));
613 : 81029 : memcpy(result->elements + list1->length, list2->elements,
614 : 81029 : list2->length * sizeof(ListCell));
615 : :
616 : : check_list_invariants(result);
617 : 81029 : return result;
618 : : }
619 : :
620 : : /*
621 : : * Truncate 'list' to contain no more than 'new_size' elements. This
622 : : * modifies the list in-place! Despite this, callers should use the
623 : : * pointer returned by this function to refer to the newly truncated
624 : : * list -- it may or may not be the same as the pointer that was
625 : : * passed.
626 : : *
627 : : * Note that any cells removed by list_truncate() are NOT pfree'd.
628 : : */
629 : : List *
630 : 536574 : list_truncate(List *list, int new_size)
631 : : {
632 [ + + ]: 536574 : if (new_size <= 0)
633 : 58819 : return NIL; /* truncate to zero length */
634 : :
635 : : /* If asked to effectively extend the list, do nothing */
636 [ + + ]: 477755 : if (new_size < list_length(list))
637 : 132609 : list->length = new_size;
638 : :
639 : : /*
640 : : * Note: unlike the individual-list-cell deletion functions, we don't move
641 : : * the list cells to new storage, even in DEBUG_LIST_MEMORY_USAGE mode.
642 : : * This is because none of them can move in this operation, so just like
643 : : * in the old cons-cell-based implementation, this function doesn't
644 : : * invalidate any pointers to cells of the list. This is also the reason
645 : : * for not wiping the memory of the deleted cells: the old code didn't
646 : : * free them either. Perhaps later we'll tighten this up.
647 : : */
648 : :
649 : 477755 : return list;
650 : : }
651 : :
652 : : /*
653 : : * Return true iff 'datum' is a member of the list. Equality is
654 : : * determined via equal(), so callers should ensure that they pass a
655 : : * Node as 'datum'.
656 : : *
657 : : * This does a simple linear search --- avoid using it on long lists.
658 : : */
659 : : bool
660 : 882449 : list_member(const List *list, const void *datum)
661 : : {
662 : : const ListCell *cell;
663 : :
664 : : Assert(IsPointerList(list));
665 : : check_list_invariants(list);
666 : :
667 [ + + + + : 1554850 : foreach(cell, list)
+ + ]
668 : : {
669 [ + + ]: 774138 : if (equal(lfirst(cell), datum))
670 : 101737 : return true;
671 : : }
672 : :
673 : 780712 : return false;
674 : : }
675 : :
676 : : /*
677 : : * Return true iff 'datum' is a member of the list. Equality is
678 : : * determined by using simple pointer comparison.
679 : : */
680 : : bool
681 : 465296 : list_member_ptr(const List *list, const void *datum)
682 : : {
683 : : const ListCell *cell;
684 : :
685 : : Assert(IsPointerList(list));
686 : : check_list_invariants(list);
687 : :
688 [ + + + + : 752054 : foreach(cell, list)
+ + ]
689 : : {
690 [ + + ]: 465560 : if (lfirst(cell) == datum)
691 : 178802 : return true;
692 : : }
693 : :
694 : 286494 : return false;
695 : : }
696 : :
697 : : /*
698 : : * Return true iff the integer 'datum' is a member of the list.
699 : : */
700 : : bool
701 : 89219 : list_member_int(const List *list, int datum)
702 : : {
703 : : const ListCell *cell;
704 : :
705 : : Assert(IsIntegerList(list));
706 : : check_list_invariants(list);
707 : :
708 [ + + + + : 5036409 : foreach(cell, list)
+ + ]
709 : : {
710 [ + + ]: 4962523 : if (lfirst_int(cell) == datum)
711 : 15333 : return true;
712 : : }
713 : :
714 : 73886 : return false;
715 : : }
716 : :
717 : : /*
718 : : * Return true iff the OID 'datum' is a member of the list.
719 : : */
720 : : bool
721 : 63473276 : list_member_oid(const List *list, Oid datum)
722 : : {
723 : : const ListCell *cell;
724 : :
725 : : Assert(IsOidList(list));
726 : : check_list_invariants(list);
727 : :
728 [ + + + + : 67133689 : foreach(cell, list)
+ + ]
729 : : {
730 [ + + ]: 4585940 : if (lfirst_oid(cell) == datum)
731 : 925527 : return true;
732 : : }
733 : :
734 : 62547749 : return false;
735 : : }
736 : :
737 : : /*
738 : : * Return true iff the TransactionId 'datum' is a member of the list.
739 : : */
740 : : bool
741 : 170945 : list_member_xid(const List *list, TransactionId datum)
742 : : {
743 : : const ListCell *cell;
744 : :
745 : : Assert(IsXidList(list));
746 : : check_list_invariants(list);
747 : :
748 [ + + + + : 211795 : foreach(cell, list)
+ + ]
749 : : {
750 [ + + ]: 211708 : if (lfirst_xid(cell) == datum)
751 : 170858 : return true;
752 : : }
753 : :
754 : 87 : return false;
755 : : }
756 : :
757 : : /*
758 : : * Delete the n'th cell (counting from 0) in list.
759 : : *
760 : : * The List is pfree'd if this was the last member.
761 : : *
762 : : * Note that this takes time proportional to the distance to the end of the
763 : : * list, since the following entries must be moved.
764 : : */
765 : : List *
766 : 2801858 : list_delete_nth_cell(List *list, int n)
767 : : {
768 : : check_list_invariants(list);
769 : :
770 : : Assert(n >= 0 && n < list->length);
771 : :
772 : : /*
773 : : * If we're about to delete the last node from the list, free the whole
774 : : * list instead and return NIL, which is the only valid representation of
775 : : * a zero-length list.
776 : : */
777 [ + + ]: 2801858 : if (list->length == 1)
778 : : {
779 : 1397351 : list_free(list);
780 : 1397351 : return NIL;
781 : : }
782 : :
783 : : /*
784 : : * Otherwise, we normally just collapse out the removed element. But for
785 : : * debugging purposes, move the whole list contents someplace else.
786 : : *
787 : : * (Note that we *must* keep the contents in the same memory context.)
788 : : */
789 : : #ifndef DEBUG_LIST_MEMORY_USAGE
790 : 1404507 : memmove(&list->elements[n], &list->elements[n + 1],
791 : 1404507 : (list->length - 1 - n) * sizeof(ListCell));
792 : 1404507 : list->length--;
793 : : #else
794 : : {
795 : : ListCell *newelems;
796 : : int newmaxlen = list->length - 1;
797 : :
798 : : newelems = (ListCell *)
799 : : MemoryContextAlloc(GetMemoryChunkContext(list),
800 : : newmaxlen * sizeof(ListCell));
801 : : memcpy(newelems, list->elements, n * sizeof(ListCell));
802 : : memcpy(&newelems[n], &list->elements[n + 1],
803 : : (list->length - 1 - n) * sizeof(ListCell));
804 : : if (list->elements != list->initial_elements)
805 : : pfree(list->elements);
806 : : else
807 : : {
808 : : /*
809 : : * As in enlarge_list(), clear the initial_elements[] space and/or
810 : : * mark it inaccessible.
811 : : */
812 : : #ifdef CLOBBER_FREED_MEMORY
813 : : wipe_mem(list->initial_elements,
814 : : list->max_length * sizeof(ListCell));
815 : : #else
816 : : VALGRIND_MAKE_MEM_NOACCESS(list->initial_elements,
817 : : list->max_length * sizeof(ListCell));
818 : : #endif
819 : : }
820 : : list->elements = newelems;
821 : : list->max_length = newmaxlen;
822 : : list->length--;
823 : : check_list_invariants(list);
824 : : }
825 : : #endif
826 : :
827 : 1404507 : return list;
828 : : }
829 : :
830 : : /*
831 : : * Delete 'cell' from 'list'.
832 : : *
833 : : * The List is pfree'd if this was the last member. However, we do not
834 : : * touch any data the cell might've been pointing to.
835 : : *
836 : : * Note that this takes time proportional to the distance to the end of the
837 : : * list, since the following entries must be moved.
838 : : */
839 : : List *
840 : 1402192 : list_delete_cell(List *list, ListCell *cell)
841 : : {
842 : 1402192 : return list_delete_nth_cell(list, cell - list->elements);
843 : : }
844 : :
845 : : /*
846 : : * Delete the first cell in list that matches datum, if any.
847 : : * Equality is determined via equal().
848 : : *
849 : : * This does a simple linear search --- avoid using it on long lists.
850 : : */
851 : : List *
852 : 3798 : list_delete(List *list, void *datum)
853 : : {
854 : : ListCell *cell;
855 : :
856 : : Assert(IsPointerList(list));
857 : : check_list_invariants(list);
858 : :
859 [ + + + - : 4040 : foreach(cell, list)
+ + ]
860 : : {
861 [ + + ]: 4037 : if (equal(lfirst(cell), datum))
862 : 3795 : return list_delete_cell(list, cell);
863 : : }
864 : :
865 : : /* Didn't find a match: return the list unmodified */
866 : 3 : return list;
867 : : }
868 : :
869 : : /* As above, but use simple pointer equality */
870 : : List *
871 : 1387973 : list_delete_ptr(List *list, void *datum)
872 : : {
873 : : ListCell *cell;
874 : :
875 : : Assert(IsPointerList(list));
876 : : check_list_invariants(list);
877 : :
878 [ + - + - : 1388343 : foreach(cell, list)
+ - ]
879 : : {
880 [ + + ]: 1388343 : if (lfirst(cell) == datum)
881 : 1387973 : return list_delete_cell(list, cell);
882 : : }
883 : :
884 : : /* Didn't find a match: return the list unmodified */
885 : 0 : return list;
886 : : }
887 : :
888 : : /* As above, but for integers */
889 : : List *
890 : 144 : list_delete_int(List *list, int datum)
891 : : {
892 : : ListCell *cell;
893 : :
894 : : Assert(IsIntegerList(list));
895 : : check_list_invariants(list);
896 : :
897 [ + - + - : 149 : foreach(cell, list)
+ - ]
898 : : {
899 [ + + ]: 149 : if (lfirst_int(cell) == datum)
900 : 144 : return list_delete_cell(list, cell);
901 : : }
902 : :
903 : : /* Didn't find a match: return the list unmodified */
904 : 0 : return list;
905 : : }
906 : :
907 : : /* As above, but for OIDs */
908 : : List *
909 : 4936 : list_delete_oid(List *list, Oid datum)
910 : : {
911 : : ListCell *cell;
912 : :
913 : : Assert(IsOidList(list));
914 : : check_list_invariants(list);
915 : :
916 [ + + + - : 4936 : foreach(cell, list)
+ + ]
917 : : {
918 [ + - ]: 1160 : if (lfirst_oid(cell) == datum)
919 : 1160 : return list_delete_cell(list, cell);
920 : : }
921 : :
922 : : /* Didn't find a match: return the list unmodified */
923 : 3776 : return list;
924 : : }
925 : :
926 : : /*
927 : : * Delete the first element of the list.
928 : : *
929 : : * This is useful to replace the Lisp-y code "list = lnext(list);" in cases
930 : : * where the intent is to alter the list rather than just traverse it.
931 : : * Beware that the list is modified, whereas the Lisp-y coding leaves
932 : : * the original list head intact in case there's another pointer to it.
933 : : *
934 : : * Note that this takes time proportional to the length of the list,
935 : : * since the remaining entries must be moved. Consider reversing the
936 : : * list order so that you can use list_delete_last() instead. However,
937 : : * if that causes you to replace lappend() with lcons(), you haven't
938 : : * improved matters. (In short, you can make an efficient stack from
939 : : * a List, but not an efficient FIFO queue.)
940 : : */
941 : : List *
942 : 635304 : list_delete_first(List *list)
943 : : {
944 : : check_list_invariants(list);
945 : :
946 [ - + ]: 635304 : if (list == NIL)
947 : 0 : return NIL; /* would an error be better? */
948 : :
949 : 635304 : return list_delete_nth_cell(list, 0);
950 : : }
951 : :
952 : : /*
953 : : * Delete the last element of the list.
954 : : */
955 : : List *
956 : 70752 : list_delete_last(List *list)
957 : : {
958 : : check_list_invariants(list);
959 : :
960 [ - + ]: 70752 : if (list == NIL)
961 : 0 : return NIL; /* would an error be better? */
962 : :
963 : : /* list_truncate won't free list if it goes to empty, but this should */
964 [ + + ]: 70752 : if (list_length(list) <= 1)
965 : : {
966 : 18490 : list_free(list);
967 : 18490 : return NIL;
968 : : }
969 : :
970 : 52262 : return list_truncate(list, list_length(list) - 1);
971 : : }
972 : :
973 : : /*
974 : : * Delete the first N cells of the list.
975 : : *
976 : : * The List is pfree'd if the request causes all cells to be deleted.
977 : : *
978 : : * Note that this takes time proportional to the distance to the end of the
979 : : * list, since the following entries must be moved.
980 : : */
981 : : List *
982 : 476 : list_delete_first_n(List *list, int n)
983 : : {
984 : : check_list_invariants(list);
985 : :
986 : : /* No-op request? */
987 [ + + ]: 476 : if (n <= 0)
988 : 10 : return list;
989 : :
990 : : /* Delete whole list? */
991 [ - + ]: 466 : if (n >= list_length(list))
992 : : {
993 : 0 : list_free(list);
994 : 0 : return NIL;
995 : : }
996 : :
997 : : /*
998 : : * Otherwise, we normally just collapse out the removed elements. But for
999 : : * debugging purposes, move the whole list contents someplace else.
1000 : : *
1001 : : * (Note that we *must* keep the contents in the same memory context.)
1002 : : */
1003 : : #ifndef DEBUG_LIST_MEMORY_USAGE
1004 : 466 : memmove(&list->elements[0], &list->elements[n],
1005 : 466 : (list->length - n) * sizeof(ListCell));
1006 : 466 : list->length -= n;
1007 : : #else
1008 : : {
1009 : : ListCell *newelems;
1010 : : int newmaxlen = list->length - n;
1011 : :
1012 : : newelems = (ListCell *)
1013 : : MemoryContextAlloc(GetMemoryChunkContext(list),
1014 : : newmaxlen * sizeof(ListCell));
1015 : : memcpy(newelems, &list->elements[n], newmaxlen * sizeof(ListCell));
1016 : : if (list->elements != list->initial_elements)
1017 : : pfree(list->elements);
1018 : : else
1019 : : {
1020 : : /*
1021 : : * As in enlarge_list(), clear the initial_elements[] space and/or
1022 : : * mark it inaccessible.
1023 : : */
1024 : : #ifdef CLOBBER_FREED_MEMORY
1025 : : wipe_mem(list->initial_elements,
1026 : : list->max_length * sizeof(ListCell));
1027 : : #else
1028 : : VALGRIND_MAKE_MEM_NOACCESS(list->initial_elements,
1029 : : list->max_length * sizeof(ListCell));
1030 : : #endif
1031 : : }
1032 : : list->elements = newelems;
1033 : : list->max_length = newmaxlen;
1034 : : list->length = newmaxlen;
1035 : : check_list_invariants(list);
1036 : : }
1037 : : #endif
1038 : :
1039 : 466 : return list;
1040 : : }
1041 : :
1042 : : /*
1043 : : * Generate the union of two lists. This is calculated by copying
1044 : : * list1 via list_copy(), then adding to it all the members of list2
1045 : : * that aren't already in list1.
1046 : : *
1047 : : * Whether an element is already a member of the list is determined
1048 : : * via equal().
1049 : : *
1050 : : * The returned list is newly-allocated, although the content of the
1051 : : * cells is the same (i.e. any pointed-to objects are not copied).
1052 : : *
1053 : : * NB: this function will NOT remove any duplicates that are present
1054 : : * in list1 (so it only performs a "union" if list1 is known unique to
1055 : : * start with). Also, if you are about to write "x = list_union(x, y)"
1056 : : * you probably want to use list_concat_unique() instead to avoid wasting
1057 : : * the storage of the old x list.
1058 : : *
1059 : : * Note that this takes time proportional to the product of the list
1060 : : * lengths, so beware of using it on long lists. (We could probably
1061 : : * improve that, but really you should be using some other data structure
1062 : : * if this'd be a performance bottleneck.)
1063 : : */
1064 : : List *
1065 : 8756 : list_union(const List *list1, const List *list2)
1066 : : {
1067 : : List *result;
1068 : : const ListCell *cell;
1069 : :
1070 : : Assert(IsPointerList(list1));
1071 : : Assert(IsPointerList(list2));
1072 : :
1073 : 8756 : result = list_copy(list1);
1074 [ + + + + : 17964 : foreach(cell, list2)
+ + ]
1075 : : {
1076 [ + + ]: 9208 : if (!list_member(result, lfirst(cell)))
1077 : 9146 : result = lappend(result, lfirst(cell));
1078 : : }
1079 : :
1080 : : check_list_invariants(result);
1081 : 8756 : return result;
1082 : : }
1083 : :
1084 : : /*
1085 : : * This variant of list_union() determines duplicates via simple
1086 : : * pointer comparison.
1087 : : */
1088 : : List *
1089 : 0 : list_union_ptr(const List *list1, const List *list2)
1090 : : {
1091 : : List *result;
1092 : : const ListCell *cell;
1093 : :
1094 : : Assert(IsPointerList(list1));
1095 : : Assert(IsPointerList(list2));
1096 : :
1097 : 0 : result = list_copy(list1);
1098 [ # # # # : 0 : foreach(cell, list2)
# # ]
1099 : : {
1100 [ # # ]: 0 : if (!list_member_ptr(result, lfirst(cell)))
1101 : 0 : result = lappend(result, lfirst(cell));
1102 : : }
1103 : :
1104 : : check_list_invariants(result);
1105 : 0 : return result;
1106 : : }
1107 : :
1108 : : /*
1109 : : * This variant of list_union() operates upon lists of integers.
1110 : : */
1111 : : List *
1112 : 5211 : list_union_int(const List *list1, const List *list2)
1113 : : {
1114 : : List *result;
1115 : : const ListCell *cell;
1116 : :
1117 : : Assert(IsIntegerList(list1));
1118 : : Assert(IsIntegerList(list2));
1119 : :
1120 : 5211 : result = list_copy(list1);
1121 [ + + + + : 10362 : foreach(cell, list2)
+ + ]
1122 : : {
1123 [ + + ]: 5151 : if (!list_member_int(result, lfirst_int(cell)))
1124 : 4983 : result = lappend_int(result, lfirst_int(cell));
1125 : : }
1126 : :
1127 : : check_list_invariants(result);
1128 : 5211 : return result;
1129 : : }
1130 : :
1131 : : /*
1132 : : * This variant of list_union() operates upon lists of OIDs.
1133 : : */
1134 : : List *
1135 : 0 : list_union_oid(const List *list1, const List *list2)
1136 : : {
1137 : : List *result;
1138 : : const ListCell *cell;
1139 : :
1140 : : Assert(IsOidList(list1));
1141 : : Assert(IsOidList(list2));
1142 : :
1143 : 0 : result = list_copy(list1);
1144 [ # # # # : 0 : foreach(cell, list2)
# # ]
1145 : : {
1146 [ # # ]: 0 : if (!list_member_oid(result, lfirst_oid(cell)))
1147 : 0 : result = lappend_oid(result, lfirst_oid(cell));
1148 : : }
1149 : :
1150 : : check_list_invariants(result);
1151 : 0 : return result;
1152 : : }
1153 : :
1154 : : /*
1155 : : * Return a list that contains all the cells that are in both list1 and
1156 : : * list2. The returned list is freshly allocated via palloc(), but the
1157 : : * cells themselves point to the same objects as the cells of the
1158 : : * input lists.
1159 : : *
1160 : : * Duplicate entries in list1 will not be suppressed, so it's only a true
1161 : : * "intersection" if list1 is known unique beforehand.
1162 : : *
1163 : : * This variant works on lists of pointers, and determines list
1164 : : * membership via equal(). Note that the list1 member will be pointed
1165 : : * to in the result.
1166 : : *
1167 : : * Note that this takes time proportional to the product of the list
1168 : : * lengths, so beware of using it on long lists. (We could probably
1169 : : * improve that, but really you should be using some other data structure
1170 : : * if this'd be a performance bottleneck.)
1171 : : */
1172 : : List *
1173 : 0 : list_intersection(const List *list1, const List *list2)
1174 : : {
1175 : : List *result;
1176 : : const ListCell *cell;
1177 : :
1178 [ # # # # ]: 0 : if (list1 == NIL || list2 == NIL)
1179 : 0 : return NIL;
1180 : :
1181 : : Assert(IsPointerList(list1));
1182 : : Assert(IsPointerList(list2));
1183 : :
1184 : 0 : result = NIL;
1185 [ # # # # : 0 : foreach(cell, list1)
# # ]
1186 : : {
1187 [ # # ]: 0 : if (list_member(list2, lfirst(cell)))
1188 : 0 : result = lappend(result, lfirst(cell));
1189 : : }
1190 : :
1191 : : check_list_invariants(result);
1192 : 0 : return result;
1193 : : }
1194 : :
1195 : : /*
1196 : : * As list_intersection but operates on lists of integers.
1197 : : */
1198 : : List *
1199 : 354 : list_intersection_int(const List *list1, const List *list2)
1200 : : {
1201 : : List *result;
1202 : : const ListCell *cell;
1203 : :
1204 [ + - - + ]: 354 : if (list1 == NIL || list2 == NIL)
1205 : 0 : return NIL;
1206 : :
1207 : : Assert(IsIntegerList(list1));
1208 : : Assert(IsIntegerList(list2));
1209 : :
1210 : 354 : result = NIL;
1211 [ + - + + : 740 : foreach(cell, list1)
+ + ]
1212 : : {
1213 [ + + ]: 386 : if (list_member_int(list2, lfirst_int(cell)))
1214 : 156 : result = lappend_int(result, lfirst_int(cell));
1215 : : }
1216 : :
1217 : : check_list_invariants(result);
1218 : 354 : return result;
1219 : : }
1220 : :
1221 : : /*
1222 : : * Return a list that contains all the cells in list1 that are not in
1223 : : * list2. The returned list is freshly allocated via palloc(), but the
1224 : : * cells themselves point to the same objects as the cells of the
1225 : : * input lists.
1226 : : *
1227 : : * This variant works on lists of pointers, and determines list
1228 : : * membership via equal()
1229 : : *
1230 : : * Note that this takes time proportional to the product of the list
1231 : : * lengths, so beware of using it on long lists. (We could probably
1232 : : * improve that, but really you should be using some other data structure
1233 : : * if this'd be a performance bottleneck.)
1234 : : */
1235 : : List *
1236 : 41072 : list_difference(const List *list1, const List *list2)
1237 : : {
1238 : : const ListCell *cell;
1239 : 41072 : List *result = NIL;
1240 : :
1241 : : Assert(IsPointerList(list1));
1242 : : Assert(IsPointerList(list2));
1243 : :
1244 [ + + ]: 41072 : if (list2 == NIL)
1245 : 1335 : return list_copy(list1);
1246 : :
1247 [ + - + + : 85577 : foreach(cell, list1)
+ + ]
1248 : : {
1249 [ + + ]: 45840 : if (!list_member(list2, lfirst(cell)))
1250 : 1317 : result = lappend(result, lfirst(cell));
1251 : : }
1252 : :
1253 : : check_list_invariants(result);
1254 : 39737 : return result;
1255 : : }
1256 : :
1257 : : /*
1258 : : * This variant of list_difference() determines list membership via
1259 : : * simple pointer equality.
1260 : : */
1261 : : List *
1262 : 19962 : list_difference_ptr(const List *list1, const List *list2)
1263 : : {
1264 : : const ListCell *cell;
1265 : 19962 : List *result = NIL;
1266 : :
1267 : : Assert(IsPointerList(list1));
1268 : : Assert(IsPointerList(list2));
1269 : :
1270 [ + + ]: 19962 : if (list2 == NIL)
1271 : 16845 : return list_copy(list1);
1272 : :
1273 [ + + + + : 7868 : foreach(cell, list1)
+ + ]
1274 : : {
1275 [ + + ]: 4751 : if (!list_member_ptr(list2, lfirst(cell)))
1276 : 2063 : result = lappend(result, lfirst(cell));
1277 : : }
1278 : :
1279 : : check_list_invariants(result);
1280 : 3117 : return result;
1281 : : }
1282 : :
1283 : : /*
1284 : : * This variant of list_difference() operates upon lists of integers.
1285 : : */
1286 : : List *
1287 : 2625 : list_difference_int(const List *list1, const List *list2)
1288 : : {
1289 : : const ListCell *cell;
1290 : 2625 : List *result = NIL;
1291 : :
1292 : : Assert(IsIntegerList(list1));
1293 : : Assert(IsIntegerList(list2));
1294 : :
1295 [ + + ]: 2625 : if (list2 == NIL)
1296 : 2005 : return list_copy(list1);
1297 : :
1298 [ + - + + : 1840 : foreach(cell, list1)
+ + ]
1299 : : {
1300 [ + + ]: 1220 : if (!list_member_int(list2, lfirst_int(cell)))
1301 : 496 : result = lappend_int(result, lfirst_int(cell));
1302 : : }
1303 : :
1304 : : check_list_invariants(result);
1305 : 620 : return result;
1306 : : }
1307 : :
1308 : : /*
1309 : : * This variant of list_difference() operates upon lists of OIDs.
1310 : : */
1311 : : List *
1312 : 7761 : list_difference_oid(const List *list1, const List *list2)
1313 : : {
1314 : : const ListCell *cell;
1315 : 7761 : List *result = NIL;
1316 : :
1317 : : Assert(IsOidList(list1));
1318 : : Assert(IsOidList(list2));
1319 : :
1320 [ + + ]: 7761 : if (list2 == NIL)
1321 : 7353 : return list_copy(list1);
1322 : :
1323 [ + + + + : 2716 : foreach(cell, list1)
+ + ]
1324 : : {
1325 [ + + ]: 2308 : if (!list_member_oid(list2, lfirst_oid(cell)))
1326 : 1324 : result = lappend_oid(result, lfirst_oid(cell));
1327 : : }
1328 : :
1329 : : check_list_invariants(result);
1330 : 408 : return result;
1331 : : }
1332 : :
1333 : : /*
1334 : : * Append datum to list, but only if it isn't already in the list.
1335 : : *
1336 : : * Whether an element is already a member of the list is determined
1337 : : * via equal().
1338 : : *
1339 : : * This does a simple linear search --- avoid using it on long lists.
1340 : : */
1341 : : List *
1342 : 147656 : list_append_unique(List *list, void *datum)
1343 : : {
1344 [ + + ]: 147656 : if (list_member(list, datum))
1345 : 11931 : return list;
1346 : : else
1347 : 135725 : return lappend(list, datum);
1348 : : }
1349 : :
1350 : : /*
1351 : : * This variant of list_append_unique() determines list membership via
1352 : : * simple pointer equality.
1353 : : */
1354 : : List *
1355 : 387778 : list_append_unique_ptr(List *list, void *datum)
1356 : : {
1357 [ + + ]: 387778 : if (list_member_ptr(list, datum))
1358 : 154990 : return list;
1359 : : else
1360 : 232788 : return lappend(list, datum);
1361 : : }
1362 : :
1363 : : /*
1364 : : * This variant of list_append_unique() operates upon lists of integers.
1365 : : */
1366 : : List *
1367 : 0 : list_append_unique_int(List *list, int datum)
1368 : : {
1369 [ # # ]: 0 : if (list_member_int(list, datum))
1370 : 0 : return list;
1371 : : else
1372 : 0 : return lappend_int(list, datum);
1373 : : }
1374 : :
1375 : : /*
1376 : : * This variant of list_append_unique() operates upon lists of OIDs.
1377 : : */
1378 : : List *
1379 : 4243 : list_append_unique_oid(List *list, Oid datum)
1380 : : {
1381 [ + + ]: 4243 : if (list_member_oid(list, datum))
1382 : 1367 : return list;
1383 : : else
1384 : 2876 : return lappend_oid(list, datum);
1385 : : }
1386 : :
1387 : : /*
1388 : : * Append to list1 each member of list2 that isn't already in list1.
1389 : : *
1390 : : * Whether an element is already a member of the list is determined
1391 : : * via equal().
1392 : : *
1393 : : * This is almost the same functionality as list_union(), but list1 is
1394 : : * modified in-place rather than being copied. However, callers of this
1395 : : * function may have strict ordering expectations -- i.e. that the relative
1396 : : * order of those list2 elements that are not duplicates is preserved.
1397 : : *
1398 : : * Note that this takes time proportional to the product of the list
1399 : : * lengths, so beware of using it on long lists. (We could probably
1400 : : * improve that, but really you should be using some other data structure
1401 : : * if this'd be a performance bottleneck.)
1402 : : */
1403 : : List *
1404 : 3161 : list_concat_unique(List *list1, const List *list2)
1405 : : {
1406 : : ListCell *cell;
1407 : :
1408 : : Assert(IsPointerList(list1));
1409 : : Assert(IsPointerList(list2));
1410 : :
1411 [ + + + + : 5818 : foreach(cell, list2)
+ + ]
1412 : : {
1413 [ + + ]: 2657 : if (!list_member(list1, lfirst(cell)))
1414 : 2632 : list1 = lappend(list1, lfirst(cell));
1415 : : }
1416 : :
1417 : : check_list_invariants(list1);
1418 : 3161 : return list1;
1419 : : }
1420 : :
1421 : : /*
1422 : : * This variant of list_concat_unique() determines list membership via
1423 : : * simple pointer equality.
1424 : : */
1425 : : List *
1426 : 1721 : list_concat_unique_ptr(List *list1, const List *list2)
1427 : : {
1428 : : ListCell *cell;
1429 : :
1430 : : Assert(IsPointerList(list1));
1431 : : Assert(IsPointerList(list2));
1432 : :
1433 [ + - + + : 5885 : foreach(cell, list2)
+ + ]
1434 : : {
1435 [ + + ]: 4164 : if (!list_member_ptr(list1, lfirst(cell)))
1436 : 2081 : list1 = lappend(list1, lfirst(cell));
1437 : : }
1438 : :
1439 : : check_list_invariants(list1);
1440 : 1721 : return list1;
1441 : : }
1442 : :
1443 : : /*
1444 : : * This variant of list_concat_unique() operates upon lists of integers.
1445 : : */
1446 : : List *
1447 : 0 : list_concat_unique_int(List *list1, const List *list2)
1448 : : {
1449 : : ListCell *cell;
1450 : :
1451 : : Assert(IsIntegerList(list1));
1452 : : Assert(IsIntegerList(list2));
1453 : :
1454 [ # # # # : 0 : foreach(cell, list2)
# # ]
1455 : : {
1456 [ # # ]: 0 : if (!list_member_int(list1, lfirst_int(cell)))
1457 : 0 : list1 = lappend_int(list1, lfirst_int(cell));
1458 : : }
1459 : :
1460 : : check_list_invariants(list1);
1461 : 0 : return list1;
1462 : : }
1463 : :
1464 : : /*
1465 : : * This variant of list_concat_unique() operates upon lists of OIDs.
1466 : : */
1467 : : List *
1468 : 17006 : list_concat_unique_oid(List *list1, const List *list2)
1469 : : {
1470 : : ListCell *cell;
1471 : :
1472 : : Assert(IsOidList(list1));
1473 : : Assert(IsOidList(list2));
1474 : :
1475 [ + + + + : 18926 : foreach(cell, list2)
+ + ]
1476 : : {
1477 [ + + ]: 1920 : if (!list_member_oid(list1, lfirst_oid(cell)))
1478 : 1406 : list1 = lappend_oid(list1, lfirst_oid(cell));
1479 : : }
1480 : :
1481 : : check_list_invariants(list1);
1482 : 17006 : return list1;
1483 : : }
1484 : :
1485 : : /*
1486 : : * Remove adjacent duplicates in a list of OIDs.
1487 : : *
1488 : : * It is caller's responsibility to have sorted the list to bring duplicates
1489 : : * together, perhaps via list_sort(list, list_oid_cmp).
1490 : : *
1491 : : * Note that this takes time proportional to the length of the list.
1492 : : */
1493 : : void
1494 : 1305 : list_deduplicate_oid(List *list)
1495 : : {
1496 : : int len;
1497 : :
1498 : : Assert(IsOidList(list));
1499 : 1305 : len = list_length(list);
1500 [ + + ]: 1305 : if (len > 1)
1501 : : {
1502 : 176 : ListCell *elements = list->elements;
1503 : 176 : int i = 0;
1504 : :
1505 [ + + ]: 492 : for (int j = 1; j < len; j++)
1506 : : {
1507 [ + + ]: 316 : if (elements[i].oid_value != elements[j].oid_value)
1508 : 281 : elements[++i].oid_value = elements[j].oid_value;
1509 : : }
1510 : 176 : list->length = i + 1;
1511 : : }
1512 : : check_list_invariants(list);
1513 : 1305 : }
1514 : :
1515 : : /*
1516 : : * Free all storage in a list, and optionally the pointed-to elements
1517 : : */
1518 : : static void
1519 : 19523484 : list_free_private(List *list, bool deep)
1520 : : {
1521 [ + + ]: 19523484 : if (list == NIL)
1522 : 14926411 : return; /* nothing to do */
1523 : :
1524 : : check_list_invariants(list);
1525 : :
1526 [ + + ]: 4597073 : if (deep)
1527 : : {
1528 [ + + ]: 1352761 : for (int i = 0; i < list->length; i++)
1529 : 1071560 : pfree(lfirst(&list->elements[i]));
1530 : : }
1531 [ + + ]: 4597073 : if (list->elements != list->initial_elements)
1532 : 109989 : pfree(list->elements);
1533 : 4597073 : pfree(list);
1534 : : }
1535 : :
1536 : : /*
1537 : : * Free all the cells of the list, as well as the list itself. Any
1538 : : * objects that are pointed-to by the cells of the list are NOT
1539 : : * free'd.
1540 : : *
1541 : : * On return, the argument to this function has been freed, so the
1542 : : * caller would be wise to set it to NIL for safety's sake.
1543 : : */
1544 : : void
1545 : 17587864 : list_free(List *list)
1546 : : {
1547 : 17587864 : list_free_private(list, false);
1548 : 17587864 : }
1549 : :
1550 : : /*
1551 : : * Free all the cells of the list, the list itself, and all the
1552 : : * objects pointed-to by the cells of the list (each element in the
1553 : : * list must contain a pointer to a palloc()'d region of memory!)
1554 : : *
1555 : : * On return, the argument to this function has been freed, so the
1556 : : * caller would be wise to set it to NIL for safety's sake.
1557 : : */
1558 : : void
1559 : 1935620 : list_free_deep(List *list)
1560 : : {
1561 : : /*
1562 : : * A "deep" free operation only makes sense on a list of pointers.
1563 : : */
1564 : : Assert(IsPointerList(list));
1565 : 1935620 : list_free_private(list, true);
1566 : 1935620 : }
1567 : :
1568 : : /*
1569 : : * Return a shallow copy of the specified list.
1570 : : */
1571 : : List *
1572 : 8516468 : list_copy(const List *oldlist)
1573 : : {
1574 : : List *newlist;
1575 : :
1576 [ + + ]: 8516468 : if (oldlist == NIL)
1577 : 1860582 : return NIL;
1578 : :
1579 : 6655886 : newlist = new_list(oldlist->type, oldlist->length);
1580 : 6655886 : memcpy(newlist->elements, oldlist->elements,
1581 : 6655886 : newlist->length * sizeof(ListCell));
1582 : :
1583 : : check_list_invariants(newlist);
1584 : 6655886 : return newlist;
1585 : : }
1586 : :
1587 : : /*
1588 : : * Return a shallow copy of the specified list containing only the first 'len'
1589 : : * elements. If oldlist is shorter than 'len' then we copy the entire list.
1590 : : */
1591 : : List *
1592 : 983412 : list_copy_head(const List *oldlist, int len)
1593 : : {
1594 : : List *newlist;
1595 : :
1596 [ + - + + ]: 983412 : if (oldlist == NIL || len <= 0)
1597 : 832685 : return NIL;
1598 : :
1599 : 150727 : len = Min(oldlist->length, len);
1600 : :
1601 : 150727 : newlist = new_list(oldlist->type, len);
1602 : 150727 : memcpy(newlist->elements, oldlist->elements, len * sizeof(ListCell));
1603 : :
1604 : : check_list_invariants(newlist);
1605 : 150727 : return newlist;
1606 : : }
1607 : :
1608 : : /*
1609 : : * Return a shallow copy of the specified list, without the first N elements.
1610 : : */
1611 : : List *
1612 : 71133 : list_copy_tail(const List *oldlist, int nskip)
1613 : : {
1614 : : List *newlist;
1615 : :
1616 [ - + ]: 71133 : if (nskip < 0)
1617 : 0 : nskip = 0; /* would it be better to elog? */
1618 : :
1619 [ + - + + ]: 71133 : if (oldlist == NIL || nskip >= oldlist->length)
1620 : 1534 : return NIL;
1621 : :
1622 : 69599 : newlist = new_list(oldlist->type, oldlist->length - nskip);
1623 : 69599 : memcpy(newlist->elements, &oldlist->elements[nskip],
1624 : 69599 : newlist->length * sizeof(ListCell));
1625 : :
1626 : : check_list_invariants(newlist);
1627 : 69599 : return newlist;
1628 : : }
1629 : :
1630 : : /*
1631 : : * Return a deep copy of the specified list.
1632 : : *
1633 : : * The list elements are copied via copyObject(), so that this function's
1634 : : * idea of a "deep" copy is considerably deeper than what list_free_deep()
1635 : : * means by the same word.
1636 : : */
1637 : : List *
1638 : 15324591 : list_copy_deep(const List *oldlist)
1639 : : {
1640 : : List *newlist;
1641 : :
1642 [ - + ]: 15324591 : if (oldlist == NIL)
1643 : 0 : return NIL;
1644 : :
1645 : : /* This is only sensible for pointer Lists */
1646 : : Assert(IsA(oldlist, List));
1647 : :
1648 : 15324591 : newlist = new_list(oldlist->type, oldlist->length);
1649 [ + + ]: 64020125 : for (int i = 0; i < newlist->length; i++)
1650 : 48695534 : lfirst(&newlist->elements[i]) =
1651 : 48695534 : copyObjectImpl(lfirst(&oldlist->elements[i]));
1652 : :
1653 : : check_list_invariants(newlist);
1654 : 15324591 : return newlist;
1655 : : }
1656 : :
1657 : : /*
1658 : : * Sort a list according to the specified comparator function.
1659 : : *
1660 : : * The list is sorted in-place.
1661 : : *
1662 : : * The comparator function is declared to receive arguments of type
1663 : : * const ListCell *; this allows it to use lfirst() and variants
1664 : : * without casting its arguments. Otherwise it behaves the same as
1665 : : * the comparator function for standard qsort().
1666 : : *
1667 : : * Like qsort(), this provides no guarantees about sort stability
1668 : : * for equal keys.
1669 : : *
1670 : : * This is based on qsort(), so it likewise has O(N log N) runtime.
1671 : : */
1672 : : void
1673 : 366844 : list_sort(List *list, list_sort_comparator cmp)
1674 : : {
1675 : : typedef int (*qsort_comparator) (const void *a, const void *b);
1676 : : int len;
1677 : :
1678 : : check_list_invariants(list);
1679 : :
1680 : : /* Nothing to do if there's less than two elements */
1681 : 366844 : len = list_length(list);
1682 [ + + ]: 366844 : if (len > 1)
1683 : 129223 : qsort(list->elements, len, sizeof(ListCell), (qsort_comparator) cmp);
1684 : 366844 : }
1685 : :
1686 : : /*
1687 : : * list_sort comparator for sorting a list into ascending int order.
1688 : : */
1689 : : int
1690 : 66 : list_int_cmp(const ListCell *p1, const ListCell *p2)
1691 : : {
1692 : 66 : int v1 = lfirst_int(p1);
1693 : 66 : int v2 = lfirst_int(p2);
1694 : :
1695 : 66 : return pg_cmp_s32(v1, v2);
1696 : : }
1697 : :
1698 : : /*
1699 : : * list_sort comparator for sorting a list into ascending OID order.
1700 : : */
1701 : : int
1702 : 151874 : list_oid_cmp(const ListCell *p1, const ListCell *p2)
1703 : : {
1704 : 151874 : Oid v1 = lfirst_oid(p1);
1705 : 151874 : Oid v2 = lfirst_oid(p2);
1706 : :
1707 : 151874 : return pg_cmp_u32(v1, v2);
1708 : : }
|