From 9f252554e31bb24a5d75607c47a2a71b770a681c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Twupack?= Date: Sat, 12 Jul 2014 18:39:23 +0200 Subject: [PATCH 1/4] vim-patch:7.4.341 Problem: sort() doesn't handle numbers well. Solution: Add an argument to specify sorting on numbers. (Christian Brabandt) https://code.google.com/p/vim/source/detail?r=adc4a84f72eb44dae657af713922a6e2c1f64ae3 --- src/nvim/eval.c | 27 +++++++++++++++++++++++---- src/nvim/testdir/test55.in | 5 +++++ src/nvim/testdir/test55.ok | 4 ++++ src/nvim/version.c | 2 +- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d8c2e73150..8d06660b1b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -13362,6 +13362,7 @@ static void f_sinh(typval_T *argvars, typval_T *rettv) static int item_compare_ic; +static bool item_compare_numeric; static char_u *item_compare_func; static dict_T *item_compare_selfdict; static int item_compare_func_err; @@ -13384,10 +13385,18 @@ static int item_compare(const void *s1, const void *s2) p1 = (char_u *)""; if (p2 == NULL) p2 = (char_u *)""; - if (item_compare_ic) - res = STRICMP(p1, p2); - else - res = STRCMP(p1, p2); + if (!item_compare_numeric) { + if (item_compare_ic) { + res = STRICMP(p1, p2); + } else { + res = STRCMP(p1, p2); + } + } else { + double n1, n2; + n1 = strtod((char *)p1, (char **)&p1); + n2 = strtod((char *)p2, (char **)&p2); + res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; + } free(tofree1); free(tofree2); return res; @@ -13454,6 +13463,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) return; /* short list sorts pretty quickly */ item_compare_ic = FALSE; + item_compare_numeric = false; item_compare_func = NULL; item_compare_selfdict = NULL; @@ -13471,6 +13481,15 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) item_compare_ic = TRUE; else item_compare_func = get_tv_string(&argvars[1]); + if (item_compare_func != NULL) { + if (STRCMP(item_compare_func, "n") == 0) { + item_compare_func = NULL; + item_compare_numeric = true; + } else if (STRCMP(item_compare_func, "i") == 0) { + item_compare_func = NULL; + item_compare_ic = TRUE; + } + } } if (argvars[2].v_type != VAR_UNKNOWN) { diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in index 85a8063774..f12dc2d22f 100644 --- a/src/nvim/testdir/test55.in +++ b/src/nvim/testdir/test55.in @@ -332,6 +332,11 @@ let l = [0, 1, 2, 3] :$put =string(reverse(sort(l))) :$put =string(sort(reverse(sort(l)))) :$put =string(uniq(sort(l))) +:let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'foo', 'FOOBAR',{}, []] +:$put =string(sort(copy(l), 'n')) +:$put =string(sort(copy(l), 1)) +:$put =string(sort(copy(l), 'i')) +:$put =string(sort(copy(l))) :" :" splitting a string to a List :$put =string(split(' aa bb ')) diff --git a/src/nvim/testdir/test55.ok b/src/nvim/testdir/test55.ok index be476e8e93..901bc94066 100644 --- a/src/nvim/testdir/test55.ok +++ b/src/nvim/testdir/test55.ok @@ -101,6 +101,10 @@ caught a:000[3] [[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'] ['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]] ['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]] +[-1, 0, 0, 'foo', 'FOOBAR', {}, [], 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255] +['foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] +['foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] +['FOOBAR', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] ['aa', 'bb'] ['aa', 'bb'] ['', 'aa', 'bb', ''] diff --git a/src/nvim/version.c b/src/nvim/version.c index fc0b85fde9..f96e557dd8 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -254,7 +254,7 @@ static int included_patches[] = { 344, 343, //342 NA - //341, + 341, //340 NA 339, 338, From c68468500f5aac86414a54c753af53e8e3f8b841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Twupack?= Date: Fri, 5 Sep 2014 22:58:07 +0200 Subject: [PATCH 2/4] vim-patch:7.4.347 Problem: test55 fails on some systems. Solution: Remove the elements that all result in zero and can end up in an arbitrary position. https://code.google.com/p/vim/source/detail?r=v7-4-347 --- src/nvim/testdir/test55.in | 3 ++- src/nvim/testdir/test55.ok | 2 +- src/nvim/version.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in index f12dc2d22f..ace97bf30e 100644 --- a/src/nvim/testdir/test55.in +++ b/src/nvim/testdir/test55.in @@ -332,8 +332,9 @@ let l = [0, 1, 2, 3] :$put =string(reverse(sort(l))) :$put =string(sort(reverse(sort(l)))) :$put =string(uniq(sort(l))) -:let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'foo', 'FOOBAR',{}, []] +:let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0.22, 'foo'] :$put =string(sort(copy(l), 'n')) +:let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'foo', 'FOOBAR',{}, []] :$put =string(sort(copy(l), 1)) :$put =string(sort(copy(l), 'i')) :$put =string(sort(copy(l))) diff --git a/src/nvim/testdir/test55.ok b/src/nvim/testdir/test55.ok index 901bc94066..3969995a1e 100644 --- a/src/nvim/testdir/test55.ok +++ b/src/nvim/testdir/test55.ok @@ -101,7 +101,7 @@ caught a:000[3] [[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'] ['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]] ['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]] -[-1, 0, 0, 'foo', 'FOOBAR', {}, [], 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255] +[-1, 'foo', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255] ['foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] ['foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] ['FOOBAR', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] diff --git a/src/nvim/version.c b/src/nvim/version.c index f96e557dd8..f99767cf19 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -248,7 +248,7 @@ static int included_patches[] = { //350, 349, 348, - //347, + 347, 346, 345, 344, From 75413496ae9169807e74d711e29a2f0107ceed6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Twupack?= Date: Fri, 5 Sep 2014 23:34:51 +0200 Subject: [PATCH 3/4] vim-patch:7.4.351 Problem: sort() is not stable. Solution: When the items are identical, compare the pointers. https://code.google.com/p/vim/source/detail?r=v7-4-351 --- src/nvim/eval.c | 21 +++++++++++++++++++-- src/nvim/testdir/test55.in | 4 ++-- src/nvim/testdir/test55.ok | 8 ++++---- src/nvim/version.c | 2 +- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 8d06660b1b..d8fd6f95c5 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -13366,6 +13366,7 @@ static bool item_compare_numeric; static char_u *item_compare_func; static dict_T *item_compare_selfdict; static int item_compare_func_err; +static bool item_compare_keep_zero; #define ITEM_COMPARE_FAIL 999 /* @@ -13397,6 +13398,13 @@ static int item_compare(const void *s1, const void *s2) n2 = strtod((char *)p2, (char **)&p2); res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; } + + // When the result would be zero, compare the pointers themselves. Makes + // the sort stable. + if (res == 0 && !item_compare_keep_zero) { + res = s1 > s2 ? 1 : -1; + } + free(tofree1); free(tofree2); return res; @@ -13413,8 +13421,8 @@ static int item_compare2(const void *s1, const void *s2) if (item_compare_func_err) return 0; - /* copy the values. This is needed to be able to set v_lock to VAR_FIXED - * in the copy without changing the original list items. */ + // Copy the values. This is needed to be able to set v_lock to VAR_FIXED + // in the copy without changing the original list items. copy_tv(&(*(listitem_T **)s1)->li_tv, &argv[0]); copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]); @@ -13432,6 +13440,13 @@ static int item_compare2(const void *s1, const void *s2) if (item_compare_func_err) res = ITEM_COMPARE_FAIL; /* return value has wrong type */ clear_tv(&rettv); + + // When the result would be zero, compare the pointers themselves. Makes + // the sort stable. + if (res == 0 && !item_compare_keep_zero) { + res = s1 > s2 ? 1 : -1; + } + return res; } @@ -13513,6 +13528,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) } item_compare_func_err = FALSE; + item_compare_keep_zero = false; // Test the compare function. if (item_compare_func != NULL && item_compare2(&ptrs[0], &ptrs[1]) == ITEM_COMPARE_FAIL) { @@ -13539,6 +13555,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) // f_uniq(): ptrs will be a stack of items to remove. item_compare_func_err = FALSE; + item_compare_keep_zero = true; item_compare_func_ptr = item_compare_func ? item_compare2 : item_compare; for (li = l->lv_first; li != NULL && li->li_next != NULL; li = li->li_next) { diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in index ace97bf30e..8e073f30f2 100644 --- a/src/nvim/testdir/test55.in +++ b/src/nvim/testdir/test55.in @@ -332,9 +332,9 @@ let l = [0, 1, 2, 3] :$put =string(reverse(sort(l))) :$put =string(sort(reverse(sort(l)))) :$put =string(uniq(sort(l))) -:let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0.22, 'foo'] +:let l=[7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four'] :$put =string(sort(copy(l), 'n')) -:let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'foo', 'FOOBAR',{}, []] +:let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []] :$put =string(sort(copy(l), 1)) :$put =string(sort(copy(l), 'i')) :$put =string(sort(copy(l))) diff --git a/src/nvim/testdir/test55.ok b/src/nvim/testdir/test55.ok index 3969995a1e..dfd8060db7 100644 --- a/src/nvim/testdir/test55.ok +++ b/src/nvim/testdir/test55.ok @@ -101,10 +101,10 @@ caught a:000[3] [[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'] ['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]] ['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]] -[-1, 'foo', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255] -['foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] -['foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] -['FOOBAR', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] +[-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255] +['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] +['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] +['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] ['aa', 'bb'] ['aa', 'bb'] ['', 'aa', 'bb', ''] diff --git a/src/nvim/version.c b/src/nvim/version.c index f99767cf19..e062970193 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -244,7 +244,7 @@ static int included_patches[] = { //354 NA 353, 352, - //351, + 351, //350, 349, 348, From eeef120c86bca2dd69a8392f6aee73ba438bf392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Twupack?= Date: Tue, 9 Sep 2014 20:53:24 +0200 Subject: [PATCH 4/4] vim-patch:7.4.358 Problem: Sort is not always stable. Solution: Add an index instead of relying on the pointer to remain the same. Idea by Jun Takimoto. https://code.google.com/p/vim/source/detail?r=v7-4-358 --- src/nvim/eval.c | 46 ++++++++++++++++++++++++++++++---------------- src/nvim/version.c | 2 +- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d8fd6f95c5..f0badb5802 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -13360,6 +13360,11 @@ static void f_sinh(typval_T *argvars, typval_T *rettv) rettv->vval.v_float = 0.0; } +/// struct used in the array that's given to qsort() +typedef struct { + listitem_T *item; + int idx; +} sortItem_T; static int item_compare_ic; static bool item_compare_numeric; @@ -13374,14 +13379,17 @@ static bool item_compare_keep_zero; */ static int item_compare(const void *s1, const void *s2) { + sortItem_T *si1, *si2; char_u *p1, *p2; char_u *tofree1, *tofree2; int res; char_u numbuf1[NUMBUFLEN]; char_u numbuf2[NUMBUFLEN]; - p1 = tv2string(&(*(listitem_T **)s1)->li_tv, &tofree1, numbuf1, 0); - p2 = tv2string(&(*(listitem_T **)s2)->li_tv, &tofree2, numbuf2, 0); + si1 = (sortItem_T *)s1; + si2 = (sortItem_T *)s2; + p1 = tv2string(&si1->item->li_tv, &tofree1, numbuf1, 0); + p2 = tv2string(&si2->item->li_tv, &tofree2, numbuf2, 0); if (p1 == NULL) p1 = (char_u *)""; if (p2 == NULL) @@ -13402,7 +13410,7 @@ static int item_compare(const void *s1, const void *s2) // When the result would be zero, compare the pointers themselves. Makes // the sort stable. if (res == 0 && !item_compare_keep_zero) { - res = s1 > s2 ? 1 : -1; + res = si1->idx > si2->idx ? 1 : -1; } free(tofree1); @@ -13412,6 +13420,7 @@ static int item_compare(const void *s1, const void *s2) static int item_compare2(const void *s1, const void *s2) { + sortItem_T *si1, *si2; int res; typval_T rettv; typval_T argv[3]; @@ -13421,10 +13430,13 @@ static int item_compare2(const void *s1, const void *s2) if (item_compare_func_err) return 0; + si1 = (sortItem_T *)s1; + si2 = (sortItem_T *)s2; + // Copy the values. This is needed to be able to set v_lock to VAR_FIXED // in the copy without changing the original list items. - copy_tv(&(*(listitem_T **)s1)->li_tv, &argv[0]); - copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]); + copy_tv(&si1->item->li_tv, &argv[0]); + copy_tv(&si2->item->li_tv, &argv[1]); rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ res = call_func(item_compare_func, (int)STRLEN(item_compare_func), @@ -13444,7 +13456,7 @@ static int item_compare2(const void *s1, const void *s2) // When the result would be zero, compare the pointers themselves. Makes // the sort stable. if (res == 0 && !item_compare_keep_zero) { - res = s1 > s2 ? 1 : -1; + res = si1->idx > si2->idx ? 1 : -1; } return res; @@ -13457,7 +13469,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) { list_T *l; listitem_T *li; - listitem_T **ptrs; + sortItem_T *ptrs; long len; long i; @@ -13518,13 +13530,15 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) } /* Make an array with each entry pointing to an item in the List. */ - ptrs = xmalloc((size_t)(len * sizeof (listitem_T *))); + ptrs = xmalloc((size_t)(len * sizeof (sortItem_T))); i = 0; if (sort) { // sort(): ptrs will be the list to sort. for (li = l->lv_first; li != NULL; li = li->li_next) { - ptrs[i++] = li; + ptrs[i].item = li; + ptrs[i].idx = i; + i++; } item_compare_func_err = FALSE; @@ -13535,7 +13549,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) EMSG(_("E702: Sort compare function failed")); } else { // Sort the array with item pointers. - qsort(ptrs, (size_t)len, sizeof (listitem_T *), + qsort(ptrs, (size_t)len, sizeof (sortItem_T), item_compare_func == NULL ? item_compare : item_compare2); if (!item_compare_func_err) { @@ -13546,7 +13560,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) l->lv_len = 0; for (i = 0; i < len; i++) { - list_append(l, ptrs[i]); + list_append(l, ptrs[i].item); } } } @@ -13560,7 +13574,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) for (li = l->lv_first; li != NULL && li->li_next != NULL; li = li->li_next) { if (item_compare_func_ptr(&li, &li->li_next) == 0) { - ptrs[i++] = li; + ptrs[i++].item = li; } if (item_compare_func_err) { EMSG(_("E882: Uniq compare function failed")); @@ -13570,12 +13584,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) if (!item_compare_func_err) { while (--i >= 0) { - li = ptrs[i]->li_next; - ptrs[i]->li_next = li->li_next; + li = ptrs[i].item->li_next; + ptrs[i].item->li_next = li->li_next; if (li->li_next != NULL) { - li->li_next->li_prev = ptrs[i]; + li->li_next->li_prev = ptrs[i].item; } else { - l->lv_last = ptrs[i]; + l->lv_last = ptrs[i].item; } list_fix_watch(l, li); listitem_free(li); diff --git a/src/nvim/version.c b/src/nvim/version.c index e062970193..68c62d8e61 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -237,7 +237,7 @@ static int included_patches[] = { //361, //360, //359, - //358, + 358, 357, //356 NA //355,