comparison src/list.c @ 26676:b856b797c5d1 v8.2.3867

patch 8.2.3867: implementation of some list functions too complicated Commit: https://github.com/vim/vim/commit/d92813a59877c707e4b64bea6d786aad152acb45 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Tue Dec 21 13:19:42 2021 +0000 patch 8.2.3867: implementation of some list functions too complicated Problem: Implementation of some list functions too complicated. Solution: Refactor do_sort_uniq(), f_count() and extend() (Yegappan Lakshmanan, closes #9378)
author Bram Moolenaar <Bram@vim.org>
date Tue, 21 Dec 2021 14:30:03 +0100
parents 7c055fdd6200
children 2126feddeda6
comparison
equal deleted inserted replaced
26675:3a473d09904c 26676:b856b797c5d1
1985 1985
1986 return res; 1986 return res;
1987 } 1987 }
1988 1988
1989 /* 1989 /*
1990 * sort() List "l"
1991 */
1992 static void
1993 do_sort(list_T *l, sortinfo_T *info)
1994 {
1995 long len;
1996 sortItem_T *ptrs;
1997 long i = 0;
1998 listitem_T *li;
1999
2000 len = list_len(l);
2001
2002 // Make an array with each entry pointing to an item in the List.
2003 ptrs = ALLOC_MULT(sortItem_T, len);
2004 if (ptrs == NULL)
2005 return;
2006
2007 // sort(): ptrs will be the list to sort
2008 FOR_ALL_LIST_ITEMS(l, li)
2009 {
2010 ptrs[i].item = li;
2011 ptrs[i].idx = i;
2012 ++i;
2013 }
2014
2015 info->item_compare_func_err = FALSE;
2016 info->item_compare_keep_zero = FALSE;
2017 // test the compare function
2018 if ((info->item_compare_func != NULL
2019 || info->item_compare_partial != NULL)
2020 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
2021 == ITEM_COMPARE_FAIL)
2022 emsg(_("E702: Sort compare function failed"));
2023 else
2024 {
2025 // Sort the array with item pointers.
2026 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
2027 info->item_compare_func == NULL
2028 && info->item_compare_partial == NULL
2029 ? item_compare : item_compare2);
2030
2031 if (!info->item_compare_func_err)
2032 {
2033 // Clear the List and append the items in sorted order.
2034 l->lv_first = l->lv_u.mat.lv_last
2035 = l->lv_u.mat.lv_idx_item = NULL;
2036 l->lv_len = 0;
2037 for (i = 0; i < len; ++i)
2038 list_append(l, ptrs[i].item);
2039 }
2040 }
2041
2042 vim_free(ptrs);
2043 }
2044
2045 /*
2046 * uniq() List "l"
2047 */
2048 static void
2049 do_uniq(list_T *l, sortinfo_T *info)
2050 {
2051 long len;
2052 sortItem_T *ptrs;
2053 long i = 0;
2054 listitem_T *li;
2055 int (*item_compare_func_ptr)(const void *, const void *);
2056
2057 len = list_len(l);
2058
2059 // Make an array with each entry pointing to an item in the List.
2060 ptrs = ALLOC_MULT(sortItem_T, len);
2061 if (ptrs == NULL)
2062 return;
2063
2064 // f_uniq(): ptrs will be a stack of items to remove
2065 info->item_compare_func_err = FALSE;
2066 info->item_compare_keep_zero = TRUE;
2067 item_compare_func_ptr = info->item_compare_func != NULL
2068 || info->item_compare_partial != NULL
2069 ? item_compare2 : item_compare;
2070
2071 for (li = l->lv_first; li != NULL && li->li_next != NULL;
2072 li = li->li_next)
2073 {
2074 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
2075 == 0)
2076 ptrs[i++].item = li;
2077 if (info->item_compare_func_err)
2078 {
2079 emsg(_("E882: Uniq compare function failed"));
2080 break;
2081 }
2082 }
2083
2084 if (!info->item_compare_func_err)
2085 {
2086 while (--i >= 0)
2087 {
2088 li = ptrs[i].item->li_next;
2089 ptrs[i].item->li_next = li->li_next;
2090 if (li->li_next != NULL)
2091 li->li_next->li_prev = ptrs[i].item;
2092 else
2093 l->lv_u.mat.lv_last = ptrs[i].item;
2094 list_fix_watch(l, li);
2095 listitem_free(l, li);
2096 l->lv_len--;
2097 }
2098 }
2099
2100 vim_free(ptrs);
2101 }
2102
2103 /*
2104 * Parse the optional arguments to sort() and uniq() and return the values in
2105 * 'info'.
2106 */
2107 static int
2108 parse_sort_uniq_args(typval_T *argvars, sortinfo_T *info)
2109 {
2110 info->item_compare_ic = FALSE;
2111 info->item_compare_lc = FALSE;
2112 info->item_compare_numeric = FALSE;
2113 info->item_compare_numbers = FALSE;
2114 #ifdef FEAT_FLOAT
2115 info->item_compare_float = FALSE;
2116 #endif
2117 info->item_compare_func = NULL;
2118 info->item_compare_partial = NULL;
2119 info->item_compare_selfdict = NULL;
2120
2121 if (argvars[1].v_type == VAR_UNKNOWN)
2122 return OK;
2123
2124 // optional second argument: {func}
2125 if (argvars[1].v_type == VAR_FUNC)
2126 info->item_compare_func = argvars[1].vval.v_string;
2127 else if (argvars[1].v_type == VAR_PARTIAL)
2128 info->item_compare_partial = argvars[1].vval.v_partial;
2129 else
2130 {
2131 int error = FALSE;
2132 int nr = 0;
2133
2134 if (argvars[1].v_type == VAR_NUMBER)
2135 {
2136 nr = tv_get_number_chk(&argvars[1], &error);
2137 if (error)
2138 return FAIL;
2139 if (nr == 1)
2140 info->item_compare_ic = TRUE;
2141 }
2142 if (nr != 1)
2143 {
2144 if (argvars[1].v_type != VAR_NUMBER)
2145 info->item_compare_func = tv_get_string(&argvars[1]);
2146 else if (nr != 0)
2147 {
2148 emsg(_(e_invarg));
2149 return FAIL;
2150 }
2151 }
2152 if (info->item_compare_func != NULL)
2153 {
2154 if (*info->item_compare_func == NUL)
2155 {
2156 // empty string means default sort
2157 info->item_compare_func = NULL;
2158 }
2159 else if (STRCMP(info->item_compare_func, "n") == 0)
2160 {
2161 info->item_compare_func = NULL;
2162 info->item_compare_numeric = TRUE;
2163 }
2164 else if (STRCMP(info->item_compare_func, "N") == 0)
2165 {
2166 info->item_compare_func = NULL;
2167 info->item_compare_numbers = TRUE;
2168 }
2169 #ifdef FEAT_FLOAT
2170 else if (STRCMP(info->item_compare_func, "f") == 0)
2171 {
2172 info->item_compare_func = NULL;
2173 info->item_compare_float = TRUE;
2174 }
2175 #endif
2176 else if (STRCMP(info->item_compare_func, "i") == 0)
2177 {
2178 info->item_compare_func = NULL;
2179 info->item_compare_ic = TRUE;
2180 }
2181 else if (STRCMP(info->item_compare_func, "l") == 0)
2182 {
2183 info->item_compare_func = NULL;
2184 info->item_compare_lc = TRUE;
2185 }
2186 }
2187 }
2188
2189 if (argvars[2].v_type != VAR_UNKNOWN)
2190 {
2191 // optional third argument: {dict}
2192 if (argvars[2].v_type != VAR_DICT)
2193 {
2194 emsg(_(e_dictreq));
2195 return FAIL;
2196 }
2197 info->item_compare_selfdict = argvars[2].vval.v_dict;
2198 }
2199
2200 return OK;
2201 }
2202
2203 /*
1990 * "sort()" or "uniq()" function 2204 * "sort()" or "uniq()" function
1991 */ 2205 */
1992 static void 2206 static void
1993 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) 2207 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
1994 { 2208 {
1995 list_T *l; 2209 list_T *l;
1996 listitem_T *li;
1997 sortItem_T *ptrs;
1998 sortinfo_T *old_sortinfo; 2210 sortinfo_T *old_sortinfo;
1999 sortinfo_T info; 2211 sortinfo_T info;
2000 long len; 2212 long len;
2001 long i;
2002 2213
2003 if (in_vim9script() 2214 if (in_vim9script()
2004 && (check_for_list_arg(argvars, 0) == FAIL 2215 && (check_for_list_arg(argvars, 0) == FAIL
2005 || (argvars[1].v_type != VAR_UNKNOWN 2216 || (argvars[1].v_type != VAR_UNKNOWN
2006 && check_for_opt_dict_arg(argvars, 2) == FAIL))) 2217 && check_for_opt_dict_arg(argvars, 2) == FAIL)))
2007 return; 2218 return;
2008 2219
2220 if (argvars[0].v_type != VAR_LIST)
2221 {
2222 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
2223 return;
2224 }
2225
2009 // Pointer to current info struct used in compare function. Save and 2226 // Pointer to current info struct used in compare function. Save and
2010 // restore the current one for nested calls. 2227 // restore the current one for nested calls.
2011 old_sortinfo = sortinfo; 2228 old_sortinfo = sortinfo;
2012 sortinfo = &info; 2229 sortinfo = &info;
2013 2230
2014 if (argvars[0].v_type != VAR_LIST) 2231 l = argvars[0].vval.v_list;
2015 semsg(_(e_listarg), sort ? "sort()" : "uniq()"); 2232 if (l != NULL && value_check_lock(l->lv_lock,
2233 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
2234 TRUE))
2235 goto theend;
2236 rettv_list_set(rettv, l);
2237 if (l == NULL)
2238 goto theend;
2239 CHECK_LIST_MATERIALIZE(l);
2240
2241 len = list_len(l);
2242 if (len <= 1)
2243 goto theend; // short list sorts pretty quickly
2244
2245 if (parse_sort_uniq_args(argvars, &info) == FAIL)
2246 goto theend;
2247
2248 if (sort)
2249 do_sort(l, &info);
2016 else 2250 else
2017 { 2251 do_uniq(l, &info);
2018 l = argvars[0].vval.v_list; 2252
2019 if (l != NULL && value_check_lock(l->lv_lock,
2020 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
2021 TRUE))
2022 goto theend;
2023 rettv_list_set(rettv, l);
2024 if (l == NULL)
2025 goto theend;
2026 CHECK_LIST_MATERIALIZE(l);
2027
2028 len = list_len(l);
2029 if (len <= 1)
2030 goto theend; // short list sorts pretty quickly
2031
2032 info.item_compare_ic = FALSE;
2033 info.item_compare_lc = FALSE;
2034 info.item_compare_numeric = FALSE;
2035 info.item_compare_numbers = FALSE;
2036 #ifdef FEAT_FLOAT
2037 info.item_compare_float = FALSE;
2038 #endif
2039 info.item_compare_func = NULL;
2040 info.item_compare_partial = NULL;
2041 info.item_compare_selfdict = NULL;
2042 if (argvars[1].v_type != VAR_UNKNOWN)
2043 {
2044 // optional second argument: {func}
2045 if (argvars[1].v_type == VAR_FUNC)
2046 info.item_compare_func = argvars[1].vval.v_string;
2047 else if (argvars[1].v_type == VAR_PARTIAL)
2048 info.item_compare_partial = argvars[1].vval.v_partial;
2049 else
2050 {
2051 int error = FALSE;
2052 int nr = 0;
2053
2054 if (argvars[1].v_type == VAR_NUMBER)
2055 {
2056 nr = tv_get_number_chk(&argvars[1], &error);
2057 if (error)
2058 goto theend; // type error; errmsg already given
2059 if (nr == 1)
2060 info.item_compare_ic = TRUE;
2061 }
2062 if (nr != 1)
2063 {
2064 if (argvars[1].v_type != VAR_NUMBER)
2065 info.item_compare_func = tv_get_string(&argvars[1]);
2066 else if (nr != 0)
2067 {
2068 emsg(_(e_invarg));
2069 goto theend;
2070 }
2071 }
2072 if (info.item_compare_func != NULL)
2073 {
2074 if (*info.item_compare_func == NUL)
2075 {
2076 // empty string means default sort
2077 info.item_compare_func = NULL;
2078 }
2079 else if (STRCMP(info.item_compare_func, "n") == 0)
2080 {
2081 info.item_compare_func = NULL;
2082 info.item_compare_numeric = TRUE;
2083 }
2084 else if (STRCMP(info.item_compare_func, "N") == 0)
2085 {
2086 info.item_compare_func = NULL;
2087 info.item_compare_numbers = TRUE;
2088 }
2089 #ifdef FEAT_FLOAT
2090 else if (STRCMP(info.item_compare_func, "f") == 0)
2091 {
2092 info.item_compare_func = NULL;
2093 info.item_compare_float = TRUE;
2094 }
2095 #endif
2096 else if (STRCMP(info.item_compare_func, "i") == 0)
2097 {
2098 info.item_compare_func = NULL;
2099 info.item_compare_ic = TRUE;
2100 }
2101 else if (STRCMP(info.item_compare_func, "l") == 0)
2102 {
2103 info.item_compare_func = NULL;
2104 info.item_compare_lc = TRUE;
2105 }
2106 }
2107 }
2108
2109 if (argvars[2].v_type != VAR_UNKNOWN)
2110 {
2111 // optional third argument: {dict}
2112 if (argvars[2].v_type != VAR_DICT)
2113 {
2114 emsg(_(e_dictreq));
2115 goto theend;
2116 }
2117 info.item_compare_selfdict = argvars[2].vval.v_dict;
2118 }
2119 }
2120
2121 // Make an array with each entry pointing to an item in the List.
2122 ptrs = ALLOC_MULT(sortItem_T, len);
2123 if (ptrs == NULL)
2124 goto theend;
2125
2126 i = 0;
2127 if (sort)
2128 {
2129 // sort(): ptrs will be the list to sort
2130 FOR_ALL_LIST_ITEMS(l, li)
2131 {
2132 ptrs[i].item = li;
2133 ptrs[i].idx = i;
2134 ++i;
2135 }
2136
2137 info.item_compare_func_err = FALSE;
2138 info.item_compare_keep_zero = FALSE;
2139 // test the compare function
2140 if ((info.item_compare_func != NULL
2141 || info.item_compare_partial != NULL)
2142 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
2143 == ITEM_COMPARE_FAIL)
2144 emsg(_("E702: Sort compare function failed"));
2145 else
2146 {
2147 // Sort the array with item pointers.
2148 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
2149 info.item_compare_func == NULL
2150 && info.item_compare_partial == NULL
2151 ? item_compare : item_compare2);
2152
2153 if (!info.item_compare_func_err)
2154 {
2155 // Clear the List and append the items in sorted order.
2156 l->lv_first = l->lv_u.mat.lv_last
2157 = l->lv_u.mat.lv_idx_item = NULL;
2158 l->lv_len = 0;
2159 for (i = 0; i < len; ++i)
2160 list_append(l, ptrs[i].item);
2161 }
2162 }
2163 }
2164 else
2165 {
2166 int (*item_compare_func_ptr)(const void *, const void *);
2167
2168 // f_uniq(): ptrs will be a stack of items to remove
2169 info.item_compare_func_err = FALSE;
2170 info.item_compare_keep_zero = TRUE;
2171 item_compare_func_ptr = info.item_compare_func != NULL
2172 || info.item_compare_partial != NULL
2173 ? item_compare2 : item_compare;
2174
2175 for (li = l->lv_first; li != NULL && li->li_next != NULL;
2176 li = li->li_next)
2177 {
2178 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
2179 == 0)
2180 ptrs[i++].item = li;
2181 if (info.item_compare_func_err)
2182 {
2183 emsg(_("E882: Uniq compare function failed"));
2184 break;
2185 }
2186 }
2187
2188 if (!info.item_compare_func_err)
2189 {
2190 while (--i >= 0)
2191 {
2192 li = ptrs[i].item->li_next;
2193 ptrs[i].item->li_next = li->li_next;
2194 if (li->li_next != NULL)
2195 li->li_next->li_prev = ptrs[i].item;
2196 else
2197 l->lv_u.mat.lv_last = ptrs[i].item;
2198 list_fix_watch(l, li);
2199 listitem_free(l, li);
2200 l->lv_len--;
2201 }
2202 }
2203 }
2204
2205 vim_free(ptrs);
2206 }
2207 theend: 2253 theend:
2208 sortinfo = old_sortinfo; 2254 sortinfo = old_sortinfo;
2209 } 2255 }
2210 2256
2211 /* 2257 /*
2833 else 2879 else
2834 emsg(_(e_listblobreq)); 2880 emsg(_(e_listblobreq));
2835 } 2881 }
2836 2882
2837 /* 2883 /*
2884 * Count the number of times "needle" occurs in string "haystack". Case is
2885 * ignored if "ic" is TRUE.
2886 */
2887 static long
2888 count_string(char_u *haystack, char_u *needle, int ic)
2889 {
2890 long n = 0;
2891 char_u *p = haystack;
2892 char_u *next;
2893
2894 if (p == NULL || needle == NULL || *needle == NUL)
2895 return 0;
2896
2897 if (ic)
2898 {
2899 size_t len = STRLEN(needle);
2900
2901 while (*p != NUL)
2902 {
2903 if (MB_STRNICMP(p, needle, len) == 0)
2904 {
2905 ++n;
2906 p += len;
2907 }
2908 else
2909 MB_PTR_ADV(p);
2910 }
2911 }
2912 else
2913 while ((next = (char_u *)strstr((char *)p, (char *)needle)) != NULL)
2914 {
2915 ++n;
2916 p = next + STRLEN(needle);
2917 }
2918
2919 return n;
2920 }
2921
2922 /*
2923 * Count the number of times item "needle" occurs in List "l" starting at index
2924 * "idx". Case is ignored if "ic" is TRUE.
2925 */
2926 static long
2927 count_list(list_T *l, typval_T *needle, long idx, int ic)
2928 {
2929 long n = 0;
2930 listitem_T *li;
2931
2932 if (l == NULL)
2933 return 0;
2934
2935 CHECK_LIST_MATERIALIZE(l);
2936
2937 if (list_len(l) == 0)
2938 return 0;
2939
2940 li = list_find(l, idx);
2941 if (li == NULL)
2942 {
2943 semsg(_(e_listidx), idx);
2944 return 0;
2945 }
2946
2947 for ( ; li != NULL; li = li->li_next)
2948 if (tv_equal(&li->li_tv, needle, ic, FALSE))
2949 ++n;
2950
2951 return n;
2952 }
2953
2954 /*
2955 * Count the number of times item "needle" occurs in Dict "d". Case is ignored
2956 * if "ic" is TRUE.
2957 */
2958 static long
2959 count_dict(dict_T *d, typval_T *needle, int ic)
2960 {
2961 int todo;
2962 hashitem_T *hi;
2963 long n = 0;
2964
2965 if (d == NULL)
2966 return 0;
2967
2968 todo = (int)d->dv_hashtab.ht_used;
2969 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2970 {
2971 if (!HASHITEM_EMPTY(hi))
2972 {
2973 --todo;
2974 if (tv_equal(&HI2DI(hi)->di_tv, needle, ic, FALSE))
2975 ++n;
2976 }
2977 }
2978
2979 return n;
2980 }
2981
2982 /*
2838 * "count()" function 2983 * "count()" function
2839 */ 2984 */
2840 void 2985 void
2841 f_count(typval_T *argvars, typval_T *rettv) 2986 f_count(typval_T *argvars, typval_T *rettv)
2842 { 2987 {
2852 return; 2997 return;
2853 2998
2854 if (argvars[2].v_type != VAR_UNKNOWN) 2999 if (argvars[2].v_type != VAR_UNKNOWN)
2855 ic = (int)tv_get_bool_chk(&argvars[2], &error); 3000 ic = (int)tv_get_bool_chk(&argvars[2], &error);
2856 3001
2857 if (argvars[0].v_type == VAR_STRING) 3002 if (!error && argvars[0].v_type == VAR_STRING)
2858 { 3003 n = count_string(argvars[0].vval.v_string,
2859 char_u *expr = tv_get_string_chk(&argvars[1]); 3004 tv_get_string_chk(&argvars[1]), ic);
2860 char_u *p = argvars[0].vval.v_string; 3005 else if (!error && argvars[0].v_type == VAR_LIST)
2861 char_u *next; 3006 {
2862 3007 long idx = 0;
2863 if (!error && expr != NULL && *expr != NUL && p != NULL) 3008
2864 { 3009 if (argvars[2].v_type != VAR_UNKNOWN
2865 if (ic) 3010 && argvars[3].v_type != VAR_UNKNOWN)
2866 { 3011 idx = (long)tv_get_number_chk(&argvars[3], &error);
2867 size_t len = STRLEN(expr); 3012 if (!error)
2868 3013 n = count_list(argvars[0].vval.v_list, &argvars[1], idx, ic);
2869 while (*p != NUL) 3014 }
2870 { 3015 else if (!error && argvars[0].v_type == VAR_DICT)
2871 if (MB_STRNICMP(p, expr, len) == 0) 3016 {
2872 { 3017 if (argvars[2].v_type != VAR_UNKNOWN
2873 ++n; 3018 && argvars[3].v_type != VAR_UNKNOWN)
2874 p += len; 3019 emsg(_(e_invarg));
2875 } 3020 else
2876 else 3021 n = count_dict(argvars[0].vval.v_dict, &argvars[1], ic);
2877 MB_PTR_ADV(p);
2878 }
2879 }
2880 else
2881 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2882 != NULL)
2883 {
2884 ++n;
2885 p = next + STRLEN(expr);
2886 }
2887 }
2888
2889 }
2890 else if (argvars[0].v_type == VAR_LIST)
2891 {
2892 listitem_T *li;
2893 list_T *l;
2894 long idx;
2895
2896 if ((l = argvars[0].vval.v_list) != NULL)
2897 {
2898 CHECK_LIST_MATERIALIZE(l);
2899 li = l->lv_first;
2900 if (argvars[2].v_type != VAR_UNKNOWN)
2901 {
2902 if (argvars[3].v_type != VAR_UNKNOWN)
2903 {
2904 idx = (long)tv_get_number_chk(&argvars[3], &error);
2905 if (!error)
2906 {
2907 li = list_find(l, idx);
2908 if (li == NULL)
2909 semsg(_(e_listidx), idx);
2910 }
2911 }
2912 if (error)
2913 li = NULL;
2914 }
2915
2916 for ( ; li != NULL; li = li->li_next)
2917 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2918 ++n;
2919 }
2920 }
2921 else if (argvars[0].v_type == VAR_DICT)
2922 {
2923 int todo;
2924 dict_T *d;
2925 hashitem_T *hi;
2926
2927 if ((d = argvars[0].vval.v_dict) != NULL)
2928 {
2929 if (argvars[2].v_type != VAR_UNKNOWN)
2930 {
2931 if (argvars[3].v_type != VAR_UNKNOWN)
2932 emsg(_(e_invarg));
2933 }
2934
2935 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2936 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2937 {
2938 if (!HASHITEM_EMPTY(hi))
2939 {
2940 --todo;
2941 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2942 ++n;
2943 }
2944 }
2945 }
2946 } 3022 }
2947 else 3023 else
2948 semsg(_(e_listdictarg), "count()"); 3024 semsg(_(e_listdictarg), "count()");
2949 rettv->vval.v_number = n; 3025 rettv->vval.v_number = n;
2950 } 3026 }
2951 3027
2952 /* 3028 /*
3029 * extend() a List. Append List argvars[1] to List argvars[0] before index
3030 * argvars[3] and return the resulting list in "rettv". "is_new" is TRUE for
3031 * extendnew().
3032 */
3033 static void
3034 extend_list(
3035 typval_T *argvars,
3036 type_T *type,
3037 char *func_name,
3038 char_u *arg_errmsg,
3039 int is_new,
3040 typval_T *rettv)
3041 {
3042 list_T *l1, *l2;
3043 listitem_T *item;
3044 long before;
3045 int error = FALSE;
3046
3047 l1 = argvars[0].vval.v_list;
3048 if (l1 == NULL)
3049 {
3050 emsg(_(e_cannot_extend_null_list));
3051 return;
3052 }
3053 l2 = argvars[1].vval.v_list;
3054 if ((is_new || !value_check_lock(l1->lv_lock, arg_errmsg, TRUE))
3055 && l2 != NULL)
3056 {
3057 if (is_new)
3058 {
3059 l1 = list_copy(l1, FALSE, get_copyID());
3060 if (l1 == NULL)
3061 return;
3062 }
3063
3064 if (argvars[2].v_type != VAR_UNKNOWN)
3065 {
3066 before = (long)tv_get_number_chk(&argvars[2], &error);
3067 if (error)
3068 return; // type error; errmsg already given
3069
3070 if (before == l1->lv_len)
3071 item = NULL;
3072 else
3073 {
3074 item = list_find(l1, before);
3075 if (item == NULL)
3076 {
3077 semsg(_(e_listidx), before);
3078 return;
3079 }
3080 }
3081 }
3082 else
3083 item = NULL;
3084 if (type != NULL && check_typval_arg_type(
3085 type, &argvars[1], func_name, 2) == FAIL)
3086 return;
3087 list_extend(l1, l2, item);
3088
3089 if (is_new)
3090 {
3091 rettv->v_type = VAR_LIST;
3092 rettv->vval.v_list = l1;
3093 rettv->v_lock = FALSE;
3094 }
3095 else
3096 copy_tv(&argvars[0], rettv);
3097 }
3098 }
3099
3100 /*
3101 * extend() a Dict. Append Dict argvars[1] to Dict argvars[0] and return the
3102 * resulting Dict in "rettv". "is_new" is TRUE for extendnew().
3103 */
3104 static void
3105 extend_dict(
3106 typval_T *argvars,
3107 type_T *type,
3108 char *func_name,
3109 char_u *arg_errmsg,
3110 int is_new,
3111 typval_T *rettv)
3112 {
3113 dict_T *d1, *d2;
3114 char_u *action;
3115 int i;
3116
3117 d1 = argvars[0].vval.v_dict;
3118 if (d1 == NULL)
3119 {
3120 emsg(_(e_cannot_extend_null_dict));
3121 return;
3122 }
3123 d2 = argvars[1].vval.v_dict;
3124 if ((is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TRUE))
3125 && d2 != NULL)
3126 {
3127 if (is_new)
3128 {
3129 d1 = dict_copy(d1, FALSE, get_copyID());
3130 if (d1 == NULL)
3131 return;
3132 }
3133
3134 // Check the third argument.
3135 if (argvars[2].v_type != VAR_UNKNOWN)
3136 {
3137 static char *(av[]) = {"keep", "force", "error"};
3138
3139 action = tv_get_string_chk(&argvars[2]);
3140 if (action == NULL)
3141 return;
3142 for (i = 0; i < 3; ++i)
3143 if (STRCMP(action, av[i]) == 0)
3144 break;
3145 if (i == 3)
3146 {
3147 semsg(_(e_invarg2), action);
3148 return;
3149 }
3150 }
3151 else
3152 action = (char_u *)"force";
3153
3154 if (type != NULL && check_typval_arg_type(type, &argvars[1],
3155 func_name, 2) == FAIL)
3156 return;
3157 dict_extend(d1, d2, action, func_name);
3158
3159 if (is_new)
3160 {
3161 rettv->v_type = VAR_DICT;
3162 rettv->vval.v_dict = d1;
3163 rettv->v_lock = FALSE;
3164 }
3165 else
3166 copy_tv(&argvars[0], rettv);
3167 }
3168 }
3169
3170 /*
2953 * "extend()" or "extendnew()" function. "is_new" is TRUE for extendnew(). 3171 * "extend()" or "extendnew()" function. "is_new" is TRUE for extendnew().
2954 */ 3172 */
2955 static void 3173 static void
2956 extend(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg, int is_new) 3174 extend(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg, int is_new)
2957 { 3175 {
2965 ga_init2(&type_list, sizeof(type_T *), 10); 3183 ga_init2(&type_list, sizeof(type_T *), 10);
2966 type = typval2type(argvars, get_copyID(), &type_list, TRUE); 3184 type = typval2type(argvars, get_copyID(), &type_list, TRUE);
2967 } 3185 }
2968 3186
2969 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) 3187 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
2970 { 3188 extend_list(argvars, type, func_name, arg_errmsg, is_new, rettv);
2971 list_T *l1, *l2;
2972 listitem_T *item;
2973 long before;
2974 int error = FALSE;
2975
2976 l1 = argvars[0].vval.v_list;
2977 if (l1 == NULL)
2978 {
2979 emsg(_(e_cannot_extend_null_list));
2980 goto theend;
2981 }
2982 l2 = argvars[1].vval.v_list;
2983 if ((is_new || !value_check_lock(l1->lv_lock, arg_errmsg, TRUE))
2984 && l2 != NULL)
2985 {
2986 if (is_new)
2987 {
2988 l1 = list_copy(l1, FALSE, get_copyID());
2989 if (l1 == NULL)
2990 goto theend;
2991 }
2992
2993 if (argvars[2].v_type != VAR_UNKNOWN)
2994 {
2995 before = (long)tv_get_number_chk(&argvars[2], &error);
2996 if (error)
2997 goto theend; // type error; errmsg already given
2998
2999 if (before == l1->lv_len)
3000 item = NULL;
3001 else
3002 {
3003 item = list_find(l1, before);
3004 if (item == NULL)
3005 {
3006 semsg(_(e_listidx), before);
3007 goto theend;
3008 }
3009 }
3010 }
3011 else
3012 item = NULL;
3013 if (type != NULL && check_typval_arg_type(
3014 type, &argvars[1], func_name, 2) == FAIL)
3015 goto theend;
3016 list_extend(l1, l2, item);
3017
3018 if (is_new)
3019 {
3020 rettv->v_type = VAR_LIST;
3021 rettv->vval.v_list = l1;
3022 rettv->v_lock = FALSE;
3023 }
3024 else
3025 copy_tv(&argvars[0], rettv);
3026 }
3027 }
3028 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) 3189 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3029 { 3190 extend_dict(argvars, type, func_name, arg_errmsg, is_new, rettv);
3030 dict_T *d1, *d2;
3031 char_u *action;
3032 int i;
3033
3034 d1 = argvars[0].vval.v_dict;
3035 if (d1 == NULL)
3036 {
3037 emsg(_(e_cannot_extend_null_dict));
3038 goto theend;
3039 }
3040 d2 = argvars[1].vval.v_dict;
3041 if ((is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TRUE))
3042 && d2 != NULL)
3043 {
3044 if (is_new)
3045 {
3046 d1 = dict_copy(d1, FALSE, get_copyID());
3047 if (d1 == NULL)
3048 goto theend;
3049 }
3050
3051 // Check the third argument.
3052 if (argvars[2].v_type != VAR_UNKNOWN)
3053 {
3054 static char *(av[]) = {"keep", "force", "error"};
3055
3056 action = tv_get_string_chk(&argvars[2]);
3057 if (action == NULL)
3058 goto theend; // type error; errmsg already given
3059 for (i = 0; i < 3; ++i)
3060 if (STRCMP(action, av[i]) == 0)
3061 break;
3062 if (i == 3)
3063 {
3064 semsg(_(e_invarg2), action);
3065 goto theend;
3066 }
3067 }
3068 else
3069 action = (char_u *)"force";
3070
3071 if (type != NULL && check_typval_arg_type(type, &argvars[1],
3072 func_name, 2) == FAIL)
3073 goto theend;
3074 dict_extend(d1, d2, action, func_name);
3075
3076 if (is_new)
3077 {
3078 rettv->v_type = VAR_DICT;
3079 rettv->vval.v_dict = d1;
3080 rettv->v_lock = FALSE;
3081 }
3082 else
3083 copy_tv(&argvars[0], rettv);
3084 }
3085 }
3086 else 3191 else
3087 semsg(_(e_listdictarg), func_name); 3192 semsg(_(e_listdictarg), func_name);
3088 3193
3089 theend:
3090 if (type != NULL) 3194 if (type != NULL)
3091 clear_type_list(&type_list); 3195 clear_type_list(&type_list);
3092 } 3196 }
3093 3197
3094 /* 3198 /*
3306 } 3410 }
3307 } 3411 }
3308 } 3412 }
3309 3413
3310 /* 3414 /*
3311 * reduce() on a List 3415 * reduce() List argvars[0] using the function 'funcname' with arguments in
3416 * 'funcexe' starting with the initial value argvars[2] and return the result
3417 * in 'rettv'.
3312 */ 3418 */
3313 static void 3419 static void
3314 reduce_list( 3420 reduce_list(
3315 typval_T *argvars, 3421 typval_T *argvars,
3316 char_u *func_name, 3422 char_u *func_name,
3363 } 3469 }
3364 l->lv_lock = prev_locked; 3470 l->lv_lock = prev_locked;
3365 } 3471 }
3366 3472
3367 /* 3473 /*
3368 * reduce() on a String 3474 * reduce() String argvars[0] using the function 'funcname' with arguments in
3475 * 'funcexe' starting with the initial value argvars[2] and return the result
3476 * in 'rettv'.
3369 */ 3477 */
3370 static void 3478 static void
3371 reduce_string( 3479 reduce_string(
3372 typval_T *argvars, 3480 typval_T *argvars,
3373 char_u *func_name, 3481 char_u *func_name,
3412 return; 3520 return;
3413 } 3521 }
3414 } 3522 }
3415 3523
3416 /* 3524 /*
3417 * reduce() on a Blob 3525 * reduce() Blob argvars[0] using the function 'funcname' with arguments in
3526 * 'funcexe' starting with the initial value argvars[2] and return the result
3527 * in 'rettv'.
3418 */ 3528 */
3419 static void 3529 static void
3420 reduce_blob( 3530 reduce_blob(
3421 typval_T *argvars, 3531 typval_T *argvars,
3422 char_u *func_name, 3532 char_u *func_name,
3468 } 3578 }
3469 } 3579 }
3470 3580
3471 /* 3581 /*
3472 * "reduce(list, { accumulator, element -> value } [, initial])" function 3582 * "reduce(list, { accumulator, element -> value } [, initial])" function
3583 * "reduce(blob, { accumulator, element -> value } [, initial])"
3584 * "reduce(string, { accumulator, element -> value } [, initial])"
3473 */ 3585 */
3474 void 3586 void
3475 f_reduce(typval_T *argvars, typval_T *rettv) 3587 f_reduce(typval_T *argvars, typval_T *rettv)
3476 { 3588 {
3477 char_u *func_name; 3589 char_u *func_name;