diff src/ov-fcn-handle.cc @ 10321:97b4bd6f0925

partially rewrite function handles
author Jaroslav Hajek <highegg@gmail.com>
date Sat, 13 Feb 2010 08:17:21 +0100
parents 57a59eae83cc
children 21551cc88061
line wrap: on
line diff
--- 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;
 }