changeset 10321:97b4bd6f0925

partially rewrite function handles
author Jaroslav Hajek <highegg@gmail.com>
date Sat, 13 Feb 2010 08:17:21 +0100
parents 907d470e261b
children 21551cc88061
files src/ChangeLog src/load-path.cc src/load-path.h src/ov-fcn-handle.cc src/ov-fcn-handle.h src/symtab.cc src/symtab.h
diffstat 7 files changed, 152 insertions(+), 135 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Fri Feb 12 14:53:55 2010 +0100
+++ b/src/ChangeLog	Sat Feb 13 08:17:21 2010 +0100
@@ -1,3 +1,16 @@
+2010-02-13  Jaroslav Hajek  <highegg@gmail.com>
+
+	* load-path.cc (load_path::do_any_class_method): Rename to
+	do_overloads. Return a list of classes.
+	* load-path.h (load_path::any_class_method): Likewise.
+	* symtab.cc (get_dispatch_type): Rewrite.
+	* symtab.h (get_dispatch_type): Update decl.
+	* ov-fcn-handle.h (octave_fcn_handle): Partially rewrite.
+	(octave_fcn_handle::builtin_overloads, octave_fcn_handle::overloads,
+	octave_fcn_handle::has_overloads): New members.
+	* ov-fcn-handle.cc (octave_fcn_handle::do_multi_index_op): Rewrite.
+	(make_fcn_handle): Partially rewrite.
+
 2010-02-11  John W. Eaton  <jwe@octave.org>
 
 	* DLD-FUNCTIONS/config-module.awk, genprops.awk, graphics.h.in,
--- a/src/load-path.cc	Fri Feb 12 14:53:55 2010 +0100
+++ b/src/load-path.cc	Sat Feb 13 08:17:21 2010 +0100
@@ -1075,10 +1075,10 @@
   return retval;
 }
 
-bool
-load_path::do_any_class_method (const std::string& meth) const
+std::list<std::string>
+load_path::do_overloads (const std::string& meth) const
 {
-  bool retval = false;
+  std::list<std::string> retval;
 
   //  update ();
 
@@ -1088,10 +1088,7 @@
       const fcn_map_type& m = q->second;
 
       if (m.find (meth) != m.end ())
-        {
-          retval = true;
-          break;
-        }
+        retval.push_back (q->first);
     }
 
   return retval;
--- a/src/load-path.h	Fri Feb 12 14:53:55 2010 +0100
+++ b/src/load-path.h	Sat Feb 13 08:17:21 2010 +0100
@@ -108,10 +108,10 @@
       ? instance->do_methods (class_name) : std::list<std::string> ();
   }
 
-  static bool any_class_method (const std::string& meth)
+  static std::list<std::string> overloads (const std::string& meth)
   {
     return instance_ok ()
-      ? instance->do_any_class_method (meth) : false;
+      ? instance->do_overloads (meth) : std::list<std::string> ();
   }
 
   static std::string find_fcn (const std::string& fcn, std::string& dir_name)
@@ -479,7 +479,7 @@
 
   std::list<std::string> do_methods (const std::string& class_name) const;
 
-  bool do_any_class_method (const std::string& meth) const;
+  std::list<std::string> do_overloads (const std::string& meth) const;
 
   std::string do_find_file (const std::string& file) const;
 
--- a/src/ov-fcn-handle.cc	Fri Feb 12 14:53:55 2010 +0100
+++ b/src/ov-fcn-handle.cc	Sat Feb 13 08:17:21 2010 +0100
@@ -72,7 +72,7 @@
 
 octave_fcn_handle::octave_fcn_handle (const octave_value& f,
                                       const std::string& n)
-  : fcn (f), nm (n)
+  : fcn (f), nm (n), has_overloads (false)
 {
   octave_user_function *uf = fcn.user_function_value (true);
 
@@ -125,46 +125,39 @@
 {
   octave_value_list retval;
 
-  if (fcn.is_defined ())
-    out_of_date_check (fcn, std::string (), false);
+  out_of_date_check (fcn, std::string (), false);
 
-  if (disp.get () && ! args.empty ())
+  if (has_overloads)
     {
       // Possibly overloaded function.
-      octave_value ovfcn = fcn;
+      octave_value ov_fcn;
 
-      // No need to compute built-in class dispatch if we don't have builtin class overloads.
-      bool builtin_class = ! disp->empty ();
-      // Get dynamic (class) dispatch type.
-      std::string dt = get_dispatch_type (args, builtin_class);
+      // Compute dispatch type.
+      builtin_type_t btyp;
+      std::string dispatch_type = get_dispatch_type (args, btyp);
 
-      if (! dt.empty ())
+      // Retrieve overload.
+      if (btyp != btyp_unknown)
         {
-          str_ov_map::iterator pos = disp->find (dt);
-          if (pos != disp->end ())
+          out_of_date_check (builtin_overloads[btyp], dispatch_type, false);
+          ov_fcn = builtin_overloads[btyp];
+        }
+      else
+        {
+          str_ov_map::iterator it = overloads.find (dispatch_type);
+          if (it != overloads.end ())
             {
-              out_of_date_check (pos->second, dt, false);
-              ovfcn = pos->second;
-            }
-          else if (! builtin_class)
-            {
-              octave_value method = symbol_table::find_method (nm, dt);
-              if (method.is_defined ())
-                (*disp)[dt] = ovfcn = method;
+              out_of_date_check (it->second, dispatch_type, false);
+              ov_fcn = it->second;
             }
         }
 
-      if (ovfcn.is_defined ())
-        retval = ovfcn.do_multi_index_op (nargout, args);
-      else if (fcn.is_undefined ())
-        {
-          if (dt.empty ())
-            dt = args(0).class_name ();
-
-          error ("no %s method to handle class %s", nm.c_str (), dt.c_str ());
-        }
+      if (ov_fcn.is_defined ())
+        retval = ov_fcn.do_multi_index_op (nargout, args);
+      else if (fcn.is_defined ())
+        retval = fcn.do_multi_index_op (nargout, args);
       else
-        error ("invalid function handle");
+        error ("%s: no method for class %s", nm.c_str (), dispatch_type.c_str ());
     }
   else
     {
@@ -172,7 +165,7 @@
       if (fcn.is_defined ())
         retval = fcn.do_multi_index_op (nargout, args);
       else
-        error ("invalid function handle");
+        error ("%s: no longer valid function handle", nm.c_str ());
     }
 
   return retval;
@@ -1463,49 +1456,57 @@
   bool handle_ok = false;
   octave_value f = symbol_table::find_function (tnm, octave_value_list (),
                                                 local_funcs);
+  octave_function *fptr = f.function_value (true);
 
-  if (f.is_undefined ())
+  if (local_funcs && fptr 
+      && (fptr->is_nested_function () || fptr->is_private_function ()
+          || fptr->is_class_constructor ()))
     {
-      if (load_path::any_class_method (tnm))
-        handle_ok = true;
-      else
-        {
-          load_path::update ();
-          if (load_path::any_class_method (tnm))
-            handle_ok = true;
-        }
+      // Locally visible function.
+      retval = octave_value (new octave_fcn_handle (f, tnm));
     }
   else
-    handle_ok = true;
-
-  octave_function *fptr = f.is_defined () ? f.function_value () : 0;
-
+    {
+      // Globally visible (or no match yet). Query overloads.
+      std::list<std::string> classes = load_path::overloads (tnm);
+      bool any_match = fptr != 0 || classes.size () > 0;
+      if (! any_match)
+        {
+          // No match found, try updating load_path and query classes again.
+          load_path::update ();
+          classes = load_path::overloads (tnm);
+          any_match = classes.size () > 0;
+        }
 
-  if (handle_ok)
-    {
-      // If it's a subfunction, private function, or class constructor,
-      // we want no dispatch.
-      if (fptr && (fptr->is_nested_function () || fptr->is_private_function ()
-          || fptr->is_class_constructor ()))
-        retval = octave_value (new octave_fcn_handle (f, tnm));
-      else
+      if (any_match)
         {
-          typedef octave_fcn_handle::str_ov_map str_ov_map;
-          std::auto_ptr<str_ov_map> disp (new str_ov_map);
-          const string_vector cnames = get_builtin_classes ();
-          for (octave_idx_type i = 0; i < cnames.length (); i++)
+          octave_fcn_handle *fh = new octave_fcn_handle (f, tnm);
+          retval = fh;
+
+          for (std::list<std::string>::iterator iter = classes.begin ();
+               iter != classes.end (); iter++)
             {
-              std::string cnam = cnames(i);
-              octave_value method = symbol_table::find_method (tnm, cnam);
-              if (method.is_defined ())
-                (*disp)[cnam] = method;
-            }
+              std::string class_name = *iter;
+              octave_value fmeth = symbol_table::find_method (tnm, class_name);
 
-          retval = octave_value (new octave_fcn_handle (f, tnm, disp.release ()));
+              bool is_builtin = false;
+              for (int i = 0; i < btyp_num_types; i++)
+                {
+                  // FIXME: Too slow? Maybe binary lookup?
+                  if (class_name == btyp_class_name[i])
+                    {
+                      is_builtin = true;
+                      fh->set_overload (static_cast<builtin_type_t> (i), fmeth);
+                    }
+                }
+
+              if (! is_builtin)
+                fh->set_overload (class_name, fmeth);
+            }
         }
+      else
+        error ("@%s: no function and no method found", tnm.c_str ());
     }
-  else
-    error ("error creating function handle \"@%s\"", nm.c_str ());
 
   return retval;
 }
--- a/src/ov-fcn-handle.h	Fri Feb 12 14:53:55 2010 +0100
+++ b/src/ov-fcn-handle.h	Sat Feb 13 08:17:21 2010 +0100
@@ -44,27 +44,26 @@
 
   typedef std::map<std::string, octave_value> str_ov_map;
 
-  octave_fcn_handle (const octave_value& f, const std::string& n,
-                     str_ov_map *sdisp)
-    : fcn (f), nm (n), disp (sdisp) { }
-
 public:
 
   static const std::string anonymous;
 
   octave_fcn_handle (void)
-    : fcn (), nm () { }
+    : fcn (), nm (), has_overloads (false) { }
 
   octave_fcn_handle (const std::string& n)
-    : fcn (), nm (n) { }
+    : fcn (), nm (n), has_overloads (false) { }
 
   octave_fcn_handle (const octave_value& f,  const std::string& n = anonymous);
 
   octave_fcn_handle (const octave_fcn_handle& fh)
-    : octave_base_value (fh), fcn (fh.fcn), nm (fh.nm)
-   { 
-     if (fh.disp.get ())
-       disp.reset (new str_ov_map (*fh.disp));
+    : octave_base_value (fh), fcn (fh.fcn), nm (fh.nm),
+    has_overloads (fh.has_overloads)
+   {
+     for (int i = 0; i < btyp_num_types; i++)
+       builtin_overloads[i] = fh.builtin_overloads[i];
+
+     overloads = fh.overloads;
    }
 
   ~octave_fcn_handle (void) { }
@@ -92,7 +91,7 @@
 
   builtin_type_t builtin_type (void) const { return btyp_func_handle; }
 
-  bool is_overloaded (void) const { return disp.get () && ! disp->empty (); }
+  bool is_overloaded (void) const { return has_overloads; }
 
   dim_vector dims (void) const { static dim_vector dv (1, 1); return dv; }
 
@@ -108,6 +107,22 @@
 
   std::string fcn_name (void) const { return nm; }
 
+  void set_overload (builtin_type_t btyp, const octave_value& ov_fcn)
+    {
+      if (btyp != btyp_unknown)
+        {
+          has_overloads = true;
+          builtin_overloads[btyp] = ov_fcn;
+        }
+
+    }
+
+  void set_overload (const std::string& dispatch_type, const octave_value& ov_fcn)
+    {
+      has_overloads = true;
+      overloads[dispatch_type] = ov_fcn;
+    }
+
   bool save_ascii (std::ostream& os);
 
   bool load_ascii (std::istream& is);
@@ -143,9 +158,14 @@
   // The name of the handle, including the "@".
   std::string nm;
 
-  // A pointer to statical dispatch to standard classes. If null, we don't want
-  // to dispatch at all.
-  std::auto_ptr<str_ov_map> disp;
+  // Whether the function is overloaded at all.
+  bool has_overloads;
+
+  // Overloads for builtin types. We use array to make lookup faster.
+  octave_value builtin_overloads[btyp_num_types];
+
+  // Overloads for other classes.
+  str_ov_map overloads;
 
   friend octave_value make_fcn_handle (const std::string &, bool);
 };
--- a/src/symtab.cc	Fri Feb 12 14:53:55 2010 +0100
+++ b/src/symtab.cc	Sat Feb 13 08:17:21 2010 +0100
@@ -477,7 +477,7 @@
 
 std::string
 get_dispatch_type (const octave_value_list& args, 
-                   bool& builtin_class)
+                   builtin_type_t& builtin_type)
 {
   static builtin_type_t (*sup_table)[btyp_num_types] = build_sup_table ();
   std::string dispatch_type;
@@ -486,63 +486,49 @@
 
   if (n > 0)
     {
-      // Find first object, if any.
-
-      for (int i = 0; i < n; i++)
+      int i = 0;
+      builtin_type = args(0).builtin_type ();
+      if (builtin_type != btyp_unknown)
         {
-          octave_value arg = args(i);
-
-          if (arg.is_object ())
+          for (i = 1; i < n; i++)
             {
-              dispatch_type = arg.class_name ();
-              for (int j = i+1; j < n; j++)
+              builtin_type_t bti = args(i).builtin_type ();
+              if (bti != btyp_unknown)
+                builtin_type = sup_table[builtin_type][bti];
+              else
                 {
-                  octave_value arg1 = args(j);
-
-                  if (arg1.is_object ())
-                    {
-                      std::string cname = arg1.class_name ();
-
-                      // Only switch to type of ARG if it is marked superior
-                      // to the current DISPATCH_TYPE.
-                      if (! symbol_table::is_superiorto (dispatch_type, cname)
-                          && symbol_table::is_superiorto (cname, dispatch_type))
-                        dispatch_type = cname;
-                    }
+                  builtin_type = btyp_unknown;
+                  break;
                 }
-
-              builtin_class = false;
-              break;
             }
         }
 
-      // No object.
+      if (builtin_type == btyp_unknown)
+        {
+          // There's a non-builtin class in the argument list.
+          dispatch_type = args(i).class_name ();
 
-      if (builtin_class)
-        {
-          // Use the builtin_type mechanism to do this by one method call per
-          // element. 
+          for (int j = i+1; j < n; j++)
+            {
+              octave_value arg = args(j);
 
-          int i = 0;
-          builtin_type_t btyp = args(0).builtin_type ();
-          if (btyp != btyp_unknown)
-            {
-              for (i = 1; i < n; i++)
+              if (arg.builtin_type () == btyp_unknown)
                 {
-                  builtin_type_t bti = args(i).builtin_type ();
-                  if (bti == btyp_unknown)
-                    break;
-                  btyp = sup_table[btyp][bti];
+                  std::string cname = arg.class_name ();
+
+                  // Only switch to type of ARG if it is marked superior
+                  // to the current DISPATCH_TYPE.
+                  if (! symbol_table::is_superiorto (dispatch_type, cname)
+                      && symbol_table::is_superiorto (cname, dispatch_type))
+                    dispatch_type = cname;
                 }
             }
-
-          // If there was an unknown type, we just take the class name of that value.
-          if (i == n)
-            dispatch_type = btyp_class_name[btyp];
-          else
-            dispatch_type = args(i).class_name ();
         }
+      else
+        dispatch_type = btyp_class_name[builtin_type];
     }
+  else
+    builtin_type = btyp_unknown;
 
   return dispatch_type;
 }
@@ -550,8 +536,8 @@
 std::string
 get_dispatch_type (const octave_value_list& args)
 {
-  bool builtin_class = true;
-  return get_dispatch_type (args, builtin_class);
+  builtin_type_t builtin_type;
+  return get_dispatch_type (args, builtin_type);
 }
 
 // Find the definition of NAME according to the following precedence
--- a/src/symtab.h	Fri Feb 12 14:53:55 2010 +0100
+++ b/src/symtab.h	Sat Feb 13 08:17:21 2010 +0100
@@ -2373,6 +2373,6 @@
 extern OCTINTERP_API std::string
 get_dispatch_type (const octave_value_list& args);
 extern OCTINTERP_API std::string
-get_dispatch_type (const octave_value_list& args, bool& builtin_class);
+get_dispatch_type (const octave_value_list& args, builtin_type_t& builtin_type);
 
 #endif