Author: pburba
Date: Mon Mar 15 19:00:28 2010
New Revision: 923389

URL: http://svn.apache.org/viewvc?rev=923389&view=rev
Log:
Fix a bug where the ordering of arguments to svn_rangelist_intersect can
produce different results.

* subversion/include/svn_mergeinfo.h

  (svn_mergeinfo_intersect2):
  (svn_rangelist_intersect):
   Correct/improve doc strings to reflect long standing behaviors regarding
   rangelist intersection and range inheritance.

* subversion/libsvn_subr/mergeinfo.c

  (rangelist_intersect_or_remove): Fix bug where the order of arguments
   could effect the result when finding an intersection.  Address an old
   ### FIXME by adjusting argument names and comments to apply to either
   an intersection or removal (i.e. make them generic).

* subversion/tests/libsvn_subr/mergeinfo-test.c

  (test_rangelist_intersect): Test that order of rangelists passed to
   svn_rangelist_intersect() don't effect the result.  Test that the
   intersection of two ranges is non-inheritable only when both ranges
   are non-inheritable.  Lastly, test that ranges of differing inheritance
   do not intersect when considering inheritance.

Modified:
    subversion/trunk/subversion/include/svn_mergeinfo.h
    subversion/trunk/subversion/libsvn_subr/mergeinfo.c
    subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c

Modified: subversion/trunk/subversion/include/svn_mergeinfo.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_mergeinfo.h?rev=923389&r1=923388&r2=923389&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_mergeinfo.h (original)
+++ subversion/trunk/subversion/include/svn_mergeinfo.h Mon Mar 15 19:00:28 2010
@@ -311,8 +311,7 @@ svn_mergeinfo_intersect(svn_mergeinfo_t 
  *
  * @a consider_inheritance determines how to account for the inheritability
  * of the two mergeinfo's ranges when calculating the range equivalence,
- * as described for svn_mergeinfo_diff().  If @a consider_inheritance is
- * FALSE then @a *mergeinfo's ranges are always inheritable.
+ * @see svn_rangelist_intersect().
  *
  * @since New in 1.7.
  */
@@ -331,7 +330,11 @@ svn_mergeinfo_intersect2(svn_mergeinfo_t
  * @a consider_inheritance determines how to account for the inheritability
  * of the two rangelist's ranges when calculating the intersection,
  * @see svn_mergeinfo_diff().  If @a consider_inheritance is FALSE then
- * the ranges in @a *rangelist are always inheritable.
+ * ranges with different inheritance can intersect, but the the resulting
+ * @a *rangelist is non-inheritable only if the corresponding ranges from
+ * both @a rangelist1 and @a rangelist2 are non-inheritable.
+ * If @a consider_inheritance is TRUE, then ranges with different
+ * inheritance can never intersect.
  *
  * Note: @a rangelist1 and @a rangelist2 must be sorted as said by @c
  * svn_sort_compare_ranges(). @a *rangelist is guaranteed to be in sorted

Modified: subversion/trunk/subversion/libsvn_subr/mergeinfo.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/mergeinfo.c?rev=923389&r1=923388&r2=923389&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/trunk/subversion/libsvn_subr/mergeinfo.c Mon Mar 15 19:00:28 2010
@@ -857,15 +857,42 @@ svn_mergeinfo__set_inheritance(svn_merge
   return;
 }
 
-/* Either remove any overlapping ranges described by ERASER from
-   WHITEBOARD (when DO_REMOVE is TRUE), or capture the overlap, and
-   place the remaining or overlapping ranges in OUTPUT. */
-/*  ### FIXME: Some variables names and inline comments for this method
-    ### are legacy from when it was solely the remove() impl. */
+/* If DO_REMOVE is true, then remove any overlapping ranges described by
+   RANGELIST1 from RANGELIST2 and place the results in *OUTPUT.  When
+   DO_REMOVE is true, RANGELIST1 is effectively the "eraser" and RANGELIST2
+   the "whiteboard".
+
+   If DO_REMOVE is false, then capture the intersection between RANGELIST1
+   and RANGELIST2 and place the results in *OUTPUT.  The ordering of
+   RANGELIST1 and RANGELIST2 doesn't matter when DO_REMOVE is false.
+
+   If CONSIDER_INHERITANCE is true, then take the inheritance of the
+   ranges in RANGELIST1 and RANGELIST2 into account when comparing them
+   for intersection, see the doc string for svn_rangelist_intersection().
+
+   If CONSIDER_INHERITANCE is true, then ranges with differing inheritance
+   may intersect, but the resulting intersection is non-inheritable only
+   if both ranges were non-inheritable, e.g.:
+
+   RANGELIST1  RANGELIST2  CONSIDER     DO_REMOVE  *OUTPUT
+                           INHERITANCE
+   ----------  ------      -----------  ---------  -------
+
+   90-420*     1-100       TRUE         FALSE      Empty Rangelist
+   90-420      1-100*      TRUE         FALSE      Empty Rangelist
+   90-420      1-100       TRUE         FALSE      90-100
+   90-420*     1-100*      TRUE         FALSE      90-100*
+
+   90-420*     1-100       FALSE        FALSE      90-100
+   90-420      1-100*      FALSE        FALSE      90-100
+   90-420      1-100       FALSE        FALSE      90-100
+   90-420*     1-100*      FALSE        FALSE      90-100*
+
+   Allocate the contents of *OUTPUT in POOL. */
 static svn_error_t *
 rangelist_intersect_or_remove(apr_array_header_t **output,
-                              const apr_array_header_t *eraser,
-                              const apr_array_header_t *whiteboard,
+                              const apr_array_header_t *rangelist1,
+                              const apr_array_header_t *rangelist2,
                               svn_boolean_t do_remove,
                               svn_boolean_t consider_inheritance,
                               apr_pool_t *pool)
@@ -879,37 +906,46 @@ rangelist_intersect_or_remove(apr_array_
   j = 0;
   lasti = -1;  /* Initialized to a value that "i" will never be. */
 
-  while (i < whiteboard->nelts && j < eraser->nelts)
+  while (i < rangelist2->nelts && j < rangelist1->nelts)
     {
       svn_merge_range_t *elt1, *elt2;
 
-      elt2 = APR_ARRAY_IDX(eraser, j, svn_merge_range_t *);
+      elt2 = APR_ARRAY_IDX(rangelist1, j, svn_merge_range_t *);
 
-      /* Instead of making a copy of the entire array of whiteboard
-         elements, we just keep a copy of the current whiteboard element
+      /* Instead of making a copy of the entire array of rangelist2
+         elements, we just keep a copy of the current rangelist2 element
          that needs to be used, and modify our copy if necessary. */
       if (i != lasti)
         {
-          wboardelt = *(APR_ARRAY_IDX(whiteboard, i, svn_merge_range_t *));
+          wboardelt = *(APR_ARRAY_IDX(rangelist2, i, svn_merge_range_t *));
           lasti = i;
         }
 
       elt1 = &wboardelt;
 
-      /* If the whiteboard range is contained completely in the
-         eraser, we increment the whiteboard.
+      /* If the rangelist2 range is contained completely in the
+         rangelist1, we increment the rangelist2.
          If the ranges intersect, and match exactly, we increment both
-         eraser and whiteboard.
+         rangelist1 and rangelist2.
          Otherwise, we have to generate a range for the left part of
-         the removal of eraser from whiteboard, and possibly change
-         the whiteboard to the remaining portion of the right part of
+         the removal of rangelist1 from rangelist2, and possibly change
+         the rangelist2 to the remaining portion of the right part of
          the removal, to test against. */
       if (range_contains(elt2, elt1, consider_inheritance))
         {
           if (!do_remove)
-            SVN_ERR(combine_with_lastrange(elt1, *output,
-                                           consider_inheritance, pool,
-                                           pool));
+            {
+              svn_merge_range_t tmp_range;
+              tmp_range.start = elt1->start;
+              tmp_range.end = elt1->end;
+              /* The intersection of two ranges is non-inheritable only
+                 if both ranges are non-inheritable. */
+              tmp_range.inheritable =
+                (elt1->inheritable || elt2->inheritable);
+              SVN_ERR(combine_with_lastrange(&tmp_range, *output,
+                                             consider_inheritance, pool,
+                                             pool));
+            }
 
           i++;
 
@@ -920,21 +956,26 @@ rangelist_intersect_or_remove(apr_array_
         {
           if (elt1->start < elt2->start)
             {
-              /* The whiteboard range starts before the eraser range. */
+              /* The rangelist2 range starts before the rangelist1 range. */
               svn_merge_range_t tmp_range;
-              tmp_range.inheritable = elt1->inheritable;
               if (do_remove)
                 {
-                  /* Retain the range that falls before the eraser start. */
+                  /* Retain the range that falls before the rangelist1
+                     start. */
                   tmp_range.start = elt1->start;
                   tmp_range.end = elt2->start;
+                  tmp_range.inheritable = elt1->inheritable;
                 }
               else
                 {
-                  /* Retain the range that falls between the eraser
-                     start and whiteboard end. */
+                  /* Retain the range that falls between the rangelist1
+                     start and rangelist2 end. */
                   tmp_range.start = elt2->start;
                   tmp_range.end = MIN(elt1->end, elt2->end);
+                  /* The intersection of two ranges is non-inheritable only
+                     if both ranges are non-inheritable. */
+                  tmp_range.inheritable =
+                    (elt1->inheritable || elt2->inheritable);
                 }
 
               SVN_ERR(combine_with_lastrange(&tmp_range,
@@ -942,18 +983,21 @@ rangelist_intersect_or_remove(apr_array_
                                              pool, pool));
             }
 
-          /* Set up the rest of the whiteboard range for further
+          /* Set up the rest of the rangelist2 range for further
              processing.  */
           if (elt1->end > elt2->end)
             {
-              /* The whiteboard range ends after the eraser range. */
+              /* The rangelist2 range ends after the rangelist1 range. */
               if (!do_remove)
                 {
                   /* Partial overlap. */
                   svn_merge_range_t tmp_range;
-                  tmp_range.start = MAX(elt1->start, elt2->start);
+                  tmp_range.start = MAX(elt1->start, elt2->start;)
                   tmp_range.end = elt2->end;
-                  tmp_range.inheritable = elt1->inheritable;
+                  /* The intersection of two ranges is non-inheritable only
+                     if both ranges are non-inheritable. */
+                  tmp_range.inheritable =
+                    (elt1->inheritable || elt2->inheritable);
                   SVN_ERR(combine_with_lastrange(&tmp_range,
                                                  *output,
                                                  consider_inheritance,
@@ -968,12 +1012,12 @@ rangelist_intersect_or_remove(apr_array_
         }
       else  /* ranges don't intersect */
         {
-          /* See which side of the whiteboard the eraser is on.  If it
-             is on the left side, we need to move the eraser.
+          /* See which side of the rangelist2 the rangelist1 is on.  If it
+             is on the left side, we need to move the rangelist1.
 
-             If it is on past the whiteboard on the right side, we
-             need to output the whiteboard and increment the
-             whiteboard.  */
+             If it is on past the rangelist2 on the right side, we
+             need to output the rangelist2 and increment the
+             rangelist2.  */
           if (svn_sort_compare_ranges(&elt2, &elt1) < 0)
             j++;
           else
@@ -1000,23 +1044,23 @@ rangelist_intersect_or_remove(apr_array_
 
   if (do_remove)
     {
-      /* Copy the current whiteboard element if we didn't hit the end
-         of the whiteboard, and we still had it around.  This element
-         may have been touched, so we can't just walk the whiteboard
+      /* Copy the current rangelist2 element if we didn't hit the end
+         of the rangelist2, and we still had it around.  This element
+         may have been touched, so we can't just walk the rangelist2
          array, we have to use our copy.  This case only happens when
-         we ran out of eraser before whiteboard, *and* we had changed
-         the whiteboard element. */
-      if (i == lasti && i < whiteboard->nelts)
+         we ran out of rangelist1 before rangelist2, *and* we had changed
+         the rangelist2 element. */
+      if (i == lasti && i < rangelist2->nelts)
         {
           SVN_ERR(combine_with_lastrange(&wboardelt, *output,
                                          consider_inheritance, pool, pool));
           i++;
         }
 
-      /* Copy any other remaining untouched whiteboard elements.  */
-      for (; i < whiteboard->nelts; i++)
+      /* Copy any other remaining untouched rangelist2 elements.  */
+      for (; i < rangelist2->nelts; i++)
         {
-          svn_merge_range_t *elt = APR_ARRAY_IDX(whiteboard, i,
+          svn_merge_range_t *elt = APR_ARRAY_IDX(rangelist2, i,
                                                  svn_merge_range_t *);
 
           SVN_ERR(combine_with_lastrange(elt, *output,

Modified: subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c?rev=923389&r1=923388&r2=923389&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c Mon Mar 15 
19:00:28 2010
@@ -479,21 +479,68 @@ static svn_error_t *
 test_rangelist_intersect(apr_pool_t *pool)
 {
   apr_array_header_t *rangelist1, *rangelist2, *intersection;
-  svn_merge_range_t expected_intersection[] =
-    { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE}, {30, 32, TRUE},
+
+  /* Expected intersection when considering inheritance. */
+  svn_merge_range_t intersection_consider_inheritance[] =
+    { {0, 1, TRUE}, {11, 12, TRUE}, {30, 32, FALSE}, {39, 42, TRUE} };
+
+  /* Expected intersection when ignoring inheritance. */
+  svn_merge_range_t intersection_ignore_inheritance[] =
+    { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE}, {30, 32, FALSE},
       {39, 42, TRUE} };
 
-  SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16,30-32,40-42", pool));
-  SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4,7,9,11-12,31-34,38-44",
+  SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16,30-32*,40-42", pool));
+  SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4*,7,9,11-12,31-34*,38-44",
                               pool));
   rangelist1 = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
   rangelist2 = apr_hash_get(info2, "/trunk", APR_HASH_KEY_STRING);
 
+  /* Check the intersection while considering inheritance twice, reversing
+     the order of the rangelist arguments on the second call to
+     svn_rangelist_intersection.  The order *should* have no effect on
+     the result -- see http://svn.haxx.se/dev/archive-2010-03/0351.shtml.
+
+     '3-4*' has different inheritance than '1-6', so no intersection is
+     expected.  '30-32*' and '31-34*' have the same inheritance, so intersect
+     at '31-32*'.  Per the svn_rangelist_intersect API, since both ranges
+     are non-inheritable, so is the result. */
   SVN_ERR(svn_rangelist_intersect(&intersection, rangelist1, rangelist2,
                                   TRUE, pool));
 
-  return verify_ranges_match(intersection, expected_intersection, 5,
-                             "svn_rangelist_intersect", "intersect", pool);
+  SVN_ERR(verify_ranges_match(intersection,
+                              intersection_consider_inheritance,
+                              4, "svn_rangelist_intersect", "intersect",
+                              pool));
+
+  SVN_ERR(svn_rangelist_intersect(&intersection, rangelist2, rangelist1,
+                                  TRUE, pool));
+
+  SVN_ERR(verify_ranges_match(intersection,
+                              intersection_consider_inheritance,
+                              4, "svn_rangelist_intersect", "intersect",
+                              pool));
+
+  /* Check the intersection while ignoring inheritance.  The one difference
+     from when we consider inheritance is that '3-4*' and '1-6' now intersect,
+     since we don't care about inheritability, just the start and end ranges.
+     Per the svn_rangelist_intersect API, since only one range is
+     non-inheritable the result is inheritable. */
+  SVN_ERR(svn_rangelist_intersect(&intersection, rangelist1, rangelist2,
+                                  FALSE, pool));
+
+  SVN_ERR(verify_ranges_match(intersection,
+                              intersection_ignore_inheritance,
+                              5, "svn_rangelist_intersect", "intersect",
+                              pool));
+
+  SVN_ERR(svn_rangelist_intersect(&intersection, rangelist2, rangelist1,
+                                  FALSE, pool));
+
+  SVN_ERR(verify_ranges_match(intersection,
+                              intersection_ignore_inheritance,
+                              5, "svn_rangelist_intersect", "intersect",
+                              pool));
+  return SVN_NO_ERROR;
 }
 
 static svn_error_t *


Reply via email to