changeset 10087:090173f2db40

improve overload dispatching of built-in classes
author Jaroslav Hajek <highegg@gmail.com>
date Tue, 12 Jan 2010 13:20:17 +0100
parents 76df75b10c80
children 5edee330d4cb
files src/ChangeLog src/ov-base.cc src/ov-base.h src/ov-cell.h src/ov-fcn-handle.cc src/ov-fcn-handle.h src/ov-struct.h src/symtab.cc src/symtab.h
diffstat 9 files changed, 155 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue Jan 12 09:03:42 2010 +0100
+++ b/src/ChangeLog	Tue Jan 12 13:20:17 2010 +0100
@@ -1,3 +1,18 @@
+2010-01-12  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov-base.h (builtin_type_t): New enum constants: btyp_cell,
+	btyp_struct and btyp_func_handle.
+	(btyp_isinteger, btyp_isfloat, btyp_isarray): New funcs.
+	(btyp_class_name): New array.
+	(get_builtin_classes): New func.
+	* ov-cell.h (octave_cell::builtin_type): New virtual override.
+	* ov-struct.h (octave_struct::builtin_type): New virtual override.
+	* ov-fcn-handle.h (octave_fcn_handle::builtin_type): New virtual override.
+	* symtab.cc (get_dispatch_type): Rewrite. Add overload.
+	* symtab.h: Update decls.
+	* ov-fcn-handle.cc (octave_fcn_handle::do_multi_index_op): Rewrite.
+	(get_builtin_classes): Remove.
+
 2010-01-12  Jaroslav Hajek  <highegg@gmail.com>
 
 	* oct-obj.cc (octave_value_list::any_cell): New method.
--- a/src/ov-base.cc	Tue Jan 12 09:03:42 2010 +0100
+++ b/src/ov-base.cc	Tue Jan 12 13:20:17 2010 +0100
@@ -78,6 +78,36 @@
   return retval;
 }
 
+std::string btyp_class_name[btyp_num_types] = 
+{
+  "double", "single", "double", "single",
+  "int8", "int16", "int32", "int64",
+  "uint8", "uint16", "uint32", "uint64",
+  "logical", "char",
+  "struct", "cell", "function_handle"
+};
+
+string_vector
+get_builtin_classes (void)
+{
+  static string_vector retval;
+
+  if (retval.is_empty ())
+    {
+      int n = btyp_num_types - 2;
+      retval = string_vector (n);
+      int j = 0;
+      for (int i = 0; i < btyp_num_types; i++)
+        {
+          builtin_type_t ityp = static_cast<builtin_type_t> (i);
+          if (ityp != btyp_complex && ityp != btyp_float_complex)
+            retval(j++) = btyp_class_name[i];
+        }
+    }
+
+  return retval;
+}
+
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_base_value,
 				     "<unknown type>", "unknown");
 
--- a/src/ov-base.h	Tue Jan 12 09:03:42 2010 +0100
+++ b/src/ov-base.h	Tue Jan 12 13:20:17 2010 +0100
@@ -71,13 +71,31 @@
   btyp_uint64,
   btyp_bool,
   btyp_char,
+  btyp_struct,
+  btyp_cell,
+  btyp_func_handle,
   btyp_unknown,
   btyp_num_types = btyp_unknown
 };
 
+extern OCTINTERP_API std::string 
+btyp_class_name [btyp_num_types];
+
+extern OCTINTERP_API string_vector
+get_builtin_classes (void); 
+
 inline bool btyp_isnumeric (builtin_type_t btyp)
 { return btyp <= btyp_uint64; }
 
+inline bool btyp_isinteger (builtin_type_t btyp)
+{ return btyp >= btyp_int8 && btyp <= btyp_uint64; }
+
+inline bool btyp_isfloat (builtin_type_t btyp)
+{ return btyp <= btyp_float_complex; }
+
+inline bool btyp_isarray (builtin_type_t btyp)
+{ return btyp <= btyp_char; }
+
 // Compute a numeric type for a possibly mixed-type operation, using these rules:
 // bool -> double
 // single + double -> single
--- a/src/ov-cell.h	Tue Jan 12 09:03:42 2010 +0100
+++ b/src/ov-cell.h	Tue Jan 12 13:20:17 2010 +0100
@@ -119,6 +119,8 @@
 
   bool is_cell (void) const { return true; }
 
+  builtin_type_t builtin_type (void) const { return btyp_cell; }
+
   bool is_cellstr (void) const;
 
   bool is_true (void) const;
--- a/src/ov-fcn-handle.cc	Tue Jan 12 09:03:42 2010 +0100
+++ b/src/ov-fcn-handle.cc	Tue Jan 12 13:20:17 2010 +0100
@@ -131,36 +131,24 @@
       // Possibly overloaded function.
       octave_value ovfcn = 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 ddt = get_dispatch_type (args);
+      std::string dt = get_dispatch_type (args, builtin_class);
 
-      if (ddt.empty ())
+      if (! dt.empty ())
         {
-          // Static dispatch (class of 1st arg)?
-          if (! disp->empty ())
-            {
-              std::string sdt = args(0).class_name ();
-              str_ov_map::iterator pos = disp->find (sdt);
-              if (pos != disp->end ())
-                {
-                  out_of_date_check (pos->second, sdt, false);
-                  ovfcn = pos->second;
-                }
-            }
-        }
-      else
-        {
-          str_ov_map::iterator pos = disp->find (ddt);
+          str_ov_map::iterator pos = disp->find (dt);
           if (pos != disp->end ())
             {
-              out_of_date_check (pos->second, ddt, false);
+              out_of_date_check (pos->second, dt, false);
               ovfcn = pos->second;
             }
-          else
+          else if (! builtin_class)
             {
-              octave_value method = symbol_table::find_method (nm, ddt);
+              octave_value method = symbol_table::find_method (nm, dt);
               if (method.is_defined ())
-                (*disp)[ddt] = ovfcn = method;
+                (*disp)[dt] = ovfcn = method;
             }
         }
 
@@ -168,10 +156,10 @@
         retval = ovfcn.do_multi_index_op (nargout, args);
       else if (fcn.is_undefined ())
         {
-          if (ddt.empty ())
-            ddt = args(0).class_name ();
+          if (dt.empty ())
+            dt = args(0).class_name ();
 
-          error ("no %s method to handle class %s", nm.c_str (), ddt.c_str ());
+          error ("no %s method to handle class %s", nm.c_str (), dt.c_str ());
         }
       else
         error ("invalid function handle");
@@ -1336,40 +1324,6 @@
 			   current_print_indent_level ());
 }
 
-static string_vector
-get_builtin_classes (void)
-{
-  // FIXME: this should really be read from somewhere else.
-  static const char *cnames[15] = {
-      "double",
-      "single",
-      "int8",
-      "int16",
-      "int32",
-      "int64",
-      "uint8",
-      "uint16",
-      "uint32",
-      "uint64",
-      "logical",
-      "char",
-      "cell",
-      "struct",
-      "function_handle"
-  };
-
-  static string_vector retval;
-
-  if (retval.is_empty ())
-    {
-      retval = string_vector (15);
-      for (int i = 0; i < 15; i++)
-        retval(i) = cnames[i];
-    }
-
-  return retval;
-}
-
 octave_value
 make_fcn_handle (const std::string& nm, bool local_funcs)
 {
--- a/src/ov-fcn-handle.h	Tue Jan 12 09:03:42 2010 +0100
+++ b/src/ov-fcn-handle.h	Tue Jan 12 13:20:17 2010 +0100
@@ -87,6 +87,8 @@
 
   bool is_function_handle (void) const { return true; }
 
+  builtin_type_t builtin_type (void) const { return btyp_func_handle; }
+
   bool is_overloaded (void) const { return disp.get () && ! disp->empty (); }
 
   dim_vector dims (void) const { static dim_vector dv (1, 1); return dv; }
--- a/src/ov-struct.h	Tue Jan 12 09:03:42 2010 +0100
+++ b/src/ov-struct.h	Tue Jan 12 13:20:17 2010 +0100
@@ -120,6 +120,8 @@
 
   bool is_map (void) const { return true; }
 
+  builtin_type_t builtin_type (void) const { return btyp_struct; }
+
   Octave_map map_value (void) const { return map; }
 
   string_vector map_keys (void) const { return map.keys (); }
--- a/src/symtab.cc	Tue Jan 12 09:03:42 2010 +0100
+++ b/src/symtab.cc	Tue Jan 12 13:20:17 2010 +0100
@@ -448,9 +448,38 @@
   return retval;
 }
 
+// :-) JWE, can you parse this? Returns a 2D array with second dimension equal
+// to btyp_num_types (static constant). Only the leftmost dimension can be
+// variable in C/C++. Typedefs are boring.
+
+static builtin_type_t (*build_sup_table (void))[btyp_num_types]
+{
+  static builtin_type_t sup_table[btyp_num_types][btyp_num_types];
+  for (int i = 0; i < btyp_num_types; i++)
+    for (int j = 0; j < btyp_num_types; j++)
+      {
+        builtin_type_t ityp = static_cast<builtin_type_t> (i);
+        builtin_type_t jtyp = static_cast<builtin_type_t> (j);
+        // FIXME: Is this really right?
+        bool use_j = 
+          (jtyp == btyp_func_handle || ityp == btyp_bool
+           || (btyp_isarray (ityp) 
+               && (! btyp_isarray (jtyp) 
+                   || (btyp_isinteger (jtyp) && ! btyp_isinteger (ityp))
+                   || ((ityp == btyp_double || ityp == btyp_complex || ityp == btyp_char)
+                       && (jtyp == btyp_float || jtyp == btyp_float_complex)))));
+
+        sup_table[i][j] = use_j ? jtyp : ityp;
+      }
+
+  return sup_table;
+}
+
 std::string
-get_dispatch_type (const octave_value_list& args)
+get_dispatch_type (const octave_value_list& args, 
+                   bool& builtin_class)
 {
+  static builtin_type_t (*sup_table)[btyp_num_types] = build_sup_table ();
   std::string dispatch_type;
 
   int n = args.length ();
@@ -459,39 +488,62 @@
     {
       // Find first object, if any.
 
-      int i;
-
-      for (i = 0; i < n; i++)
+      for (int i = 0; i < n; i++)
 	{
 	  octave_value arg = args(i);
 
 	  if (arg.is_object ())
 	    {
 	      dispatch_type = arg.class_name ();
-	      break;
+              for (int j = i+1; j < n; j++)
+                {
+                  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_class = false;
+              break;
 	    }
 	}
 
-      for (int j = i+1; j < n; j++)
-	{
-	  octave_value arg = args(j);
+      // No object.
 
-	  if (arg.is_object ())
-	    {
-	      std::string cname = arg.class_name ();
+      if (builtin_class)
+        {
+          // Use the builtin_type mechanism to do this by one method call per
+          // element. 
 
-	      // 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_t btyp = args(0).builtin_type ();
+          for (int i = 1; i < n; i++)
+            btyp = sup_table[btyp][args(i).builtin_type ()];
+
+          if (btyp != btyp_unknown)
+            dispatch_type = btyp_class_name[btyp];
+          else
+            builtin_class = false;
+        }
     }
 
   return dispatch_type;
 }
 
+std::string
+get_dispatch_type (const octave_value_list& args)
+{
+  bool builtin_class = true;
+  return get_dispatch_type (args, builtin_class);
+}
+
 // Find the definition of NAME according to the following precedence
 // list:
 //
@@ -639,9 +691,6 @@
     {
       std::string dispatch_type = get_dispatch_type (args);
 
-      if (dispatch_type.empty ())
-        dispatch_type = args(0).class_name ();
-
       octave_value fcn = find_method (dispatch_type);
 
       if (fcn.is_defined ())
--- a/src/symtab.h	Tue Jan 12 09:03:42 2010 +0100
+++ b/src/symtab.h	Tue Jan 12 13:20:17 2010 +0100
@@ -2370,7 +2370,10 @@
                                const std::string& dispatch_type = std::string (),
                                bool check_relative = true);
 
-extern std::string get_dispatch_type (const octave_value_list& args);
+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);
 
 #endif