diff libinterp/octave-value/ov-classdef.cc @ 15913:8521321604df classdef

Initial support for object array semantic. * libinterp/octave-value/ov-classdef.h (class cdef_object_array): New class. (cdef_object_rep::empty_clone, cdef_object_rep::copy, cdef_object_rep::make_array, cdef_object_rep::is_array, cdef_object_rep::array_value): New methods. (cdef_object::empty_clone, cdef_object::make_array, cdef_object::copy, cdef_object::is_array, cdef_object::array_value): Likewise. (cdef_object_base::empty_clone, cdef_object_base::make_array): Likewise. (handle_cdef_object::copy): Likewise. (value_cdef_object::copy): Likewise. (cdef_class::cdef_class_rep::copy, cdef_property::cdef_property_rep::copy, cdef_method::cdef_method_rep::copy, cdef_package::cdef_package_rep::copy): Likewise. (handle_cdef_object::handle_cdef_object): New copy constructor. (cdef_object::make_unique): New method. (cdef_object::subsasgn): Use it. (cdef_class::cdef_class_rep::meta): New member. (cdef_class::cdef_class_rep::cdef_class_rep): Initialize it. (cdef_class::cdef_class_rep::mark_as_meta_class, cdef_class::cdef_class_rep::is_meta): Use and manipulate it. (cdef_class::mark_as_meta_class, cdef_class::is_meta): Likewise. (cdef_class::cdef_class_rep::construct_object, cdef_class::cdef_class_rep::is_abstract, cdef_class::cdef_class_rep::is_sealed): New methods. (cdef_class::construct_object, cdef_class::is_abstract, cdef_class::is_sealed): Likewise. (cdef_class::cdef_class_rep::cdef_class_rep): New copy constructor. (cdef_property::cdef_property_rep::default_value): Remove member. (cdef_property::cdef_property_rep::get_value ()): Use "DefaultValue" slot. (cdef_property::cdef_property_rep::set_value (octave_value)): Remove method. (cdef_property::set_value (octave_value)): Likewise. (cdef_property::cdef_property_rep::cdef_property_rep): New copy constructor. (cdef_method::cdef_method_rep::cdef_method_rep): Likewise. (cdef_package::cdef_package_rep::cdef_package_rep): Likewise. (octave_classdef::empty_clone): Call cdef_object::empty_clone. (octave_classdef::undef_subsasgn): New method. (class cdef_property, class cdef_method, class cdef_package): Mark cdef_class as friend. * libinterp/octave-value/ov-classdef.cc: Include Array.cc. (make_class): Initialize "Abstract" property. Do not register classes with empty name. (make_meta_class): New static function. (make_method): Check whether function object is valid. (make_package): Do not register packages with empty name. (octave_classdef::undef_subsasgn): New method. (class cdef_object_array): New class. (cdef_class::cdef_class_rep::cdef_class_rep): Initialize meta. (cdef_class::cdef_class_rep::find_methods, cdef_class::cdef_class_rep::find_names): Use cdef_method::is_constructor instead of relying on the method name. (cdef_class::cdef_class_rep::construct_object): New method. (cdef_class::cdef_class_rep::construct): Use it. (install_classdef): Use make_meta_class. Create "Abstract" property for class meta.class.
author Michael Goffioul <michael.goffioul@gmail.com>
date Tue, 08 Jan 2013 12:34:30 -0500
parents b18b7e560236
children 837a4a9b5049
line wrap: on
line diff
--- a/libinterp/octave-value/ov-classdef.cc	Sun Jan 06 22:22:13 2013 -0500
+++ b/libinterp/octave-value/ov-classdef.cc	Tue Jan 08 12:34:30 2013 -0500
@@ -41,6 +41,8 @@
 #include "symtab.h"
 #include "toplev.h"
 
+#include "Array.cc"
+
 static std::map<std::string, cdef_class> all_classes;
 static std::map<std::string, cdef_package> all_packages;
 
@@ -611,6 +613,7 @@
   cdef_class cls (name, super_list);
 
   cls.set_class (cdef_class::meta_class ());
+  cls.put ("Abstract", false);
   cls.put ("ConstructOnLoad", false);
   cls.put ("ContainingPackage", Matrix ());
   cls.put ("Description", std::string ());
@@ -657,7 +660,8 @@
   if (error_state)
     return cdef_class ();
 
-  all_classes[name] = cls;
+  if (! name.empty ())
+    all_classes[name] = cls;
 
   return cls;
 }
@@ -668,6 +672,17 @@
   return make_class (name, std::list<cdef_class> (1, super));
 }
 
+static cdef_class
+make_meta_class (const std::string& name, const cdef_class& super)
+{
+  cdef_class cls = make_class (name, super);
+
+  cls.put ("Sealed", true);
+  cls.mark_as_meta_class ();
+
+  return cls;
+}
+
 static cdef_property
 make_property (const cdef_class& cls, const std::string& name,
 	       const octave_value& get_method = Matrix (),
@@ -675,8 +690,6 @@
 	       const octave_value& set_method = Matrix (),
 	       const std::string& set_access = "public")
 {
-  // FIXME: what about default value?
-
   cdef_property prop (name);
 
   prop.set_class (cdef_class::meta_property ());
@@ -730,7 +743,8 @@
   meth.put ("Sealed", true);
   meth.put ("Static", is_static);
 
-  make_function_of_class (cls, fcn);
+  if (fcn.is_defined ())
+    make_function_of_class (cls, fcn);
 
   meth.set_function (fcn);
 
@@ -757,7 +771,8 @@
   pack.put ("Name", nm);
   pack.put ("ContainingPackage", to_ov (all_packages[parent]));
 
-  all_packages[nm] = pack;
+  if (! nm.empty ())
+    all_packages[nm] = pack;
 
   return pack;
 }
@@ -806,6 +821,24 @@
   return object.subsasgn (type, idx, rhs);
 }
 
+octave_value
+octave_classdef::undef_subsasgn (const std::string& type,
+                                 const std::list<octave_value_list>& idx,
+                                 const octave_value& rhs)
+{
+  if (type.length () == 1 && type[0] == '(')
+    {
+      object = object.make_array ();
+
+      if (! error_state)
+        return subsasgn (type, idx, rhs);
+    }
+  else
+    return octave_base_value::undef_subsasgn (type, idx, rhs);
+
+  return octave_value ();
+}
+
 //----------------------------------------------------------------------------
 
 class octave_classdef_proxy : public octave_function
@@ -1180,6 +1213,171 @@
         ctor_list[cls] = supcls_list;
     }
 }
+
+octave_value_list
+cdef_object_array::subsref (const std::string& type,
+                            const std::list<octave_value_list>& idx,
+                            int /* nargout */, size_t& skip,
+                            const cdef_class& /* context */)
+{
+  octave_value_list retval;
+
+  skip = 1;
+
+  switch (type[0])
+    {
+    case '(':
+        {
+          const octave_value_list& ival = idx.front ();
+          bool is_scalar = true;
+          Array<idx_vector> iv (dim_vector (1, ival.length ()));
+
+          for (int i = 0; ! error_state && i < ival.length (); i++)
+            {
+              iv(i) = ival(i).index_vector ();
+              if (! error_state)
+                is_scalar = is_scalar && iv(i).is_scalar ();
+            }
+
+          if (! error_state)
+            {
+              Array<cdef_object> ires = array.index (iv);
+
+              if (! error_state)
+                {
+                  if (is_scalar)
+                    retval(0) = to_ov (ires(0));
+                  else
+                    {
+                      cdef_object array_obj (new cdef_object_array (ires));
+
+                      array_obj.set_class (get_class ());
+
+                      retval(0) = to_ov (array_obj);
+                    }
+                }
+            }
+        }
+      break;
+
+    default:
+      ::error ("can't perform indexing operation on array of %s objects",
+               class_name ().c_str ());
+      break;
+    }
+
+  return retval;
+}
+
+octave_value
+cdef_object_array::subsasgn (const std::string& type,
+                             const std::list<octave_value_list>& idx,
+                             const octave_value& rhs)
+{
+  octave_value retval;
+
+  switch (type[0])
+    {
+    case '(':
+      if (type.length () == 1)
+        {
+          cdef_object rhs_obj = to_cdef (rhs);
+
+          if (! error_state)
+            {
+              if (rhs_obj.get_class () == get_class ())
+                {
+                  const octave_value_list& ival = idx.front ();
+                  bool is_scalar = true;
+                  Array<idx_vector> iv (dim_vector (1, ival.length ()));
+
+                  for (int i = 0; ! error_state && i < ival.length (); i++)
+                    {
+                      iv(i) = ival(i).index_vector ();
+                      if (! error_state)
+                        is_scalar = is_scalar && iv(i).is_scalar ();
+                    }
+
+                  if (! error_state)
+                    {
+                      Array<cdef_object> rhs_mat;
+
+                      if (! rhs_obj.is_array ())
+                        {
+                          rhs_mat = Array<cdef_object> (dim_vector (1, 1));
+                          rhs_mat(0) = rhs_obj;
+                        }
+                      else
+                        rhs_mat = rhs_obj.array_value ();
+
+                      if (! error_state)
+                        {
+                          octave_idx_type n = array.numel ();
+
+                          array.assign (iv, rhs_mat, cdef_object ());
+
+                          if (! error_state)
+                            {
+                              if (array.numel () > n)
+                                fill_empty_values ();
+
+                              if (! error_state)
+                                {
+                                  refcount++;
+                                  retval = to_ov (cdef_object (this));
+                                }
+                            }
+                        }
+                    }
+                }
+              else
+                ::error ("can't assign %s object into array of %s objects.",
+                         rhs_obj.class_name ().c_str (),
+                         class_name ().c_str ());
+            }
+        }
+      else
+        ::error ("can't perform indexing operation on array of %s objects",
+                 class_name ().c_str ());
+      break;
+
+    default:
+      ::error ("can't perform indexing operation on array of %s objects",
+               class_name ().c_str ());
+      break;
+    }
+
+  return retval;
+}
+
+void
+cdef_object_array::fill_empty_values (void)
+{
+  cdef_class cls = get_class ();
+
+  if (! error_state)
+    {
+      cdef_object obj;
+
+      int n = array.numel ();
+
+      for (int i = 0; ! error_state && i < n; i++)
+        {
+          if (! array.xelem (i).ok ())
+            {
+              if (! obj.ok ())
+                {
+                  obj = cls.construct_object (octave_value_list ());
+
+                  if (! error_state)
+                    array.xelem (i) = obj;
+                }
+              else
+                array.xelem (i) = obj.copy ();
+            }
+        }
+    }
+}
   
 bool cdef_object_scalar::is_constructed_for (const cdef_class& cls) const
 {
@@ -1219,7 +1417,7 @@
 
 cdef_class::cdef_class_rep::cdef_class_rep (const std::list<cdef_class>& superclasses)
      : handle_cdef_object (), member_count (0), handle_class (false),
-       object_count (0)
+       object_count (0), meta (false)
 {
   put ("SuperClasses", to_ov (superclasses));
   implicit_ctor_list = superclasses;
@@ -1474,14 +1672,12 @@
 
   method_const_iterator it;
 
-  std::string cls_name = get_base_name (get_name ());
-
   for (it = method_map.begin (); it != method_map.end (); ++it)
     {
-      std::string nm = it->second.get_name ();
-
-      if (nm != cls_name)
+      if (! it->second.is_constructor ())
         {
+          std::string nm = it->second.get_name ();
+
           if (meths.find (nm) == meths.end ())
             {
               if (only_inherited)
@@ -1624,15 +1820,13 @@
 {
   load_all_methods ();
 
-  std::string cls_name = get_base_name (get_name ());
-
   for (method_const_iterator it = method_map.begin ();
        ! error_state && it != method_map.end(); ++it)
     {
-      std::string nm = it->second.get_name ();
-
-      if (nm != cls_name)
+      if (! it->second.is_constructor ())
         {
+          std::string nm = it->second.get_name ();
+
           if (! all)
             {
               octave_value acc = it->second.get ("Access");
@@ -1848,27 +2042,93 @@
 octave_value
 cdef_class::cdef_class_rep::construct (const octave_value_list& args)
 {
-  cdef_object_rep *r;
-
-  if (is_handle_class ())
-    r = new handle_cdef_object ();
+  cdef_object obj = construct_object (args);
+
+  if (! error_state && obj.ok ())
+    return to_ov (obj);
+
+  return octave_value ();
+}
+
+cdef_object
+cdef_class::cdef_class_rep::construct_object (const octave_value_list& args)
+{
+  if (! is_abstract ())
+    {
+      cdef_object obj;
+
+      if (is_meta_class ())
+        {
+          // This code path is only used to create empty meta objects
+          // as filler for the empty values within a meta object array.
+
+          cdef_class this_cls = wrap ();
+
+          static cdef_object empty_class;
+
+          if (this_cls == cdef_class::meta_class ())
+            {
+              if (! empty_class.ok ())
+                empty_class = make_class ("", std::list<cdef_class> ());
+              obj = empty_class;
+            }
+          else if (this_cls == cdef_class::meta_property ())
+            {
+              static cdef_property empty_property;
+
+              if (! empty_class.ok ())
+                empty_class = make_class ("", std::list<cdef_class> ());
+              if (! empty_property.ok ())
+                empty_property = make_property (empty_class, "");
+              obj = empty_property;
+            }
+          else if (this_cls == cdef_class::meta_method ())
+            {
+              static cdef_method empty_method;
+
+              if (! empty_class.ok ())
+                empty_class = make_class ("", std::list<cdef_class> ());
+              if (! empty_method.ok ())
+                empty_method = make_method (empty_class, "", octave_value ());
+              obj = empty_method;
+            }
+          else if (this_cls == cdef_class::meta_package ())
+            {
+              static cdef_package empty_package;
+
+              if (! empty_package.ok ())
+                empty_package = make_package ("");
+              obj = empty_package;
+            }
+          else
+            panic_impossible ();
+
+          return obj;
+        }
+      else
+        {
+          if (is_handle_class ())
+            obj = cdef_object (new handle_cdef_object ());
+          else
+            obj = cdef_object (new value_cdef_object ());
+          obj.set_class (wrap ());
+
+          initialize_object (obj);
+
+          if (! error_state)
+            {
+              run_constructor (obj, args);
+
+              if (! error_state)
+                return obj;
+            }
+        }
+    }
   else
-    r = new value_cdef_object ();
-  r->set_class (wrap ());
-
-  cdef_object obj (r);
-
-  initialize_object (obj);
-
-  if (! error_state)
-    {
-      run_constructor (obj, args);
-
-      if (! error_state)
-        return to_ov (obj);
-    }
-
-  return octave_value();
+    error ("cannot instantiate object for abstract class `%s'",
+           get_name ().c_str ());
+
+  return cdef_object ();
 }
 
 static octave_value
@@ -2443,27 +2703,20 @@
 
   /* bootstrap */
   cdef_class handle = make_class ("handle");
-  cdef_class meta_class = cdef_class::_meta_class = make_class ("meta.class", handle);
+  cdef_class meta_class = cdef_class::_meta_class = make_meta_class ("meta.class", handle);
   handle.set_class (meta_class);
   meta_class.set_class (meta_class);
 
   /* meta classes */
-  cdef_class meta_property = cdef_class::_meta_property = make_class ("meta.property", handle);
-  cdef_class meta_method = cdef_class::_meta_method = make_class ("meta.method", handle);
-  cdef_class meta_package = cdef_class::_meta_package = make_class ("meta.package", handle);
-
-  cdef_class meta_event = make_class ("meta.event", handle);
-  cdef_class meta_dynproperty = make_class ("meta.dynamicproperty", handle);
-
-  /* meta classes are all sealed */
-  meta_class.put ("Sealed", true);
-  meta_property.put ("Sealed", true);
-  meta_method.put ("Sealed", true);
-  meta_package.put ("Sealed", true);
-  meta_event.put ("Sealed", true);
-  meta_dynproperty.put ("Sealed", true);
+  cdef_class meta_property = cdef_class::_meta_property = make_meta_class ("meta.property", handle);
+  cdef_class meta_method = cdef_class::_meta_method = make_meta_class ("meta.method", handle);
+  cdef_class meta_package = cdef_class::_meta_package = make_meta_class ("meta.package", handle);
+
+  cdef_class meta_event = make_meta_class ("meta.event", handle);
+  cdef_class meta_dynproperty = make_meta_class ("meta.dynamicproperty", handle);
 
   /* meta.class properties */
+  meta_class.install_property (make_attribute (meta_class, "Abstract"));
   meta_class.install_property (make_attribute (meta_class, "ConstructOnLoad"));
   meta_class.install_property (make_property  (meta_class, "ContainingPackage"));
   meta_class.install_property (make_property  (meta_class, "Description"));