diff src/ov-class.cc @ 9529:8e5009334661

partially revert e79470be3ecb
author Jaroslav Hajek <highegg@gmail.com>
date Mon, 17 Aug 2009 13:09:12 +0200
parents e79470be3ecb
children 8bf27324a9d0
line wrap: on
line diff
--- 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
 {