changeset 13932:6ead4dc1ca55

subsref, subsasgn: allow empty subscript structs * ov.cc (decode_subscripts): Move here. * utils.cc: From here. * utils.h: Delete decl. * ov.cc (decode_subscripts): Empty type_string and idx and return early if map is empty with fields type and subs. (Fsubsref): Return VAL if subscript struct is empty. (Fsubsasgn): Return RHS if subscript struct is empty.
author John W. Eaton <jwe@octave.org>
date Wed, 23 Nov 2011 02:35:37 -0500
parents 9de488c6c59c
children c3c8f513cf1f
files src/ov.cc src/utils.cc src/utils.h
diffstat 3 files changed, 134 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/src/ov.cc	Wed Nov 23 09:42:50 2011 -0800
+++ b/src/ov.cc	Wed Nov 23 02:35:37 2011 -0500
@@ -2714,6 +2714,83 @@
 %!assert (sizeof ({"foo", "bar", "baaz"}), 10)
 */
 
+static void
+decode_subscripts (const char* name, const octave_value& arg,
+                   std::string& type_string,
+                   std::list<octave_value_list>& idx)
+{
+  const octave_map m = arg.map_value ();
+
+  if (! error_state
+      && m.nfields () == 2 && m.contains ("type") && m.contains ("subs"))
+    {
+      octave_idx_type nel = m.numel ();
+
+      type_string = std::string (nel, '\0');
+      idx = std::list<octave_value_list> ();
+
+      if (nel == 0)
+        return;
+
+      const Cell type = m.contents ("type");
+      const Cell subs = m.contents ("subs");
+
+      for (int k = 0; k < nel; k++)
+        {
+          std::string item = type(k).string_value ();
+
+          if (! error_state)
+            {
+              if (item == "{}")
+                type_string[k] = '{';
+              else if (item == "()")
+                type_string[k] = '(';
+              else if (item == ".")
+                type_string[k] = '.';
+              else
+                {
+                  error("%s: invalid indexing type `%s'", name, item.c_str ());
+                  return;
+                }
+            }
+          else
+            {
+              error ("%s: expecting type(%d) to be a character string",
+                     name, k+1);
+              return;
+            }
+
+          octave_value_list idx_item;
+
+          if (subs(k).is_string ())
+            idx_item(0) = subs(k);
+          else if (subs(k).is_cell ())
+            {
+              Cell subs_cell = subs(k).cell_value ();
+
+              for (int n = 0; n < subs_cell.length (); n++)
+                {
+                  if (subs_cell(n).is_string ()
+                      && subs_cell(n).string_value () == ":")
+                    idx_item(n) = octave_value(octave_value::magic_colon_t);
+                  else
+                    idx_item(n) = subs_cell(n);
+                }
+            }
+          else
+            {
+              error ("%s: expecting subs(%d) to be a character string or cell array",
+                     name, k+1);
+              return;
+            }
+
+          idx.push_back (idx_item);
+        }
+    }
+  else
+    error ("%s: second argument must be a structure with fields `type' and `subs'", name);
+}
+
 DEFUN (subsref, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} subsref (@var{val}, @var{idx})\n\
@@ -2746,6 +2823,9 @@
 \n\
 @noindent\n\
 Note that this is the same as writing @code{val(:,1:2)}.\n\
+\n\
+If @var{idx} is an empty structure array with fields @samp{type}\n\
+and @samp{subs}, return @var{val}.\n\
 @seealso{subsasgn, substruct}\n\
 @end deftypefn")
 {
@@ -2760,8 +2840,12 @@
 
       if (! error_state)
         {
-          octave_value tmp = args(0);
-          retval = tmp.subsref (type, idx, nargout);
+          octave_value arg0 = args(0);
+
+          if (type.empty ())
+            retval = arg0;
+          else
+            retval = arg0.subsref (type, idx, nargout);
         }
     }
   else
@@ -2798,6 +2882,9 @@
 @end example\n\
 \n\
 Note that this is the same as writing @code{val(:,1:2) = 0}.\n\
+\n\
+If @var{idx} is an empty structure array with fields @samp{type}\n\
+and @samp{subs}, return @var{rhs}.\n\
 @seealso{subsref, substruct}\n\
 @end deftypefn")
 {
@@ -2810,12 +2897,24 @@
 
       decode_subscripts ("subsasgn", args(1), type, idx);
 
-      octave_value arg0 = args(0);
-
-      arg0.make_unique ();
-
       if (! error_state)
-        retval = arg0.subsasgn (type, idx, args(2));
+        {
+          if (type.empty ())
+            {
+              // Regularize a null matrix if stored into a variable.
+
+              retval = args(2).storable_value ();
+            }
+          else
+            {
+              octave_value arg0 = args(0);
+
+              arg0.make_unique ();
+
+              if (! error_state)
+                retval= arg0.subsasgn (type, idx, args(2));
+            }
+        }
     }
   else
     print_usage ();
@@ -2826,15 +2925,18 @@
 /*
 %!test
 %! a = reshape ([1:25], 5,5);
-%! idx1 = substruct ( "()", {3, 3});
-%! idx2 = substruct ( "()", {2:2:5, 2:2:5});
-%! idx3 = substruct ( "()", {":", [1,5]});
-%! assert (subsref (a, idx1), 13)
-%! assert (subsref (a, idx2), [7 17; 9 19])
-%! assert (subsref (a, idx3), [1:5; 21:25]')
+%! idx1 = substruct ("()", {3, 3});
+%! idx2 = substruct ("()", {2:2:5, 2:2:5});
+%! idx3 = substruct ("()", {":", [1,5]});
+%! idx4 = struct ("type", {}, "subs", {});
+%! assert (subsref (a, idx1), 13);
+%! assert (subsref (a, idx2), [7 17; 9 19]);
+%! assert (subsref (a, idx3), [1:5; 21:25]');
+%! assert (subsref (a, idx4), a);
 %! a = subsasgn (a, idx1, 0);
 %! a = subsasgn (a, idx2, 0);
 %! a = subsasgn (a, idx3, 0);
+%!# a = subsasgn (a, idx4, 0);
 %! b = [0    6   11   16    0
 %!      0    0   12    0    0
 %!      0    8    0   18    0
@@ -2844,23 +2946,26 @@
 
 %!test
 %! c = num2cell (reshape ([1:25],5,5));
-%! idx1 = substruct  ( "{}", {3, 3});
-%! idx2 = substruct  ( "()", {2:2:5, 2:2:5});
-%! idx3 = substruct  ( "()", {":", [1,5]});
-%! idx2p = substruct  ( "{}", {2:2:5, 2:2:5});
-%! idx3p = substruct  ( "{}", {":", [1,5]});
-%! assert ({ subsref(c, idx1) }, {13})
-%! assert ({ subsref(c, idx2p) }, {7 9 17 19})
-%! assert ({ subsref(c, idx3p) }, num2cell ([1:5, 21:25]))
+%! idx1 = substruct  ("{}", {3, 3});
+%! idx2 = substruct  ("()", {2:2:5, 2:2:5});
+%! idx3 = substruct  ("()", {":", [1,5]});
+%! idx2p = substruct ("{}", {2:2:5, 2:2:5});
+%! idx3p = substruct ("{}", {":", [1,5]});
+%! idx4 = struct ("type", {}, "subs", {});
+%! assert ({ subsref(c, idx1) }, {13});
+%! assert ({ subsref(c, idx2p) }, {7 9 17 19});
+%! assert ({ subsref(c, idx3p) }, num2cell ([1:5, 21:25]));
+%! assert (subsref(c, idx4), c);
 %! c = subsasgn (c, idx1, 0);
 %! c = subsasgn (c, idx2, 0);
 %! c = subsasgn (c, idx3, 0);
+%!# c = subsasgn (c, idx4, 0);
 %! d = {0    6   11   16    0
 %!      0    0   12    0    0
 %!      0    8    0   18    0
 %!      0    0   14    0    0
 %!      0   10   15   20    0};
-%! assert (c,d);
+%! assert (c, d);
 
 %!test
 %! s.a = "ohai";
@@ -2869,16 +2974,19 @@
 %! idx1 = substruct (".", "a");
 %! idx2 = substruct (".", "b");
 %! idx3 = substruct (".", "c");
-%! assert (subsref (s, idx1), "ohai")
-%! assert (subsref (s, idx2), "dere")
-%! assert (subsref (s, idx3), 42)
+%! idx4 = struct ("type", {}, "subs", {});
+%! assert (subsref (s, idx1), "ohai");
+%! assert (subsref (s, idx2), "dere");
+%! assert (subsref (s, idx3), 42);
+%! assert (subsref (s, idx4), s);
 %! s = subsasgn (s, idx1, "Hello");
 %! s = subsasgn (s, idx2, "There");
 %! s = subsasgn (s, idx3, 163);
+%!# s = subsasgn (s, idx4, 163);
 %! t.a = "Hello";
 %! t.b = "There";
 %! t.c = 163;
-%! assert (s, t)
+%! assert (s, t);
 
 */
 
--- a/src/utils.cc	Wed Nov 23 09:42:50 2011 -0800
+++ b/src/utils.cc	Wed Nov 23 02:35:37 2011 -0500
@@ -1162,79 +1162,6 @@
   return retval;
 }
 
-void
-decode_subscripts (const char* name, const octave_value& arg,
-                   std::string& type_string,
-                   std::list<octave_value_list>& idx)
-{
-  const octave_map m = arg.map_value ();
-
-  if (! error_state
-      && m.nfields () == 2 && m.contains ("type") && m.contains ("subs"))
-    {
-      const Cell type = m.contents ("type");
-      const Cell subs = m.contents ("subs");
-
-      octave_idx_type nel = type.numel ();
-
-      type_string = std::string (nel, '\0');
-
-      for (int k = 0; k < nel; k++)
-        {
-          std::string item = type(k).string_value ();
-
-          if (! error_state)
-            {
-              if (item == "{}")
-                type_string[k] = '{';
-              else if (item == "()")
-                type_string[k] = '(';
-              else if (item == ".")
-                type_string[k] = '.';
-              else
-                {
-                  error("%s: invalid indexing type `%s'", name, item.c_str ());
-                  return;
-                }
-            }
-          else
-            {
-              error ("%s: expecting type(%d) to be a character string",
-                     name, k+1);
-              return;
-            }
-
-          octave_value_list idx_item;
-
-          if (subs(k).is_string ())
-            idx_item(0) = subs(k);
-          else if (subs(k).is_cell ())
-            {
-              Cell subs_cell = subs(k).cell_value ();
-
-              for (int n = 0; n < subs_cell.length (); n++)
-                {
-                  if (subs_cell(n).is_string ()
-                      && subs_cell(n).string_value () == ":")
-                    idx_item(n) = octave_value(octave_value::magic_colon_t);
-                  else
-                    idx_item(n) = subs_cell(n);
-                }
-            }
-          else
-            {
-              error ("%s: expecting subs(%d) to be a character string or cell array",
-                     name, k+1);
-              return;
-            }
-
-          idx.push_back (idx_item);
-        }
-    }
-  else
-    error ("%s: second argument must be a structure with fields `type' and `subs'", name);
-}
-
 Matrix
 identity_matrix (octave_idx_type nr, octave_idx_type nc)
 {
--- a/src/utils.h	Wed Nov 23 09:42:50 2011 -0800
+++ b/src/utils.h	Wed Nov 23 02:35:37 2011 -0500
@@ -97,11 +97,6 @@
 extern OCTINTERP_API octave_idx_type
 dims_to_numel (const dim_vector& dims, const octave_value_list& idx);
 
-extern OCTINTERP_API void
-decode_subscripts (const char* name, const octave_value& arg,
-                   std::string& type_string,
-                   std::list<octave_value_list>& idx);
-
 extern OCTINTERP_API Matrix
 identity_matrix (octave_idx_type nr, octave_idx_type nc);