changeset 9529:8e5009334661

partially revert e79470be3ecb
author Jaroslav Hajek <highegg@gmail.com>
date Mon, 17 Aug 2009 13:09:12 +0200
parents ec066ba012c8
children f3df413338c5
files src/ChangeLog src/ov-class.cc src/ov-class.h src/ov-struct.cc src/ov-struct.h src/ov-usr-fcn.cc
diffstat 6 files changed, 424 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Sun Aug 16 08:25:24 2009 +0200
+++ b/src/ChangeLog	Mon Aug 17 13:09:12 2009 +0200
@@ -1,3 +1,11 @@
+2009-08-17  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov-struct.h, ov-struct.cc: Revert to e08d72bb988e.
+	* ov-class.h, ov-class.cc: Partially revert to e08d72bb988e.
+	(octave_class::subsasgn): Cut&paste code from octave_struct::subsasgn
+	for the nested dot indexing.
+	* ov-usr-fcn.cc (Voptimize_subasgn_calls): Default to true.
+
 2009-08-13  John W. Eaton  <jwe@octave.org>
 
 	* DLD-FUNCTIONS/fft.cc, DLD-FUNCTIONS/fft2.cc,
--- a/src/ov-class.cc	Sun Aug 16 08:25:24 2009 +0200
+++ b/src/ov-class.cc	Mon Aug 17 13:09:12 2009 +0200
@@ -68,7 +68,7 @@
 
 octave_class::octave_class (const Octave_map& m, const std::string& id, 
 			    const octave_value_list& parents)
-  : octave_struct (m), c_name (id), obsolete_copies (0)
+  : octave_base_value (), map (m), c_name (id), obsolete_copies (0)
 {
   octave_idx_type n = parents.length ();
 
@@ -138,6 +138,24 @@
   error ("invalid index for class");
 }
 
+static void
+gripe_invalid_index_for_assignment (void)
+{
+  error ("invalid index for class assignment");
+}
+
+static void
+gripe_invalid_index_type (const std::string& nm, char t)
+{
+  error ("%s cannot be indexed with %c", nm.c_str (), t);
+}
+
+static void
+gripe_failed_assignment (void)
+{
+  error ("assignment to class element failed");
+}
+
 static inline octave_value_list
 sanitize (const octave_value_list& ovl)
 {
@@ -371,7 +389,68 @@
   octave_value_list retval;
 
   if (in_class_method () || called_from_builtin ())
-    retval = octave_struct::subsref (type, idx, nargout);
+    {
+      // FIXME -- this block of code is the same as the body of
+      // octave_struct::subsref.  Maybe it could be shared instead of
+      // duplicated.
+
+      int skip = 1;
+
+      switch (type[0])
+	{
+	case '(':
+	  {
+	    if (type.length () > 1 && type[1] == '.')
+	      {
+		std::list<octave_value_list>::const_iterator p = idx.begin ();
+		octave_value_list key_idx = *++p;
+
+		Cell tmp = dotref (key_idx);
+
+		if (! error_state)
+		  {
+		    Cell t = tmp.index (idx.front ());
+
+		    retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
+
+		    // We handled two index elements, so tell
+		    // next_subsref to skip both of them.
+
+		    skip++;
+		  }
+	      }
+	    else
+	      retval(0) = octave_value (map.index (idx.front ()),
+					class_name ());
+	  }
+	  break;
+
+	case '.':
+	  {
+	    if (map.numel() > 0)
+	      {
+		Cell t = dotref (idx.front ());
+
+		retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
+	      }
+	  }
+	  break;
+
+	case '{':
+	  gripe_invalid_index_type (type_name (), type[0]);
+	  break;
+
+	default:
+	  panic_impossible ();
+	}
+
+      // FIXME -- perhaps there should be an
+      // octave_value_list::next_subsref member function?  See also
+      // octave_user_function::subsref.
+
+      if (idx.size () > 1)
+	retval = retval(0).next_subsref (nargout, type, idx, skip);
+    }
   else
     {
       octave_value meth = symbol_table::find_method ("subsref", class_name ());
@@ -422,59 +501,20 @@
   return retval;
 }
 
-octave_value 
-octave_class::subsref (const std::string& type,
-                       const std::list<octave_value_list>& idx,
-                       bool auto_add)
-{
-  if (in_class_method () || called_from_builtin ())
-    return octave_struct::subsref (type, idx, auto_add);
-  else
-    return subsref (type, idx);
-
-}
-
-void
-octave_class::gripe_failed_assignment (void)
-{
-  error ("assignment to class element failed");
-}
-
-octave_value 
-octave_class::dotasgn (const octave_value_list& idx, const octave_value& rhs)
+octave_value
+octave_class::numeric_conv (const Cell& val, const std::string& type)
 {
   octave_value retval;
 
-  // Find the class in which this method resides before 
-  // attempting to access the requested field.
-
-  std::string method_class = get_current_method_class ();
-
-  octave_base_value *obvp = find_parent_class (method_class);
-
-  if (obvp)
+  if (val.length () == 1)
     {
-      assert (idx.length () == 1);
-
-      std::string key = idx(0).string_value ();
+      retval = val(0);
 
-      if (! error_state)
-        {
-          obvp->assign (key, rhs);
-
-          if (! error_state)
-            {
-              count++;
-              retval = octave_value (this);
-            }
-          else
-            gripe_failed_assignment ();
-        }
-      else
-        gripe_failed_assignment ();
+      if (type.length () > 0 && type[0] == '.' && ! retval.is_map ())
+	retval = Octave_map ();
     }
   else
-    error ("malformed class");
+    gripe_invalid_index_for_assignment ();
 
   return retval;
 }
@@ -484,14 +524,14 @@
 			const std::list<octave_value_list>& idx,
 			const octave_value& rhs)
 {
+  octave_value retval;
+
   if (! (in_class_method () || called_from_builtin ()))
     {
       octave_value meth = symbol_table::find_method ("subsasgn", class_name ());
 
       if (meth.is_defined ())
 	{
-          octave_value retval;
-
 	  octave_value_list args;
 
           if (rhs.is_cs_list ())
@@ -554,7 +594,246 @@
 	}
     }
 
-  return octave_struct::subsasgn (type, idx, rhs);
+  // FIXME -- this block of code is the same as the body of
+  // octave_struct::subsasgn.  Maybe it could be shared instead of
+  // duplicated.
+
+  int n = type.length ();
+
+  octave_value t_rhs = rhs;
+
+  if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
+    {
+      switch (type[0])
+	{
+	case '(':
+	  {
+	    if (type.length () > 1 && type[1] == '.')
+	      {
+		std::list<octave_value_list>::const_iterator p = idx.begin ();
+		octave_value_list t_idx = *p;
+
+		octave_value_list key_idx = *++p;
+
+		assert (key_idx.length () == 1);
+
+		std::string key = key_idx(0).string_value ();
+
+		if (! error_state)
+		  {
+		    octave_value u;
+
+		    if (! map.contains (key))
+		      u = octave_value::empty_conv (type.substr (2), rhs);
+		    else
+		      {
+			Cell map_val = map.contents (key);
+
+			Cell map_elt = map_val.index (idx.front (), true);
+
+			u = numeric_conv (map_elt, type.substr (2));
+		      }
+
+		    if (! error_state)
+		      {
+			std::list<octave_value_list> next_idx (idx);
+
+			// We handled two index elements, so subsasgn to
+			// needs to skip both of them.
+
+			next_idx.erase (next_idx.begin ());
+			next_idx.erase (next_idx.begin ());
+
+			u.make_unique ();
+
+			t_rhs = u.subsasgn (type.substr (2), next_idx, rhs);
+		      }
+		  }
+		else
+		  gripe_invalid_index_for_assignment ();
+	      }
+	    else
+	      gripe_invalid_index_for_assignment ();
+	  }
+	  break;
+
+	case '.':
+	  {
+	    octave_value_list key_idx = idx.front ();
+
+	    assert (key_idx.length () == 1);
+
+	    std::string key = key_idx(0).string_value ();
+
+            std::list<octave_value_list> next_idx (idx);
+
+            next_idx.erase (next_idx.begin ());
+
+            std::string next_type = type.substr (1);
+
+            Cell tmpc (1, 1);
+            Octave_map::iterator pkey = map.seek (key);
+            if (pkey != map.end ())
+              {
+                pkey->second.make_unique ();
+                tmpc = pkey->second;
+              }
+
+            // FIXME: better code reuse?
+            if (! error_state)
+              {
+                if (tmpc.numel () == 1)
+                  {
+                    octave_value& tmp = tmpc(0);
+
+                    if (! tmp.is_defined () || tmp.is_zero_by_zero ())
+                      {
+                        tmp = octave_value::empty_conv (next_type, rhs);
+                        tmp.make_unique (); // probably a no-op.
+                      }
+                    else
+                      // optimization: ignore the copy still stored inside our map.
+                      tmp.make_unique (1);
+
+                    if (! error_state)
+                      t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
+                  }
+                else
+                  gripe_indexed_cs_list ();
+              }
+	  }
+	  break;
+
+	case '{':
+	  gripe_invalid_index_type (type_name (), type[0]);
+	  break;
+
+	default:
+	  panic_impossible ();
+	}
+    }
+
+  if (! error_state)
+    {
+      switch (type[0])
+	{
+	case '(':
+	  {
+	    if (n > 1 && type[1] == '.')
+	      {
+		std::list<octave_value_list>::const_iterator p = idx.begin ();
+		octave_value_list key_idx = *++p;
+
+		assert (key_idx.length () == 1);
+
+		std::string key = key_idx(0).string_value ();
+
+		if (! error_state)
+		  {
+		    map.assign (idx.front (), key, t_rhs);
+
+		    if (! error_state)
+		      {
+			count++;
+			retval = octave_value (this);
+		      }
+		    else
+		      gripe_failed_assignment ();
+		  }
+		else
+		  gripe_failed_assignment ();
+	      }
+	    else
+	      {
+		if (t_rhs.is_object () || t_rhs.is_map ())
+		  {
+		    Octave_map rhs_map = t_rhs.map_value ();
+
+		    if (! error_state)
+		      {
+			map.assign (idx.front (), rhs_map);
+
+			if (! error_state)
+			  {
+			    count++;
+			    retval = octave_value (this);
+			  }
+			else
+			  gripe_failed_assignment ();
+		      }
+		    else
+		      error ("invalid class assignment");
+		  }
+		else
+		  {
+		    if (t_rhs.is_empty ())
+		      {
+			map.maybe_delete_elements (idx.front());
+
+			if (! error_state)
+			  {
+			    count++;
+			    retval = octave_value (this);
+			  }
+			else
+			  gripe_failed_assignment ();
+		      }
+		    else
+		      error ("invalid class assignment");
+		  }
+	      }
+	  }
+	  break;
+
+	case '.':
+	  {
+	    // Find the class in which this method resides before 
+	    // attempting to access the requested field.
+
+	    std::string method_class = get_current_method_class ();
+
+	    octave_base_value *obvp = find_parent_class (method_class);
+
+	    if (obvp)
+	      {
+		octave_value_list key_idx = idx.front ();
+
+		assert (key_idx.length () == 1);
+
+		std::string key = key_idx(0).string_value ();
+
+		if (! error_state)
+		  {
+		    obvp->assign (key, t_rhs);
+
+		    if (! error_state)
+		      {
+			count++;
+			retval = octave_value (this);
+		      }
+		    else
+		      gripe_failed_assignment ();
+		  }
+		else
+		  gripe_failed_assignment ();
+	      }
+	    else
+	      error ("malformed class");
+	  }
+	  break;
+
+	case '{':
+	  gripe_invalid_index_type (type_name (), type[0]);
+	  break;
+
+	default:
+	  panic_impossible ();
+	}
+    }
+  else
+    gripe_failed_assignment ();
+
+  return retval;
 }
 
 idx_vector
@@ -591,6 +870,25 @@
   return retval;
 }
 
+size_t
+octave_class::byte_size (void) const
+{
+  // Neglect the size of the fieldnames.
+
+  size_t retval = 0;
+
+  for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++)
+    {
+      std::string key = map.key (p);
+
+      octave_value val = octave_value (map.contents (p));
+
+      retval += val.byte_size ();
+    }
+
+  return retval;
+}
+
 string_vector
 octave_class::map_keys (void) const
 {
--- a/src/ov-class.h	Sun Aug 16 08:25:24 2009 +0200
+++ b/src/ov-class.h	Mon Aug 17 13:09:12 2009 +0200
@@ -1,7 +1,6 @@
 /*
 
 Copyright (C) 2007, 2008, 2009 John W. Eaton
-Copyright (C) 2009 VZLU Prague
 
 This file is part of Octave.
 
@@ -36,7 +35,6 @@
 #include "oct-alloc.h"
 #include "oct-map.h"
 #include "ov-base.h"
-#include "ov-struct.h"
 #include "ov-typeinfo.h"
 
 class octave_value_list;
@@ -46,19 +44,19 @@
 // Data structures.
 
 class
-octave_class : public octave_struct
+octave_class : public octave_base_value
 {
 public:
 
   octave_class (void)
-    : octave_struct (), obsolete_copies (0) { }
+    : octave_base_value (), obsolete_copies (0)  { }
 
   octave_class (const Octave_map& m, const std::string& id)
-    : octave_struct (m), c_name (id), obsolete_copies (0) { }
+    : octave_base_value (), map (m), c_name (id), obsolete_copies (0) { }
 
   octave_class (const octave_class& s)
-    : octave_struct (s), c_name (s.c_name),
-      parent_list (s.parent_list), obsolete_copies (0) { }
+    : octave_base_value (s), map (s.map), c_name (s.c_name),
+      parent_list (s.parent_list), obsolete_copies (0)  { }
 
   octave_class (const Octave_map& m, const std::string& id, 
                 const octave_value_list& parents);
@@ -76,8 +74,6 @@
 
   Cell dotref (const octave_value_list& idx);
 
-  octave_value dotasgn (const octave_value_list& idx, const octave_value& rhs);
-
   Matrix size (void);
 
   octave_idx_type numel (const octave_value_list&); 
@@ -89,14 +85,13 @@
       return tmp.length () > 0 ? tmp(0) : octave_value ();
     }
 
-  octave_value subsref (const std::string& type,
-			const std::list<octave_value_list>& idx,
-                        bool auto_add);
-
   octave_value_list subsref (const std::string& type,
 			     const std::list<octave_value_list>& idx,
 			     int nargout);
 
+  static octave_value numeric_conv (const Cell& val,
+				    const std::string& type);
+
   void assign(const std::string& k, const octave_value& rhs)
   { map.assign (k, rhs); };
 
@@ -108,12 +103,34 @@
 
   dim_vector dims (void) const { return map.dims (); }
 
+  size_t byte_size (void) const;
+
+  // This is the number of elements in each field.  The total number
+  // of elements is numel () * nfields ().
+  octave_idx_type numel (void) const
+  {
+    dim_vector dv = dims ();
+    return dv.numel ();
+  }
+
+  octave_idx_type nfields (void) const { return map.nfields (); }
+
   size_t nparents (void) const { return parent_list.size (); }
 
+  octave_value reshape (const dim_vector& new_dims) const
+    { return map.reshape (new_dims); }
+
+  octave_value resize (const dim_vector& dv, bool = false) const
+    { Octave_map tmap = map; tmap.resize (dv); return tmap; }
+
+  bool is_defined (void) const { return true; }
+
   bool is_map (void) const { return false; }
 
   bool is_object (void) const { return true; }
 
+  Octave_map map_value (void) const { return map; }
+
   string_vector map_keys (void) const;
 
   std::list<std::string> parent_class_name_list (void) const
@@ -156,11 +173,9 @@
 
   mxArray *as_mxArray (void) const;
 
-protected:
+private:
 
-  void gripe_failed_assignment (void);
-
-private:
+  Octave_map map;
 
   DECLARE_OCTAVE_ALLOCATOR
 
--- a/src/ov-struct.cc	Sun Aug 16 08:25:24 2009 +0200
+++ b/src/ov-struct.cc	Mon Aug 17 13:09:12 2009 +0200
@@ -93,8 +93,8 @@
   error ("%s cannot be indexed with %c", nm.c_str (), t);
 }
 
-void
-octave_struct::gripe_failed_assignment (void)
+static void
+gripe_failed_assignment (void)
 {
   error ("assignment to structure element failed");
 }
@@ -254,43 +254,6 @@
 }
 
 octave_value
-octave_struct::dotasgn (const octave_value_list& idx, const octave_value& rhs)
-{
-  octave_value retval;
-
-  assert (idx.length () == 1);
-
-  std::string key = idx(0).string_value ();
-
-  if (rhs.is_cs_list ())
-    {
-      Cell tmp_cell = Cell (rhs.list_value ());
-
-      // The shape of the RHS is irrelevant, we just want
-      // the number of elements to agree and to preserve the
-      // shape of the left hand side of the assignment.
-
-      if (numel () == tmp_cell.numel ())
-        tmp_cell = tmp_cell.reshape (dims ());
-
-      map.assign (key, tmp_cell);
-    }
-  else
-    // Regularize a null matrix if stored into a struct component.
-    map.assign (key, rhs.storable_value ());
-
-  if (! error_state)
-    {
-      count++;
-      retval = octave_value (this);
-    }
-  else
-    gripe_failed_assignment ();
-
-  return retval;
-}
-
-octave_value
 octave_struct::subsasgn (const std::string& type,
 			 const std::list<octave_value_list>& idx,
 			 const octave_value& rhs)
@@ -493,8 +456,7 @@
 	      }
 	    else
 	      {
-		if (t_rhs.is_map()
-                    || (is_object () && t_rhs.is_object ()))
+		if (t_rhs.is_map())
 		  {
 		    Octave_map rhs_map = t_rhs.map_value ();
 
@@ -536,7 +498,36 @@
 
 	case '.':
 	  {
-            retval = dotasgn (idx.front (), t_rhs);
+	    octave_value_list key_idx = idx.front ();
+
+	    assert (key_idx.length () == 1);
+
+	    std::string key = key_idx(0).string_value ();
+
+	    if (t_rhs.is_cs_list ())
+	      {
+		Cell tmp_cell = Cell (t_rhs.list_value ());
+
+		// The shape of the RHS is irrelevant, we just want
+		// the number of elements to agree and to preserve the
+		// shape of the left hand side of the assignment.
+
+		if (numel () == tmp_cell.numel ())
+		  tmp_cell = tmp_cell.reshape (dims ());
+
+		map.assign (key, tmp_cell);
+	      }
+	    else
+              // Regularize a null matrix if stored into a struct component.
+	      map.assign (key, t_rhs.storable_value ());
+
+	    if (! error_state)
+	      {
+		count++;
+		retval = octave_value (this);
+	      }
+	    else
+	      gripe_failed_assignment ();
 	  }
 	  break;
 
--- a/src/ov-struct.h	Sun Aug 16 08:25:24 2009 +0200
+++ b/src/ov-struct.h	Mon Aug 17 13:09:12 2009 +0200
@@ -63,13 +63,7 @@
   octave_base_value *clone (void) const { return new octave_struct (*this); }
   octave_base_value *empty_clone (void) const { return new octave_struct (); }
 
-  virtual Cell dotref (const octave_value_list& idx)
-    { return dotref (idx, false); }
-
-  Cell dotref (const octave_value_list& idx, bool auto_add);
-
-  virtual octave_value dotasgn (const octave_value_list& idx,
-                                const octave_value& rhs);
+  Cell dotref (const octave_value_list& idx, bool auto_add = false);
 
   octave_value subsref (const std::string& type,
 			const std::list<octave_value_list>& idx)
@@ -155,8 +149,6 @@
 
 protected:
 
-  virtual void gripe_failed_assignment (void);
-
   // The associative array used to manage the structure data.
   Octave_map map;
 
--- a/src/ov-usr-fcn.cc	Sun Aug 16 08:25:24 2009 +0200
+++ b/src/ov-usr-fcn.cc	Mon Aug 17 13:09:12 2009 +0200
@@ -53,7 +53,7 @@
 static int Vmax_recursion_depth = 256;
 
 // Whether to optimize subsasgn method calls.
-static bool Voptimize_subsasgn_calls = false;
+static bool Voptimize_subsasgn_calls = true;
 
 // User defined scripts.