changeset 16696:665fa0f621cc classdef

Support combination of object array extension and multi-level indexing. * libinterp/octave-value/ov-classdef.h (octave_classdef::subsref(string, list<octave_value_list, bool)): New method. (cdef_object_array:subsref, cdef_object_scalar::subsref, cdef_object_rep): Add boolean argument "auto_add". (cdef_object_array::fill_empty_values(Array&)): New method. (cdef_object_array::fill_empty_values()): Rewrite using the overload. (cdef_object::subsasgn, cdef_object::make_unique): New boolean argument "ignore_copies" for assignment optimization. * libinterp/octave-value/ov-classdef.cc (octave_classdef::subsref(string, list<octave_value_list, bool)): New method. (cdef_object_array::fill_empty_values()): Move implementation to the overload version. (cdef_object_array::subsasgn): Optimize assignment to avoir unnecessary copies of value objects. (cdef_object_array::subsref): New auto_add argument for automatic extension of the array. (cdef_object_scalar::subsref): New auto_add argument. Implement (-indexing by delegating to a new array object.
author Michael Goffioul <michael.goffioul@gmail.com>
date Thu, 23 May 2013 21:41:51 -0400
parents 2823f8e3da77
children 13b3b92ea99c
files libinterp/octave-value/ov-classdef.cc libinterp/octave-value/ov-classdef.h
diffstat 2 files changed, 82 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/ov-classdef.cc	Thu May 23 14:12:33 2013 -0400
+++ b/libinterp/octave-value/ov-classdef.cc	Thu May 23 21:41:51 2013 -0400
@@ -775,6 +775,28 @@
 }
 
 octave_value
+octave_classdef::subsref (const std::string& type,
+                          const std::list<octave_value_list>& idx,
+                          bool auto_add)
+{
+  size_t skip = 0;
+  octave_value_list retval;
+
+  // FIXME: should check "subsref" method first
+  // ? not sure this still applied with auto_add version of subsref
+
+  retval = object.subsref (type, idx, 1, skip, cdef_class (), auto_add);
+
+  if (! error_state)
+    {
+      if (type.length () > skip && idx.size () > skip)
+	retval = retval(0).next_subsref (1, type, idx, skip);
+    }
+
+  return retval.length () > 0 ? retval(0) : octave_value ();
+}
+
+octave_value
 octave_classdef::subsasgn (const std::string& type,
                            const std::list<octave_value_list>& idx,
                            const octave_value& rhs)
@@ -1028,7 +1050,7 @@
 cdef_object_scalar::subsref (const std::string& type,
                              const std::list<octave_value_list>& idx,
                              int nargout, size_t& skip,
-                             const cdef_class& context)
+                             const cdef_class& context, bool auto_add)
 {
   skip = 0;
 
@@ -1096,6 +1118,23 @@
 	    }
 	  break;
 	}
+
+    case '(':
+        {
+          refcount++;
+
+          cdef_object this_obj (this);
+
+          Array<cdef_object> arr (dim_vector (1, 1), this_obj);
+
+          cdef_object new_obj = cdef_object (new cdef_object_array (arr));
+
+          new_obj.set_class (get_class ());
+
+          retval = new_obj.subsref (type, idx, nargout, skip, cls, auto_add);
+        }
+      break;
+
     default:
       error ("object cannot be indexed with `%c'", type[0]);
       break;
@@ -1221,7 +1260,7 @@
 cdef_object_array::subsref (const std::string& type,
                             const std::list<octave_value_list>& idx,
                             int /* nargout */, size_t& skip,
-                            const cdef_class& /* context */)
+                            const cdef_class& /* context */, bool auto_add)
 {
   octave_value_list retval;
 
@@ -1244,10 +1283,17 @@
 
           if (! error_state)
             {
-              Array<cdef_object> ires = array.index (iv);
+              Array<cdef_object> ires = array.index (iv, auto_add);
 
               if (! error_state)
                 {
+                  // If resizing is enabled (auto_add = true), it's possible
+                  // indexing was out-of-bound and the result array contains
+                  // invalid cdef_objects.
+
+                  if (auto_add)
+                    fill_empty_values (ires);
+
                   if (is_scalar)
                     retval(0) = to_ov (ires(0));
                   else
@@ -1406,18 +1452,26 @@
                 {
                   cdef_object obj = a(0);
 
+                  int ignore_copies = 0;
+
                   // If the object in 'a' is not valid, this means the index
                   // was out-of-bound and we need to create a new object.
 
                   if (! obj.ok ())
                     obj = get_class ().construct_object (octave_value_list ());
+                  else
+                    // Optimize the subsasgn call to come. There are 2 copies
+                    // that we can safely ignore:
+                    // - 1 in "array"
+                    // - 1 in "a"
+                    ignore_copies = 2;
 
                   std::list<octave_value_list> next_idx (idx);
 
                   next_idx.erase (next_idx.begin ());
 
                   octave_value tmp = obj.subsasgn (type.substr (1), next_idx,
-                                                   rhs);
+                                                   rhs, ignore_copies);
 
                   if (! error_state)
                     {
@@ -1467,7 +1521,7 @@
 }
 
 void
-cdef_object_array::fill_empty_values (void)
+cdef_object_array::fill_empty_values (Array<cdef_object>& arr)
 {
   cdef_class cls = get_class ();
 
@@ -1475,21 +1529,21 @@
     {
       cdef_object obj;
 
-      int n = array.numel ();
+      int n = arr.numel ();
 
       for (int i = 0; ! error_state && i < n; i++)
         {
-          if (! array.xelem (i).ok ())
+          if (! arr.xelem (i).ok ())
             {
               if (! obj.ok ())
                 {
                   obj = cls.construct_object (octave_value_list ());
 
                   if (! error_state)
-                    array.xelem (i) = obj;
+                    arr.xelem (i) = obj;
                 }
               else
-                array.xelem (i) = obj.copy ();
+                arr.xelem (i) = obj.copy ();
             }
         }
     }
--- a/libinterp/octave-value/ov-classdef.h	Thu May 23 14:12:33 2013 -0400
+++ b/libinterp/octave-value/ov-classdef.h	Thu May 23 21:41:51 2013 -0400
@@ -108,7 +108,7 @@
 
   virtual octave_value_list
   subsref (const std::string&, const std::list<octave_value_list>&,
-           int, size_t&, const cdef_class&)
+           int, size_t&, const cdef_class&, bool)
     {
       gripe_invalid_object ("subsref");
       return octave_value_list ();
@@ -256,14 +256,15 @@
 
   octave_value_list
   subsref (const std::string& type, const std::list<octave_value_list>& idx,
-           int nargout, size_t& skip, const cdef_class& context)
-    { return rep->subsref (type, idx, nargout, skip, context); }
+           int nargout, size_t& skip, const cdef_class& context,
+           bool auto_add = false)
+    { return rep->subsref (type, idx, nargout, skip, context, auto_add); }
 
   octave_value
   subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
-            const octave_value& rhs)
+            const octave_value& rhs, int ignore_copies = 0)
     {
-      make_unique ();
+      make_unique (ignore_copies);
       return rep->subsasgn (type, idx, rhs);
     }
 
@@ -294,9 +295,9 @@
 protected:
   cdef_object_rep* get_rep (void) { return rep; }
 
-  void make_unique (void)
+  void make_unique (int ignore_copies)
     {
-      if (rep->refcount > 1)
+      if (rep->refcount > ignore_copies + 1)
         *this = clone ();
     }
 
@@ -369,7 +370,8 @@
 
   octave_value_list
   subsref (const std::string& type, const std::list<octave_value_list>& idx,
-           int nargout, size_t& skip, const cdef_class& context);
+           int nargout, size_t& skip, const cdef_class& context,
+           bool auto_add);
 
   octave_value
   subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
@@ -379,7 +381,9 @@
   Array<cdef_object> array;
 
 private:
-  void fill_empty_values (void);
+  void fill_empty_values (void) { fill_empty_values (array); }
+
+  void fill_empty_values (Array<cdef_object>& arr);
 
   // Private copying!
   cdef_object_array (const cdef_object_array& obj)
@@ -417,7 +421,8 @@
 
   octave_value_list
   subsref (const std::string& type, const std::list<octave_value_list>& idx,
-           int nargout, size_t& skip, const cdef_class& context);
+           int nargout, size_t& skip, const cdef_class& context,
+           bool auto_add);
 
   octave_value
   subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
@@ -1415,6 +1420,10 @@
       return (retval.length () > 0 ? retval(0) : octave_value ());
     }
 
+  octave_value subsref (const std::string& type,
+			const std::list<octave_value_list>& idx,
+                        bool auto_add);
+
   octave_value subsasgn (const std::string& type,
                          const std::list<octave_value_list>& idx,
                          const octave_value& rhs);