To: vim_dev@googlegroups.com Subject: Patch 8.2.2738 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2738 Problem: Extending a list with itself can give wrong result. Solution: Remember the item before where the insertion happens and skip to after the already inserted items. (closes #1112) Files: src/list.c, src/testdir/test_listdict.vim *** ../vim-8.2.2737/src/list.c 2021-03-18 22:15:00.585208312 +0100 --- src/list.c 2021-04-08 20:03:57.604402672 +0200 *************** *** 894,899 **** --- 894,900 ---- { listitem_T *item; int todo; + listitem_T *bef_prev; // NULL list is equivalent to an empty list: nothing to do. if (l2 == NULL || l2->lv_len == 0) *************** *** 903,911 **** CHECK_LIST_MATERIALIZE(l1); CHECK_LIST_MATERIALIZE(l2); // We also quit the loop when we have inserted the original item count of // the list, avoid a hang when we extend a list with itself. ! for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next) if (list_insert_tv(l1, &item->li_tv, bef) == FAIL) return FAIL; return OK; --- 904,918 ---- CHECK_LIST_MATERIALIZE(l1); CHECK_LIST_MATERIALIZE(l2); + // When exending a list with itself, at some point we run into the item + // that was before "bef" and need to skip over the already inserted items + // to "bef". + bef_prev = bef == NULL ? NULL : bef->li_prev; + // We also quit the loop when we have inserted the original item count of // the list, avoid a hang when we extend a list with itself. ! for (item = l2->lv_first; item != NULL && --todo >= 0; ! item = item == bef_prev ? bef : item->li_next) if (list_insert_tv(l1, &item->li_tv, bef) == FAIL) return FAIL; return OK; *** ../vim-8.2.2737/src/testdir/test_listdict.vim 2021-01-12 20:23:35.778707890 +0100 --- src/testdir/test_listdict.vim 2021-04-08 20:06:07.739925937 +0200 *************** *** 862,867 **** --- 862,881 ---- " Extend g: dictionary with an invalid variable name call assert_fails("call extend(g:, {'-!' : 10})", 'E461:') + + " Extend a list with itself. + let l = [1, 5, 7] + call extend(l, l, 0) + call assert_equal([1, 5, 7, 1, 5, 7], l) + let l = [1, 5, 7] + call extend(l, l, 1) + call assert_equal([1, 1, 5, 7, 5, 7], l) + let l = [1, 5, 7] + call extend(l, l, 2) + call assert_equal([1, 5, 1, 5, 7, 7], l) + let l = [1, 5, 7] + call extend(l, l, 3) + call assert_equal([1, 5, 7, 1, 5, 7], l) endfunc func Test_listdict_extendnew() *** ../vim-8.2.2737/src/version.c 2021-04-08 18:27:49.525472168 +0200 --- src/version.c 2021-04-08 20:07:32.055624428 +0200 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2738, /**/ -- From "know your smileys": :~) A man with a tape recorder up his nose /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///