changeset 17697:7ed397c8ca68

improve compatibility of null assignment (bug #31287) * Array.cc (Array<T>::delete_elements (const Array<idx_vector>&)): Improve compatibility when indices references an empty slice. * Sparse.cc (Sparse<T>::delete_elements (const idx_vector&, const idx_vector&)): Likewise. (Sparse<T>::delete_elements (const idx_vector&)): Likewise. * index.tst: New tests.
author John W. Eaton <jwe@octave.org>
date Fri, 11 Oct 2013 23:39:54 -0400
parents cd5a6008ae72
children d0a197b9962a
files liboctave/array/Array.cc liboctave/array/Sparse.cc test/index.tst
diffstat 3 files changed, 343 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/array/Array.cc
+++ b/liboctave/array/Array.cc
@@ -1460,12 +1460,14 @@
 void
 Array<T>::delete_elements (const Array<idx_vector>& ia)
 {
-  if (ia.length () == 1)
+  int ial = ia.length ();
+
+  if (ial == 1)
     delete_elements (ia(0));
   else
     {
-      int len = ia.length (), k, dim = -1;
-      for (k = 0; k < len; k++)
+      int k, dim = -1;
+      for (k = 0; k < ial; k++)
         {
           if (! ia(k).is_colon ())
             {
@@ -1481,14 +1483,51 @@
           dv(0) = 0;
           *this = Array<T> (dv);
         }
-      else if (k == len)
+      else if (k == ial)
         {
           delete_elements (dim, ia(dim));
         }
       else
         {
-          (*current_liboctave_error_handler)
-            ("a null assignment can only have one non-colon index");
+          // Allow the null assignment to succeed if it won't change
+          // anything because the indices reference an empty slice,
+          // provided that there is at most one non-colon (or
+          // equivalent) index.  So, we still have the requirement of
+          // deleting a slice, but it is OK if the slice is empty.
+
+          // For compatibility with Matlab, stop checking once we see
+          // more than one non-colon index or an empty index.  Matlab
+          // considers "[]" to be an empty index but not "false".  We
+          // accept both.
+
+          bool empty_assignment = false;
+
+          int num_non_colon_indices = 0;
+
+          int nd = ndims ();
+
+          for (int i = 0; i < ial; i++)
+            {
+              octave_idx_type dim_len = i >= nd ? 1 : dimensions(i);
+
+              if (ia(i).length (dim_len) == 0)
+                {
+                  empty_assignment = true;
+                  break;
+                }
+
+              if (! ia(i).is_colon_equiv (dim_len))
+                {
+                  num_non_colon_indices++;
+
+                  if (num_non_colon_indices == 2)
+                    break;
+                }
+            }
+
+          if (! empty_assignment)
+            (*current_liboctave_error_handler)
+              ("a null assignment can only have one non-colon index");
         }
     }
 
--- a/liboctave/array/Sparse.cc
+++ b/liboctave/array/Sparse.cc
@@ -1215,11 +1215,16 @@
       else
         *this = index (idx.complement (nc));
     }
-  else
+  else if (idx.length (nel) != 0)
     {
-      *this = index (idx_vector::colon);
-      delete_elements (idx);
-      *this = transpose (); // We want a row vector.
+      if (idx.is_colon_equiv (nel))
+        *this = Sparse<T> ();
+      else
+        {
+          *this = index (idx_vector::colon);
+          delete_elements (idx);
+          *this = transpose (); // We want a row vector.
+        }
     }
 }
 
@@ -1324,8 +1329,21 @@
         }
     }
   else
-    (*current_liboctave_error_handler)
-      ("a null assignment can only have one non-colon index");
+    {
+      // Empty assignment (no elements to delete) is OK if there is at
+      // least one zero-length index and at most one other index that is
+      // non-colon (or equivalent) index.  Since we only have two
+      // indices, we just need to check that we have at least one zero
+      // length index.  Matlab considers "[]" to be an empty index but
+      // not "false".  We accept both.
+
+      bool empty_assignment
+        = (idx_i.length (nr) == 0 || idx_j.length (nc) == 0);
+
+      if (! empty_assignment)
+        (*current_liboctave_error_handler)
+          ("a null assignment can only have one non-colon index");
+    }
 }
 
 template <class T>
--- a/test/index.tst
+++ b/test/index.tst
@@ -227,3 +227,277 @@
 %!error d(3,6);
 %!error dd(3,6);
 
+## bug 31287
+%!test
+%! y = ones (2, 2, 2);
+%! x = ones (2, 2, 2);
+%! x(false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2, 2);
+%! x = ones (2, 2, 2);
+%! x(false,[]) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2, 2);
+%! x = ones (2, 2, 2);
+%! x(false,[],false) = [];
+%! assert (x, y);
+
+%!shared x, y
+%! y = ones (2, 2, 2);
+%! x = ones (2, 2, 2);
+%! x(false, 1) = [];
+%! assert (x, y);
+
+%!shared x, y
+%! y = ones (2, 2, 2);
+%! x = ones (2, 2, 2);
+%! x(false, false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x([], []) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse (ones (2, 2));
+%! x = sparse (ones (2, 2));
+%! x([], []) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(1, []) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x([], 1, []) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(1, [], 1, 1) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x([], 1, 1) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! ea2 = ones (3, 2, 0, 2);
+%! x(1, ea2) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse (ones (2, 2));
+%! x = sparse (ones (2, 2));
+%! ea2 = ones (3, 2, 0, 2);
+%! x(1, ea2) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! ea2 = ones (3, 2, 0, 2);
+%! x([], 1, ea2) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! ea2 = ones (3, 2, 0, 2);
+%! x(1, ea2, ea2) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! ea2 = ones (3, 2, 0, 2);
+%! x(1, ea2, 1) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(false, 1) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse (ones (2, 2));
+%! x = sparse (ones (2, 2));
+%! x(false, 1) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(1, [], false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(false, false) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse (ones (2, 2));
+%! x = sparse (ones (2, 2));
+%! x(false, false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(false, [], false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x([], false, false, false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(1, [], false, false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(:, false) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse (ones (2, 2));
+%! x = sparse (ones (2, 2));
+%! x(:, false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(false, :) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse (ones (2, 2));
+%! x = sparse (ones (2, 2));
+%! x(false, :) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(false, :, [], 1) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(:, [], false) = [];
+%! assert (x, y);
+
+%!shared x, y
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%!error x(1, 1, []) = [];
+
+%!shared x, y
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(false, false, 1) = [];
+%! assert (x, y);
+
+%!shared x, y
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(false, false, []) = [];
+%! assert (x, y);
+
+%!shared x, y
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(false, false, [], false) = [];
+%! assert (x, y);
+
+%!shared x, y
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(1, false, [], false) = [];
+%! assert (x, y);
+
+%!shared x, y
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(:, false, 1) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x([]) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse (ones (2, 2));
+%! x = sparse (ones (2, 2));
+%! x([]) = [];
+%! assert (x, y);
+
+%!test
+%! y = [];
+%! x = ones (2, 2);
+%! x(:) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse ([]);
+%! x = sparse (ones (2, 2));
+%! x(:) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x(false) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse (ones (2, 2));
+%! x = sparse (ones (2, 2));
+%! x(false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x([], false) = [];
+%! assert (x, y);
+
+%!test
+%! y = sparse (ones (2, 2));
+%! x = sparse (ones (2, 2));
+%! x([], false) = [];
+%! assert (x, y);
+
+%!test
+%! y = ones (2, 2);
+%! x = ones (2, 2);
+%! x([], false, :) = [];
+%! assert (x, y);