vim-patch:9.0.1515: reverse() does not work for a String

Problem:    reverse() does not work for a String.
Solution:   Implement reverse() for a String. (Yegappan Lakshmanan,
            closes vim/vim#12179)

03ff1c2dde

vim-patch:9.0.1738: Duplicate code to reverse a string

Problem:  Duplicate code to reverse a string
Solution: Move reverse_text() to strings.c and remove string_reverse().

closes: vim/vim#12847

4dd266cb66

Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
zeertzjq
2023-08-19 17:44:19 +08:00
parent d7ae9ae3e5
commit 4c7df98e4e
8 changed files with 51 additions and 22 deletions

View File

@@ -5666,11 +5666,13 @@ resolve({filename}) *resolve()* *E65
path name) and also keeps a trailing path separator. path name) and also keeps a trailing path separator.
reverse({object}) *reverse()* reverse({object}) *reverse()*
Reverse the order of items in {object} in-place. Reverse the order of items in {object}. {object} can be a
{object} can be a |List| or a |Blob|. |List|, a |Blob| or a |String|. For a List and a Blob the
Returns {object}. items are reversed in-place and {object} is returned.
Returns zero if {object} is not a List or a Blob. For a String a new String is returned.
If you want an object to remain unmodified make a copy first: >vim Returns zero if {object} is not a List, Blob or a String.
If you want a List or Blob to remain unmodified make a copy
first: >vim
let revlist = reverse(copy(mylist)) let revlist = reverse(copy(mylist))
< <

View File

@@ -626,6 +626,7 @@ String manipulation: *string-functions*
strdisplaywidth() size of string when displayed, deals with tabs strdisplaywidth() size of string when displayed, deals with tabs
setcellwidths() set character cell width overrides setcellwidths() set character cell width overrides
getcellwidths() get character cell width overrides getcellwidths() get character cell width overrides
reverse() reverse the order of characters in a string
substitute() substitute a pattern match with a string substitute() substitute a pattern match with a string
submatch() get a specific match in ":s" and substitute() submatch() get a specific match in ":s" and substitute()
strpart() get part of a string using byte index strpart() get part of a string using byte index
@@ -664,7 +665,7 @@ List manipulation: *list-functions*
reduce() reduce a List to a value reduce() reduce a List to a value
slice() take a slice of a List slice() take a slice of a List
sort() sort a List sort() sort a List
reverse() reverse the order of a List or Blob reverse() reverse the order of items in a List
uniq() remove copies of repeated adjacent items uniq() remove copies of repeated adjacent items
split() split a String into a List split() split a String into a List
join() join List items into a String join() join List items into a String
@@ -731,6 +732,7 @@ Floating point computation: *float-functions*
Blob manipulation: *blob-functions* Blob manipulation: *blob-functions*
blob2list() get a list of numbers from a blob blob2list() get a list of numbers from a blob
list2blob() get a blob from a list of numbers list2blob() get a blob from a list of numbers
reverse() reverse the order of numbers in a blob
Other computation: *bitwise-function* Other computation: *bitwise-function*
and() bitwise AND and() bitwise AND

View File

@@ -6762,11 +6762,13 @@ vim.fn['repeat'] = function(expr, count) end
--- @return any --- @return any
function vim.fn.resolve(filename) end function vim.fn.resolve(filename) end
--- Reverse the order of items in {object} in-place. --- Reverse the order of items in {object}. {object} can be a
--- {object} can be a |List| or a |Blob|. --- |List|, a |Blob| or a |String|. For a List and a Blob the
--- Returns {object}. --- items are reversed in-place and {object} is returned.
--- Returns zero if {object} is not a List or a Blob. --- For a String a new String is returned.
--- If you want an object to remain unmodified make a copy first: >vim --- Returns zero if {object} is not a List, Blob or a String.
--- If you want a List or Blob to remain unmodified make a copy
--- first: >vim
--- let revlist = reverse(copy(mylist)) --- let revlist = reverse(copy(mylist))
--- < --- <
--- ---

View File

@@ -8151,11 +8151,13 @@ M.funcs = {
args = 1, args = 1,
base = 1, base = 1,
desc = [=[ desc = [=[
Reverse the order of items in {object} in-place. Reverse the order of items in {object}. {object} can be a
{object} can be a |List| or a |Blob|. |List|, a |Blob| or a |String|. For a List and a Blob the
Returns {object}. items are reversed in-place and {object} is returned.
Returns zero if {object} is not a List or a Blob. For a String a new String is returned.
If you want an object to remain unmodified make a copy first: >vim Returns zero if {object} is not a List, Blob or a String.
If you want a List or Blob to remain unmodified make a copy
first: >vim
let revlist = reverse(copy(mylist)) let revlist = reverse(copy(mylist))
< <
]=], ]=],

View File

@@ -6209,6 +6209,13 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
tv_blob_set(b, len - i - 1, tmp); tv_blob_set(b, len - i - 1, tmp);
} }
tv_blob_set_ret(rettv, b); tv_blob_set_ret(rettv, b);
} else if (argvars[0].v_type == VAR_STRING) {
rettv->v_type = VAR_STRING;
if (argvars[0].vval.v_string != NULL) {
rettv->vval.v_string = reverse_text(argvars[0].vval.v_string);
} else {
rettv->vval.v_string = NULL;
}
} else if (argvars[0].v_type != VAR_LIST) { } else if (argvars[0].v_type != VAR_LIST) {
semsg(_(e_listblobarg), "reverse()"); semsg(_(e_listblobarg), "reverse()");
} else { } else {

View File

@@ -2168,20 +2168,17 @@ int kv_do_printf(StringBuilder *str, const char *fmt, ...)
/// ///
/// @return the allocated string. /// @return the allocated string.
char *reverse_text(char *s) char *reverse_text(char *s)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{ {
// Reverse the pattern.
size_t len = strlen(s); size_t len = strlen(s);
char *rev = xmalloc(len + 1); char *rev = xmalloc(len + 1);
size_t rev_i = len; for (size_t s_i = 0, rev_i = len; s_i < len; s_i++) {
for (size_t s_i = 0; s_i < len; s_i++) {
const int mb_len = utfc_ptr2len(s + s_i); const int mb_len = utfc_ptr2len(s + s_i);
rev_i -= (size_t)mb_len; rev_i -= (size_t)mb_len;
memmove(rev + rev_i, s + s_i, (size_t)mb_len); memmove(rev + rev_i, s + s_i, (size_t)mb_len);
s_i += (size_t)mb_len - 1; s_i += (size_t)mb_len - 1;
} }
rev[len] = NUL; rev[len] = NUL;
return rev; return rev;
} }

View File

@@ -3148,4 +3148,21 @@ func Test_delfunc_while_listing()
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
endfunc endfunc
" Test for the reverse() function with a string
func Test_string_reverse()
call assert_equal('', reverse(v:_null_string))
for [s1, s2] in [['', ''], ['a', 'a'], ['ab', 'ba'], ['abc', 'cba'],
\ ['abcd', 'dcba'], ['«-«-»-»', '»-»-«-«'],
\ ['🇦', '🇦'], ['🇦🇧', '🇧🇦'], ['🇦🇧🇨', '🇨🇧🇦'],
\ ['🇦«🇧-🇨»🇩', '🇩»🇨-🇧«🇦']]
call assert_equal(s2, reverse(s1))
endfor
" test in latin1 encoding
let save_enc = &encoding
" set encoding=latin1
call assert_equal('dcba', reverse('abcd'))
let &encoding = save_enc
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -894,7 +894,7 @@ func Test_reverse_sort_uniq()
END END
call CheckLegacyAndVim9Success(lines) call CheckLegacyAndVim9Success(lines)
call assert_fails('call reverse("")', 'E899:') call assert_fails('call reverse({})', 'E899:')
call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:') call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:')
call assert_fails("call sort([1, 2], function('min'), 1)", "E1206:") call assert_fails("call sort([1, 2], function('min'), 1)", "E1206:")
call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:") call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")