Commit: patch 9.2.1138: dict2list() can be improved

2 views
Skip to first unread message

Christian Brabandt

unread,
Sep 28, 2026, 3:15:13 PM (13 days ago) Sep 28
to vim...@googlegroups.com
patch 9.2.1138: dict2list() can be improved

Commit: https://github.com/vim/vim/commit/635876686a2adbd168af84e3c5975305f834b74b
Author: Yasuhiro Matsumoto <matt...@gmail.com>
Date: Mon Sep 28 19:01:38 2026 +0000

patch 9.2.1138: dict2list() can be improved

Problem: items() builds each key/value pair by allocating an empty
list and appending two items
Solution: Preallocate the list with two items (Yasuhiro Matsumoto).

Cover pair mutation and shared value references. All 59 list/dictionary
tests pass. Local five-run medians improve by 40% for 4096 entries and
44% for 65536 entries.

closes: #21384

Signed-off-by: Yasuhiro Matsumoto <matt...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/dict.c b/src/dict.c
index 00584423f..c08afcbc8 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -1622,7 +1622,7 @@ dict2list(typval_T *argvars, typval_T *rettv, dict2list_T what)
else
{
// items()
- l2 = list_alloc();
+ l2 = list_alloc_with_items(2);
li->li_tv.v_type = VAR_LIST;
li->li_tv.v_lock = 0;
li->li_tv.vval.v_list = l2;
@@ -1630,9 +1630,11 @@ dict2list(typval_T *argvars, typval_T *rettv, dict2list_T what)
goto alloc_failed;
++l2->lv_refcount;

- if (list_append_string(l2, di->di_key, -1) == FAIL
- || list_append_tv(l2, &di->di_tv) == FAIL)
+ l2->lv_first->li_tv.v_type = VAR_STRING;
+ l2->lv_first->li_tv.vval.v_string = vim_strsave(di->di_key);
+ if (l2->lv_first->li_tv.vval.v_string == NULL)
goto alloc_failed;
+ copy_tv(&di->di_tv, &l2->lv_u.mat.lv_last->li_tv);
}
li = li->li_next;
}
diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim
index 9a8f807ec..7ca9f7041 100644
--- a/src/testdir/test_listdict.vim
+++ b/src/testdir/test_listdict.vim
@@ -1591,6 +1591,24 @@ func Test_null_list()
unlockvar l
endfunc

+" The key/value pairs can be edited and retain references to their values.
+func Test_dict_items_edit_result()
+ let shared = [1, 2]
+ let d = {'key': shared}
+ let pairs = items(d)
+ call assert_equal([['key', [1, 2]]], pairs)
+ call assert_true(pairs[0][1] is shared)
+ call add(pairs[0][1], 3)
+ call assert_equal([1, 2, 3], d.key)
+ unlet d
+ let pair = remove(pairs, 0)
+ call assert_equal('key', remove(pair, 0))
+ call insert(pair, 'new')
+ call add(pair, 42)
+ call assert_equal(['new', [1, 2, 3], 42], pair)
+ call assert_equal([], pairs)
+endfunc
+
" Test for a null dict
func Test_null_dict()
let lines =<< trim END
diff --git a/src/version.c b/src/version.c
index 0d18d8a7a..ece3847c8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -763,6 +763,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1138,
/**/
1137,
/**/
Reply all
Reply to author
Forward
0 new messages