Mercurial > vim
comparison src/list.c @ 19181:94eda51ba9ba v8.2.0149
patch 8.2.0149: maintaining a Vim9 branch separately is more work
Commit: https://github.com/vim/vim/commit/8a7d6542b33e5d2b352262305c3bfdb2d14e1cf8
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Jan 26 15:56:19 2020 +0100
patch 8.2.0149: maintaining a Vim9 branch separately is more work
Problem: Maintaining a Vim9 branch separately is more work.
Solution: Merge the Vim9 script changes.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 26 Jan 2020 16:00:05 +0100 |
parents | 09f28c17ac58 |
children | 09f01421a356 |
comparison
equal
deleted
inserted
replaced
19180:8edf0aeb71b9 | 19181:94eda51ba9ba |
---|---|
63 for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next) | 63 for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next) |
64 if (lw->lw_item == item) | 64 if (lw->lw_item == item) |
65 lw->lw_item = item->li_next; | 65 lw->lw_item = item->li_next; |
66 } | 66 } |
67 | 67 |
68 static void | |
69 list_init(list_T *l) | |
70 { | |
71 // Prepend the list to the list of lists for garbage collection. | |
72 if (first_list != NULL) | |
73 first_list->lv_used_prev = l; | |
74 l->lv_used_prev = NULL; | |
75 l->lv_used_next = first_list; | |
76 first_list = l; | |
77 } | |
78 | |
68 /* | 79 /* |
69 * Allocate an empty header for a list. | 80 * Allocate an empty header for a list. |
70 * Caller should take care of the reference count. | 81 * Caller should take care of the reference count. |
71 */ | 82 */ |
72 list_T * | 83 list_T * |
74 { | 85 { |
75 list_T *l; | 86 list_T *l; |
76 | 87 |
77 l = ALLOC_CLEAR_ONE(list_T); | 88 l = ALLOC_CLEAR_ONE(list_T); |
78 if (l != NULL) | 89 if (l != NULL) |
79 { | 90 list_init(l); |
80 // Prepend the list to the list of lists for garbage collection. | |
81 if (first_list != NULL) | |
82 first_list->lv_used_prev = l; | |
83 l->lv_used_prev = NULL; | |
84 l->lv_used_next = first_list; | |
85 first_list = l; | |
86 } | |
87 return l; | 91 return l; |
88 } | 92 } |
89 | 93 |
90 /* | 94 /* |
91 * list_alloc() with an ID for alloc_fail(). | 95 * list_alloc() with an ID for alloc_fail(). |
99 #endif | 103 #endif |
100 return (list_alloc()); | 104 return (list_alloc()); |
101 } | 105 } |
102 | 106 |
103 /* | 107 /* |
108 * Allocate space for a list, plus "count" items. | |
109 * Next list_set_item() must be called for each item. | |
110 */ | |
111 list_T * | |
112 list_alloc_with_items(int count) | |
113 { | |
114 list_T *l; | |
115 | |
116 l = (list_T *)alloc_clear(sizeof(list_T) + count * sizeof(listitem_T)); | |
117 if (l != NULL) | |
118 { | |
119 list_init(l); | |
120 | |
121 if (count > 0) | |
122 { | |
123 listitem_T *li = (listitem_T *)(l + 1); | |
124 int i; | |
125 | |
126 l->lv_len = count; | |
127 l->lv_with_items = count; | |
128 l->lv_first = li; | |
129 l->lv_last = li + count - 1; | |
130 for (i = 0; i < count; ++i) | |
131 { | |
132 if (i == 0) | |
133 li->li_prev = NULL; | |
134 else | |
135 li->li_prev = li - 1; | |
136 if (i == count - 1) | |
137 li->li_next = NULL; | |
138 else | |
139 li->li_next = li + 1; | |
140 ++li; | |
141 } | |
142 } | |
143 } | |
144 return l; | |
145 } | |
146 | |
147 /* | |
148 * Set item "idx" for a list previously allocated with list_alloc_with_items(). | |
149 * The contents of "tv" is moved into the list item. | |
150 * Each item must be set exactly once. | |
151 */ | |
152 void | |
153 list_set_item(list_T *l, int idx, typval_T *tv) | |
154 { | |
155 listitem_T *li = (listitem_T *)(l + 1) + idx; | |
156 | |
157 li->li_tv = *tv; | |
158 } | |
159 | |
160 /* | |
104 * Allocate an empty list for a return value, with reference count set. | 161 * Allocate an empty list for a return value, with reference count set. |
105 * Returns OK or FAIL. | 162 * Returns OK or FAIL. |
106 */ | 163 */ |
107 int | 164 int |
108 rettv_list_alloc(typval_T *rettv) | 165 rettv_list_alloc(typval_T *rettv) |
161 static void | 218 static void |
162 list_free_contents(list_T *l) | 219 list_free_contents(list_T *l) |
163 { | 220 { |
164 listitem_T *item; | 221 listitem_T *item; |
165 | 222 |
166 for (item = l->lv_first; item != NULL; item = l->lv_first) | 223 if (l->lv_first != &range_list_item) |
167 { | 224 for (item = l->lv_first; item != NULL; item = l->lv_first) |
168 // Remove the item before deleting it. | 225 { |
169 l->lv_first = item->li_next; | 226 // Remove the item before deleting it. |
170 clear_tv(&item->li_tv); | 227 l->lv_first = item->li_next; |
171 vim_free(item); | 228 clear_tv(&item->li_tv); |
172 } | 229 list_free_item(l, item); |
230 } | |
173 } | 231 } |
174 | 232 |
175 /* | 233 /* |
176 * Go through the list of lists and free items without the copyID. | 234 * Go through the list of lists and free items without the copyID. |
177 * But don't free a list that has a watcher (used in a for loop), these | 235 * But don't free a list that has a watcher (used in a for loop), these |
248 { | 306 { |
249 return ALLOC_ONE(listitem_T); | 307 return ALLOC_ONE(listitem_T); |
250 } | 308 } |
251 | 309 |
252 /* | 310 /* |
253 * Free a list item. Also clears the value. Does not notify watchers. | 311 * Free a list item, unless it was allocated together with the list itself. |
254 */ | 312 * Does not clear the value. Does not notify watchers. |
255 void | 313 */ |
256 listitem_free(listitem_T *item) | 314 void |
315 list_free_item(list_T *l, listitem_T *item) | |
316 { | |
317 if (l->lv_with_items == 0 || item < (listitem_T *)l | |
318 || item >= (listitem_T *)(l + 1) + l->lv_with_items) | |
319 vim_free(item); | |
320 } | |
321 | |
322 /* | |
323 * Free a list item, unless it was allocated together with the list itself. | |
324 * Also clears the value. Does not notify watchers. | |
325 */ | |
326 void | |
327 listitem_free(list_T *l, listitem_T *item) | |
257 { | 328 { |
258 clear_tv(&item->li_tv); | 329 clear_tv(&item->li_tv); |
259 vim_free(item); | 330 list_free_item(l, item); |
260 } | 331 } |
261 | 332 |
262 /* | 333 /* |
263 * Remove a list item from a List and free it. Also clears the value. | 334 * Remove a list item from a List and free it. Also clears the value. |
264 */ | 335 */ |
265 void | 336 void |
266 listitem_remove(list_T *l, listitem_T *item) | 337 listitem_remove(list_T *l, listitem_T *item) |
267 { | 338 { |
268 vimlist_remove(l, item, item); | 339 vimlist_remove(l, item, item); |
269 listitem_free(item); | 340 listitem_free(l, item); |
270 } | 341 } |
271 | 342 |
272 /* | 343 /* |
273 * Get the number of items in a list. | 344 * Get the number of items in a list. |
274 */ | 345 */ |
297 if (l1 == l2) | 368 if (l1 == l2) |
298 return TRUE; | 369 return TRUE; |
299 if (list_len(l1) != list_len(l2)) | 370 if (list_len(l1) != list_len(l2)) |
300 return FALSE; | 371 return FALSE; |
301 | 372 |
373 range_list_materialize(l1); | |
374 range_list_materialize(l2); | |
375 | |
302 for (item1 = l1->lv_first, item2 = l2->lv_first; | 376 for (item1 = l1->lv_first, item2 = l2->lv_first; |
303 item1 != NULL && item2 != NULL; | 377 item1 != NULL && item2 != NULL; |
304 item1 = item1->li_next, item2 = item2->li_next) | 378 item1 = item1->li_next, item2 = item2->li_next) |
305 if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive)) | 379 if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive)) |
306 return FALSE; | 380 return FALSE; |
327 | 401 |
328 // Check for index out of range. | 402 // Check for index out of range. |
329 if (n < 0 || n >= l->lv_len) | 403 if (n < 0 || n >= l->lv_len) |
330 return NULL; | 404 return NULL; |
331 | 405 |
406 range_list_materialize(l); | |
407 | |
332 // When there is a cached index may start search from there. | 408 // When there is a cached index may start search from there. |
333 if (l->lv_idx_item != NULL) | 409 if (l->lv_idx_item != NULL) |
334 { | 410 { |
335 if (n < l->lv_idx / 2) | 411 if (n < l->lv_idx / 2) |
336 { | 412 { |
396 long idx, | 472 long idx, |
397 int *errorp) // set to TRUE when something wrong | 473 int *errorp) // set to TRUE when something wrong |
398 { | 474 { |
399 listitem_T *li; | 475 listitem_T *li; |
400 | 476 |
477 if (l != NULL && l->lv_first == &range_list_item) | |
478 { | |
479 long n = idx; | |
480 | |
481 // not materialized range() list: compute the value. | |
482 // Negative index is relative to the end. | |
483 if (n < 0) | |
484 n = l->lv_len + n; | |
485 | |
486 // Check for index out of range. | |
487 if (n < 0 || n >= l->lv_len) | |
488 { | |
489 if (errorp != NULL) | |
490 *errorp = TRUE; | |
491 return -1L; | |
492 } | |
493 | |
494 return l->lv_start + n * l->lv_stride; | |
495 } | |
496 | |
401 li = list_find(l, idx); | 497 li = list_find(l, idx); |
402 if (li == NULL) | 498 if (li == NULL) |
403 { | 499 { |
404 if (errorp != NULL) | 500 if (errorp != NULL) |
405 *errorp = TRUE; | 501 *errorp = TRUE; |
435 long idx = 0; | 531 long idx = 0; |
436 listitem_T *li; | 532 listitem_T *li; |
437 | 533 |
438 if (l == NULL) | 534 if (l == NULL) |
439 return -1; | 535 return -1; |
536 range_list_materialize(l); | |
440 idx = 0; | 537 idx = 0; |
441 for (li = l->lv_first; li != NULL && li != item; li = li->li_next) | 538 for (li = l->lv_first; li != NULL && li != item; li = li->li_next) |
442 ++idx; | 539 ++idx; |
443 if (li == NULL) | 540 if (li == NULL) |
444 return -1; | 541 return -1; |
449 * Append item "item" to the end of list "l". | 546 * Append item "item" to the end of list "l". |
450 */ | 547 */ |
451 void | 548 void |
452 list_append(list_T *l, listitem_T *item) | 549 list_append(list_T *l, listitem_T *item) |
453 { | 550 { |
551 range_list_materialize(l); | |
454 if (l->lv_last == NULL) | 552 if (l->lv_last == NULL) |
455 { | 553 { |
456 // empty list | 554 // empty list |
457 l->lv_first = item; | 555 l->lv_first = item; |
458 l->lv_last = item; | 556 l->lv_last = item; |
467 ++l->lv_len; | 565 ++l->lv_len; |
468 item->li_next = NULL; | 566 item->li_next = NULL; |
469 } | 567 } |
470 | 568 |
471 /* | 569 /* |
472 * Append typval_T "tv" to the end of list "l". | 570 * Append typval_T "tv" to the end of list "l". "tv" is copied. |
473 * Return FAIL when out of memory. | 571 * Return FAIL when out of memory. |
474 */ | 572 */ |
475 int | 573 int |
476 list_append_tv(list_T *l, typval_T *tv) | 574 list_append_tv(list_T *l, typval_T *tv) |
477 { | 575 { |
478 listitem_T *li = listitem_alloc(); | 576 listitem_T *li = listitem_alloc(); |
479 | 577 |
480 if (li == NULL) | 578 if (li == NULL) |
481 return FAIL; | 579 return FAIL; |
482 copy_tv(tv, &li->li_tv); | 580 copy_tv(tv, &li->li_tv); |
581 list_append(l, li); | |
582 return OK; | |
583 } | |
584 | |
585 /* | |
586 * As list_append_tv() but move the value instead of copying it. | |
587 * Return FAIL when out of memory. | |
588 */ | |
589 int | |
590 list_append_tv_move(list_T *l, typval_T *tv) | |
591 { | |
592 listitem_T *li = listitem_alloc(); | |
593 | |
594 if (li == NULL) | |
595 return FAIL; | |
596 li->li_tv = *tv; | |
483 list_append(l, li); | 597 list_append(l, li); |
484 return OK; | 598 return OK; |
485 } | 599 } |
486 | 600 |
487 /* | 601 /* |
582 } | 696 } |
583 | 697 |
584 void | 698 void |
585 list_insert(list_T *l, listitem_T *ni, listitem_T *item) | 699 list_insert(list_T *l, listitem_T *ni, listitem_T *item) |
586 { | 700 { |
701 range_list_materialize(l); | |
587 if (item == NULL) | 702 if (item == NULL) |
588 // Append new item at end of list. | 703 // Append new item at end of list. |
589 list_append(l, ni); | 704 list_append(l, ni); |
590 else | 705 else |
591 { | 706 { |
615 int | 730 int |
616 list_extend(list_T *l1, list_T *l2, listitem_T *bef) | 731 list_extend(list_T *l1, list_T *l2, listitem_T *bef) |
617 { | 732 { |
618 listitem_T *item; | 733 listitem_T *item; |
619 int todo = l2->lv_len; | 734 int todo = l2->lv_len; |
735 | |
736 range_list_materialize(l1); | |
737 range_list_materialize(l2); | |
620 | 738 |
621 // We also quit the loop when we have inserted the original item count of | 739 // We also quit the loop when we have inserted the original item count of |
622 // the list, avoid a hang when we extend a list with itself. | 740 // the list, avoid a hang when we extend a list with itself. |
623 for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next) | 741 for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next) |
624 if (list_insert_tv(l1, &item->li_tv, bef) == FAIL) | 742 if (list_insert_tv(l1, &item->li_tv, bef) == FAIL) |
673 // Do this before adding the items, because one of the items may | 791 // Do this before adding the items, because one of the items may |
674 // refer back to this list. | 792 // refer back to this list. |
675 orig->lv_copyID = copyID; | 793 orig->lv_copyID = copyID; |
676 orig->lv_copylist = copy; | 794 orig->lv_copylist = copy; |
677 } | 795 } |
796 range_list_materialize(orig); | |
678 for (item = orig->lv_first; item != NULL && !got_int; | 797 for (item = orig->lv_first; item != NULL && !got_int; |
679 item = item->li_next) | 798 item = item->li_next) |
680 { | 799 { |
681 ni = listitem_alloc(); | 800 ni = listitem_alloc(); |
682 if (ni == NULL) | 801 if (ni == NULL) |
712 */ | 831 */ |
713 void | 832 void |
714 vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2) | 833 vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2) |
715 { | 834 { |
716 listitem_T *ip; | 835 listitem_T *ip; |
836 | |
837 range_list_materialize(l); | |
717 | 838 |
718 // notify watchers | 839 // notify watchers |
719 for (ip = item; ip != NULL; ip = ip->li_next) | 840 for (ip = item; ip != NULL; ip = ip->li_next) |
720 { | 841 { |
721 --l->lv_len; | 842 --l->lv_len; |
746 | 867 |
747 if (tv->vval.v_list == NULL) | 868 if (tv->vval.v_list == NULL) |
748 return NULL; | 869 return NULL; |
749 ga_init2(&ga, (int)sizeof(char), 80); | 870 ga_init2(&ga, (int)sizeof(char), 80); |
750 ga_append(&ga, '['); | 871 ga_append(&ga, '['); |
872 range_list_materialize(tv->vval.v_list); | |
751 if (list_join(&ga, tv->vval.v_list, (char_u *)", ", | 873 if (list_join(&ga, tv->vval.v_list, (char_u *)", ", |
752 FALSE, restore_copyID, copyID) == FAIL) | 874 FALSE, restore_copyID, copyID) == FAIL) |
753 { | 875 { |
754 vim_free(ga.ga_data); | 876 vim_free(ga.ga_data); |
755 return NULL; | 877 return NULL; |
783 char_u numbuf[NUMBUFLEN]; | 905 char_u numbuf[NUMBUFLEN]; |
784 listitem_T *item; | 906 listitem_T *item; |
785 char_u *s; | 907 char_u *s; |
786 | 908 |
787 // Stringify each item in the list. | 909 // Stringify each item in the list. |
910 range_list_materialize(l); | |
788 for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) | 911 for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) |
789 { | 912 { |
790 s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID, | 913 s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID, |
791 echo_style, restore_copyID, !echo_style); | 914 echo_style, restore_copyID, !echo_style); |
792 if (s == NULL) | 915 if (s == NULL) |
913 /* | 1036 /* |
914 * Allocate a variable for a List and fill it from "*arg". | 1037 * Allocate a variable for a List and fill it from "*arg". |
915 * Return OK or FAIL. | 1038 * Return OK or FAIL. |
916 */ | 1039 */ |
917 int | 1040 int |
918 get_list_tv(char_u **arg, typval_T *rettv, int evaluate) | 1041 get_list_tv(char_u **arg, typval_T *rettv, int evaluate, int do_error) |
919 { | 1042 { |
920 list_T *l = NULL; | 1043 list_T *l = NULL; |
921 typval_T tv; | 1044 typval_T tv; |
922 listitem_T *item; | 1045 listitem_T *item; |
923 | 1046 |
948 | 1071 |
949 if (**arg == ']') | 1072 if (**arg == ']') |
950 break; | 1073 break; |
951 if (**arg != ',') | 1074 if (**arg != ',') |
952 { | 1075 { |
953 semsg(_("E696: Missing comma in List: %s"), *arg); | 1076 if (do_error) |
1077 semsg(_("E696: Missing comma in List: %s"), *arg); | |
954 goto failret; | 1078 goto failret; |
955 } | 1079 } |
956 *arg = skipwhite(*arg + 1); | 1080 *arg = skipwhite(*arg + 1); |
957 } | 1081 } |
958 | 1082 |
959 if (**arg != ']') | 1083 if (**arg != ']') |
960 { | 1084 { |
961 semsg(_("E697: Missing end of List ']': %s"), *arg); | 1085 if (do_error) |
1086 semsg(_("E697: Missing end of List ']': %s"), *arg); | |
962 failret: | 1087 failret: |
963 if (evaluate) | 1088 if (evaluate) |
964 list_free(l); | 1089 list_free(l); |
965 return FAIL; | 1090 return FAIL; |
966 } | 1091 } |
981 listitem_T *li; | 1106 listitem_T *li; |
982 int c; | 1107 int c; |
983 int ret = OK; | 1108 int ret = OK; |
984 char_u *s; | 1109 char_u *s; |
985 | 1110 |
1111 range_list_materialize(list); | |
986 for (li = list->lv_first; li != NULL; li = li->li_next) | 1112 for (li = list->lv_first; li != NULL; li = li->li_next) |
987 { | 1113 { |
988 for (s = tv_get_string(&li->li_tv); *s != NUL; ++s) | 1114 for (s = tv_get_string(&li->li_tv); *s != NUL; ++s) |
989 { | 1115 { |
990 if (*s == '\n') | 1116 if (*s == '\n') |
1067 return; // empty list results in empty string | 1193 return; // empty list results in empty string |
1068 | 1194 |
1069 if (argvars[1].v_type != VAR_UNKNOWN) | 1195 if (argvars[1].v_type != VAR_UNKNOWN) |
1070 utf8 = (int)tv_get_number_chk(&argvars[1], NULL); | 1196 utf8 = (int)tv_get_number_chk(&argvars[1], NULL); |
1071 | 1197 |
1198 range_list_materialize(l); | |
1072 ga_init2(&ga, 1, 80); | 1199 ga_init2(&ga, 1, 80); |
1073 if (has_mbyte || utf8) | 1200 if (has_mbyte || utf8) |
1074 { | 1201 { |
1075 char_u buf[MB_MAXBYTES + 1]; | 1202 char_u buf[MB_MAXBYTES + 1]; |
1076 int (*char2bytes)(int, char_u *); | 1203 int (*char2bytes)(int, char_u *); |
1121 if (argvars[2].v_type == VAR_UNKNOWN) | 1248 if (argvars[2].v_type == VAR_UNKNOWN) |
1122 { | 1249 { |
1123 // Remove one item, return its value. | 1250 // Remove one item, return its value. |
1124 vimlist_remove(l, item, item); | 1251 vimlist_remove(l, item, item); |
1125 *rettv = item->li_tv; | 1252 *rettv = item->li_tv; |
1126 vim_free(item); | 1253 list_free_item(l, item); |
1127 } | 1254 } |
1128 else | 1255 else |
1129 { | 1256 { |
1130 // Remove range of items, return list with values. | 1257 // Remove range of items, return list with values. |
1131 int end = (long)tv_get_number_chk(&argvars[2], &error); | 1258 int end = (long)tv_get_number_chk(&argvars[2], &error); |
1359 if (l == NULL || var_check_lock(l->lv_lock, | 1486 if (l == NULL || var_check_lock(l->lv_lock, |
1360 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), | 1487 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), |
1361 TRUE)) | 1488 TRUE)) |
1362 goto theend; | 1489 goto theend; |
1363 rettv_list_set(rettv, l); | 1490 rettv_list_set(rettv, l); |
1491 range_list_materialize(l); | |
1364 | 1492 |
1365 len = list_len(l); | 1493 len = list_len(l); |
1366 if (len <= 1) | 1494 if (len <= 1) |
1367 goto theend; // short list sorts pretty quickly | 1495 goto theend; // short list sorts pretty quickly |
1368 | 1496 |
1517 if (li->li_next != NULL) | 1645 if (li->li_next != NULL) |
1518 li->li_next->li_prev = ptrs[i].item; | 1646 li->li_next->li_prev = ptrs[i].item; |
1519 else | 1647 else |
1520 l->lv_last = ptrs[i].item; | 1648 l->lv_last = ptrs[i].item; |
1521 list_fix_watch(l, li); | 1649 list_fix_watch(l, li); |
1522 listitem_free(li); | 1650 listitem_free(l, li); |
1523 l->lv_len--; | 1651 l->lv_len--; |
1524 } | 1652 } |
1525 } | 1653 } |
1526 } | 1654 } |
1527 | 1655 |
1727 else // argvars[0].v_type == VAR_LIST | 1855 else // argvars[0].v_type == VAR_LIST |
1728 { | 1856 { |
1729 // set_vim_var_nr() doesn't set the type | 1857 // set_vim_var_nr() doesn't set the type |
1730 set_vim_var_type(VV_KEY, VAR_NUMBER); | 1858 set_vim_var_type(VV_KEY, VAR_NUMBER); |
1731 | 1859 |
1860 range_list_materialize(l); | |
1732 for (li = l->lv_first; li != NULL; li = nli) | 1861 for (li = l->lv_first; li != NULL; li = nli) |
1733 { | 1862 { |
1734 if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) | 1863 if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) |
1735 break; | 1864 break; |
1736 nli = li->li_next; | 1865 nli = li->li_next; |