changeset 21405:120bb822c6f4

Handle empty vectors for size of ones(), zeros(), inf(), etc... (bug #47298) * utils.cc (get_dimensions): handle empty vectors for size. Bug is that empty vectors of size 0x1, 1x0, and 0x1x1, would return a single element. Origin of the bug is that dim.redim(n) would still leave 2 dimensions even if n<2. When n=0 (n=1 had a separate path), dim would still have 2 but the loop over the dimensions vector would then never run, leaving dim_vector intact, i.e., of size 1x1. * data.cc: add tests for ones(), zeros(), inf(), nan(), and other functions that follow the same code path.
author Carnë Draug <carandraug@octave.org>
date Sun, 28 Feb 2016 19:07:24 +0000
parents 0daaca299102
children 1f69fc65539e
files libinterp/corefcn/data.cc libinterp/corefcn/utils.cc
diffstat 2 files changed, 37 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/data.cc	Sat Mar 05 02:35:31 2016 +0000
+++ b/libinterp/corefcn/data.cc	Sun Feb 28 19:07:24 2016 +0000
@@ -4237,6 +4237,23 @@
 %!assert (size (ones (3, 4, 5, "int8")), [3, 4, 5])
 */
 
+/*
+## Tests for bug #47298
+## Matlab requires the size to be a row vector.  In that logic, it supports
+## n to be a 1x0 vector (returns 0x0) but not a 0x1 vector.  Octave supports
+## any vector and therefore must support 0x1, 1x0, and 0x0x1 (but not 0x1x1).
+%!test
+%! funcs = {@zeros, @ones, @inf, @nan, @NA, @i, @pi, @e};
+%! for idx = 1:numel (funcs)
+%!   func = funcs{idx};
+%!   assert (func (zeros (1, 0)), zeros (0, 0))
+%!   assert (func (zeros (0, 1)), zeros (0, 0))
+%!   assert (func (zeros (0, 1, 1)), zeros (0, 0))
+%!   fail ([func2str(func) " ([])"])
+%!   fail ([func2str(func) " (zeros (0, 0, 1))"])
+%! endfor
+*/
+
 DEFUN (zeros, args, ,
        "-*- texinfo -*-\n\
 @deftypefn  {} {} zeros (@var{n})\n\
--- a/libinterp/corefcn/utils.cc	Sat Mar 05 02:35:31 2016 +0000
+++ b/libinterp/corefcn/utils.cc	Sun Feb 28 19:07:24 2016 +0000
@@ -1118,26 +1118,29 @@
 get_dimensions (const octave_value& a, const char *warn_for,
                 dim_vector& dim)
 {
-  if (a.is_scalar_type ())
+  // We support dimensions to be specified by any vector, even if it's a
+  // vector of dimensions 0x1, 1x0, 1x1x0, or 1x1x6.  If the vector ends
+  // up being empty, the final dimensions end up being 0x0.
+  if (! a.dims ().is_vector ())
+    error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
+
+  const Array<int> v = a.int_vector_value ();
+  const octave_idx_type n = v.numel ();
+
+  dim.resize (n); // even if n < 2, resize sets it back to 2
+  if (n == 0)
     {
-      dim.resize (2);
-      dim(0) = a.idx_type_value ();
-      dim(1) = dim(0);
+      dim(0) = 0;
+      dim(1) = 0;
+    }
+  else if (n == 1)
+    {
+      dim(0) = v(0);
+      dim(1) = v(0);
     }
   else
-    {
-      octave_idx_type nr = a.rows ();
-      octave_idx_type nc = a.columns ();
-
-      if (nr != 1 && nc != 1)
-        error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
-
-      Array<double> v = a.vector_value ();
-      octave_idx_type n = v.numel ();
-      dim.resize (n);
-      for (octave_idx_type i = 0; i < n; i++)
-        dim(i) = static_cast<int> (fix (v(i)));
-    }
+    for (octave_idx_type i = 0; i < n; i++)
+      dim(i) = v(i);
 
   check_dimensions (dim, warn_for);
 }