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