diff src/DLD-FUNCTIONS/cellfun.cc @ 13230:c73cc5b67feb

fix nargout handling for functions called by cellfun * cellfun.cc (Fcellfun): Handle functions that produce zero outputs. Set nargout = 0 when calling functions if nargout for cellfun itself is 0.
author John W. Eaton <jwe@octave.org>
date Mon, 26 Sep 2011 13:08:42 -0400
parents 983720941822
children 20ed9548070f
line wrap: on
line diff
--- a/src/DLD-FUNCTIONS/cellfun.cc	Sun Sep 25 22:33:47 2011 -0400
+++ b/src/DLD-FUNCTIONS/cellfun.cc	Mon Sep 26 13:08:42 2011 -0400
@@ -538,53 +538,64 @@
               if (error_state)
                 return retval;
 
-              if (tmp.length () < nargout1)
+              if (nargout > 0 && tmp.length () < nargout)
                 {
-                  if (tmp.length () < nargout)
-                    {
-                      error ("cellfun: too many output arguments");
-                      return octave_value_list ();
-                    }
-                  else
-                    nargout1 = 0;
+                  error ("cellfun: function returned fewer than nargout values");
+                  return retval;
                 }
 
-              if (count == 0)
+              if  (nargout > 0
+                   || (nargout == 0
+                       && tmp.length () > 0 && tmp(0).is_defined ()))
                 {
-                  for (int j = 0; j < nargout1; j++)
-                    {
-                      octave_value val = tmp(j);
+                  int num_to_copy = tmp.length ();
+
+                  if (num_to_copy > nargout1)
+                    num_to_copy = nargout1;
 
-                      if (val.numel () == 1)
-                        retv[j] = val.resize (fdims);
-                      else
+                  if (count == 0)
+                    {
+                      for (int j = 0; j < num_to_copy; j++)
                         {
-                          error ("cellfun: all values must be scalars when UniformOutput = true");
-                          break;
+                          if (tmp(j).is_defined ())
+                            {
+                              octave_value val = tmp(j);
+
+                              if (val.numel () == 1)
+                                retv[j] = val.resize (fdims);
+                              else
+                                {
+                                  error ("cellfun: all values must be scalars when UniformOutput = true");
+                                  break;
+                                }
+                            }
                         }
                     }
-                }
-              else
-                {
-                  for (int j = 0; j < nargout1; j++)
+                  else
                     {
-                      octave_value val = tmp(j);
-
-                      if (! retv[j].fast_elem_insert (count, val))
+                      for (int j = 0; j < num_to_copy; j++)
                         {
-                          if (val.numel () == 1)
+                          if (tmp(j).is_defined ())
                             {
-                              idx_list.front ()(0) = count + 1.0;
-                              retv[j].assign (octave_value::op_asn_eq,
-                                              idx_type, idx_list, val);
+                              octave_value val = tmp(j);
+
+                              if (! retv[j].fast_elem_insert (count, val))
+                                {
+                                  if (val.numel () == 1)
+                                    {
+                                      idx_list.front ()(0) = count + 1.0;
+                                      retv[j].assign (octave_value::op_asn_eq,
+                                                      idx_type, idx_list, val);
 
-                              if (error_state)
-                                break;
-                            }
-                          else
-                            {
-                              error ("cellfun: all values must be scalars when UniformOutput = true");
-                              break;
+                                      if (error_state)
+                                        break;
+                                    }
+                                  else
+                                    {
+                                      error ("cellfun: all values must be scalars when UniformOutput = true");
+                                      break;
+                                    }
+                                }
                             }
                         }
                     }
@@ -607,10 +618,13 @@
       else
         {
           OCTAVE_LOCAL_BUFFER (Cell, results, nargout1);
+
           for (int j = 0; j < nargout1; j++)
-            results[j].resize (fdims);
+            results[j].resize (fdims, Matrix ());
 
-          for (octave_idx_type count = 0; count < k ; count++)
+          bool have_some_output = false;
+
+          for (octave_idx_type count = 0; count < k; count++)
             {
               for (int j = 0; j < nargin; j++)
                 {
@@ -618,31 +632,43 @@
                     inputlist.xelem (j) = cinputs[j](count);
                 }
 
-              const octave_value_list tmp = get_output_list (count, nargout, inputlist,
-                                                             func, error_handler);
+              const octave_value_list tmp
+                = get_output_list (count, nargout, inputlist, func,
+                                   error_handler);
 
               if (error_state)
                 return retval;
 
-              if (tmp.length () < nargout1)
+              if (nargout > 0 && tmp.length () < nargout)
                 {
-                  if (tmp.length () < nargout)
-                    {
-                      error ("cellfun: too many output arguments");
-                      return octave_value_list ();
-                    }
-                  else
-                    nargout1 = 0;
+                  error ("cellfun: function returned fewer than nargout values");
+                  return retval;
                 }
 
+              if  (nargout > 0
+                   || (nargout == 0
+                       && tmp.length () > 0 && tmp(0).is_defined ()))
+                {
+                  int num_to_copy = tmp.length ();
+
+                  if (num_to_copy > nargout1)
+                    num_to_copy = nargout1;
+
+                  if (num_to_copy > 0)
+                    have_some_output = true;
+
+                  for (int j = 0; j < num_to_copy; j++)
+                    results[j](count) = tmp(j);
+                }
+            }
+
+          if (have_some_output || fdims.any_zero ())
+            {
+              retval.resize (nargout1);
 
               for (int j = 0; j < nargout1; j++)
-                results[j](count) = tmp(j);
+                retval(j) = results[j];
             }
-
-          retval.resize(nargout1);
-          for (int j = 0; j < nargout1; j++)
-            retval(j) = results[j];
         }
     }
   else
@@ -653,6 +679,35 @@
 
 /*
 
+%!function r = f11 (x)
+%!  global __cellfun_test_num_outputs__
+%!  __cellfun_test_num_outputs__ = nargout;
+%!  r = x;
+%! endfunction
+
+%!function f01 (x)
+%!  global __cellfun_test_num_outputs__
+%!  __cellfun_test_num_outputs__ = nargout;
+%! endfunction
+
+%!test
+%! global __cellfun_test_num_outputs__
+%! cellfun (@f11, {1});
+%! assert (__cellfun_test_num_outputs__, 0)
+%! x = cellfun (@f11, {1});
+%! assert (__cellfun_test_num_outputs__, 1)
+
+%!test
+%! global __cellfun_test_num_outputs__
+%! cellfun (@f01, {1});
+%! assert (__cellfun_test_num_outputs__, 0)
+
+%!error x = cellfun (@f01, {1, 2});
+
+%!test
+%! assert (cellfun (@f11, {1, 2}), [1, 2])
+%! assert (cellfun (@f11, {1, 2}, 'uniformoutput', false), {1, 2})
+
 %!test
 %!  [a,b] = cellfun (@(x) x, cell (2, 0));
 %!  assert (a, zeros (2, 0));