mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
patch 8.2.4695: JSON encoding could be faster
Problem: JSON encoding could be faster. Solution: Optimize encoding JSON strings. (closes #10086)
This commit is contained in:
87
src/json.c
87
src/json.c
@@ -114,23 +114,45 @@ json_encode_lsp_msg(typval_T *val)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup table to quickly know if the given ASCII character must be escaped.
|
||||||
|
*/
|
||||||
|
static const char ascii_needs_escape[128] = {
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x0.
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1.
|
||||||
|
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x2.
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x3.
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 0x5.
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x6.
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode the utf-8 encoded string "str" into "gap".
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
write_string(garray_T *gap, char_u *str)
|
write_string(garray_T *gap, char_u *str)
|
||||||
{
|
{
|
||||||
char_u *res = str;
|
char_u *res = str;
|
||||||
char_u numbuf[NUMBUFLEN];
|
char_u numbuf[NUMBUFLEN];
|
||||||
|
char_u *from;
|
||||||
if (res == NULL)
|
|
||||||
ga_concat(gap, (char_u *)"\"\"");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if defined(USE_ICONV)
|
#if defined(USE_ICONV)
|
||||||
vimconv_T conv;
|
vimconv_T conv;
|
||||||
char_u *converted = NULL;
|
char_u *converted = NULL;
|
||||||
|
#endif
|
||||||
|
int c;
|
||||||
|
|
||||||
|
if (res == NULL)
|
||||||
|
{
|
||||||
|
ga_concat(gap, (char_u *)"\"\"");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(USE_ICONV)
|
||||||
if (!enc_utf8)
|
if (!enc_utf8)
|
||||||
{
|
{
|
||||||
// Convert the text from 'encoding' to utf-8, the JSON string is
|
// Convert the text from 'encoding' to utf-8, because a JSON string is
|
||||||
// always utf-8.
|
// always utf-8.
|
||||||
conv.vc_type = CONV_NONE;
|
conv.vc_type = CONV_NONE;
|
||||||
convert_setup(&conv, p_enc, (char_u*)"utf-8");
|
convert_setup(&conv, p_enc, (char_u*)"utf-8");
|
||||||
@@ -140,11 +162,24 @@ write_string(garray_T *gap, char_u *str)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ga_append(gap, '"');
|
ga_append(gap, '"');
|
||||||
while (*res != NUL)
|
// `from` is the beginning of a sequence of bytes we can directly copy from
|
||||||
|
// the input string, avoiding the overhead associated to decoding/encoding
|
||||||
|
// them.
|
||||||
|
from = res;
|
||||||
|
while ((c = *res) != NUL)
|
||||||
{
|
{
|
||||||
int c;
|
|
||||||
// always use utf-8 encoding, ignore 'encoding'
|
// always use utf-8 encoding, ignore 'encoding'
|
||||||
c = utf_ptr2char(res);
|
if (c < 0x80)
|
||||||
|
{
|
||||||
|
if (!ascii_needs_escape[c])
|
||||||
|
{
|
||||||
|
res += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != from)
|
||||||
|
ga_concat_len(gap, from, res - from);
|
||||||
|
from = res + 1;
|
||||||
|
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
@@ -164,26 +199,44 @@ write_string(garray_T *gap, char_u *str)
|
|||||||
ga_append(gap, c);
|
ga_append(gap, c);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (c >= 0x20)
|
vim_snprintf((char *)numbuf, NUMBUFLEN, "\\u%04lx",
|
||||||
{
|
(long)c);
|
||||||
numbuf[utf_char2bytes(c, numbuf)] = NUL;
|
|
||||||
ga_concat(gap, numbuf);
|
ga_concat(gap, numbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res += 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vim_snprintf((char *)numbuf, NUMBUFLEN,
|
int l = utf_ptr2len(res);
|
||||||
"\\u%04lx", (long)c);
|
|
||||||
|
if (l > 1)
|
||||||
|
{
|
||||||
|
res += l;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid utf-8 sequence, replace it with the Unicode replacement
|
||||||
|
// character U+FFFD.
|
||||||
|
if (res != from)
|
||||||
|
ga_concat_len(gap, from, res - from);
|
||||||
|
from = res + 1;
|
||||||
|
|
||||||
|
numbuf[utf_char2bytes(0xFFFD, numbuf)] = NUL;
|
||||||
ga_concat(gap, numbuf);
|
ga_concat(gap, numbuf);
|
||||||
|
|
||||||
|
res += l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res += utf_ptr2len(res);
|
|
||||||
}
|
if (res != from)
|
||||||
|
ga_concat_len(gap, from, res - from);
|
||||||
|
|
||||||
ga_append(gap, '"');
|
ga_append(gap, '"');
|
||||||
#if defined(USE_ICONV)
|
#if defined(USE_ICONV)
|
||||||
vim_free(converted);
|
vim_free(converted);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return TRUE if "key" can be used without quotes.
|
* Return TRUE if "key" can be used without quotes.
|
||||||
|
@@ -107,6 +107,9 @@ func Test_json_encode()
|
|||||||
call assert_equal('"café"', json_encode("caf\xe9"))
|
call assert_equal('"café"', json_encode("caf\xe9"))
|
||||||
let &encoding = save_encoding
|
let &encoding = save_encoding
|
||||||
|
|
||||||
|
" Invalid utf-8 sequences are replaced with U+FFFD (replacement character)
|
||||||
|
call assert_equal('"foo' . "\ufffd" . '"', json_encode("foo\xAB"))
|
||||||
|
|
||||||
call assert_fails('echo json_encode(function("tr"))', 'E1161: Cannot json encode a func')
|
call assert_fails('echo json_encode(function("tr"))', 'E1161: Cannot json encode a func')
|
||||||
call assert_fails('echo json_encode([function("tr")])', 'E1161: Cannot json encode a func')
|
call assert_fails('echo json_encode([function("tr")])', 'E1161: Cannot json encode a func')
|
||||||
|
|
||||||
|
@@ -746,6 +746,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
4695,
|
||||||
/**/
|
/**/
|
||||||
4694,
|
4694,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user