3ef2ca
To: vim_dev@googlegroups.com
3ef2ca
Subject: Patch 7.4.358
3ef2ca
Fcc: outbox
3ef2ca
From: Bram Moolenaar <Bram@moolenaar.net>
3ef2ca
Mime-Version: 1.0
3ef2ca
Content-Type: text/plain; charset=UTF-8
3ef2ca
Content-Transfer-Encoding: 8bit
3ef2ca
------------
3ef2ca
3ef2ca
Patch 7.4.358 (after 7.4.351)
3ef2ca
Problem:    Sort is not always stable.
3ef2ca
Solution:   Add an index instead of relying on the pointer to remain the same.
3ef2ca
	    Idea by Jun Takimoto.
3ef2ca
Files:	    src/eval.c
3ef2ca
3ef2ca
3ef2ca
*** ../vim-7.4.357/src/eval.c	2014-07-02 19:06:14.686326091 +0200
3ef2ca
--- src/eval.c	2014-07-09 17:42:05.699813489 +0200
3ef2ca
***************
3ef2ca
*** 17329,17334 ****
3ef2ca
--- 17329,17341 ----
3ef2ca
  #endif
3ef2ca
  	item_compare2 __ARGS((const void *s1, const void *s2));
3ef2ca
  
3ef2ca
+ /* struct used in the array that's given to qsort() */
3ef2ca
+ typedef struct
3ef2ca
+ {
3ef2ca
+     listitem_T	*item;
3ef2ca
+     int		idx;
3ef2ca
+ } sortItem_T;
3ef2ca
+ 
3ef2ca
  static int	item_compare_ic;
3ef2ca
  static int	item_compare_numeric;
3ef2ca
  static char_u	*item_compare_func;
3ef2ca
***************
3ef2ca
*** 17349,17362 ****
3ef2ca
      const void	*s1;
3ef2ca
      const void	*s2;
3ef2ca
  {
3ef2ca
      char_u	*p1, *p2;
3ef2ca
      char_u	*tofree1, *tofree2;
3ef2ca
      int		res;
3ef2ca
      char_u	numbuf1[NUMBUFLEN];
3ef2ca
      char_u	numbuf2[NUMBUFLEN];
3ef2ca
  
3ef2ca
!     p1 = tv2string(&(*(listitem_T **)s1)->li_tv, &tofree1, numbuf1, 0);
3ef2ca
!     p2 = tv2string(&(*(listitem_T **)s2)->li_tv, &tofree2, numbuf2, 0);
3ef2ca
      if (p1 == NULL)
3ef2ca
  	p1 = (char_u *)"";
3ef2ca
      if (p2 == NULL)
3ef2ca
--- 17356,17372 ----
3ef2ca
      const void	*s1;
3ef2ca
      const void	*s2;
3ef2ca
  {
3ef2ca
+     sortItem_T  *si1, *si2;
3ef2ca
      char_u	*p1, *p2;
3ef2ca
      char_u	*tofree1, *tofree2;
3ef2ca
      int		res;
3ef2ca
      char_u	numbuf1[NUMBUFLEN];
3ef2ca
      char_u	numbuf2[NUMBUFLEN];
3ef2ca
  
3ef2ca
!     si1 = (sortItem_T *)s1;
3ef2ca
!     si2 = (sortItem_T *)s2;
3ef2ca
!     p1 = tv2string(&si1->item->li_tv, &tofree1, numbuf1, 0);
3ef2ca
!     p2 = tv2string(&si2->item->li_tv, &tofree2, numbuf2, 0);
3ef2ca
      if (p1 == NULL)
3ef2ca
  	p1 = (char_u *)"";
3ef2ca
      if (p2 == NULL)
3ef2ca
***************
3ef2ca
*** 17379,17385 ****
3ef2ca
      /* When the result would be zero, compare the pointers themselves.  Makes
3ef2ca
       * the sort stable. */
3ef2ca
      if (res == 0 && !item_compare_keep_zero)
3ef2ca
! 	res = s1 > s2 ? 1 : -1;
3ef2ca
  
3ef2ca
      vim_free(tofree1);
3ef2ca
      vim_free(tofree2);
3ef2ca
--- 17389,17395 ----
3ef2ca
      /* When the result would be zero, compare the pointers themselves.  Makes
3ef2ca
       * the sort stable. */
3ef2ca
      if (res == 0 && !item_compare_keep_zero)
3ef2ca
! 	res = si1->idx > si2->idx ? 1 : -1;
3ef2ca
  
3ef2ca
      vim_free(tofree1);
3ef2ca
      vim_free(tofree2);
3ef2ca
***************
3ef2ca
*** 17394,17399 ****
3ef2ca
--- 17404,17410 ----
3ef2ca
      const void	*s1;
3ef2ca
      const void	*s2;
3ef2ca
  {
3ef2ca
+     sortItem_T  *si1, *si2;
3ef2ca
      int		res;
3ef2ca
      typval_T	rettv;
3ef2ca
      typval_T	argv[3];
3ef2ca
***************
3ef2ca
*** 17403,17412 ****
3ef2ca
      if (item_compare_func_err)
3ef2ca
  	return 0;
3ef2ca
  
3ef2ca
      /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
3ef2ca
       * in the copy without changing the original list items. */
3ef2ca
!     copy_tv(&(*(listitem_T **)s1)->li_tv, &argv[0]);
3ef2ca
!     copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]);
3ef2ca
  
3ef2ca
      rettv.v_type = VAR_UNKNOWN;		/* clear_tv() uses this */
3ef2ca
      res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
3ef2ca
--- 17414,17426 ----
3ef2ca
      if (item_compare_func_err)
3ef2ca
  	return 0;
3ef2ca
  
3ef2ca
+     si1 = (sortItem_T *)s1;
3ef2ca
+     si2 = (sortItem_T *)s2;
3ef2ca
+ 
3ef2ca
      /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
3ef2ca
       * in the copy without changing the original list items. */
3ef2ca
!     copy_tv(&si1->item->li_tv, &argv[0]);
3ef2ca
!     copy_tv(&si2->item->li_tv, &argv[1]);
3ef2ca
  
3ef2ca
      rettv.v_type = VAR_UNKNOWN;		/* clear_tv() uses this */
3ef2ca
      res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
3ef2ca
***************
3ef2ca
*** 17426,17432 ****
3ef2ca
      /* When the result would be zero, compare the pointers themselves.  Makes
3ef2ca
       * the sort stable. */
3ef2ca
      if (res == 0 && !item_compare_keep_zero)
3ef2ca
! 	res = s1 > s2 ? 1 : -1;
3ef2ca
  
3ef2ca
      return res;
3ef2ca
  }
3ef2ca
--- 17440,17446 ----
3ef2ca
      /* When the result would be zero, compare the pointers themselves.  Makes
3ef2ca
       * the sort stable. */
3ef2ca
      if (res == 0 && !item_compare_keep_zero)
3ef2ca
! 	res = si1->idx > si2->idx ? 1 : -1;
3ef2ca
  
3ef2ca
      return res;
3ef2ca
  }
3ef2ca
***************
3ef2ca
*** 17442,17448 ****
3ef2ca
  {
3ef2ca
      list_T	*l;
3ef2ca
      listitem_T	*li;
3ef2ca
!     listitem_T	**ptrs;
3ef2ca
      long	len;
3ef2ca
      long	i;
3ef2ca
  
3ef2ca
--- 17456,17462 ----
3ef2ca
  {
3ef2ca
      list_T	*l;
3ef2ca
      listitem_T	*li;
3ef2ca
!     sortItem_T	*ptrs;
3ef2ca
      long	len;
3ef2ca
      long	i;
3ef2ca
  
3ef2ca
***************
3ef2ca
*** 17510,17516 ****
3ef2ca
  	}
3ef2ca
  
3ef2ca
  	/* Make an array with each entry pointing to an item in the List. */
3ef2ca
! 	ptrs = (listitem_T **)alloc((int)(len * sizeof(listitem_T *)));
3ef2ca
  	if (ptrs == NULL)
3ef2ca
  	    return;
3ef2ca
  
3ef2ca
--- 17524,17530 ----
3ef2ca
  	}
3ef2ca
  
3ef2ca
  	/* Make an array with each entry pointing to an item in the List. */
3ef2ca
! 	ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
3ef2ca
  	if (ptrs == NULL)
3ef2ca
  	    return;
3ef2ca
  
3ef2ca
***************
3ef2ca
*** 17519,17525 ****
3ef2ca
  	{
3ef2ca
  	    /* sort(): ptrs will be the list to sort */
3ef2ca
  	    for (li = l->lv_first; li != NULL; li = li->li_next)
3ef2ca
! 		ptrs[i++] = li;
3ef2ca
  
3ef2ca
  	    item_compare_func_err = FALSE;
3ef2ca
  	    item_compare_keep_zero = FALSE;
3ef2ca
--- 17533,17543 ----
3ef2ca
  	{
3ef2ca
  	    /* sort(): ptrs will be the list to sort */
3ef2ca
  	    for (li = l->lv_first; li != NULL; li = li->li_next)
3ef2ca
! 	    {
3ef2ca
! 		ptrs[i].item = li;
3ef2ca
! 		ptrs[i].idx = i;
3ef2ca
! 		++i;
3ef2ca
! 	    }
3ef2ca
  
3ef2ca
  	    item_compare_func_err = FALSE;
3ef2ca
  	    item_compare_keep_zero = FALSE;
3ef2ca
***************
3ef2ca
*** 17531,17537 ****
3ef2ca
  	    else
3ef2ca
  	    {
3ef2ca
  		/* Sort the array with item pointers. */
3ef2ca
! 		qsort((void *)ptrs, (size_t)len, sizeof(listitem_T *),
3ef2ca
  		    item_compare_func == NULL ? item_compare : item_compare2);
3ef2ca
  
3ef2ca
  		if (!item_compare_func_err)
3ef2ca
--- 17549,17555 ----
3ef2ca
  	    else
3ef2ca
  	    {
3ef2ca
  		/* Sort the array with item pointers. */
3ef2ca
! 		qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
3ef2ca
  		    item_compare_func == NULL ? item_compare : item_compare2);
3ef2ca
  
3ef2ca
  		if (!item_compare_func_err)
3ef2ca
***************
3ef2ca
*** 17540,17546 ****
3ef2ca
  		    l->lv_first = l->lv_last = l->lv_idx_item = NULL;
3ef2ca
  		    l->lv_len = 0;
3ef2ca
  		    for (i = 0; i < len; ++i)
3ef2ca
! 			list_append(l, ptrs[i]);
3ef2ca
  		}
3ef2ca
  	    }
3ef2ca
  	}
3ef2ca
--- 17558,17564 ----
3ef2ca
  		    l->lv_first = l->lv_last = l->lv_idx_item = NULL;
3ef2ca
  		    l->lv_len = 0;
3ef2ca
  		    for (i = 0; i < len; ++i)
3ef2ca
! 			list_append(l, ptrs[i].item);
3ef2ca
  		}
3ef2ca
  	    }
3ef2ca
  	}
3ef2ca
***************
3ef2ca
*** 17559,17565 ****
3ef2ca
  	    {
3ef2ca
  		if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
3ef2ca
  									 == 0)
3ef2ca
! 		    ptrs[i++] = li;
3ef2ca
  		if (item_compare_func_err)
3ef2ca
  		{
3ef2ca
  		    EMSG(_("E882: Uniq compare function failed"));
3ef2ca
--- 17577,17583 ----
3ef2ca
  	    {
3ef2ca
  		if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
3ef2ca
  									 == 0)
3ef2ca
! 		    ptrs[i++].item = li;
3ef2ca
  		if (item_compare_func_err)
3ef2ca
  		{
3ef2ca
  		    EMSG(_("E882: Uniq compare function failed"));
3ef2ca
***************
3ef2ca
*** 17571,17582 ****
3ef2ca
  	    {
3ef2ca
  		while (--i >= 0)
3ef2ca
  		{
3ef2ca
! 		    li = ptrs[i]->li_next;
3ef2ca
! 		    ptrs[i]->li_next = li->li_next;
3ef2ca
  		    if (li->li_next != NULL)
3ef2ca
! 			li->li_next->li_prev = ptrs[i];
3ef2ca
  		    else
3ef2ca
! 			l->lv_last = ptrs[i];
3ef2ca
  		    list_fix_watch(l, li);
3ef2ca
  		    listitem_free(li);
3ef2ca
  		    l->lv_len--;
3ef2ca
--- 17589,17600 ----
3ef2ca
  	    {
3ef2ca
  		while (--i >= 0)
3ef2ca
  		{
3ef2ca
! 		    li = ptrs[i].item->li_next;
3ef2ca
! 		    ptrs[i].item->li_next = li->li_next;
3ef2ca
  		    if (li->li_next != NULL)
3ef2ca
! 			li->li_next->li_prev = ptrs[i].item;
3ef2ca
  		    else
3ef2ca
! 			l->lv_last = ptrs[i].item;
3ef2ca
  		    list_fix_watch(l, li);
3ef2ca
  		    listitem_free(li);
3ef2ca
  		    l->lv_len--;
3ef2ca
*** ../vim-7.4.357/src/version.c	2014-07-09 14:00:45.175044250 +0200
3ef2ca
--- src/version.c	2014-07-09 17:23:12.791836515 +0200
3ef2ca
***************
3ef2ca
*** 736,737 ****
3ef2ca
--- 736,739 ----
3ef2ca
  {   /* Add new patch number below this line */
3ef2ca
+ /**/
3ef2ca
+     358,
3ef2ca
  /**/
3ef2ca
3ef2ca
-- 
3ef2ca
An indication you must be a manager:
3ef2ca
You can explain to somebody the difference between "re-engineering",
3ef2ca
"down-sizing", "right-sizing", and "firing people's asses".
3ef2ca
3ef2ca
 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net   \\\
3ef2ca
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
3ef2ca
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
3ef2ca
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///