patch 9.2.1139: list2blob() can be improved
Commit:
https://github.com/vim/vim/commit/c77608d35e899a0103d022fb9edb19c58ea00396
Author: Yasuhiro Matsumoto <
matt...@gmail.com>
Date: Mon Sep 28 19:08:51 2026 +0000
patch 9.2.1139: list2blob() can be improved
Problem: list2blob() appends one byte at a time.
Solution: Preallocate the buffer and write the bytes directly
(Yasuhiro Matsumoto).
Cover large conversions, descending ranges, and invalid trailing items.
All 33 blob tests pass. Local five-run medians improve by 17% for 4096
items and 19% for 65536 items.
closes: #21385
Signed-off-by: Yasuhiro Matsumoto <
matt...@gmail.com>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/src/blob.c b/src/blob.c
index a85df43d8..11becf8a6 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -1021,6 +1021,10 @@ f_list2blob(typval_T *argvars, typval_T *rettv)
if (l == NULL)
return;
+ // The result has one byte per list item; reserve all space at once.
+ if (ga_grow(&blob->bv_ga, list_len(l)) == FAIL)
+ return;
+
CHECK_LIST_MATERIALIZE(l);
FOR_ALL_LIST_ITEMS(l, li)
{
@@ -1036,7 +1040,7 @@ f_list2blob(typval_T *argvars, typval_T *rettv)
ga_clear(&blob->bv_ga);
return;
}
- ga_append(&blob->bv_ga, n);
+ ((char_u *)blob->bv_ga.ga_data)[blob->bv_ga.ga_len++] = (char_u)n;
}
}
diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim
index 9c773f344..a4f7e0ba3 100644
--- a/src/testdir/test_blob.vim
+++ b/src/testdir/test_blob.vim
@@ -790,6 +790,21 @@ func Test_list2blob()
call assert_equal(0z00010203, list2blob(range(4)))
endfunc
+func Test_list2blob_large()
+ let values = repeat(range(256), 32)
+ let b = list2blob(values)
+ call assert_equal(values, blob2list(b))
+ call add(b, 42)
+ call assert_equal(42, remove(b, -1))
+ call assert_equal(values, blob2list(b))
+ call assert_equal(range(255, 0, -1), blob2list(list2blob(range(255, 0, -1))))
+
+ call add(values, 256)
+ call assert_fails('call list2blob(values)', 'E1239:')
+ let values[-1] = []
+ call assert_fails('call list2blob(values)', 'E745:')
+endfunc
+
" The following used to cause an out-of-bounds memory access
func Test_blob2string()
let v = '0z' .. repeat('01010101.', 444)
diff --git a/src/version.c b/src/version.c
index ece3847c8..f67c2bd9c 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 */
+/**/
+ 1139,
/**/
1138,
/**/