changeset 8345:c777f3ce02d8

smarter conversion lookup
author Jaroslav Hajek <highegg@gmail.com>
date Tue, 25 Nov 2008 14:04:55 +0100
parents b5f10b123440
children 8302788f09db
files src/ChangeLog src/ov-base.cc src/ov-base.h src/ov-bool-mat.cc src/ov-bool-mat.h src/ov-bool-sparse.cc src/ov-bool-sparse.h src/ov-bool.cc src/ov-bool.h src/ov-complex.cc src/ov-complex.h src/ov-cx-mat.cc src/ov-cx-mat.h src/ov-null-mat.cc src/ov-null-mat.h src/ov-range.cc src/ov-range.h src/ov-re-mat.cc src/ov-re-mat.h src/ov-scalar.cc src/ov-scalar.h src/ov-str-mat.cc src/ov-str-mat.h src/ov.cc src/ov.h
diffstat 25 files changed, 145 insertions(+), 171 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,19 @@
+2008-11-25  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov-base.h (octave_base_value::type_conv_info): New class.
+	* ov-base.h, ov-bool-mat.cc, ov-bool-mat.h, ov-bool-sparse.cc,
+	ov-bool-sparse.h, ov-bool.cc, ov-bool.h, ov-complex.cc, ov-complex.h,
+	ov-cx-mat.cc, ov-cx-mat.h, ov-null-mat.cc, ov-null-mat.h,
+	ov-range.cc, ov-range.h, ov-re-mat.cc, ov-re-mat.h, ov-scalar.cc,
+	ov-scalar.h, ov-str-mat.cc, ov-str-mat.h, ov.h:
+	Return type_conv_info instead of type_conv_fcn from
+	numeric_conversion_function and numeric_demotion_function
+	methods.
+	* ov-base.cc (octave_base_value::numeric_assign): Try biased conversion
+	first if possible.
+	* ov.cc (do_binary_op): Likewise. Also, search recursively.
+	* ov.cc (do_cat_op): Likewise.
+
 2008-11-24  David Bateman  <dbateman@free.fr>
 
 	* graphics.cc (F__go_delete__): Check validity of handles before
--- a/src/ov-base.cc
+++ b/src/ov-base.cc
@@ -1150,9 +1150,26 @@
 	{
 	  octave_value tmp_rhs;
 
-	  octave_base_value::type_conv_fcn cf_rhs
+	  octave_base_value::type_conv_info cf_rhs
 	    = rhs.numeric_conversion_function ();
 
+	  octave_base_value::type_conv_info cf_this
+	    = numeric_conversion_function ();
+
+          // Try biased (one-sided) conversions first.
+          if (cf_rhs.type_id () >= 0
+              && (octave_value_typeinfo::lookup_assign_op (octave_value::op_asn_eq,
+                                                           t_lhs, cf_rhs.type_id ())
+                  || octave_value_typeinfo::lookup_pref_assign_conv (t_lhs, 
+                                                                     cf_rhs.type_id ()) >= 0))
+            cf_this = 0;
+          else if (cf_this.type_id () >= 0
+                   && (octave_value_typeinfo::lookup_assign_op (octave_value::op_asn_eq,
+                                                                cf_this.type_id (), t_rhs)
+                       || octave_value_typeinfo::lookup_pref_assign_conv (cf_this.type_id (),
+                                                                          t_rhs) >= 0))
+            cf_rhs = 0;
+
 	  if (cf_rhs)
 	    {
 	      octave_base_value *tmp = cf_rhs (rhs.get_rep ());
@@ -1169,9 +1186,6 @@
 	  else
 	    tmp_rhs = rhs;
 
-	  octave_base_value::type_conv_fcn cf_this
-	    = numeric_conversion_function ();
-
 	  count++;
 	  octave_value tmp_lhs = octave_value (this);
 
--- a/src/ov-base.h
+++ b/src/ov-base.h
@@ -106,6 +106,24 @@
 
   typedef octave_base_value * (*type_conv_fcn) (const octave_base_value&);
 
+  // type conversion, including result type information
+  class type_conv_info
+  {
+  public:
+    type_conv_info (type_conv_fcn f = 0, int t = -1) : _fcn (f), _type_id (t) { }
+
+    operator type_conv_fcn (void) const { return _fcn; }
+
+    octave_base_value * operator () (const octave_base_value &v) const 
+      { return (*_fcn) (v); }
+
+    int type_id (void) const { return _type_id; }
+
+  private:
+    type_conv_fcn _fcn;
+    int _type_id;
+  };
+
   friend class octave_value;
 
   octave_base_value (void) : count (1) { }
@@ -120,13 +138,13 @@
   virtual octave_base_value *
   empty_clone (void) const { return new octave_base_value (); }
 
-  virtual type_conv_fcn
+  virtual type_conv_info
   numeric_conversion_function (void) const
-    { return static_cast<type_conv_fcn> (0); }
+    { return type_conv_info (); }
 
-  virtual type_conv_fcn
+  virtual type_conv_info
   numeric_demotion_function (void) const
-    { return static_cast<type_conv_fcn> (0); }
+    { return type_conv_info (); }
 
   virtual octave_value squeeze (void) const;
 
--- a/src/ov-bool-mat.cc
+++ b/src/ov-bool-mat.cc
@@ -62,10 +62,11 @@
   return new octave_matrix (NDArray (v.bool_array_value ()));
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_bool_matrix::numeric_conversion_function (void) const
 {
-  return default_numeric_conversion_function;
+  return octave_base_value::type_conv_info (default_numeric_conversion_function,
+                                            octave_matrix::static_type_id ());
 }
 
 octave_base_value *
--- a/src/ov-bool-mat.h
+++ b/src/ov-bool-mat.h
@@ -73,7 +73,7 @@
   octave_base_value *clone (void) const { return new octave_bool_matrix (*this); }
   octave_base_value *empty_clone (void) const { return new octave_bool_matrix (); }
 
-  type_conv_fcn numeric_conversion_function (void) const;
+  type_conv_info numeric_conversion_function (void) const;
 
   octave_base_value *try_narrowing_conversion (void);
 
--- a/src/ov-bool-sparse.cc
+++ b/src/ov-bool-sparse.cc
@@ -58,10 +58,11 @@
   return new octave_sparse_matrix (SparseMatrix (v.sparse_bool_matrix_value ()));
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_sparse_bool_matrix::numeric_conversion_function (void) const
 {
-  return default_numeric_conversion_function;
+  return octave_base_value::type_conv_info (default_numeric_conversion_function,
+                                            octave_sparse_matrix::static_type_id ());
 }
 
 octave_base_value *
--- a/src/ov-bool-sparse.h
+++ b/src/ov-bool-sparse.h
@@ -80,7 +80,7 @@
   octave_base_value *clone (void) const { return new octave_sparse_bool_matrix (*this); }
   octave_base_value *empty_clone (void) const { return new octave_sparse_bool_matrix (); }
 
-  type_conv_fcn numeric_conversion_function (void) const;
+  type_conv_info numeric_conversion_function (void) const;
 
   octave_base_value *try_narrowing_conversion (void);
 
--- a/src/ov-bool.cc
+++ b/src/ov-bool.cc
@@ -58,10 +58,12 @@
   return new octave_scalar (v.bool_value ());
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_bool::numeric_conversion_function (void) const
 {
-  return default_numeric_conversion_function;
+  return octave_base_value::type_conv_info (default_numeric_conversion_function,
+                                            octave_scalar::static_type_id ());
+
 }
 
 static inline bool
--- a/src/ov-bool.h
+++ b/src/ov-bool.h
@@ -66,7 +66,7 @@
   octave_base_value *clone (void) const { return new octave_bool (*this); }
   octave_base_value *empty_clone (void) const { return new octave_bool (); }
 
-  type_conv_fcn numeric_conversion_function (void) const;
+  type_conv_info numeric_conversion_function (void) const;
 
   octave_value do_index_op (const octave_value_list& idx,
 			    bool resize_ok = false);
--- a/src/ov-complex.cc
+++ b/src/ov-complex.cc
@@ -63,10 +63,11 @@
   return new octave_float_complex (v.float_complex_value ());
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_complex::numeric_demotion_function (void) const
 {
-  return default_numeric_demotion_function;
+  return octave_base_value::type_conv_info(default_numeric_demotion_function,
+                                           octave_float_complex::static_type_id ());
 }
 
 octave_base_value *
--- a/src/ov-complex.h
+++ b/src/ov-complex.h
@@ -73,7 +73,7 @@
   octave_base_value *empty_clone (void) const
     { return new octave_complex_matrix (); }
 
-  type_conv_fcn numeric_demotion_function (void) const;
+  type_conv_info numeric_demotion_function (void) const;
 
   octave_base_value *try_narrowing_conversion (void);
 
--- a/src/ov-cx-mat.cc
+++ b/src/ov-cx-mat.cc
@@ -69,10 +69,11 @@
   return new octave_float_complex_matrix (v.float_complex_matrix_value ());
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_complex_matrix::numeric_demotion_function (void) const
 {
-  return default_numeric_demotion_function;
+  return octave_base_value::type_conv_info(default_numeric_demotion_function,
+                                           octave_float_complex_matrix::static_type_id ());
 }
 
 octave_base_value *
--- a/src/ov-cx-mat.h
+++ b/src/ov-cx-mat.h
@@ -86,7 +86,7 @@
   octave_base_value *clone (void) const { return new octave_complex_matrix (*this); }
   octave_base_value *empty_clone (void) const { return new octave_complex_matrix (); }
 
-  type_conv_fcn numeric_demotion_function (void) const;
+  type_conv_info numeric_demotion_function (void) const;
 
   octave_base_value *try_narrowing_conversion (void);
 
--- a/src/ov-null-mat.cc
+++ b/src/ov-null-mat.cc
@@ -40,10 +40,11 @@
   return a.empty_clone ();
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_null_matrix::numeric_conversion_function (void) const
 {
-  return default_null_matrix_numeric_conversion_function;
+  return octave_base_value::type_conv_info (default_null_matrix_numeric_conversion_function, 
+                                            octave_matrix::static_type_id ());
 }
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_null_str, "null_string", "char");
@@ -58,10 +59,11 @@
   return a.empty_clone ();
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_null_str::numeric_conversion_function (void) const
 {
-  return default_null_str_numeric_conversion_function;
+  return octave_base_value::type_conv_info (default_null_str_numeric_conversion_function, 
+                                            octave_char_matrix_str::static_type_id ());
 }
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_null_sq_str, "null_sq_string", "char");
@@ -76,10 +78,11 @@
   return a.empty_clone ();
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_null_sq_str::numeric_conversion_function (void) const
 {
-  return default_null_sq_str_numeric_conversion_function;
+  return octave_base_value::type_conv_info (default_null_sq_str_numeric_conversion_function, 
+                                            octave_char_matrix_sq_str::static_type_id ());
 }
 
 DEFUN (isnull, args, ,
--- a/src/ov-null-mat.h
+++ b/src/ov-null-mat.h
@@ -47,7 +47,7 @@
 
   bool is_null_value (void) const { return true; }
 
-  type_conv_fcn numeric_conversion_function (void) const;
+  type_conv_info numeric_conversion_function (void) const;
 
 private:
 
@@ -68,7 +68,7 @@
 
   bool is_null_value (void) const { return true; }
 
-  type_conv_fcn numeric_conversion_function (void) const;
+  type_conv_info numeric_conversion_function (void) const;
 
 
 private:
@@ -90,7 +90,7 @@
 
   bool is_null_value (void) const { return true; }
 
-  type_conv_fcn numeric_conversion_function (void) const;
+  type_conv_info numeric_conversion_function (void) const;
 
 private:
 
--- a/src/ov-range.cc
+++ b/src/ov-range.cc
@@ -54,10 +54,11 @@
   return new octave_matrix (v.matrix_value ());
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_range::numeric_conversion_function (void) const
 {
-  return default_numeric_conversion_function;
+  return octave_base_value::type_conv_info (default_numeric_conversion_function,
+                                            octave_matrix::static_type_id ());
 }
 
 octave_base_value *
--- a/src/ov-range.h
+++ b/src/ov-range.h
@@ -84,7 +84,7 @@
   // to create an empty matrix (0x0) instead of an empty range (1x0).
   octave_base_value *empty_clone (void) const { return new octave_matrix (); }
 
-  type_conv_fcn numeric_conversion_function (void) const;
+  type_conv_info numeric_conversion_function (void) const;
 
   octave_base_value *try_narrowing_conversion (void);
 
--- a/src/ov-re-mat.cc
+++ b/src/ov-re-mat.cc
@@ -81,10 +81,11 @@
   return new octave_float_matrix (v.float_matrix_value ());
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_matrix::numeric_demotion_function (void) const
 {
-  return default_numeric_demotion_function;
+  return octave_base_value::type_conv_info(default_numeric_demotion_function,
+                                           octave_float_matrix::static_type_id ());
 }
 
 octave_base_value *
--- a/src/ov-re-mat.h
+++ b/src/ov-re-mat.h
@@ -86,7 +86,7 @@
   octave_base_value *clone (void) const { return new octave_matrix (*this); }
   octave_base_value *empty_clone (void) const { return new octave_matrix (); }
 
-  type_conv_fcn numeric_demotion_function (void) const;
+  type_conv_info numeric_demotion_function (void) const;
 
   octave_base_value *try_narrowing_conversion (void);
 
--- a/src/ov-scalar.cc
+++ b/src/ov-scalar.cc
@@ -65,10 +65,11 @@
   return new octave_float_scalar (v.float_value ());
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_scalar::numeric_demotion_function (void) const
 {
-  return default_numeric_demotion_function;
+  return octave_base_value::type_conv_info(default_numeric_demotion_function,
+                                           octave_float_scalar::static_type_id ());
 }
 
 octave_value
--- a/src/ov-scalar.h
+++ b/src/ov-scalar.h
@@ -76,7 +76,7 @@
   octave_value do_index_op (const octave_value_list& idx,
 			    bool resize_ok = false);
 
-  type_conv_fcn numeric_demotion_function (void) const;
+  type_conv_info numeric_demotion_function (void) const;
 
   idx_vector index_vector (void) const { return idx_vector (scalar); }
 
--- a/src/ov-str-mat.cc
+++ b/src/ov-str-mat.cc
@@ -66,21 +66,16 @@
 
   NDArray nda = v.array_value (true);
 
-  if (! error_state)
-    {
-      if (nda.numel () == 1)
-	retval = new octave_scalar (nda(0));
-      else
-	retval = new octave_matrix (nda);
-    }
+  if (! error_state) retval = new octave_matrix (nda);
 
   return retval;
 }
 
-octave_base_value::type_conv_fcn
+octave_base_value::type_conv_info
 octave_char_matrix_str::numeric_conversion_function (void) const
 {
-  return default_numeric_conversion_function;
+  return octave_base_value::type_conv_info (default_numeric_conversion_function,
+                                            octave_matrix::static_type_id ());
 }
 
 octave_value
--- a/src/ov-str-mat.h
+++ b/src/ov-str-mat.h
@@ -85,7 +85,7 @@
   octave_base_value *clone (void) const { return new octave_char_matrix_str (*this); }
   octave_base_value *empty_clone (void) const { return new octave_char_matrix_str (); }
 
-  type_conv_fcn numeric_conversion_function (void) const;
+  type_conv_info numeric_conversion_function (void) const;
 
   octave_value do_index_op (const octave_value_list& idx,
 			    bool resize_ok = false)
--- a/src/ov.cc
+++ b/src/ov.cc
@@ -1614,7 +1614,18 @@
       else
 	{
 	  octave_value tv1;
-	  octave_base_value::type_conv_fcn cf1 = v1.numeric_conversion_function ();
+	  octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function ();
+
+	  octave_value tv2;
+	  octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function ();
+
+          // Try biased (one-sided) conversions first.
+          if (cf2.type_id () >= 0 &&
+              octave_value_typeinfo::lookup_binary_op (op, t1, cf2.type_id ()))
+            cf1 = 0;
+          else if (cf1.type_id () >= 0 &&
+                   octave_value_typeinfo::lookup_binary_op (op, cf1.type_id (), t2))
+            cf2 = 0;
 
 	  if (cf1)
 	    {
@@ -1634,9 +1645,6 @@
 	  else
 	    tv1 = v1;
 
-	  octave_value tv2;
-	  octave_base_value::type_conv_fcn cf2 = v2.numeric_conversion_function ();
-
 	  if (cf2)
 	    {
 	      octave_base_value *tmp = cf2 (*v2.rep);
@@ -1657,87 +1665,23 @@
 
 	  if (cf1 || cf2)
 	    {
-	      f = octave_value_typeinfo::lookup_binary_op (op, t1, t2);
-
-	      if (f)
-		{
-		  try
-		    {
-		      retval = f (*tv1.rep, *tv2.rep);
-		    }
-		  catch (octave_execution_exception)
-		    {
-		      gripe_library_execution_error ();
-		    }
-		}
-	      else
-		{
-		  //demote double -> single and try again
-		  cf1 = tv1.numeric_demotion_function ();
-
-		  if (cf1)
-		    {
-		      octave_base_value *tmp = cf1 (*tv1.rep);
-
-		      if (tmp)
-			{
-			  tv1 = octave_value (tmp);
-			  t1 = tv1.type_id ();
-			}
-		      else
-			{
-			  gripe_binary_op_conv (octave_value::binary_op_as_string (op));
-			  return retval;
-			}
-		    }
-
-		  cf2 = tv2.numeric_demotion_function ();
-
-		  if (cf2)
-		    {
-		      octave_base_value *tmp = cf2 (*tv2.rep);
-
-		      if (tmp)
-			{
-			  tv2 = octave_value (tmp);
-			  t2 = tv2.type_id ();
-			}
-		      else
-			{
-			  gripe_binary_op_conv (octave_value::binary_op_as_string (op));
-			  return retval;
-			}
-		    }
-
-		  if (cf1 || cf2)
-		    {
-		      f = octave_value_typeinfo::lookup_binary_op (op, t1, t2);
-
-		      if (f)
-			{
-			  try
-			    {
-			      retval = f (*tv1.rep, *tv2.rep);
-			    }
-			  catch (octave_execution_exception)
-			    {
-			      gripe_library_execution_error ();
-			    }
-			}
-		      else
-			gripe_binary_op (octave_value::binary_op_as_string (op),
-					 v1.type_name (), v2.type_name ());
-		    }
-		  else
-		    gripe_binary_op (octave_value::binary_op_as_string (op),
-				     v1.type_name (), v2.type_name ());
-		}
+              retval = do_binary_op (op, tv1, tv2);
 	    }
 	  else
 	    {
 	      //demote double -> single and try again
 	      cf1 = tv1.numeric_demotion_function ();
 
+	      cf2 = tv2.numeric_demotion_function ();
+
+              // Try biased (one-sided) conversions first.
+              if (cf2.type_id () >= 0
+                  && octave_value_typeinfo::lookup_binary_op (op, t1, cf2.type_id ()))
+                cf1 = 0;
+              else if (cf1.type_id () >= 0
+                       && octave_value_typeinfo::lookup_binary_op (op, cf1.type_id (), t2))
+                cf2 = 0;
+
 	      if (cf1)
 		{
 		  octave_base_value *tmp = cf1 (*tv1.rep);
@@ -1754,8 +1698,6 @@
 		    }
 		}
 
-	      cf2 = tv2.numeric_demotion_function ();
-
 	      if (cf2)
 		{
 		  octave_base_value *tmp = cf2 (*tv2.rep);
@@ -1931,7 +1873,18 @@
   else
     {
       octave_value tv1;
-      octave_base_value::type_conv_fcn cf1 = v1.numeric_conversion_function ();
+      octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function ();
+
+      octave_value tv2;
+      octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function ();
+
+      // Try biased (one-sided) conversions first.
+      if (cf2.type_id () >= 0
+          && octave_value_typeinfo::lookup_cat_op (t1, cf2.type_id ()))
+        cf1 = 0;
+      else if (cf1.type_id () >= 0
+               && octave_value_typeinfo::lookup_cat_op (cf1.type_id (), t2))
+        cf2 = 0;
 
       if (cf1)
 	{
@@ -1951,9 +1904,6 @@
       else
 	tv1 = v1;
 
-      octave_value tv2;
-      octave_base_value::type_conv_fcn cf2 = v2.numeric_conversion_function ();
-
       if (cf2)
 	{
 	  octave_base_value *tmp = cf2 (*v2.rep);
@@ -1974,21 +1924,7 @@
 
       if (cf1 || cf2)
 	{
-	  f = octave_value_typeinfo::lookup_cat_op (t1, t2);
-
-	  if (f)
-	    {
-	      try
-		{
-		  retval = f (*tv1.rep, *tv2.rep, ra_idx);
-		}
-	      catch (octave_execution_exception)
-		{
-		  gripe_library_execution_error ();
-		}
-	    }
-	  else
-	    gripe_cat_op (v1.type_name (), v2.type_name ());
+          retval = do_cat_op (tv1, tv2, ra_idx);
 	}
       else
 	gripe_cat_op (v1.type_name (), v2.type_name ());
@@ -2079,24 +2015,7 @@
 	      if (tmp)
 		{
 		  tv = octave_value (tmp);
-		  t = tv.type_id ();
-
-		  f = octave_value_typeinfo::lookup_unary_op (op, t);
-
-		  if (f)
-		    {
-		      try
-			{
-			  retval = f (*tv.rep);
-			}
-		      catch (octave_execution_exception)
-			{
-			  gripe_library_execution_error ();
-			}
-		    }
-		  else
-		    gripe_unary_op (octave_value::unary_op_as_string (op),
-				    v.type_name ());
+                  retval = do_unary_op (op, tv);
 		}
 	      else
 		gripe_unary_op_conv (octave_value::unary_op_as_string (op));
--- a/src/ov.h
+++ b/src/ov.h
@@ -315,10 +315,10 @@
 
   int get_count (void) const { return rep->count; }
 
-  octave_base_value::type_conv_fcn numeric_conversion_function (void) const
+  octave_base_value::type_conv_info numeric_conversion_function (void) const
     { return rep->numeric_conversion_function (); }
 
-  octave_base_value::type_conv_fcn numeric_demotion_function (void) const
+  octave_base_value::type_conv_info numeric_demotion_function (void) const
     { return rep->numeric_demotion_function (); }
 
   void maybe_mutate (void);