changeset 9607:1be3c73ed7b5

reuse temporary arrays in nested expressions
author Jaroslav Hajek <highegg@gmail.com>
date Thu, 03 Sep 2009 08:48:51 +0200
parents a04352386a6b
children 1c76e806c2a7
files liboctave/CNDArray.h liboctave/ChangeLog liboctave/MArrayN.cc liboctave/MArrayN.h liboctave/boolNDArray.cc liboctave/boolNDArray.h liboctave/dNDArray.h liboctave/fCNDArray.h liboctave/fNDArray.h liboctave/intNDArray.h liboctave/mx-inlines.cc src/ChangeLog src/OPERATORS/op-bm-bm.cc src/OPERATORS/op-cm-cm.cc src/OPERATORS/op-fcm-fcm.cc src/OPERATORS/op-fm-fm.cc src/OPERATORS/op-int.h src/OPERATORS/op-m-m.cc src/ov-bool-mat.h src/ov-cx-mat.h src/ov-flt-cx-mat.h src/ov-flt-re-mat.h src/ov-intx.h src/ov-re-mat.h src/ov.cc src/ov.h src/pt-binop.cc src/pt-unop.cc
diffstat 28 files changed, 296 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/CNDArray.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/CNDArray.h	Thu Sep 03 08:48:51 2009 +0200
@@ -138,6 +138,12 @@
 
   ComplexNDArray diag (octave_idx_type k = 0) const;
 
+  ComplexNDArray& changesign (void) 
+    { 
+      MArrayN<Complex>::changesign (); 
+      return *this; 
+    }
+
   typedef double (*dmapper) (const Complex&);
   typedef Complex (*cmapper) (const Complex&);
   typedef bool (*bmapper) (const Complex&);
--- a/liboctave/ChangeLog	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/ChangeLog	Thu Sep 03 08:48:51 2009 +0200
@@ -1,3 +1,22 @@
+2009-09-03  Jaroslav Hajek  <highegg@gmail.com>
+
+	* mx-inlines.cc (DEFMXUNOPEQ): New macro.
+	(mx_inline_not2, mx_inline_uminus2): New loops.
+	* boolNDArray.cc (boolNDArray::invert): New method.
+	* boolNDArray.h: Declare it.
+	* MArrayN.cc (MArrayN<T>::changesign): New method.
+	* MArrayN.h: Declare it.
+	* dNDArray.cc (NDArray::changesign): New method.
+	* dNDArray.h: Declare it.
+	* fNDArray.cc (FloatNDArray::changesign): New method.
+	* fNDArray.h: Declare it.
+	* CNDArray.cc (ComplexNDArray::changesign): New method.
+	* CNDArray.h: Declare it.
+	* fCNDArray.cc (FloatComplexNDArray::changesign): New method.
+	* fCNDArray.h: Declare it.
+	* intNDArray.cc (intNDArray::changesign): New method.
+	* intNDArray.h: Declare it.
+
 2009-09-02  Jaroslav Hajek  <highegg@gmail.com>
 
 	* oct-cmplx.h: Rewrite the comaprison ops. Use FLOAT_TRUNCATE.
--- a/liboctave/MArrayN.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/MArrayN.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -29,8 +29,18 @@
 #include "lo-error.h"
 
 #include "MArray-defs.h"
+#include "mx-inlines.cc"
 
 // N-dimensional array with math ops.
+template <class T>
+void
+MArrayN<T>::changesign (void)
+{
+  if (Array<T>::is_shared ())
+    *this = - *this;
+  else
+    do_mx_inplace_op<MArrayN<T> > (*this, mx_inline_uminus2);
+}
 
 // Element by element MArrayN by scalar ops.
 
--- a/liboctave/MArrayN.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/MArrayN.h	Thu Sep 03 08:48:51 2009 +0200
@@ -109,6 +109,8 @@
   {
     return ArrayN<T>::template map<U> (fcn);
   }
+
+  void changesign (void);
 };
 
 #endif
--- a/liboctave/boolNDArray.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/boolNDArray.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -42,6 +42,17 @@
   return do_mx_unary_op<boolNDArray> (*this, mx_inline_not);
 }
 
+boolNDArray&
+boolNDArray::invert (void)
+{
+  if (is_shared ())
+    *this = ! *this;
+  else
+    do_mx_inplace_op<boolNDArray> (*this, mx_inline_not2);
+
+  return *this;
+}
+
 // FIXME -- this is not quite the right thing.
 
 boolNDArray
--- a/liboctave/boolNDArray.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/boolNDArray.h	Thu Sep 03 08:48:51 2009 +0200
@@ -59,6 +59,8 @@
 
   boolNDArray operator ! (void) const;
 
+  boolNDArray& invert (void); 
+
   bool any_element_is_nan (void) const { return false; }
 
   // FIXME -- this is not quite the right thing.
--- a/liboctave/dNDArray.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/dNDArray.h	Thu Sep 03 08:48:51 2009 +0200
@@ -149,6 +149,12 @@
 
   NDArray diag (octave_idx_type k = 0) const;
 
+  NDArray& changesign (void) 
+    { 
+      MArrayN<double>::changesign (); 
+      return *this; 
+    }
+
   typedef double (*dmapper) (double);
   typedef Complex (*cmapper) (const Complex&);
   typedef bool (*bmapper) (double);
--- a/liboctave/fCNDArray.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/fCNDArray.h	Thu Sep 03 08:48:51 2009 +0200
@@ -138,6 +138,12 @@
 
   FloatComplexNDArray diag (octave_idx_type k = 0) const;
 
+  FloatComplexNDArray& changesign (void) 
+    { 
+      MArrayN<FloatComplex>::changesign (); 
+      return *this; 
+    }
+
   typedef float (*dmapper) (const FloatComplex&);
   typedef FloatComplex (*cmapper) (const FloatComplex&);
   typedef bool (*bmapper) (const FloatComplex&);
--- a/liboctave/fNDArray.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/fNDArray.h	Thu Sep 03 08:48:51 2009 +0200
@@ -146,6 +146,12 @@
 
   FloatNDArray diag (octave_idx_type k = 0) const;
 
+  FloatNDArray& changesign (void) 
+    { 
+      MArrayN<float>::changesign (); 
+      return *this; 
+    }
+
   typedef float (*dmapper) (float);
   typedef FloatComplex (*cmapper) (const FloatComplex&);
   typedef bool (*bmapper) (float);
--- a/liboctave/intNDArray.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/intNDArray.h	Thu Sep 03 08:48:51 2009 +0200
@@ -68,6 +68,12 @@
 
   intNDArray diag (octave_idx_type k = 0) const;
 
+  intNDArray& changesign (void) 
+    { 
+      MArrayN<T>::changesign (); 
+      return *this; 
+    }
+
   // FIXME -- this is not quite the right thing.
 
   boolNDArray all (int dim = -1) const;
--- a/liboctave/mx-inlines.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/liboctave/mx-inlines.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -49,6 +49,13 @@
 
 DEFMXUNOP (mx_inline_uminus, -)
 
+#define DEFMXUNOPEQ(F, OP) \
+template <class R> \
+inline void F (size_t n, R *r) \
+{ for (size_t i = 0; i < n; i++) r[i] = OP r[i]; }
+
+DEFMXUNOPEQ (mx_inline_uminus2, -)
+
 #define DEFMXUNBOOLOP(F, OP) \
 template <class X> \
 inline void F (size_t n, bool *r, const X *x) \
@@ -127,6 +134,11 @@
     r[i] = ! logical_value (x[i]);
 }
 
+inline void mx_inline_not2 (size_t n, bool *r)
+{
+  for (size_t i = 0; i < n; i++) r[i] = ! r[i];
+}
+
 #define DEFMXBOOLOP(F, NOT1, OP, NOT2) \
 template <class X, class Y> \
 inline void F (size_t n, bool *r, const X *x, const Y *y) \
@@ -222,6 +234,16 @@
   return r;
 }
 
+template <class RNDA>
+inline RNDA&
+do_mx_inplace_op (RNDA& r,
+                  void (*op) (size_t, typename RNDA::element_type *))
+{
+  op (r.numel (), r.fortran_vec ());
+  return r;
+}
+
+
 template <class RNDA, class XNDA, class YNDA>
 inline RNDA 
 do_mm_binary_op (const XNDA& x, const YNDA& y,
--- a/src/ChangeLog	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/ChangeLog	Thu Sep 03 08:48:51 2009 +0200
@@ -1,3 +1,28 @@
+2009-09-03  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov.cc (octave_value::do_non_const_unary_op): Split to
+	genuine/non-genuine case.
+	(octave_value::binary_op_to_assign_op): New method.
+	* ov.h: Declare it.
+	* ov-re-mat.h (octave_matrix::changesign): New method.
+	* ov-flt-re-mat.h (octave_float_matrix::changesign): New method.
+	* ov-cx-mat.h (octave_complex_matrix::changesign): New method.
+	* ov-flt-cx-mat.h (octave_float_complex_matrix::changesign): New
+	method.
+	* ov-intx.h (OCTAVE_VALUE_INT_MATRIX_T::changesign): New method.
+	* ov-bool-mat.h (octave_bool_matrix::invert): New method.
+	* pt-unop.cc (tree_prefix_expression::rvalue1): Use
+	do_non_const_unary_op.
+	* pt-binop.cc (tree_binary_expression::rvalue1): If possible,
+	convert to computed assignment.
+
+	* OPERATORS/op-m-m.cc: Define & install in-place minus operation.
+	* OPERATORS/op-fm-fm.cc: Ditto.
+	* OPERATORS/op-cm-cm.cc: Ditto.
+	* OPERATORS/op-fcm-fcm.cc: Ditto.
+	* OPERATORS/op-int.h: Ditto.
+	* OPERATORS/op-bm-bm.cc: Define & install in-place not operation.
+
 2009-09-03  Jaroslav Hajek  <highegg@gmail.com>
 
 	* ov-re-mat.h (octave_matrix::increment, octave_matrix::decrement):
--- a/src/OPERATORS/op-bm-bm.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/OPERATORS/op-bm-bm.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -55,6 +55,8 @@
 DEFNDUNOP_OP (uplus, bool_matrix, array, +)
 DEFNDUNOP_OP (uminus, bool_matrix, array, -)
 
+DEFNCUNOP_METHOD (invert, bool_matrix, invert)
+
 DEFUNOP (transpose, bool_matrix)
 {
   CAST_UNOP_ARG (const octave_bool_matrix&);
@@ -133,6 +135,8 @@
   INSTALL_UNOP (op_transpose, octave_bool_matrix, transpose);
   INSTALL_UNOP (op_hermitian, octave_bool_matrix, transpose);
 
+  INSTALL_NCUNOP (op_not, octave_bool_matrix, invert);
+
   INSTALL_BINOP (op_eq, octave_bool_matrix, octave_bool_matrix, eq);
   INSTALL_BINOP (op_ne, octave_bool_matrix, octave_bool_matrix, ne);
 
--- a/src/OPERATORS/op-cm-cm.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/OPERATORS/op-cm-cm.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -70,6 +70,7 @@
 
 DEFNCUNOP_METHOD (incr, complex_matrix, increment)
 DEFNCUNOP_METHOD (decr, complex_matrix, decrement)
+DEFNCUNOP_METHOD (changesign, complex_matrix, changesign)
 
 // complex matrix by complex matrix ops.
 
@@ -186,6 +187,7 @@
 
   INSTALL_NCUNOP (op_incr, octave_complex_matrix, incr);
   INSTALL_NCUNOP (op_decr, octave_complex_matrix, decr);
+  INSTALL_NCUNOP (op_uminus, octave_complex_matrix, changesign);
 
   INSTALL_BINOP (op_add, octave_complex_matrix, octave_complex_matrix, add);
   INSTALL_BINOP (op_sub, octave_complex_matrix, octave_complex_matrix, sub);
--- a/src/OPERATORS/op-fcm-fcm.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/OPERATORS/op-fcm-fcm.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -70,6 +70,7 @@
 
 DEFNCUNOP_METHOD (incr, float_complex_matrix, increment)
 DEFNCUNOP_METHOD (decr, float_complex_matrix, decrement)
+DEFNCUNOP_METHOD (changesign, float_complex_matrix, changesign)
 
 // complex matrix by complex matrix ops.
 
@@ -216,6 +217,7 @@
 
   INSTALL_NCUNOP (op_incr, octave_float_complex_matrix, incr);
   INSTALL_NCUNOP (op_decr, octave_float_complex_matrix, decr);
+  INSTALL_NCUNOP (op_uminus, octave_float_complex_matrix, changesign);
 
   INSTALL_BINOP (op_add, octave_float_complex_matrix, 
 		 octave_float_complex_matrix, add);
--- a/src/OPERATORS/op-fm-fm.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/OPERATORS/op-fm-fm.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -57,6 +57,7 @@
 
 DEFNCUNOP_METHOD (incr, float_matrix, increment)
 DEFNCUNOP_METHOD (decr, float_matrix, decrement)
+DEFNCUNOP_METHOD (changesign, float_matrix, changesign)
 
 // matrix by matrix ops.
 
@@ -188,6 +189,7 @@
 
   INSTALL_NCUNOP (op_incr, octave_float_matrix, incr);
   INSTALL_NCUNOP (op_decr, octave_float_matrix, decr);
+  INSTALL_NCUNOP (op_uminus, octave_float_matrix, changesign);
 
   INSTALL_BINOP (op_add, octave_float_matrix, octave_float_matrix, add);
   INSTALL_BINOP (op_sub, octave_float_matrix, octave_float_matrix, sub);
--- a/src/OPERATORS/op-int.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/OPERATORS/op-int.h	Thu Sep 03 08:48:51 2009 +0200
@@ -698,7 +698,8 @@
   } \
  \
   DEFNCUNOP_METHOD (m_incr, TYPE ## _matrix, increment) \
-  DEFNCUNOP_METHOD (m_decr, TYPE ## _matrix, decrement)
+  DEFNCUNOP_METHOD (m_decr, TYPE ## _matrix, decrement) \
+  DEFNCUNOP_METHOD (m_changesign, TYPE ## _matrix, changesign)
 
 #define OCTAVE_MM_INT_ARITH_OPS(PFX, T1, T2, T3)	\
   /* matrix by matrix ops. */ \
@@ -1096,7 +1097,8 @@
   INSTALL_UNOP (op_hermitian, octave_ ## TYPE ## _matrix, m_transpose); \
  \
   INSTALL_NCUNOP (op_incr, octave_ ## TYPE ## _matrix, m_incr); \
-  INSTALL_NCUNOP (op_decr, octave_ ## TYPE ## _matrix, m_decr);
+  INSTALL_NCUNOP (op_decr, octave_ ## TYPE ## _matrix, m_decr); \
+  INSTALL_NCUNOP (op_uminus, octave_ ## TYPE ## _matrix, m_changesign);
 
 #define OCTAVE_INSTALL_MM_INT_ARITH_OPS(PFX, T1, T2)			\
   INSTALL_BINOP (op_add, octave_ ## T1 ## matrix, octave_ ## T2 ## matrix, PFX ## _add); \
--- a/src/OPERATORS/op-m-m.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/OPERATORS/op-m-m.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -57,6 +57,7 @@
 
 DEFNCUNOP_METHOD (incr, matrix, increment)
 DEFNCUNOP_METHOD (decr, matrix, decrement)
+DEFNCUNOP_METHOD (changesign, matrix, changesign)
 
 // matrix by matrix ops.
 
@@ -161,6 +162,7 @@
 
   INSTALL_NCUNOP (op_incr, octave_matrix, incr);
   INSTALL_NCUNOP (op_decr, octave_matrix, decr);
+  INSTALL_NCUNOP (op_uminus, octave_matrix, changesign);
 
   INSTALL_BINOP (op_add, octave_matrix, octave_matrix, add);
   INSTALL_BINOP (op_sub, octave_matrix, octave_matrix, sub);
--- a/src/ov-bool-mat.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/ov-bool-mat.h	Thu Sep 03 08:48:51 2009 +0200
@@ -175,6 +175,9 @@
 
   octave_value convert_to_str_internal (bool pad, bool force, char type) const;
 
+  // Use matrix_ref here to clear index cache.
+  void invert (void) { matrix_ref ().invert (); }
+
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
   bool save_ascii (std::ostream& os);
--- a/src/ov-cx-mat.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/ov-cx-mat.h	Thu Sep 03 08:48:51 2009 +0200
@@ -136,6 +136,8 @@
 
   void decrement (void) { matrix -= Complex (1.0); }
 
+  void changesign (void) { matrix.changesign (); }
+
   bool save_ascii (std::ostream& os);
 
   bool load_ascii (std::istream& is);
--- a/src/ov-flt-cx-mat.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/ov-flt-cx-mat.h	Thu Sep 03 08:48:51 2009 +0200
@@ -134,6 +134,8 @@
 
   void decrement (void) { matrix -= FloatComplex (1.0); }
 
+  void changesign (void) { matrix.changesign (); }
+
   bool save_ascii (std::ostream& os);
 
   bool load_ascii (std::istream& is);
--- a/src/ov-flt-re-mat.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/ov-flt-re-mat.h	Thu Sep 03 08:48:51 2009 +0200
@@ -168,6 +168,8 @@
 
   void decrement (void) { matrix_ref () -= 1.0; }
 
+  void changesign (void) { matrix_ref ().changesign (); }
+
   octave_value convert_to_str_internal (bool pad, bool force, char type) const;
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
--- a/src/ov-intx.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/ov-intx.h	Thu Sep 03 08:48:51 2009 +0200
@@ -317,6 +317,14 @@
       OCTAVE_INT_T::clear_conv_flag ();
    }
 
+  void changesign (void)
+   { 
+     matrix_ref ().changesign (); 
+     if (OCTAVE_INT_T::get_math_trunc_flag ())
+       gripe_unop_integer_math_truncated ("-", type_name (). c_str ());
+      OCTAVE_INT_T::clear_conv_flag ();
+   }
+
   idx_vector index_vector (void) const 
     { return idx_cache ? *idx_cache : set_idx_cache (idx_vector (matrix)); }
 
--- a/src/ov-re-mat.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/ov-re-mat.h	Thu Sep 03 08:48:51 2009 +0200
@@ -182,6 +182,8 @@
 
   void decrement (void) { matrix_ref () -= 1.0; }
 
+  void changesign (void) { matrix_ref ().changesign (); }
+
   octave_value convert_to_str_internal (bool pad, bool force, char type) const;
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
--- a/src/ov.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/ov.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -474,6 +474,44 @@
   return retval;
 }
 
+octave_value::assign_op
+octave_value::binary_op_to_assign_op (binary_op op)
+{
+  assign_op retval;
+
+  switch (op)
+    {
+    case op_add:
+      retval = op_add_eq;
+      break;
+    case op_sub:
+      retval = op_sub_eq;
+      break;
+    case op_mul:
+      retval = op_mul_eq;
+      break;
+    case op_div:
+      retval = op_div_eq;
+      break;
+    case op_el_mul:
+      retval = op_el_mul_eq;
+      break;
+    case op_el_div:
+      retval = op_el_div_eq;
+      break;
+    case op_el_and:
+      retval = op_el_and_eq;
+      break;
+    case op_el_or:
+      retval = op_el_or_eq;
+      break;
+    default:
+      retval = unknown_assign_op;
+    }
+
+  return retval;
+}
+
 octave_value::octave_value (short int i)
   : rep (new octave_scalar (i))
 {
@@ -2246,77 +2284,104 @@
 const octave_value&
 octave_value::do_non_const_unary_op (unary_op op)
 {
-  octave_value retval;
-
-  int t = type_id ();
-
-  octave_value_typeinfo::non_const_unary_op_fcn f
-    = octave_value_typeinfo::lookup_non_const_unary_op (op, t);
-
-  if (f)
+  if (op == op_incr || op == op_decr)
     {
-      make_unique ();
-
-      try
-	{
-	  f (*rep);
-	}
-      catch (octave_execution_exception)
-	{
-	  gripe_library_execution_error ();
-	}
+      // Genuine.
+      int t = type_id ();
+
+      octave_value_typeinfo::non_const_unary_op_fcn f
+        = octave_value_typeinfo::lookup_non_const_unary_op (op, t);
+
+      if (f)
+        {
+          make_unique ();
+
+          try
+            {
+              f (*rep);
+            }
+          catch (octave_execution_exception)
+            {
+              gripe_library_execution_error ();
+            }
+        }
+      else
+        {
+          octave_base_value::type_conv_fcn cf = numeric_conversion_function ();
+
+          if (cf)
+            {
+              octave_base_value *tmp = cf (*rep);
+
+              if (tmp)
+                {
+                  octave_base_value *old_rep = rep;
+                  rep = tmp;
+
+                  t = type_id ();
+
+                  f = octave_value_typeinfo::lookup_non_const_unary_op (op, t);
+
+                  if (f)
+                    {
+                      try
+                        {
+                          f (*rep);
+                        }
+                      catch (octave_execution_exception)
+                        {
+                          gripe_library_execution_error ();
+                        }
+
+                      if (old_rep && --old_rep->count == 0)
+                        delete old_rep;
+                    }
+                  else
+                    {
+                      if (old_rep)
+                        {
+                          if (--rep->count == 0)
+                            delete rep;
+
+                          rep = old_rep;
+                        }
+
+                      gripe_unary_op (octave_value::unary_op_as_string (op),
+                                      type_name ());
+                    }
+                }
+              else
+                gripe_unary_op_conversion_failed
+                  (octave_value::unary_op_as_string (op), type_name ());
+            }
+          else
+            gripe_unary_op (octave_value::unary_op_as_string (op), type_name ());
+        }
     }
   else
     {
-      octave_base_value::type_conv_fcn cf = numeric_conversion_function ();
-
-      if (cf)
-	{
-	  octave_base_value *tmp = cf (*rep);
-
-	  if (tmp)
-	    {
-	      octave_base_value *old_rep = rep;
-	      rep = tmp;
-
-	      t = type_id ();
-
-	      f = octave_value_typeinfo::lookup_non_const_unary_op (op, t);
-
-	      if (f)
-		{
-		  try
-		    {
-		      f (*rep);
-		    }
-		  catch (octave_execution_exception)
-		    {
-		      gripe_library_execution_error ();
-		    }
-
-		  if (old_rep && --old_rep->count == 0)
-		    delete old_rep;
-		}
-	      else
-		{
-		  if (old_rep)
-		    {
-		      if (--rep->count == 0)
-			delete rep;
-
-		      rep = old_rep;
-		    }
-
-		  gripe_unary_op (octave_value::unary_op_as_string (op),
-				  type_name ());
-		}
-	    }
-	  else
-	    gripe_unary_op_conversion_failed
-	      (octave_value::unary_op_as_string (op), type_name ());
-	}
+      // Non-genuine.
+      int t = type_id ();
+
+      octave_value_typeinfo::non_const_unary_op_fcn f = 0;
+
+      // Only attempt to operate in-place if this variable is unshared.
+      if (rep->count == 1)
+        f = octave_value_typeinfo::lookup_non_const_unary_op (op, t);
+
+      if (f)
+        {
+          try
+            {
+              f (*rep);
+            }
+          catch (octave_execution_exception)
+            {
+              gripe_library_execution_error ();
+            }
+        }
       else
-	gripe_unary_op (octave_value::unary_op_as_string (op), type_name ());
+        *this = do_unary_op (op, *this);
     }
 
   return *this;
--- a/src/ov.h	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/ov.h	Thu Sep 03 08:48:51 2009 +0200
@@ -141,6 +141,8 @@
     unknown_assign_op
   };
 
+  static assign_op binary_op_to_assign_op (binary_op);
+
   static std::string unary_op_as_string (unary_op);
   static std::string unary_op_fcn_name (unary_op);
 
--- a/src/pt-binop.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/pt-binop.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -66,7 +66,12 @@
 
 	  if (! error_state && b.is_defined ())
 	    {
-	      retval = ::do_binary_op (etype, a, b);
+              octave_value::assign_op aop = octave_value::binary_op_to_assign_op (etype);
+
+              if (aop == octave_value::unknown_assign_op)
+                retval = ::do_binary_op (etype, a, b);
+              else
+                retval = a.assign (aop, b);
 
 	      if (error_state)
 		retval = octave_value ();
--- a/src/pt-unop.cc	Thu Sep 03 06:59:53 2009 +0200
+++ b/src/pt-unop.cc	Thu Sep 03 08:48:51 2009 +0200
@@ -89,7 +89,7 @@
 
 	  if (! error_state && val.is_defined ())
 	    {
-	      retval = ::do_unary_op (etype, val);
+	      retval = val.do_non_const_unary_op (etype);
 
 	      if (error_state)
 		retval = octave_value ();