/Users/deen/code/yugabyte-db/src/postgres/src/backend/nodes/list.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * list.c |
4 | | * implementation for PostgreSQL generic linked list package |
5 | | * |
6 | | * |
7 | | * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group |
8 | | * Portions Copyright (c) 1994, Regents of the University of California |
9 | | * |
10 | | * |
11 | | * IDENTIFICATION |
12 | | * src/backend/nodes/list.c |
13 | | * |
14 | | *------------------------------------------------------------------------- |
15 | | */ |
16 | | #include "postgres.h" |
17 | | |
18 | | #include "nodes/pg_list.h" |
19 | | |
20 | | |
21 | | /* |
22 | | * Routines to simplify writing assertions about the type of a list; a |
23 | | * NIL list is considered to be an empty list of any type. |
24 | | */ |
25 | | #define IsPointerList(l) ((l) == NIL || IsA((l), List)) |
26 | | #define IsIntegerList(l) ((l) == NIL || IsA((l), IntList)) |
27 | | #define IsOidList(l) ((l) == NIL || IsA((l), OidList)) |
28 | | |
29 | | #ifdef USE_ASSERT_CHECKING |
30 | | /* |
31 | | * Check that the specified List is valid (so far as we can tell). |
32 | | */ |
33 | | static void |
34 | | check_list_invariants(const List *list) |
35 | 238M | { |
36 | 238M | if (list == NIL) |
37 | 8.52M | return; |
38 | | |
39 | 230M | Assert(list->length > 0); |
40 | 230M | Assert(list->head != NULL); |
41 | 230M | Assert(list->tail != NULL); |
42 | | |
43 | 230M | Assert(list->type == T_List || |
44 | 230M | list->type == T_IntList || |
45 | 230M | list->type == T_OidList); |
46 | | |
47 | 230M | if (list->length == 1) |
48 | 230M | Assert(list->head == list->tail); |
49 | 230M | if (list->length == 2) |
50 | 230M | Assert(list->head->next == list->tail); |
51 | 230M | Assert(list->tail->next == NULL); |
52 | 230M | } |
53 | | #else |
54 | | #define check_list_invariants(l) |
55 | | #endif /* USE_ASSERT_CHECKING */ |
56 | | |
57 | | /* |
58 | | * Return a freshly allocated List. Since empty non-NIL lists are |
59 | | * invalid, new_list() also allocates the head cell of the new list: |
60 | | * the caller should be sure to fill in that cell's data. |
61 | | */ |
62 | | static List * |
63 | | new_list(NodeTag type) |
64 | 58.3M | { |
65 | 58.3M | List *new_list; |
66 | 58.3M | ListCell *new_head; |
67 | | |
68 | 58.3M | new_head = (ListCell *) palloc(sizeof(*new_head)); |
69 | 58.3M | new_head->next = NULL; |
70 | | /* new_head->data is left undefined! */ |
71 | | |
72 | 58.3M | new_list = (List *) palloc(sizeof(*new_list)); |
73 | 58.3M | new_list->type = type; |
74 | 58.3M | new_list->length = 1; |
75 | 58.3M | new_list->head = new_head; |
76 | 58.3M | new_list->tail = new_head; |
77 | | |
78 | 58.3M | return new_list; |
79 | 58.3M | } |
80 | | |
81 | | /* |
82 | | * Allocate a new cell and make it the head of the specified |
83 | | * list. Assumes the list it is passed is non-NIL. |
84 | | * |
85 | | * The data in the new head cell is undefined; the caller should be |
86 | | * sure to fill it in |
87 | | */ |
88 | | static void |
89 | | new_head_cell(List *list) |
90 | 1.28M | { |
91 | 1.28M | ListCell *new_head; |
92 | | |
93 | 1.28M | new_head = (ListCell *) palloc(sizeof(*new_head)); |
94 | 1.28M | new_head->next = list->head; |
95 | | |
96 | 1.28M | list->head = new_head; |
97 | 1.28M | list->length++; |
98 | 1.28M | } |
99 | | |
100 | | /* |
101 | | * Allocate a new cell and make it the tail of the specified |
102 | | * list. Assumes the list it is passed is non-NIL. |
103 | | * |
104 | | * The data in the new tail cell is undefined; the caller should be |
105 | | * sure to fill it in |
106 | | */ |
107 | | static void |
108 | | new_tail_cell(List *list) |
109 | 151M | { |
110 | 151M | ListCell *new_tail; |
111 | | |
112 | 151M | new_tail = (ListCell *) palloc(sizeof(*new_tail)); |
113 | 151M | new_tail->next = NULL; |
114 | | |
115 | 151M | list->tail->next = new_tail; |
116 | 151M | list->tail = new_tail; |
117 | 151M | list->length++; |
118 | 151M | } |
119 | | |
120 | | /* |
121 | | * Append a pointer to the list. A pointer to the modified list is |
122 | | * returned. Note that this function may or may not destructively |
123 | | * modify the list; callers should always use this function's return |
124 | | * value, rather than continuing to use the pointer passed as the |
125 | | * first argument. |
126 | | */ |
127 | | List * |
128 | | lappend(List *list, void *datum) |
129 | 180M | { |
130 | 180M | Assert(IsPointerList(list)); |
131 | | |
132 | 180M | if (list == NIL) |
133 | 32.1M | list = new_list(T_List); |
134 | 147M | else |
135 | 147M | new_tail_cell(list); |
136 | | |
137 | 180M | lfirst(list->tail) = datum; |
138 | 180M | check_list_invariants(list); |
139 | 180M | return list; |
140 | 180M | } |
141 | | |
142 | | /* |
143 | | * Append an integer to the specified list. See lappend() |
144 | | */ |
145 | | List * |
146 | | lappend_int(List *list, int datum) |
147 | 2.25M | { |
148 | 2.25M | Assert(IsIntegerList(list)); |
149 | | |
150 | 2.25M | if (list == NIL) |
151 | 898k | list = new_list(T_IntList); |
152 | 1.35M | else |
153 | 1.35M | new_tail_cell(list); |
154 | | |
155 | 2.25M | lfirst_int(list->tail) = datum; |
156 | 2.25M | check_list_invariants(list); |
157 | 2.25M | return list; |
158 | 2.25M | } |
159 | | |
160 | | /* |
161 | | * Append an OID to the specified list. See lappend() |
162 | | */ |
163 | | List * |
164 | | lappend_oid(List *list, Oid datum) |
165 | 3.94M | { |
166 | 3.94M | Assert(IsOidList(list)); |
167 | | |
168 | 3.94M | if (list == NIL) |
169 | 1.82M | list = new_list(T_OidList); |
170 | 2.11M | else |
171 | 2.11M | new_tail_cell(list); |
172 | | |
173 | 3.94M | lfirst_oid(list->tail) = datum; |
174 | 3.94M | check_list_invariants(list); |
175 | 3.94M | return list; |
176 | 3.94M | } |
177 | | |
178 | | /* |
179 | | * Add a new cell to the list, in the position after 'prev_cell'. The |
180 | | * data in the cell is left undefined, and must be filled in by the |
181 | | * caller. 'list' is assumed to be non-NIL, and 'prev_cell' is assumed |
182 | | * to be non-NULL and a member of 'list'. |
183 | | */ |
184 | | static ListCell * |
185 | | add_new_cell(List *list, ListCell *prev_cell) |
186 | 34.5k | { |
187 | 34.5k | ListCell *new_cell; |
188 | | |
189 | 34.5k | new_cell = (ListCell *) palloc(sizeof(*new_cell)); |
190 | | /* new_cell->data is left undefined! */ |
191 | 34.5k | new_cell->next = prev_cell->next; |
192 | 34.5k | prev_cell->next = new_cell; |
193 | | |
194 | 34.5k | if (list->tail == prev_cell) |
195 | 32.6k | list->tail = new_cell; |
196 | | |
197 | 34.5k | list->length++; |
198 | | |
199 | 34.5k | return new_cell; |
200 | 34.5k | } |
201 | | |
202 | | /* |
203 | | * Add a new cell to the specified list (which must be non-NIL); |
204 | | * it will be placed after the list cell 'prev' (which must be |
205 | | * non-NULL and a member of 'list'). The data placed in the new cell |
206 | | * is 'datum'. The newly-constructed cell is returned. |
207 | | */ |
208 | | ListCell * |
209 | | lappend_cell(List *list, ListCell *prev, void *datum) |
210 | 15.8k | { |
211 | 15.8k | ListCell *new_cell; |
212 | | |
213 | 15.8k | Assert(IsPointerList(list)); |
214 | | |
215 | 15.8k | new_cell = add_new_cell(list, prev); |
216 | 15.8k | lfirst(new_cell) = datum; |
217 | 15.8k | check_list_invariants(list); |
218 | 15.8k | return new_cell; |
219 | 15.8k | } |
220 | | |
221 | | ListCell * |
222 | | lappend_cell_int(List *list, ListCell *prev, int datum) |
223 | 0 | { |
224 | 0 | ListCell *new_cell; |
225 | |
|
226 | 0 | Assert(IsIntegerList(list)); |
227 | | |
228 | 0 | new_cell = add_new_cell(list, prev); |
229 | 0 | lfirst_int(new_cell) = datum; |
230 | 0 | check_list_invariants(list); |
231 | 0 | return new_cell; |
232 | 0 | } |
233 | | |
234 | | ListCell * |
235 | | lappend_cell_oid(List *list, ListCell *prev, Oid datum) |
236 | 18.7k | { |
237 | 18.7k | ListCell *new_cell; |
238 | | |
239 | 18.7k | Assert(IsOidList(list)); |
240 | | |
241 | 18.7k | new_cell = add_new_cell(list, prev); |
242 | 18.7k | lfirst_oid(new_cell) = datum; |
243 | 18.7k | check_list_invariants(list); |
244 | 18.7k | return new_cell; |
245 | 18.7k | } |
246 | | |
247 | | /* |
248 | | * Prepend a new element to the list. A pointer to the modified list |
249 | | * is returned. Note that this function may or may not destructively |
250 | | * modify the list; callers should always use this function's return |
251 | | * value, rather than continuing to use the pointer passed as the |
252 | | * second argument. |
253 | | * |
254 | | * Caution: before Postgres 8.0, the original List was unmodified and |
255 | | * could be considered to retain its separate identity. This is no longer |
256 | | * the case. |
257 | | */ |
258 | | List * |
259 | | lcons(void *datum, List *list) |
260 | 20.4M | { |
261 | 20.4M | Assert(IsPointerList(list)); |
262 | | |
263 | 20.4M | if (list == NIL) |
264 | 19.2M | list = new_list(T_List); |
265 | 1.27M | else |
266 | 1.27M | new_head_cell(list); |
267 | | |
268 | 20.4M | lfirst(list->head) = datum; |
269 | 20.4M | check_list_invariants(list); |
270 | 20.4M | return list; |
271 | 20.4M | } |
272 | | |
273 | | /* |
274 | | * Prepend an integer to the list. See lcons() |
275 | | */ |
276 | | List * |
277 | | lcons_int(int datum, List *list) |
278 | 404k | { |
279 | 404k | Assert(IsIntegerList(list)); |
280 | | |
281 | 404k | if (list == NIL) |
282 | 397k | list = new_list(T_IntList); |
283 | 6.88k | else |
284 | 6.88k | new_head_cell(list); |
285 | | |
286 | 404k | lfirst_int(list->head) = datum; |
287 | 404k | check_list_invariants(list); |
288 | 404k | return list; |
289 | 404k | } |
290 | | |
291 | | /* |
292 | | * Prepend an OID to the list. See lcons() |
293 | | */ |
294 | | List * |
295 | | lcons_oid(Oid datum, List *list) |
296 | 47.7k | { |
297 | 47.7k | Assert(IsOidList(list)); |
298 | | |
299 | 47.7k | if (list == NIL) |
300 | 41.1k | list = new_list(T_OidList); |
301 | 6.60k | else |
302 | 6.60k | new_head_cell(list); |
303 | | |
304 | 47.7k | lfirst_oid(list->head) = datum; |
305 | 47.7k | check_list_invariants(list); |
306 | 47.7k | return list; |
307 | 47.7k | } |
308 | | |
309 | | /* |
310 | | * Concatenate list2 to the end of list1, and return list1. list1 is |
311 | | * destructively changed. Callers should be sure to use the return |
312 | | * value as the new pointer to the concatenated list: the 'list1' |
313 | | * input pointer may or may not be the same as the returned pointer. |
314 | | * |
315 | | * The nodes in list2 are merely appended to the end of list1 in-place |
316 | | * (i.e. they aren't copied; the two lists will share some of the same |
317 | | * storage). Therefore, invoking list_free() on list2 will also |
318 | | * invalidate a portion of list1. |
319 | | */ |
320 | | List * |
321 | | list_concat(List *list1, List *list2) |
322 | 2.27M | { |
323 | 2.27M | if (list1 == NIL) |
324 | 1.65M | return list2; |
325 | 621k | if (list2 == NIL) |
326 | 489k | return list1; |
327 | 132k | if (list1 == list2) |
328 | 0 | elog(ERROR, "cannot list_concat() a list to itself"); |
329 | | |
330 | 132k | Assert(list1->type == list2->type); |
331 | | |
332 | 132k | list1->length += list2->length; |
333 | 132k | list1->tail->next = list2->head; |
334 | 132k | list1->tail = list2->tail; |
335 | | |
336 | 132k | check_list_invariants(list1); |
337 | 132k | return list1; |
338 | 132k | } |
339 | | |
340 | | /* |
341 | | * Truncate 'list' to contain no more than 'new_size' elements. This |
342 | | * modifies the list in-place! Despite this, callers should use the |
343 | | * pointer returned by this function to refer to the newly truncated |
344 | | * list -- it may or may not be the same as the pointer that was |
345 | | * passed. |
346 | | * |
347 | | * Note that any cells removed by list_truncate() are NOT pfree'd. |
348 | | */ |
349 | | List * |
350 | | list_truncate(List *list, int new_size) |
351 | 21.9k | { |
352 | 21.9k | ListCell *cell; |
353 | 21.9k | int n; |
354 | | |
355 | 21.9k | if (new_size <= 0) |
356 | 5.47k | return NIL; /* truncate to zero length */ |
357 | | |
358 | | /* If asked to effectively extend the list, do nothing */ |
359 | 16.4k | if (new_size >= list_length(list)) |
360 | 13.9k | return list; |
361 | | |
362 | 2.47k | n = 1; |
363 | 2.47k | foreach(cell, list) |
364 | 5.30k | { |
365 | 5.30k | if (n == new_size) |
366 | 2.47k | { |
367 | 2.47k | cell->next = NULL; |
368 | 2.47k | list->tail = cell; |
369 | 2.47k | list->length = new_size; |
370 | 2.47k | check_list_invariants(list); |
371 | 2.47k | return list; |
372 | 2.47k | } |
373 | 2.83k | n++; |
374 | 2.83k | } |
375 | | |
376 | | /* keep the compiler quiet; never reached */ |
377 | 0 | Assert(false); |
378 | 0 | return list; |
379 | 0 | } |
380 | | |
381 | | /* |
382 | | * Locate the n'th cell (counting from 0) of the list. It is an assertion |
383 | | * failure if there is no such cell. |
384 | | */ |
385 | | ListCell * |
386 | | list_nth_cell(const List *list, int n) |
387 | 13.3M | { |
388 | 13.3M | ListCell *match; |
389 | | |
390 | 13.3M | Assert(list != NIL); |
391 | 13.3M | Assert(n >= 0); |
392 | 13.3M | Assert(n < list->length); |
393 | 13.3M | check_list_invariants(list); |
394 | | |
395 | | /* Does the caller actually mean to fetch the tail? */ |
396 | 13.3M | if (n == list->length - 1) |
397 | 6.89M | return list->tail; |
398 | | |
399 | 8.73M | for (match = list->head; 6.47M n-- > 0; match = match->next2.25M ) |
400 | 2.25M | ; |
401 | | |
402 | 6.47M | return match; |
403 | 13.3M | } |
404 | | |
405 | | /* |
406 | | * Return the data value contained in the n'th element of the |
407 | | * specified list. (List elements begin at 0.) |
408 | | */ |
409 | | void * |
410 | | list_nth(const List *list, int n) |
411 | 13.3M | { |
412 | 13.3M | Assert(IsPointerList(list)); |
413 | 13.3M | return lfirst(list_nth_cell(list, n)); |
414 | 13.3M | } |
415 | | |
416 | | /* |
417 | | * Return the integer value contained in the n'th element of the |
418 | | * specified list. |
419 | | */ |
420 | | int |
421 | | list_nth_int(const List *list, int n) |
422 | 15.2k | { |
423 | 15.2k | Assert(IsIntegerList(list)); |
424 | 15.2k | return lfirst_int(list_nth_cell(list, n)); |
425 | 15.2k | } |
426 | | |
427 | | /* |
428 | | * Return the OID value contained in the n'th element of the specified |
429 | | * list. |
430 | | */ |
431 | | Oid |
432 | | list_nth_oid(const List *list, int n) |
433 | 7.35k | { |
434 | 7.35k | Assert(IsOidList(list)); |
435 | 7.35k | return lfirst_oid(list_nth_cell(list, n)); |
436 | 7.35k | } |
437 | | |
438 | | /* |
439 | | * Return true iff 'datum' is a member of the list. Equality is |
440 | | * determined via equal(), so callers should ensure that they pass a |
441 | | * Node as 'datum'. |
442 | | */ |
443 | | bool |
444 | | list_member(const List *list, const void *datum) |
445 | 11.8k | { |
446 | 11.8k | const ListCell *cell; |
447 | | |
448 | 11.8k | Assert(IsPointerList(list)); |
449 | 11.8k | check_list_invariants(list); |
450 | | |
451 | 11.8k | foreach(cell, list) |
452 | 6.52k | { |
453 | 6.52k | if (equal(lfirst(cell), datum)) |
454 | 2.59k | return true; |
455 | 6.52k | } |
456 | | |
457 | 9.27k | return false; |
458 | 11.8k | } |
459 | | |
460 | | /* |
461 | | * Return true iff 'datum' is a member of the list. Equality is |
462 | | * determined by using simple pointer comparison. |
463 | | */ |
464 | | bool |
465 | | list_member_ptr(const List *list, const void *datum) |
466 | 417k | { |
467 | 417k | const ListCell *cell; |
468 | | |
469 | 417k | Assert(IsPointerList(list)); |
470 | 417k | check_list_invariants(list); |
471 | | |
472 | 417k | foreach(cell, list) |
473 | 308k | { |
474 | 308k | if (lfirst(cell) == datum) |
475 | 230k | return true; |
476 | 308k | } |
477 | | |
478 | 187k | return false; |
479 | 417k | } |
480 | | |
481 | | /* |
482 | | * Return true iff the integer 'datum' is a member of the list. |
483 | | */ |
484 | | bool |
485 | | list_member_int(const List *list, int datum) |
486 | 58.8k | { |
487 | 58.8k | const ListCell *cell; |
488 | | |
489 | 58.8k | Assert(IsIntegerList(list)); |
490 | 58.8k | check_list_invariants(list); |
491 | | |
492 | 58.8k | foreach(cell, list) |
493 | 11.5k | { |
494 | 11.5k | if (lfirst_int(cell) == datum) |
495 | 5.11k | return true; |
496 | 11.5k | } |
497 | | |
498 | 53.7k | return false; |
499 | 58.8k | } |
500 | | |
501 | | /* |
502 | | * Return true iff the OID 'datum' is a member of the list. |
503 | | */ |
504 | | bool |
505 | | list_member_oid(const List *list, Oid datum) |
506 | 3.02M | { |
507 | 3.02M | const ListCell *cell; |
508 | | |
509 | 3.02M | Assert(IsOidList(list)); |
510 | 3.02M | check_list_invariants(list); |
511 | | |
512 | 3.02M | foreach(cell, list) |
513 | 256k | { |
514 | 256k | if (lfirst_oid(cell) == datum) |
515 | 80.7k | return true; |
516 | 256k | } |
517 | | |
518 | 2.94M | return false; |
519 | 3.02M | } |
520 | | |
521 | | /* |
522 | | * Delete 'cell' from 'list'; 'prev' is the previous element to 'cell' |
523 | | * in 'list', if any (i.e. prev == NULL iff list->head == cell) |
524 | | * |
525 | | * The cell is pfree'd, as is the List header if this was the last member. |
526 | | */ |
527 | | List * |
528 | | list_delete_cell(List *list, ListCell *cell, ListCell *prev) |
529 | 1.42M | { |
530 | 1.42M | check_list_invariants(list); |
531 | 1.42M | Assert(prev != NULL ? lnext(prev) == cell : list_head(list) == cell); |
532 | | |
533 | | /* |
534 | | * If we're about to delete the last node from the list, free the whole |
535 | | * list instead and return NIL, which is the only valid representation of |
536 | | * a zero-length list. |
537 | | */ |
538 | 1.42M | if (list->length == 1) |
539 | 789k | { |
540 | 789k | list_free(list); |
541 | 789k | return NIL; |
542 | 789k | } |
543 | | |
544 | | /* |
545 | | * Otherwise, adjust the necessary list links, deallocate the particular |
546 | | * node we have just removed, and return the list we were given. |
547 | | */ |
548 | 635k | list->length--; |
549 | | |
550 | 635k | if (prev) |
551 | 7.10k | prev->next = cell->next; |
552 | 628k | else |
553 | 628k | list->head = cell->next; |
554 | | |
555 | 635k | if (list->tail == cell) |
556 | 5.50k | list->tail = prev; |
557 | | |
558 | 635k | pfree(cell); |
559 | 635k | return list; |
560 | 1.42M | } |
561 | | |
562 | | /* |
563 | | * Delete the first cell in list that matches datum, if any. |
564 | | * Equality is determined via equal(). |
565 | | */ |
566 | | List * |
567 | | list_delete(List *list, void *datum) |
568 | 0 | { |
569 | 0 | ListCell *cell; |
570 | 0 | ListCell *prev; |
571 | |
|
572 | 0 | Assert(IsPointerList(list)); |
573 | 0 | check_list_invariants(list); |
574 | |
|
575 | 0 | prev = NULL; |
576 | 0 | foreach(cell, list) |
577 | 0 | { |
578 | 0 | if (equal(lfirst(cell), datum)) |
579 | 0 | return list_delete_cell(list, cell, prev); |
580 | | |
581 | 0 | prev = cell; |
582 | 0 | } |
583 | | |
584 | | /* Didn't find a match: return the list unmodified */ |
585 | 0 | return list; |
586 | 0 | } |
587 | | |
588 | | /* As above, but use simple pointer equality */ |
589 | | List * |
590 | | list_delete_ptr(List *list, void *datum) |
591 | 800k | { |
592 | 800k | ListCell *cell; |
593 | 800k | ListCell *prev; |
594 | | |
595 | 800k | Assert(IsPointerList(list)); |
596 | 800k | check_list_invariants(list); |
597 | | |
598 | 800k | prev = NULL; |
599 | 800k | foreach(cell, list) |
600 | 801k | { |
601 | 801k | if (lfirst(cell) == datum) |
602 | 799k | return list_delete_cell(list, cell, prev); |
603 | | |
604 | 1.69k | prev = cell; |
605 | 1.69k | } |
606 | | |
607 | | /* Didn't find a match: return the list unmodified */ |
608 | 549 | return list; |
609 | 800k | } |
610 | | |
611 | | /* As above, but for integers */ |
612 | | List * |
613 | | list_delete_int(List *list, int datum) |
614 | 5 | { |
615 | 5 | ListCell *cell; |
616 | 5 | ListCell *prev; |
617 | | |
618 | 5 | Assert(IsIntegerList(list)); |
619 | 5 | check_list_invariants(list); |
620 | | |
621 | 5 | prev = NULL; |
622 | 5 | foreach(cell, list) |
623 | 5 | { |
624 | 5 | if (lfirst_int(cell) == datum) |
625 | 5 | return list_delete_cell(list, cell, prev); |
626 | | |
627 | 0 | prev = cell; |
628 | 0 | } |
629 | | |
630 | | /* Didn't find a match: return the list unmodified */ |
631 | 0 | return list; |
632 | 5 | } |
633 | | |
634 | | /* As above, but for OIDs */ |
635 | | List * |
636 | | list_delete_oid(List *list, Oid datum) |
637 | 17 | { |
638 | 17 | ListCell *cell; |
639 | 17 | ListCell *prev; |
640 | | |
641 | 17 | Assert(IsOidList(list)); |
642 | 17 | check_list_invariants(list); |
643 | | |
644 | 17 | prev = NULL; |
645 | 17 | foreach(cell, list) |
646 | 15 | { |
647 | 15 | if (lfirst_oid(cell) == datum) |
648 | 15 | return list_delete_cell(list, cell, prev); |
649 | | |
650 | 0 | prev = cell; |
651 | 0 | } |
652 | | |
653 | | /* Didn't find a match: return the list unmodified */ |
654 | 2 | return list; |
655 | 17 | } |
656 | | |
657 | | /* |
658 | | * Delete the first element of the list. |
659 | | * |
660 | | * This is useful to replace the Lisp-y code "list = lnext(list);" in cases |
661 | | * where the intent is to alter the list rather than just traverse it. |
662 | | * Beware that the removed cell is freed, whereas the lnext() coding leaves |
663 | | * the original list head intact if there's another pointer to it. |
664 | | */ |
665 | | List * |
666 | | list_delete_first(List *list) |
667 | 487k | { |
668 | 487k | check_list_invariants(list); |
669 | | |
670 | 487k | if (list == NIL) |
671 | 0 | return NIL; /* would an error be better? */ |
672 | | |
673 | 487k | return list_delete_cell(list, list_head(list), NULL); |
674 | 487k | } |
675 | | |
676 | | /* |
677 | | * Generate the union of two lists. This is calculated by copying |
678 | | * list1 via list_copy(), then adding to it all the members of list2 |
679 | | * that aren't already in list1. |
680 | | * |
681 | | * Whether an element is already a member of the list is determined |
682 | | * via equal(). |
683 | | * |
684 | | * The returned list is newly-allocated, although the content of the |
685 | | * cells is the same (i.e. any pointed-to objects are not copied). |
686 | | * |
687 | | * NB: this function will NOT remove any duplicates that are present |
688 | | * in list1 (so it only performs a "union" if list1 is known unique to |
689 | | * start with). Also, if you are about to write "x = list_union(x, y)" |
690 | | * you probably want to use list_concat_unique() instead to avoid wasting |
691 | | * the list cells of the old x list. |
692 | | * |
693 | | * This function could probably be implemented a lot faster if it is a |
694 | | * performance bottleneck. |
695 | | */ |
696 | | List * |
697 | | list_union(const List *list1, const List *list2) |
698 | 626 | { |
699 | 626 | List *result; |
700 | 626 | const ListCell *cell; |
701 | | |
702 | 626 | Assert(IsPointerList(list1)); |
703 | 626 | Assert(IsPointerList(list2)); |
704 | | |
705 | 626 | result = list_copy(list1); |
706 | 626 | foreach(cell, list2) |
707 | 633 | { |
708 | 633 | if (!list_member(result, lfirst(cell))) |
709 | 632 | result = lappend(result, lfirst(cell)); |
710 | 633 | } |
711 | | |
712 | 626 | check_list_invariants(result); |
713 | 626 | return result; |
714 | 626 | } |
715 | | |
716 | | /* |
717 | | * This variant of list_union() determines duplicates via simple |
718 | | * pointer comparison. |
719 | | */ |
720 | | List * |
721 | | list_union_ptr(const List *list1, const List *list2) |
722 | 0 | { |
723 | 0 | List *result; |
724 | 0 | const ListCell *cell; |
725 | |
|
726 | 0 | Assert(IsPointerList(list1)); |
727 | 0 | Assert(IsPointerList(list2)); |
728 | | |
729 | 0 | result = list_copy(list1); |
730 | 0 | foreach(cell, list2) |
731 | 0 | { |
732 | 0 | if (!list_member_ptr(result, lfirst(cell))) |
733 | 0 | result = lappend(result, lfirst(cell)); |
734 | 0 | } |
735 | |
|
736 | 0 | check_list_invariants(result); |
737 | 0 | return result; |
738 | 0 | } |
739 | | |
740 | | /* |
741 | | * This variant of list_union() operates upon lists of integers. |
742 | | */ |
743 | | List * |
744 | | list_union_int(const List *list1, const List *list2) |
745 | 28 | { |
746 | 28 | List *result; |
747 | 28 | const ListCell *cell; |
748 | | |
749 | 28 | Assert(IsIntegerList(list1)); |
750 | 28 | Assert(IsIntegerList(list2)); |
751 | | |
752 | 28 | result = list_copy(list1); |
753 | 28 | foreach(cell, list2) |
754 | 18 | { |
755 | 18 | if (!list_member_int(result, lfirst_int(cell))) |
756 | 18 | result = lappend_int(result, lfirst_int(cell)); |
757 | 18 | } |
758 | | |
759 | 28 | check_list_invariants(result); |
760 | 28 | return result; |
761 | 28 | } |
762 | | |
763 | | /* |
764 | | * This variant of list_union() operates upon lists of OIDs. |
765 | | */ |
766 | | List * |
767 | | list_union_oid(const List *list1, const List *list2) |
768 | 0 | { |
769 | 0 | List *result; |
770 | 0 | const ListCell *cell; |
771 | |
|
772 | 0 | Assert(IsOidList(list1)); |
773 | 0 | Assert(IsOidList(list2)); |
774 | | |
775 | 0 | result = list_copy(list1); |
776 | 0 | foreach(cell, list2) |
777 | 0 | { |
778 | 0 | if (!list_member_oid(result, lfirst_oid(cell))) |
779 | 0 | result = lappend_oid(result, lfirst_oid(cell)); |
780 | 0 | } |
781 | |
|
782 | 0 | check_list_invariants(result); |
783 | 0 | return result; |
784 | 0 | } |
785 | | |
786 | | /* |
787 | | * Return a list that contains all the cells that are in both list1 and |
788 | | * list2. The returned list is freshly allocated via palloc(), but the |
789 | | * cells themselves point to the same objects as the cells of the |
790 | | * input lists. |
791 | | * |
792 | | * Duplicate entries in list1 will not be suppressed, so it's only a true |
793 | | * "intersection" if list1 is known unique beforehand. |
794 | | * |
795 | | * This variant works on lists of pointers, and determines list |
796 | | * membership via equal(). Note that the list1 member will be pointed |
797 | | * to in the result. |
798 | | */ |
799 | | List * |
800 | | list_intersection(const List *list1, const List *list2) |
801 | 4.04k | { |
802 | 4.04k | List *result; |
803 | 4.04k | const ListCell *cell; |
804 | | |
805 | 4.04k | if (list1 == NIL || list2 == NIL) |
806 | 3.81k | return NIL; |
807 | | |
808 | 232 | Assert(IsPointerList(list1)); |
809 | 232 | Assert(IsPointerList(list2)); |
810 | | |
811 | 232 | result = NIL; |
812 | 232 | foreach(cell, list1) |
813 | 255 | { |
814 | 255 | if (list_member(list2, lfirst(cell))) |
815 | 17 | result = lappend(result, lfirst(cell)); |
816 | 255 | } |
817 | | |
818 | 232 | check_list_invariants(result); |
819 | 232 | return result; |
820 | 232 | } |
821 | | |
822 | | /* |
823 | | * As list_intersection but operates on lists of integers. |
824 | | */ |
825 | | List * |
826 | | list_intersection_int(const List *list1, const List *list2) |
827 | 2 | { |
828 | 2 | List *result; |
829 | 2 | const ListCell *cell; |
830 | | |
831 | 2 | if (list1 == NIL || list2 == NIL) |
832 | 0 | return NIL; |
833 | | |
834 | 2 | Assert(IsIntegerList(list1)); |
835 | 2 | Assert(IsIntegerList(list2)); |
836 | | |
837 | 2 | result = NIL; |
838 | 2 | foreach(cell, list1) |
839 | 2 | { |
840 | 2 | if (list_member_int(list2, lfirst_int(cell))) |
841 | 0 | result = lappend_int(result, lfirst_int(cell)); |
842 | 2 | } |
843 | | |
844 | 2 | check_list_invariants(result); |
845 | 2 | return result; |
846 | 2 | } |
847 | | |
848 | | /* |
849 | | * Return a list that contains all the cells in list1 that are not in |
850 | | * list2. The returned list is freshly allocated via palloc(), but the |
851 | | * cells themselves point to the same objects as the cells of the |
852 | | * input lists. |
853 | | * |
854 | | * This variant works on lists of pointers, and determines list |
855 | | * membership via equal() |
856 | | */ |
857 | | List * |
858 | | list_difference(const List *list1, const List *list2) |
859 | 8.86k | { |
860 | 8.86k | const ListCell *cell; |
861 | 8.86k | List *result = NIL; |
862 | | |
863 | 8.86k | Assert(IsPointerList(list1)); |
864 | 8.86k | Assert(IsPointerList(list2)); |
865 | | |
866 | 8.86k | if (list2 == NIL) |
867 | 7.36k | return list_copy(list1); |
868 | | |
869 | 1.50k | foreach(cell, list1) |
870 | 2.11k | { |
871 | 2.11k | if (!list_member(list2, lfirst(cell))) |
872 | 354 | result = lappend(result, lfirst(cell)); |
873 | 2.11k | } |
874 | | |
875 | 1.50k | check_list_invariants(result); |
876 | 1.50k | return result; |
877 | 8.86k | } |
878 | | |
879 | | /* |
880 | | * This variant of list_difference() determines list membership via |
881 | | * simple pointer equality. |
882 | | */ |
883 | | List * |
884 | | list_difference_ptr(const List *list1, const List *list2) |
885 | 396 | { |
886 | 396 | const ListCell *cell; |
887 | 396 | List *result = NIL; |
888 | | |
889 | 396 | Assert(IsPointerList(list1)); |
890 | 396 | Assert(IsPointerList(list2)); |
891 | | |
892 | 396 | if (list2 == NIL) |
893 | 70 | return list_copy(list1); |
894 | | |
895 | 326 | foreach(cell, list1) |
896 | 682 | { |
897 | 682 | if (!list_member_ptr(list2, lfirst(cell))) |
898 | 24 | result = lappend(result, lfirst(cell)); |
899 | 682 | } |
900 | | |
901 | 326 | check_list_invariants(result); |
902 | 326 | return result; |
903 | 396 | } |
904 | | |
905 | | /* |
906 | | * This variant of list_difference() operates upon lists of integers. |
907 | | */ |
908 | | List * |
909 | | list_difference_int(const List *list1, const List *list2) |
910 | 14 | { |
911 | 14 | const ListCell *cell; |
912 | 14 | List *result = NIL; |
913 | | |
914 | 14 | Assert(IsIntegerList(list1)); |
915 | 14 | Assert(IsIntegerList(list2)); |
916 | | |
917 | 14 | if (list2 == NIL) |
918 | 14 | return list_copy(list1); |
919 | | |
920 | 0 | foreach(cell, list1) |
921 | 0 | { |
922 | 0 | if (!list_member_int(list2, lfirst_int(cell))) |
923 | 0 | result = lappend_int(result, lfirst_int(cell)); |
924 | 0 | } |
925 | |
|
926 | 0 | check_list_invariants(result); |
927 | 0 | return result; |
928 | 14 | } |
929 | | |
930 | | /* |
931 | | * This variant of list_difference() operates upon lists of OIDs. |
932 | | */ |
933 | | List * |
934 | | list_difference_oid(const List *list1, const List *list2) |
935 | 0 | { |
936 | 0 | const ListCell *cell; |
937 | 0 | List *result = NIL; |
938 | |
|
939 | 0 | Assert(IsOidList(list1)); |
940 | 0 | Assert(IsOidList(list2)); |
941 | | |
942 | 0 | if (list2 == NIL) |
943 | 0 | return list_copy(list1); |
944 | | |
945 | 0 | foreach(cell, list1) |
946 | 0 | { |
947 | 0 | if (!list_member_oid(list2, lfirst_oid(cell))) |
948 | 0 | result = lappend_oid(result, lfirst_oid(cell)); |
949 | 0 | } |
950 | |
|
951 | 0 | check_list_invariants(result); |
952 | 0 | return result; |
953 | 0 | } |
954 | | |
955 | | /* |
956 | | * Append datum to list, but only if it isn't already in the list. |
957 | | * |
958 | | * Whether an element is already a member of the list is determined |
959 | | * via equal(). |
960 | | */ |
961 | | List * |
962 | | list_append_unique(List *list, void *datum) |
963 | 453 | { |
964 | 453 | if (list_member(list, datum)) |
965 | 59 | return list; |
966 | 394 | else |
967 | 394 | return lappend(list, datum); |
968 | 453 | } |
969 | | |
970 | | /* |
971 | | * This variant of list_append_unique() determines list membership via |
972 | | * simple pointer equality. |
973 | | */ |
974 | | List * |
975 | | list_append_unique_ptr(List *list, void *datum) |
976 | 139k | { |
977 | 139k | if (list_member_ptr(list, datum)) |
978 | 8.05k | return list; |
979 | 131k | else |
980 | 131k | return lappend(list, datum); |
981 | 139k | } |
982 | | |
983 | | /* |
984 | | * This variant of list_append_unique() operates upon lists of integers. |
985 | | */ |
986 | | List * |
987 | | list_append_unique_int(List *list, int datum) |
988 | 0 | { |
989 | 0 | if (list_member_int(list, datum)) |
990 | 0 | return list; |
991 | 0 | else |
992 | 0 | return lappend_int(list, datum); |
993 | 0 | } |
994 | | |
995 | | /* |
996 | | * This variant of list_append_unique() operates upon lists of OIDs. |
997 | | */ |
998 | | List * |
999 | | list_append_unique_oid(List *list, Oid datum) |
1000 | 247 | { |
1001 | 247 | if (list_member_oid(list, datum)) |
1002 | 0 | return list; |
1003 | 247 | else |
1004 | 247 | return lappend_oid(list, datum); |
1005 | 247 | } |
1006 | | |
1007 | | /* |
1008 | | * Append to list1 each member of list2 that isn't already in list1. |
1009 | | * |
1010 | | * Whether an element is already a member of the list is determined |
1011 | | * via equal(). |
1012 | | * |
1013 | | * This is almost the same functionality as list_union(), but list1 is |
1014 | | * modified in-place rather than being copied. Note also that list2's cells |
1015 | | * are not inserted in list1, so the analogy to list_concat() isn't perfect. |
1016 | | */ |
1017 | | List * |
1018 | | list_concat_unique(List *list1, List *list2) |
1019 | 16 | { |
1020 | 16 | ListCell *cell; |
1021 | | |
1022 | 16 | Assert(IsPointerList(list1)); |
1023 | 16 | Assert(IsPointerList(list2)); |
1024 | | |
1025 | 16 | foreach(cell, list2) |
1026 | 16 | { |
1027 | 16 | if (!list_member(list1, lfirst(cell))) |
1028 | 16 | list1 = lappend(list1, lfirst(cell)); |
1029 | 16 | } |
1030 | | |
1031 | 16 | check_list_invariants(list1); |
1032 | 16 | return list1; |
1033 | 16 | } |
1034 | | |
1035 | | /* |
1036 | | * This variant of list_concat_unique() determines list membership via |
1037 | | * simple pointer equality. |
1038 | | */ |
1039 | | List * |
1040 | | list_concat_unique_ptr(List *list1, List *list2) |
1041 | 0 | { |
1042 | 0 | ListCell *cell; |
1043 | |
|
1044 | 0 | Assert(IsPointerList(list1)); |
1045 | 0 | Assert(IsPointerList(list2)); |
1046 | | |
1047 | 0 | foreach(cell, list2) |
1048 | 0 | { |
1049 | 0 | if (!list_member_ptr(list1, lfirst(cell))) |
1050 | 0 | list1 = lappend(list1, lfirst(cell)); |
1051 | 0 | } |
1052 | |
|
1053 | 0 | check_list_invariants(list1); |
1054 | 0 | return list1; |
1055 | 0 | } |
1056 | | |
1057 | | /* |
1058 | | * This variant of list_concat_unique() operates upon lists of integers. |
1059 | | */ |
1060 | | List * |
1061 | | list_concat_unique_int(List *list1, List *list2) |
1062 | 0 | { |
1063 | 0 | ListCell *cell; |
1064 | |
|
1065 | 0 | Assert(IsIntegerList(list1)); |
1066 | 0 | Assert(IsIntegerList(list2)); |
1067 | | |
1068 | 0 | foreach(cell, list2) |
1069 | 0 | { |
1070 | 0 | if (!list_member_int(list1, lfirst_int(cell))) |
1071 | 0 | list1 = lappend_int(list1, lfirst_int(cell)); |
1072 | 0 | } |
1073 | |
|
1074 | 0 | check_list_invariants(list1); |
1075 | 0 | return list1; |
1076 | 0 | } |
1077 | | |
1078 | | /* |
1079 | | * This variant of list_concat_unique() operates upon lists of OIDs. |
1080 | | */ |
1081 | | List * |
1082 | | list_concat_unique_oid(List *list1, List *list2) |
1083 | 326 | { |
1084 | 326 | ListCell *cell; |
1085 | | |
1086 | 326 | Assert(IsOidList(list1)); |
1087 | 326 | Assert(IsOidList(list2)); |
1088 | | |
1089 | 326 | foreach(cell, list2) |
1090 | 0 | { |
1091 | 0 | if (!list_member_oid(list1, lfirst_oid(cell))) |
1092 | 0 | list1 = lappend_oid(list1, lfirst_oid(cell)); |
1093 | 0 | } |
1094 | | |
1095 | 326 | check_list_invariants(list1); |
1096 | 326 | return list1; |
1097 | 326 | } |
1098 | | |
1099 | | /* |
1100 | | * Free all storage in a list, and optionally the pointed-to elements |
1101 | | */ |
1102 | | static void |
1103 | | list_free_private(List *list, bool deep) |
1104 | 8.10M | { |
1105 | 8.10M | ListCell *cell; |
1106 | | |
1107 | 8.10M | check_list_invariants(list); |
1108 | | |
1109 | 8.10M | cell = list_head(list); |
1110 | 12.2M | while (cell != NULL) |
1111 | 4.15M | { |
1112 | 4.15M | ListCell *tmp = cell; |
1113 | | |
1114 | 4.15M | cell = lnext(cell); |
1115 | 4.15M | if (deep) |
1116 | 687k | pfree(lfirst(tmp)); |
1117 | 4.15M | pfree(tmp); |
1118 | 4.15M | } |
1119 | | |
1120 | 8.10M | if (list) |
1121 | 2.64M | pfree(list); |
1122 | 8.10M | } |
1123 | | |
1124 | | /* |
1125 | | * Free all the cells of the list, as well as the list itself. Any |
1126 | | * objects that are pointed-to by the cells of the list are NOT |
1127 | | * free'd. |
1128 | | * |
1129 | | * On return, the argument to this function has been freed, so the |
1130 | | * caller would be wise to set it to NIL for safety's sake. |
1131 | | */ |
1132 | | void |
1133 | | list_free(List *list) |
1134 | 7.93M | { |
1135 | 7.93M | list_free_private(list, false); |
1136 | 7.93M | } |
1137 | | |
1138 | | /* |
1139 | | * Free all the cells of the list, the list itself, and all the |
1140 | | * objects pointed-to by the cells of the list (each element in the |
1141 | | * list must contain a pointer to a palloc()'d region of memory!) |
1142 | | * |
1143 | | * On return, the argument to this function has been freed, so the |
1144 | | * caller would be wise to set it to NIL for safety's sake. |
1145 | | */ |
1146 | | void |
1147 | | list_free_deep(List *list) |
1148 | 169k | { |
1149 | | /* |
1150 | | * A "deep" free operation only makes sense on a list of pointers. |
1151 | | */ |
1152 | 169k | Assert(IsPointerList(list)); |
1153 | 169k | list_free_private(list, true); |
1154 | 169k | } |
1155 | | |
1156 | | /* |
1157 | | * Return a shallow copy of the specified list. |
1158 | | */ |
1159 | | List * |
1160 | | list_copy(const List *oldlist) |
1161 | 4.45M | { |
1162 | 4.45M | List *newlist; |
1163 | 4.45M | ListCell *newlist_prev; |
1164 | 4.45M | ListCell *oldlist_cur; |
1165 | | |
1166 | 4.45M | if (oldlist == NIL) |
1167 | 583k | return NIL; |
1168 | | |
1169 | 3.86M | newlist = new_list(oldlist->type); |
1170 | 3.86M | newlist->length = oldlist->length; |
1171 | | |
1172 | | /* |
1173 | | * Copy over the data in the first cell; new_list() has already allocated |
1174 | | * the head cell itself |
1175 | | */ |
1176 | 3.86M | newlist->head->data = oldlist->head->data; |
1177 | | |
1178 | 3.86M | newlist_prev = newlist->head; |
1179 | 3.86M | oldlist_cur = oldlist->head->next; |
1180 | 4.90M | while (oldlist_cur) |
1181 | 1.03M | { |
1182 | 1.03M | ListCell *newlist_cur; |
1183 | | |
1184 | 1.03M | newlist_cur = (ListCell *) palloc(sizeof(*newlist_cur)); |
1185 | 1.03M | newlist_cur->data = oldlist_cur->data; |
1186 | 1.03M | newlist_prev->next = newlist_cur; |
1187 | | |
1188 | 1.03M | newlist_prev = newlist_cur; |
1189 | 1.03M | oldlist_cur = oldlist_cur->next; |
1190 | 1.03M | } |
1191 | | |
1192 | 3.86M | newlist_prev->next = NULL; |
1193 | 3.86M | newlist->tail = newlist_prev; |
1194 | | |
1195 | 3.86M | check_list_invariants(newlist); |
1196 | 3.86M | return newlist; |
1197 | 4.45M | } |
1198 | | |
1199 | | /* |
1200 | | * Return a shallow copy of the specified list, without the first N elements. |
1201 | | */ |
1202 | | List * |
1203 | | list_copy_tail(const List *oldlist, int nskip) |
1204 | 7.75k | { |
1205 | 7.75k | List *newlist; |
1206 | 7.75k | ListCell *newlist_prev; |
1207 | 7.75k | ListCell *oldlist_cur; |
1208 | | |
1209 | 7.75k | if (nskip < 0) |
1210 | 0 | nskip = 0; /* would it be better to elog? */ |
1211 | | |
1212 | 7.75k | if (oldlist == NIL || nskip >= oldlist->length) |
1213 | 101 | return NIL; |
1214 | | |
1215 | 7.65k | newlist = new_list(oldlist->type); |
1216 | 7.65k | newlist->length = oldlist->length - nskip; |
1217 | | |
1218 | | /* |
1219 | | * Skip over the unwanted elements. |
1220 | | */ |
1221 | 7.65k | oldlist_cur = oldlist->head; |
1222 | 8.33k | while (nskip-- > 0) |
1223 | 676 | oldlist_cur = oldlist_cur->next; |
1224 | | |
1225 | | /* |
1226 | | * Copy over the data in the first remaining cell; new_list() has already |
1227 | | * allocated the head cell itself |
1228 | | */ |
1229 | 7.65k | newlist->head->data = oldlist_cur->data; |
1230 | | |
1231 | 7.65k | newlist_prev = newlist->head; |
1232 | 7.65k | oldlist_cur = oldlist_cur->next; |
1233 | 198k | while (oldlist_cur) |
1234 | 190k | { |
1235 | 190k | ListCell *newlist_cur; |
1236 | | |
1237 | 190k | newlist_cur = (ListCell *) palloc(sizeof(*newlist_cur)); |
1238 | 190k | newlist_cur->data = oldlist_cur->data; |
1239 | 190k | newlist_prev->next = newlist_cur; |
1240 | | |
1241 | 190k | newlist_prev = newlist_cur; |
1242 | 190k | oldlist_cur = oldlist_cur->next; |
1243 | 190k | } |
1244 | | |
1245 | 7.65k | newlist_prev->next = NULL; |
1246 | 7.65k | newlist->tail = newlist_prev; |
1247 | | |
1248 | 7.65k | check_list_invariants(newlist); |
1249 | 7.65k | return newlist; |
1250 | 7.75k | } |
1251 | | |
1252 | | /* |
1253 | | * Sort a list as though by qsort. |
1254 | | * |
1255 | | * A new list is built and returned. Like list_copy, this doesn't make |
1256 | | * fresh copies of any pointed-to data. |
1257 | | * |
1258 | | * The comparator function receives arguments of type ListCell **. |
1259 | | */ |
1260 | | List * |
1261 | | list_qsort(const List *list, list_qsort_comparator cmp) |
1262 | 24 | { |
1263 | 24 | int len = list_length(list); |
1264 | 24 | ListCell **list_arr; |
1265 | 24 | List *newlist; |
1266 | 24 | ListCell *newlist_prev; |
1267 | 24 | ListCell *cell; |
1268 | 24 | int i; |
1269 | | |
1270 | | /* Empty list is easy */ |
1271 | 24 | if (len == 0) |
1272 | 12 | return NIL; |
1273 | | |
1274 | | /* Flatten list cells into an array, so we can use qsort */ |
1275 | 12 | list_arr = (ListCell **) palloc(sizeof(ListCell *) * len); |
1276 | 12 | i = 0; |
1277 | 12 | foreach(cell, list) |
1278 | 36 | list_arr[i++] = cell; |
1279 | | |
1280 | 12 | qsort(list_arr, len, sizeof(ListCell *), cmp); |
1281 | | |
1282 | | /* Construct new list (this code is much like list_copy) */ |
1283 | 12 | newlist = new_list(list->type); |
1284 | 12 | newlist->length = len; |
1285 | | |
1286 | | /* |
1287 | | * Copy over the data in the first cell; new_list() has already allocated |
1288 | | * the head cell itself |
1289 | | */ |
1290 | 12 | newlist->head->data = list_arr[0]->data; |
1291 | | |
1292 | 12 | newlist_prev = newlist->head; |
1293 | 36 | for (i = 1; i < len; i++24 ) |
1294 | 24 | { |
1295 | 24 | ListCell *newlist_cur; |
1296 | | |
1297 | 24 | newlist_cur = (ListCell *) palloc(sizeof(*newlist_cur)); |
1298 | 24 | newlist_cur->data = list_arr[i]->data; |
1299 | 24 | newlist_prev->next = newlist_cur; |
1300 | | |
1301 | 24 | newlist_prev = newlist_cur; |
1302 | 24 | } |
1303 | | |
1304 | 12 | newlist_prev->next = NULL; |
1305 | 12 | newlist->tail = newlist_prev; |
1306 | | |
1307 | | /* Might as well free the workspace array */ |
1308 | 12 | pfree(list_arr); |
1309 | | |
1310 | 12 | check_list_invariants(newlist); |
1311 | 12 | return newlist; |
1312 | 24 | } |
1313 | | |
1314 | | /* |
1315 | | * Temporary compatibility functions |
1316 | | * |
1317 | | * In order to avoid warnings for these function definitions, we need |
1318 | | * to include a prototype here as well as in pg_list.h. That's because |
1319 | | * we don't enable list API compatibility in list.c, so we |
1320 | | * don't see the prototypes for these functions. |
1321 | | */ |
1322 | | |
1323 | | /* |
1324 | | * Given a list, return its length. This is merely defined for the |
1325 | | * sake of backward compatibility: we can't afford to define a macro |
1326 | | * called "length", so it must be a function. New code should use the |
1327 | | * list_length() macro in order to avoid the overhead of a function |
1328 | | * call. |
1329 | | */ |
1330 | | int length(const List *list); |
1331 | | |
1332 | | int |
1333 | | length(const List *list) |
1334 | 0 | { |
1335 | 0 | return list_length(list); |
1336 | 0 | } |