comparison src/list.c @ 9560:1e68dfd7931b v7.4.2057

commit https://github.com/vim/vim/commit/da861d631d7e22654faee2789286c685ad548911 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 17 15:46:27 2016 +0200 patch 7.4.2057 Problem: eval.c is too big. Solution: Move List functions to list.c
author Christian Brabandt <cb@256bit.org>
date Sun, 17 Jul 2016 16:00:05 +0200
parents
children 5eaa708ab50d
comparison
equal deleted inserted replaced
9559:354168ab1997 9560:1e68dfd7931b
1 /* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10 /*
11 * list.c: List support
12 */
13
14 #include "vim.h"
15
16 #if defined(FEAT_EVAL) || defined(PROTO)
17
18 /* List heads for garbage collection. */
19 static list_T *first_list = NULL; /* list of all lists */
20
21 /*
22 * Add a watcher to a list.
23 */
24 void
25 list_add_watch(list_T *l, listwatch_T *lw)
26 {
27 lw->lw_next = l->lv_watch;
28 l->lv_watch = lw;
29 }
30
31 /*
32 * Remove a watcher from a list.
33 * No warning when it isn't found...
34 */
35 void
36 list_rem_watch(list_T *l, listwatch_T *lwrem)
37 {
38 listwatch_T *lw, **lwp;
39
40 lwp = &l->lv_watch;
41 for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
42 {
43 if (lw == lwrem)
44 {
45 *lwp = lw->lw_next;
46 break;
47 }
48 lwp = &lw->lw_next;
49 }
50 }
51
52 /*
53 * Just before removing an item from a list: advance watchers to the next
54 * item.
55 */
56 void
57 list_fix_watch(list_T *l, listitem_T *item)
58 {
59 listwatch_T *lw;
60
61 for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
62 if (lw->lw_item == item)
63 lw->lw_item = item->li_next;
64 }
65
66 /*
67 * Allocate an empty header for a list.
68 * Caller should take care of the reference count.
69 */
70 list_T *
71 list_alloc(void)
72 {
73 list_T *l;
74
75 l = (list_T *)alloc_clear(sizeof(list_T));
76 if (l != NULL)
77 {
78 /* Prepend the list to the list of lists for garbage collection. */
79 if (first_list != NULL)
80 first_list->lv_used_prev = l;
81 l->lv_used_prev = NULL;
82 l->lv_used_next = first_list;
83 first_list = l;
84 }
85 return l;
86 }
87
88 /*
89 * Allocate an empty list for a return value, with reference count set.
90 * Returns OK or FAIL.
91 */
92 int
93 rettv_list_alloc(typval_T *rettv)
94 {
95 list_T *l = list_alloc();
96
97 if (l == NULL)
98 return FAIL;
99
100 rettv->vval.v_list = l;
101 rettv->v_type = VAR_LIST;
102 rettv->v_lock = 0;
103 ++l->lv_refcount;
104 return OK;
105 }
106
107 /*
108 * Unreference a list: decrement the reference count and free it when it
109 * becomes zero.
110 */
111 void
112 list_unref(list_T *l)
113 {
114 if (l != NULL && --l->lv_refcount <= 0)
115 list_free(l);
116 }
117
118 /*
119 * Free a list, including all non-container items it points to.
120 * Ignores the reference count.
121 */
122 static void
123 list_free_contents(list_T *l)
124 {
125 listitem_T *item;
126
127 for (item = l->lv_first; item != NULL; item = l->lv_first)
128 {
129 /* Remove the item before deleting it. */
130 l->lv_first = item->li_next;
131 clear_tv(&item->li_tv);
132 vim_free(item);
133 }
134 }
135
136 /*
137 * Go through the list of lists and free items without the copyID.
138 * But don't free a list that has a watcher (used in a for loop), these
139 * are not referenced anywhere.
140 */
141 int
142 list_free_nonref(int copyID)
143 {
144 list_T *ll;
145 int did_free = FALSE;
146
147 for (ll = first_list; ll != NULL; ll = ll->lv_used_next)
148 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
149 && ll->lv_watch == NULL)
150 {
151 /* Free the List and ordinary items it contains, but don't recurse
152 * into Lists and Dictionaries, they will be in the list of dicts
153 * or list of lists. */
154 list_free_contents(ll);
155 did_free = TRUE;
156 }
157 return did_free;
158 }
159
160 static void
161 list_free_list(list_T *l)
162 {
163 /* Remove the list from the list of lists for garbage collection. */
164 if (l->lv_used_prev == NULL)
165 first_list = l->lv_used_next;
166 else
167 l->lv_used_prev->lv_used_next = l->lv_used_next;
168 if (l->lv_used_next != NULL)
169 l->lv_used_next->lv_used_prev = l->lv_used_prev;
170
171 vim_free(l);
172 }
173
174 void
175 list_free_items(int copyID)
176 {
177 list_T *ll, *ll_next;
178
179 for (ll = first_list; ll != NULL; ll = ll_next)
180 {
181 ll_next = ll->lv_used_next;
182 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
183 && ll->lv_watch == NULL)
184 {
185 /* Free the List and ordinary items it contains, but don't recurse
186 * into Lists and Dictionaries, they will be in the list of dicts
187 * or list of lists. */
188 list_free_list(ll);
189 }
190 }
191 }
192
193 void
194 list_free(list_T *l)
195 {
196 if (!in_free_unref_items)
197 {
198 list_free_contents(l);
199 list_free_list(l);
200 }
201 }
202
203 /*
204 * Allocate a list item.
205 * It is not initialized, don't forget to set v_lock.
206 */
207 listitem_T *
208 listitem_alloc(void)
209 {
210 return (listitem_T *)alloc(sizeof(listitem_T));
211 }
212
213 /*
214 * Free a list item. Also clears the value. Does not notify watchers.
215 */
216 void
217 listitem_free(listitem_T *item)
218 {
219 clear_tv(&item->li_tv);
220 vim_free(item);
221 }
222
223 /*
224 * Remove a list item from a List and free it. Also clears the value.
225 */
226 void
227 listitem_remove(list_T *l, listitem_T *item)
228 {
229 vimlist_remove(l, item, item);
230 listitem_free(item);
231 }
232
233 /*
234 * Get the number of items in a list.
235 */
236 long
237 list_len(list_T *l)
238 {
239 if (l == NULL)
240 return 0L;
241 return l->lv_len;
242 }
243
244 /*
245 * Return TRUE when two lists have exactly the same values.
246 */
247 int
248 list_equal(
249 list_T *l1,
250 list_T *l2,
251 int ic, /* ignore case for strings */
252 int recursive) /* TRUE when used recursively */
253 {
254 listitem_T *item1, *item2;
255
256 if (l1 == NULL || l2 == NULL)
257 return FALSE;
258 if (l1 == l2)
259 return TRUE;
260 if (list_len(l1) != list_len(l2))
261 return FALSE;
262
263 for (item1 = l1->lv_first, item2 = l2->lv_first;
264 item1 != NULL && item2 != NULL;
265 item1 = item1->li_next, item2 = item2->li_next)
266 if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive))
267 return FALSE;
268 return item1 == NULL && item2 == NULL;
269 }
270
271 /*
272 * Locate item with index "n" in list "l" and return it.
273 * A negative index is counted from the end; -1 is the last item.
274 * Returns NULL when "n" is out of range.
275 */
276 listitem_T *
277 list_find(list_T *l, long n)
278 {
279 listitem_T *item;
280 long idx;
281
282 if (l == NULL)
283 return NULL;
284
285 /* Negative index is relative to the end. */
286 if (n < 0)
287 n = l->lv_len + n;
288
289 /* Check for index out of range. */
290 if (n < 0 || n >= l->lv_len)
291 return NULL;
292
293 /* When there is a cached index may start search from there. */
294 if (l->lv_idx_item != NULL)
295 {
296 if (n < l->lv_idx / 2)
297 {
298 /* closest to the start of the list */
299 item = l->lv_first;
300 idx = 0;
301 }
302 else if (n > (l->lv_idx + l->lv_len) / 2)
303 {
304 /* closest to the end of the list */
305 item = l->lv_last;
306 idx = l->lv_len - 1;
307 }
308 else
309 {
310 /* closest to the cached index */
311 item = l->lv_idx_item;
312 idx = l->lv_idx;
313 }
314 }
315 else
316 {
317 if (n < l->lv_len / 2)
318 {
319 /* closest to the start of the list */
320 item = l->lv_first;
321 idx = 0;
322 }
323 else
324 {
325 /* closest to the end of the list */
326 item = l->lv_last;
327 idx = l->lv_len - 1;
328 }
329 }
330
331 while (n > idx)
332 {
333 /* search forward */
334 item = item->li_next;
335 ++idx;
336 }
337 while (n < idx)
338 {
339 /* search backward */
340 item = item->li_prev;
341 --idx;
342 }
343
344 /* cache the used index */
345 l->lv_idx = idx;
346 l->lv_idx_item = item;
347
348 return item;
349 }
350
351 /*
352 * Get list item "l[idx]" as a number.
353 */
354 long
355 list_find_nr(
356 list_T *l,
357 long idx,
358 int *errorp) /* set to TRUE when something wrong */
359 {
360 listitem_T *li;
361
362 li = list_find(l, idx);
363 if (li == NULL)
364 {
365 if (errorp != NULL)
366 *errorp = TRUE;
367 return -1L;
368 }
369 return (long)get_tv_number_chk(&li->li_tv, errorp);
370 }
371
372 /*
373 * Get list item "l[idx - 1]" as a string. Returns NULL for failure.
374 */
375 char_u *
376 list_find_str(list_T *l, long idx)
377 {
378 listitem_T *li;
379
380 li = list_find(l, idx - 1);
381 if (li == NULL)
382 {
383 EMSGN(_(e_listidx), idx);
384 return NULL;
385 }
386 return get_tv_string(&li->li_tv);
387 }
388
389 /*
390 * Locate "item" list "l" and return its index.
391 * Returns -1 when "item" is not in the list.
392 */
393 long
394 list_idx_of_item(list_T *l, listitem_T *item)
395 {
396 long idx = 0;
397 listitem_T *li;
398
399 if (l == NULL)
400 return -1;
401 idx = 0;
402 for (li = l->lv_first; li != NULL && li != item; li = li->li_next)
403 ++idx;
404 if (li == NULL)
405 return -1;
406 return idx;
407 }
408
409 /*
410 * Append item "item" to the end of list "l".
411 */
412 void
413 list_append(list_T *l, listitem_T *item)
414 {
415 if (l->lv_last == NULL)
416 {
417 /* empty list */
418 l->lv_first = item;
419 l->lv_last = item;
420 item->li_prev = NULL;
421 }
422 else
423 {
424 l->lv_last->li_next = item;
425 item->li_prev = l->lv_last;
426 l->lv_last = item;
427 }
428 ++l->lv_len;
429 item->li_next = NULL;
430 }
431
432 /*
433 * Append typval_T "tv" to the end of list "l".
434 * Return FAIL when out of memory.
435 */
436 int
437 list_append_tv(list_T *l, typval_T *tv)
438 {
439 listitem_T *li = listitem_alloc();
440
441 if (li == NULL)
442 return FAIL;
443 copy_tv(tv, &li->li_tv);
444 list_append(l, li);
445 return OK;
446 }
447
448 /*
449 * Add a dictionary to a list. Used by getqflist().
450 * Return FAIL when out of memory.
451 */
452 int
453 list_append_dict(list_T *list, dict_T *dict)
454 {
455 listitem_T *li = listitem_alloc();
456
457 if (li == NULL)
458 return FAIL;
459 li->li_tv.v_type = VAR_DICT;
460 li->li_tv.v_lock = 0;
461 li->li_tv.vval.v_dict = dict;
462 list_append(list, li);
463 ++dict->dv_refcount;
464 return OK;
465 }
466
467 /*
468 * Make a copy of "str" and append it as an item to list "l".
469 * When "len" >= 0 use "str[len]".
470 * Returns FAIL when out of memory.
471 */
472 int
473 list_append_string(list_T *l, char_u *str, int len)
474 {
475 listitem_T *li = listitem_alloc();
476
477 if (li == NULL)
478 return FAIL;
479 list_append(l, li);
480 li->li_tv.v_type = VAR_STRING;
481 li->li_tv.v_lock = 0;
482 if (str == NULL)
483 li->li_tv.vval.v_string = NULL;
484 else if ((li->li_tv.vval.v_string = (len >= 0 ? vim_strnsave(str, len)
485 : vim_strsave(str))) == NULL)
486 return FAIL;
487 return OK;
488 }
489
490 /*
491 * Append "n" to list "l".
492 * Returns FAIL when out of memory.
493 */
494 int
495 list_append_number(list_T *l, varnumber_T n)
496 {
497 listitem_T *li;
498
499 li = listitem_alloc();
500 if (li == NULL)
501 return FAIL;
502 li->li_tv.v_type = VAR_NUMBER;
503 li->li_tv.v_lock = 0;
504 li->li_tv.vval.v_number = n;
505 list_append(l, li);
506 return OK;
507 }
508
509 /*
510 * Insert typval_T "tv" in list "l" before "item".
511 * If "item" is NULL append at the end.
512 * Return FAIL when out of memory.
513 */
514 int
515 list_insert_tv(list_T *l, typval_T *tv, listitem_T *item)
516 {
517 listitem_T *ni = listitem_alloc();
518
519 if (ni == NULL)
520 return FAIL;
521 copy_tv(tv, &ni->li_tv);
522 list_insert(l, ni, item);
523 return OK;
524 }
525
526 void
527 list_insert(list_T *l, listitem_T *ni, listitem_T *item)
528 {
529 if (item == NULL)
530 /* Append new item at end of list. */
531 list_append(l, ni);
532 else
533 {
534 /* Insert new item before existing item. */
535 ni->li_prev = item->li_prev;
536 ni->li_next = item;
537 if (item->li_prev == NULL)
538 {
539 l->lv_first = ni;
540 ++l->lv_idx;
541 }
542 else
543 {
544 item->li_prev->li_next = ni;
545 l->lv_idx_item = NULL;
546 }
547 item->li_prev = ni;
548 ++l->lv_len;
549 }
550 }
551
552 /*
553 * Extend "l1" with "l2".
554 * If "bef" is NULL append at the end, otherwise insert before this item.
555 * Returns FAIL when out of memory.
556 */
557 int
558 list_extend(list_T *l1, list_T *l2, listitem_T *bef)
559 {
560 listitem_T *item;
561 int todo = l2->lv_len;
562
563 /* We also quit the loop when we have inserted the original item count of
564 * the list, avoid a hang when we extend a list with itself. */
565 for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next)
566 if (list_insert_tv(l1, &item->li_tv, bef) == FAIL)
567 return FAIL;
568 return OK;
569 }
570
571 /*
572 * Concatenate lists "l1" and "l2" into a new list, stored in "tv".
573 * Return FAIL when out of memory.
574 */
575 int
576 list_concat(list_T *l1, list_T *l2, typval_T *tv)
577 {
578 list_T *l;
579
580 if (l1 == NULL || l2 == NULL)
581 return FAIL;
582
583 /* make a copy of the first list. */
584 l = list_copy(l1, FALSE, 0);
585 if (l == NULL)
586 return FAIL;
587 tv->v_type = VAR_LIST;
588 tv->vval.v_list = l;
589
590 /* append all items from the second list */
591 return list_extend(l, l2, NULL);
592 }
593
594 /*
595 * Make a copy of list "orig". Shallow if "deep" is FALSE.
596 * The refcount of the new list is set to 1.
597 * See item_copy() for "copyID".
598 * Returns NULL when out of memory.
599 */
600 list_T *
601 list_copy(list_T *orig, int deep, int copyID)
602 {
603 list_T *copy;
604 listitem_T *item;
605 listitem_T *ni;
606
607 if (orig == NULL)
608 return NULL;
609
610 copy = list_alloc();
611 if (copy != NULL)
612 {
613 if (copyID != 0)
614 {
615 /* Do this before adding the items, because one of the items may
616 * refer back to this list. */
617 orig->lv_copyID = copyID;
618 orig->lv_copylist = copy;
619 }
620 for (item = orig->lv_first; item != NULL && !got_int;
621 item = item->li_next)
622 {
623 ni = listitem_alloc();
624 if (ni == NULL)
625 break;
626 if (deep)
627 {
628 if (item_copy(&item->li_tv, &ni->li_tv, deep, copyID) == FAIL)
629 {
630 vim_free(ni);
631 break;
632 }
633 }
634 else
635 copy_tv(&item->li_tv, &ni->li_tv);
636 list_append(copy, ni);
637 }
638 ++copy->lv_refcount;
639 if (item != NULL)
640 {
641 list_unref(copy);
642 copy = NULL;
643 }
644 }
645
646 return copy;
647 }
648
649 /*
650 * Remove items "item" to "item2" from list "l".
651 * Does not free the listitem or the value!
652 * This used to be called list_remove, but that conflicts with a Sun header
653 * file.
654 */
655 void
656 vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2)
657 {
658 listitem_T *ip;
659
660 /* notify watchers */
661 for (ip = item; ip != NULL; ip = ip->li_next)
662 {
663 --l->lv_len;
664 list_fix_watch(l, ip);
665 if (ip == item2)
666 break;
667 }
668
669 if (item2->li_next == NULL)
670 l->lv_last = item->li_prev;
671 else
672 item2->li_next->li_prev = item->li_prev;
673 if (item->li_prev == NULL)
674 l->lv_first = item2->li_next;
675 else
676 item->li_prev->li_next = item2->li_next;
677 l->lv_idx_item = NULL;
678 }
679
680 /*
681 * Return an allocated string with the string representation of a list.
682 * May return NULL.
683 */
684 char_u *
685 list2string(typval_T *tv, int copyID, int restore_copyID)
686 {
687 garray_T ga;
688
689 if (tv->vval.v_list == NULL)
690 return NULL;
691 ga_init2(&ga, (int)sizeof(char), 80);
692 ga_append(&ga, '[');
693 if (list_join(&ga, tv->vval.v_list, (char_u *)", ",
694 FALSE, restore_copyID, copyID) == FAIL)
695 {
696 vim_free(ga.ga_data);
697 return NULL;
698 }
699 ga_append(&ga, ']');
700 ga_append(&ga, NUL);
701 return (char_u *)ga.ga_data;
702 }
703
704 typedef struct join_S {
705 char_u *s;
706 char_u *tofree;
707 } join_T;
708
709 static int
710 list_join_inner(
711 garray_T *gap, /* to store the result in */
712 list_T *l,
713 char_u *sep,
714 int echo_style,
715 int restore_copyID,
716 int copyID,
717 garray_T *join_gap) /* to keep each list item string */
718 {
719 int i;
720 join_T *p;
721 int len;
722 int sumlen = 0;
723 int first = TRUE;
724 char_u *tofree;
725 char_u numbuf[NUMBUFLEN];
726 listitem_T *item;
727 char_u *s;
728
729 /* Stringify each item in the list. */
730 for (item = l->lv_first; item != NULL && !got_int; item = item->li_next)
731 {
732 s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID,
733 echo_style, restore_copyID, FALSE);
734 if (s == NULL)
735 return FAIL;
736
737 len = (int)STRLEN(s);
738 sumlen += len;
739
740 (void)ga_grow(join_gap, 1);
741 p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++);
742 if (tofree != NULL || s != numbuf)
743 {
744 p->s = s;
745 p->tofree = tofree;
746 }
747 else
748 {
749 p->s = vim_strnsave(s, len);
750 p->tofree = p->s;
751 }
752
753 line_breakcheck();
754 if (did_echo_string_emsg) /* recursion error, bail out */
755 break;
756 }
757
758 /* Allocate result buffer with its total size, avoid re-allocation and
759 * multiple copy operations. Add 2 for a tailing ']' and NUL. */
760 if (join_gap->ga_len >= 2)
761 sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1);
762 if (ga_grow(gap, sumlen + 2) == FAIL)
763 return FAIL;
764
765 for (i = 0; i < join_gap->ga_len && !got_int; ++i)
766 {
767 if (first)
768 first = FALSE;
769 else
770 ga_concat(gap, sep);
771 p = ((join_T *)join_gap->ga_data) + i;
772
773 if (p->s != NULL)
774 ga_concat(gap, p->s);
775 line_breakcheck();
776 }
777
778 return OK;
779 }
780
781 /*
782 * Join list "l" into a string in "*gap", using separator "sep".
783 * When "echo_style" is TRUE use String as echoed, otherwise as inside a List.
784 * Return FAIL or OK.
785 */
786 int
787 list_join(
788 garray_T *gap,
789 list_T *l,
790 char_u *sep,
791 int echo_style,
792 int restore_copyID,
793 int copyID)
794 {
795 garray_T join_ga;
796 int retval;
797 join_T *p;
798 int i;
799
800 if (l->lv_len < 1)
801 return OK; /* nothing to do */
802 ga_init2(&join_ga, (int)sizeof(join_T), l->lv_len);
803 retval = list_join_inner(gap, l, sep, echo_style, restore_copyID,
804 copyID, &join_ga);
805
806 /* Dispose each item in join_ga. */
807 if (join_ga.ga_data != NULL)
808 {
809 p = (join_T *)join_ga.ga_data;
810 for (i = 0; i < join_ga.ga_len; ++i)
811 {
812 vim_free(p->tofree);
813 ++p;
814 }
815 ga_clear(&join_ga);
816 }
817
818 return retval;
819 }
820
821 /*
822 * Allocate a variable for a List and fill it from "*arg".
823 * Return OK or FAIL.
824 */
825 int
826 get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
827 {
828 list_T *l = NULL;
829 typval_T tv;
830 listitem_T *item;
831
832 if (evaluate)
833 {
834 l = list_alloc();
835 if (l == NULL)
836 return FAIL;
837 }
838
839 *arg = skipwhite(*arg + 1);
840 while (**arg != ']' && **arg != NUL)
841 {
842 if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */
843 goto failret;
844 if (evaluate)
845 {
846 item = listitem_alloc();
847 if (item != NULL)
848 {
849 item->li_tv = tv;
850 item->li_tv.v_lock = 0;
851 list_append(l, item);
852 }
853 else
854 clear_tv(&tv);
855 }
856
857 if (**arg == ']')
858 break;
859 if (**arg != ',')
860 {
861 EMSG2(_("E696: Missing comma in List: %s"), *arg);
862 goto failret;
863 }
864 *arg = skipwhite(*arg + 1);
865 }
866
867 if (**arg != ']')
868 {
869 EMSG2(_("E697: Missing end of List ']': %s"), *arg);
870 failret:
871 if (evaluate)
872 list_free(l);
873 return FAIL;
874 }
875
876 *arg = skipwhite(*arg + 1);
877 if (evaluate)
878 {
879 rettv->v_type = VAR_LIST;
880 rettv->vval.v_list = l;
881 ++l->lv_refcount;
882 }
883
884 return OK;
885 }
886
887 #endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */