mirror of
https://github.com/neovim/neovim.git
synced 2024-12-31 17:13:26 -07:00
vim-patch:8.2.3867: implementation of some list functions too complicated (#24757)
Problem: Implementation of some list functions too complicated.
Solution: Refactor do_sort_uniq(), f_count() and extend() (Yegappan
Lakshmanan, closes vim/vim#9378)
d92813a598
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
parent
5a564bf242
commit
de6b58f659
@ -884,6 +884,86 @@ static void f_copy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
var_item_copy(NULL, &argvars[0], rettv, false, 0);
|
||||
}
|
||||
|
||||
/// Count the number of times "needle" occurs in string "haystack".
|
||||
///
|
||||
/// @param ic ignore case
|
||||
static varnumber_T count_string(const char *haystack, const char *needle, bool ic)
|
||||
{
|
||||
varnumber_T n = 0;
|
||||
const char *p = haystack;
|
||||
|
||||
if (p == NULL || needle == NULL || *needle == NUL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ic) {
|
||||
const size_t len = strlen(needle);
|
||||
|
||||
while (*p != NUL) {
|
||||
if (mb_strnicmp(p, needle, len) == 0) {
|
||||
n++;
|
||||
p += len;
|
||||
} else {
|
||||
MB_PTR_ADV(p);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const char *next;
|
||||
while ((next = strstr(p, needle)) != NULL) {
|
||||
n++;
|
||||
p = next + strlen(needle);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Count the number of times item "needle" occurs in List "l" starting at index "idx".
|
||||
///
|
||||
/// @param ic ignore case
|
||||
static varnumber_T count_list(list_T *l, typval_T *needle, int64_t idx, bool ic)
|
||||
{
|
||||
if (tv_list_len(l) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
listitem_T *li = tv_list_find(l, (int)idx);
|
||||
if (li == NULL) {
|
||||
semsg(_(e_list_index_out_of_range_nr), idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
varnumber_T n = 0;
|
||||
|
||||
for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
|
||||
if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic, false)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Count the number of times item "needle" occurs in Dict "d".
|
||||
///
|
||||
/// @param ic ignore case
|
||||
static varnumber_T count_dict(dict_T *d, typval_T *needle, bool ic)
|
||||
{
|
||||
if (d == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
varnumber_T n = 0;
|
||||
|
||||
TV_DICT_ITER(d, di, {
|
||||
if (tv_equal(&di->di_tv, needle, ic, false)) {
|
||||
n++;
|
||||
}
|
||||
});
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// "count()" function
|
||||
static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
@ -895,74 +975,26 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
ic = (int)tv_get_number_chk(&argvars[2], &error);
|
||||
}
|
||||
|
||||
if (argvars[0].v_type == VAR_STRING) {
|
||||
const char *expr = tv_get_string_chk(&argvars[1]);
|
||||
const char *p = argvars[0].vval.v_string;
|
||||
|
||||
if (!error && expr != NULL && *expr != NUL && p != NULL) {
|
||||
if (ic) {
|
||||
const size_t len = strlen(expr);
|
||||
|
||||
while (*p != NUL) {
|
||||
if (mb_strnicmp(p, expr, len) == 0) {
|
||||
n++;
|
||||
p += len;
|
||||
} else {
|
||||
MB_PTR_ADV(p);
|
||||
if (!error && argvars[0].v_type == VAR_STRING) {
|
||||
n = count_string(argvars[0].vval.v_string, tv_get_string_chk(&argvars[1]), ic);
|
||||
} else if (!error && argvars[0].v_type == VAR_LIST) {
|
||||
int64_t idx = 0;
|
||||
if (argvars[2].v_type != VAR_UNKNOWN
|
||||
&& argvars[3].v_type != VAR_UNKNOWN) {
|
||||
idx = (long)tv_get_number_chk(&argvars[3], &error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char *next;
|
||||
while ((next = strstr(p, expr)) != NULL) {
|
||||
n++;
|
||||
p = next + strlen(expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (argvars[0].v_type == VAR_LIST) {
|
||||
list_T *l = argvars[0].vval.v_list;
|
||||
|
||||
if (l != NULL) {
|
||||
listitem_T *li = tv_list_first(l);
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
if (argvars[3].v_type != VAR_UNKNOWN) {
|
||||
int64_t idx = tv_get_number_chk(&argvars[3], &error);
|
||||
if (!error) {
|
||||
li = tv_list_find(l, (int)idx);
|
||||
if (li == NULL) {
|
||||
semsg(_(e_list_index_out_of_range_nr), idx);
|
||||
n = count_list(argvars[0].vval.v_list, &argvars[1], idx, ic);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
li = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
|
||||
if (tv_equal(TV_LIST_ITEM_TV(li), &argvars[1], ic, false)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (argvars[0].v_type == VAR_DICT) {
|
||||
} else if (!error && argvars[0].v_type == VAR_DICT) {
|
||||
dict_T *d = argvars[0].vval.v_dict;
|
||||
|
||||
if (d != NULL) {
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
if (argvars[3].v_type != VAR_UNKNOWN) {
|
||||
if (argvars[2].v_type != VAR_UNKNOWN
|
||||
&& argvars[3].v_type != VAR_UNKNOWN) {
|
||||
emsg(_(e_invarg));
|
||||
}
|
||||
}
|
||||
|
||||
int todo = error ? 0 : (int)d->dv_hashtab.ht_used;
|
||||
for (hashitem_T *hi = d->dv_hashtab.ht_array; todo > 0; hi++) {
|
||||
if (!HASHITEM_EMPTY(hi)) {
|
||||
todo--;
|
||||
if (tv_equal(&TV_DICT_HI2DI(hi)->di_tv, &argvars[1], ic, false)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n = count_dict(argvars[0].vval.v_dict, &argvars[1], ic);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1875,10 +1907,12 @@ static void f_flattennew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
flatten_common(argvars, rettv, true);
|
||||
}
|
||||
|
||||
/// "extend()" or "extendnew()" function. "is_new" is true for extendnew().
|
||||
static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is_new)
|
||||
/// extend() a List. Append List argvars[1] to List argvars[0] before index
|
||||
/// argvars[3] and return the resulting list in "rettv".
|
||||
///
|
||||
/// @param is_new true for extendnew()
|
||||
static void extend_list(typval_T *argvars, const char *arg_errmsg, bool is_new, typval_T *rettv)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) {
|
||||
bool error = false;
|
||||
|
||||
list_T *l1 = argvars[0].vval.v_list;
|
||||
@ -1922,7 +1956,14 @@ static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
} else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) {
|
||||
}
|
||||
|
||||
/// extend() a Dict. Append Dict argvars[1] to Dict argvars[0] and return the
|
||||
/// resulting Dict in "rettv".
|
||||
///
|
||||
/// @param is_new true for extendnew()
|
||||
static void extend_dict(typval_T *argvars, const char *arg_errmsg, bool is_new, typval_T *rettv)
|
||||
{
|
||||
dict_T *d1 = argvars[0].vval.v_dict;
|
||||
dict_T *const d2 = argvars[1].vval.v_dict;
|
||||
if (d1 == NULL) {
|
||||
@ -1973,6 +2014,17 @@ static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is
|
||||
tv_copy(&argvars[0], rettv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// "extend()" or "extendnew()" function.
|
||||
///
|
||||
/// @param is_new true for extendnew()
|
||||
static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is_new)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) {
|
||||
extend_list(argvars, arg_errmsg, is_new, rettv);
|
||||
} else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) {
|
||||
extend_dict(argvars, arg_errmsg, is_new, rettv);
|
||||
} else {
|
||||
semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()");
|
||||
}
|
||||
|
@ -36,6 +36,19 @@
|
||||
#include "nvim/types.h"
|
||||
#include "nvim/vim.h"
|
||||
|
||||
/// struct storing information about current sort
|
||||
typedef struct {
|
||||
int item_compare_ic;
|
||||
bool item_compare_lc;
|
||||
bool item_compare_numeric;
|
||||
bool item_compare_numbers;
|
||||
bool item_compare_float;
|
||||
const char *item_compare_func;
|
||||
partial_T *item_compare_partial;
|
||||
dict_T *item_compare_selfdict;
|
||||
bool item_compare_func_err;
|
||||
} sortinfo_T;
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "eval/typval.c.generated.h"
|
||||
#endif
|
||||
@ -1065,18 +1078,6 @@ void tv_list_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
|
||||
}
|
||||
}
|
||||
|
||||
/// struct storing information about current sort
|
||||
typedef struct {
|
||||
int item_compare_ic;
|
||||
bool item_compare_lc;
|
||||
bool item_compare_numeric;
|
||||
bool item_compare_numbers;
|
||||
bool item_compare_float;
|
||||
const char *item_compare_func;
|
||||
partial_T *item_compare_partial;
|
||||
dict_T *item_compare_selfdict;
|
||||
bool item_compare_func_err;
|
||||
} sortinfo_T;
|
||||
static sortinfo_T *sortinfo = NULL;
|
||||
|
||||
#define ITEM_COMPARE_FAIL 999
|
||||
@ -1252,86 +1253,133 @@ static int item_compare2_not_keeping_zero(const void *s1, const void *s2)
|
||||
return item_compare2(s1, s2, false);
|
||||
}
|
||||
|
||||
/// "sort({list})" function
|
||||
static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
|
||||
/// sort() List "l"
|
||||
static void do_sort(list_T *l, sortinfo_T *info)
|
||||
{
|
||||
ListSortItem *ptrs;
|
||||
long len;
|
||||
int i;
|
||||
const int len = tv_list_len(l);
|
||||
|
||||
// Pointer to current info struct used in compare function. Save and restore
|
||||
// the current one for nested calls.
|
||||
sortinfo_T info;
|
||||
sortinfo_T *old_sortinfo = sortinfo;
|
||||
sortinfo = &info;
|
||||
// Make an array with each entry pointing to an item in the List.
|
||||
ListSortItem *ptrs = xmalloc((size_t)((unsigned)len * sizeof(ListSortItem)));
|
||||
|
||||
const char *const arg_errmsg = (sort
|
||||
? N_("sort() argument")
|
||||
: N_("uniq() argument"));
|
||||
// f_sort(): ptrs will be the list to sort
|
||||
int i = 0;
|
||||
TV_LIST_ITER(l, li, {
|
||||
ptrs[i].item = li;
|
||||
ptrs[i].idx = i;
|
||||
i++;
|
||||
});
|
||||
|
||||
if (argvars[0].v_type != VAR_LIST) {
|
||||
semsg(_(e_listarg), sort ? "sort()" : "uniq()");
|
||||
info->item_compare_func_err = false;
|
||||
ListSorter item_compare_func = ((info->item_compare_func == NULL
|
||||
&& info->item_compare_partial == NULL)
|
||||
? item_compare_not_keeping_zero
|
||||
: item_compare2_not_keeping_zero);
|
||||
|
||||
// Sort the array with item pointers.
|
||||
qsort(ptrs, (size_t)len, sizeof(ListSortItem), item_compare_func);
|
||||
if (!info->item_compare_func_err) {
|
||||
// Clear the list and append the items in the sorted order.
|
||||
l->lv_first = NULL;
|
||||
l->lv_last = NULL;
|
||||
l->lv_idx_item = NULL;
|
||||
l->lv_len = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
tv_list_append(l, ptrs[i].item);
|
||||
}
|
||||
}
|
||||
if (info->item_compare_func_err) {
|
||||
emsg(_("E702: Sort compare function failed"));
|
||||
}
|
||||
|
||||
xfree(ptrs);
|
||||
}
|
||||
|
||||
/// uniq() List "l"
|
||||
static void do_uniq(list_T *l, sortinfo_T *info)
|
||||
{
|
||||
const int len = tv_list_len(l);
|
||||
|
||||
// Make an array with each entry pointing to an item in the List.
|
||||
ListSortItem *ptrs = xmalloc((size_t)((unsigned)len * sizeof(ListSortItem)));
|
||||
|
||||
// f_uniq(): ptrs will be a stack of items to remove.
|
||||
|
||||
info->item_compare_func_err = false;
|
||||
ListSorter item_compare_func = ((info->item_compare_func == NULL
|
||||
&& info->item_compare_partial == NULL)
|
||||
? item_compare_keeping_zero
|
||||
: item_compare2_keeping_zero);
|
||||
|
||||
for (listitem_T *li = TV_LIST_ITEM_NEXT(l, tv_list_first(l)); li != NULL;) {
|
||||
listitem_T *const prev_li = TV_LIST_ITEM_PREV(l, li);
|
||||
if (item_compare_func(&prev_li, &li) == 0) {
|
||||
li = tv_list_item_remove(l, li);
|
||||
} else {
|
||||
list_T *const l = argvars[0].vval.v_list;
|
||||
if (value_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
|
||||
goto theend;
|
||||
li = TV_LIST_ITEM_NEXT(l, li);
|
||||
}
|
||||
if (info->item_compare_func_err) {
|
||||
emsg(_("E882: Uniq compare function failed"));
|
||||
break;
|
||||
}
|
||||
tv_list_set_ret(rettv, l);
|
||||
|
||||
len = tv_list_len(l);
|
||||
if (len <= 1) {
|
||||
goto theend; // short list sorts pretty quickly
|
||||
}
|
||||
|
||||
info.item_compare_ic = false;
|
||||
info.item_compare_lc = false;
|
||||
info.item_compare_numeric = false;
|
||||
info.item_compare_numbers = false;
|
||||
info.item_compare_float = false;
|
||||
info.item_compare_func = NULL;
|
||||
info.item_compare_partial = NULL;
|
||||
info.item_compare_selfdict = NULL;
|
||||
xfree(ptrs);
|
||||
}
|
||||
|
||||
/// Parse the optional arguments to sort() and uniq() and return the values in "info".
|
||||
static int parse_sort_uniq_args(typval_T *argvars, sortinfo_T *info)
|
||||
{
|
||||
info->item_compare_ic = false;
|
||||
info->item_compare_lc = false;
|
||||
info->item_compare_numeric = false;
|
||||
info->item_compare_numbers = false;
|
||||
info->item_compare_float = false;
|
||||
info->item_compare_func = NULL;
|
||||
info->item_compare_partial = NULL;
|
||||
info->item_compare_selfdict = NULL;
|
||||
|
||||
if (argvars[1].v_type == VAR_UNKNOWN) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||
// optional second argument: {func}
|
||||
if (argvars[1].v_type == VAR_FUNC) {
|
||||
info.item_compare_func = argvars[1].vval.v_string;
|
||||
info->item_compare_func = argvars[1].vval.v_string;
|
||||
} else if (argvars[1].v_type == VAR_PARTIAL) {
|
||||
info.item_compare_partial = argvars[1].vval.v_partial;
|
||||
info->item_compare_partial = argvars[1].vval.v_partial;
|
||||
} else {
|
||||
bool error = false;
|
||||
|
||||
i = (int)tv_get_number_chk(&argvars[1], &error);
|
||||
int nr = (int)tv_get_number_chk(&argvars[1], &error);
|
||||
if (error) {
|
||||
goto theend; // type error; errmsg already given
|
||||
return FAIL; // type error; errmsg already given
|
||||
}
|
||||
if (i == 1) {
|
||||
info.item_compare_ic = true;
|
||||
if (nr == 1) {
|
||||
info->item_compare_ic = true;
|
||||
} else if (argvars[1].v_type != VAR_NUMBER) {
|
||||
info.item_compare_func = tv_get_string(&argvars[1]);
|
||||
} else if (i != 0) {
|
||||
info->item_compare_func = tv_get_string(&argvars[1]);
|
||||
} else if (nr != 0) {
|
||||
emsg(_(e_invarg));
|
||||
goto theend;
|
||||
return FAIL;
|
||||
}
|
||||
if (info.item_compare_func != NULL) {
|
||||
if (*info.item_compare_func == NUL) {
|
||||
if (info->item_compare_func != NULL) {
|
||||
if (*info->item_compare_func == NUL) {
|
||||
// empty string means default sort
|
||||
info.item_compare_func = NULL;
|
||||
} else if (strcmp(info.item_compare_func, "n") == 0) {
|
||||
info.item_compare_func = NULL;
|
||||
info.item_compare_numeric = true;
|
||||
} else if (strcmp(info.item_compare_func, "N") == 0) {
|
||||
info.item_compare_func = NULL;
|
||||
info.item_compare_numbers = true;
|
||||
} else if (strcmp(info.item_compare_func, "f") == 0) {
|
||||
info.item_compare_func = NULL;
|
||||
info.item_compare_float = true;
|
||||
} else if (strcmp(info.item_compare_func, "i") == 0) {
|
||||
info.item_compare_func = NULL;
|
||||
info.item_compare_ic = true;
|
||||
} else if (strcmp(info.item_compare_func, "l") == 0) {
|
||||
info.item_compare_func = NULL;
|
||||
info.item_compare_lc = true;
|
||||
info->item_compare_func = NULL;
|
||||
} else if (strcmp(info->item_compare_func, "n") == 0) {
|
||||
info->item_compare_func = NULL;
|
||||
info->item_compare_numeric = true;
|
||||
} else if (strcmp(info->item_compare_func, "N") == 0) {
|
||||
info->item_compare_func = NULL;
|
||||
info->item_compare_numbers = true;
|
||||
} else if (strcmp(info->item_compare_func, "f") == 0) {
|
||||
info->item_compare_func = NULL;
|
||||
info->item_compare_float = true;
|
||||
} else if (strcmp(info->item_compare_func, "i") == 0) {
|
||||
info->item_compare_func = NULL;
|
||||
info->item_compare_ic = true;
|
||||
} else if (strcmp(info->item_compare_func, "l") == 0) {
|
||||
info->item_compare_func = NULL;
|
||||
info->item_compare_lc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1339,61 +1387,54 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
// optional third argument: {dict}
|
||||
if (tv_check_for_dict_arg(argvars, 2) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
info->item_compare_selfdict = argvars[2].vval.v_dict;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// "sort()" or "uniq()" function
|
||||
static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
|
||||
{
|
||||
if (argvars[0].v_type != VAR_LIST) {
|
||||
semsg(_(e_listarg), sort ? "sort()" : "uniq()");
|
||||
return;
|
||||
}
|
||||
|
||||
// Pointer to current info struct used in compare function. Save and restore
|
||||
// the current one for nested calls.
|
||||
sortinfo_T info;
|
||||
sortinfo_T *old_sortinfo = sortinfo;
|
||||
sortinfo = &info;
|
||||
|
||||
const char *const arg_errmsg = (sort ? N_("sort() argument") : N_("uniq() argument"));
|
||||
list_T *const l = argvars[0].vval.v_list;
|
||||
if (value_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
|
||||
goto theend;
|
||||
}
|
||||
info.item_compare_selfdict = argvars[2].vval.v_dict;
|
||||
}
|
||||
}
|
||||
tv_list_set_ret(rettv, l);
|
||||
|
||||
// Make an array with each entry pointing to an item in the List.
|
||||
ptrs = xmalloc((size_t)((unsigned)len * sizeof(ListSortItem)));
|
||||
const int len = tv_list_len(l);
|
||||
if (len <= 1) {
|
||||
goto theend; // short list sorts pretty quickly
|
||||
}
|
||||
if (parse_sort_uniq_args(argvars, &info) == FAIL) {
|
||||
goto theend;
|
||||
}
|
||||
|
||||
if (sort) {
|
||||
info.item_compare_func_err = false;
|
||||
tv_list_item_sort(l, ptrs,
|
||||
((info.item_compare_func == NULL
|
||||
&& info.item_compare_partial == NULL)
|
||||
? item_compare_not_keeping_zero
|
||||
: item_compare2_not_keeping_zero),
|
||||
&info.item_compare_func_err);
|
||||
if (info.item_compare_func_err) {
|
||||
emsg(_("E702: Sort compare function failed"));
|
||||
}
|
||||
do_sort(l, &info);
|
||||
} else {
|
||||
ListSorter item_compare_func_ptr;
|
||||
|
||||
// f_uniq(): ptrs will be a stack of items to remove.
|
||||
info.item_compare_func_err = false;
|
||||
if (info.item_compare_func != NULL
|
||||
|| info.item_compare_partial != NULL) {
|
||||
item_compare_func_ptr = item_compare2_keeping_zero;
|
||||
} else {
|
||||
item_compare_func_ptr = item_compare_keeping_zero;
|
||||
}
|
||||
|
||||
for (listitem_T *li = TV_LIST_ITEM_NEXT(l, tv_list_first(l))
|
||||
; li != NULL;) {
|
||||
listitem_T *const prev_li = TV_LIST_ITEM_PREV(l, li);
|
||||
if (item_compare_func_ptr(&prev_li, &li) == 0) {
|
||||
li = tv_list_item_remove(l, li);
|
||||
} else {
|
||||
li = TV_LIST_ITEM_NEXT(l, li);
|
||||
}
|
||||
if (info.item_compare_func_err) {
|
||||
emsg(_("E882: Uniq compare function failed"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xfree(ptrs);
|
||||
do_uniq(l, &info);
|
||||
}
|
||||
|
||||
theend:
|
||||
sortinfo = old_sortinfo;
|
||||
}
|
||||
|
||||
/// "sort"({list})" function
|
||||
/// "sort({list})" function
|
||||
void f_sort(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
do_sort_uniq(argvars, rettv, true);
|
||||
@ -1469,46 +1510,6 @@ void tv_list_reverse(list_T *const l)
|
||||
l->lv_idx = l->lv_len - l->lv_idx - 1;
|
||||
}
|
||||
|
||||
// FIXME Add unit tests for tv_list_item_sort().
|
||||
|
||||
/// Sort list using libc qsort
|
||||
///
|
||||
/// @param[in,out] l List to sort, will be sorted in-place.
|
||||
/// @param ptrs Preallocated array of items to sort, must have at least
|
||||
/// tv_list_len(l) entries. Should not be initialized.
|
||||
/// @param[in] item_compare_func Function used to compare list items.
|
||||
/// @param errp Location where information about whether error occurred is
|
||||
/// saved by item_compare_func. If boolean there appears to be
|
||||
/// true list will not be modified. Must be initialized to false
|
||||
/// by the caller.
|
||||
void tv_list_item_sort(list_T *const l, ListSortItem *const ptrs,
|
||||
const ListSorter item_compare_func, const bool *errp)
|
||||
FUNC_ATTR_NONNULL_ARG(3, 4)
|
||||
{
|
||||
const int len = tv_list_len(l);
|
||||
if (len <= 1) {
|
||||
return;
|
||||
}
|
||||
int i = 0;
|
||||
TV_LIST_ITER(l, li, {
|
||||
ptrs[i].item = li;
|
||||
ptrs[i].idx = i;
|
||||
i++;
|
||||
});
|
||||
// Sort the array with item pointers.
|
||||
qsort(ptrs, (size_t)len, sizeof(ListSortItem), item_compare_func);
|
||||
if (!(*errp)) {
|
||||
// Clear the list and append the items in the sorted order.
|
||||
l->lv_first = NULL;
|
||||
l->lv_last = NULL;
|
||||
l->lv_idx_item = NULL;
|
||||
l->lv_len = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
tv_list_append(l, ptrs[i].item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//{{{2 Indexing/searching
|
||||
|
||||
/// Locate item with a given index in a list and return it
|
||||
|
Loading…
Reference in New Issue
Block a user