changeset 10481:e8811e5dd699

avoid exception throwing in mx-inline loops
author Jaroslav Hajek <highegg@gmail.com>
date Thu, 01 Apr 2010 08:27:23 +0200
parents 19e1e4470e01
children 2645a6b1027b
files liboctave/ChangeLog liboctave/mx-inlines.cc liboctave/mx-op-defs.h
diffstat 3 files changed, 84 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog	Wed Mar 31 10:24:57 2010 +0200
+++ b/liboctave/ChangeLog	Thu Apr 01 08:27:23 2010 +0200
@@ -1,3 +1,13 @@
+2010-04-01  Jaroslav Hajek  <highegg@gmail.com>
+
+	* mx-inlines.cc: Declare all loops as throw (). Ditto for
+	corresponding applier arguments.
+	(do_mx_check): New applier.
+	(logical_value): Do not throw exceptions.
+	* mx-op-defs.h (SNANCHK, MNANCHK): New helper macros.
+	(MS_BOOL_OP, SM_BOOL_OP, MM_BOOL_OP, NDS_BOOL_OP, SND_BOOL_OP,
+	NDND_BOOL_OP): Use them here.
+
 2010-03-31  Jaroslav Hajek  <highegg@gmail.com>
 
 	* Sparse.cc (Sparse<T>::Sparse (const Array<T>&,
--- a/liboctave/mx-inlines.cc	Wed Mar 31 10:24:57 2010 +0200
+++ b/liboctave/mx-inlines.cc	Thu Apr 01 08:27:23 2010 +0200
@@ -41,26 +41,26 @@
 // Provides some commonly repeated, basic loop templates.
 
 template <class R, class S>
-inline void mx_inline_fill (size_t n, R *r, S s)
+inline void mx_inline_fill (size_t n, R *r, S s) throw ()
 { for (size_t i = 0; i < n; i++) r[i] = s; }
 
 #define DEFMXUNOP(F, OP) \
 template <class R, class X> \
-inline void F (size_t n, R *r, const X *x) \
+inline void F (size_t n, R *r, const X *x) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = OP x[i]; }
 
 DEFMXUNOP (mx_inline_uminus, -)
 
 #define DEFMXUNOPEQ(F, OP) \
 template <class R> \
-inline void F (size_t n, R *r) \
+inline void F (size_t n, R *r) throw () \
 { 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) \
+inline void F (size_t n, bool *r, const X *x) throw () \
 { const X zero = X(); for (size_t i = 0; i < n; i++) r[i] = x[i] OP zero; }
 
 DEFMXUNBOOLOP (mx_inline_iszero, ==)
@@ -68,13 +68,13 @@
 
 #define DEFMXBINOP(F, OP) \
 template <class R, class X, class Y> \
-inline void F (size_t n, R *r, const X *x, const Y *y) \
+inline void F (size_t n, R *r, const X *x, const Y *y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = x[i] OP y[i]; } \
 template <class R, class X, class Y> \
-inline void F (size_t n, R *r, const X *x, Y y) \
+inline void F (size_t n, R *r, const X *x, Y y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = x[i] OP y; } \
 template <class R, class X, class Y> \
-inline void F (size_t n, R *r, X x, const Y *y) \
+inline void F (size_t n, R *r, X x, const Y *y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = x OP y[i]; }
 
 DEFMXBINOP (mx_inline_add, +)
@@ -84,10 +84,10 @@
 
 #define DEFMXBINOPEQ(F, OP) \
 template <class R, class X> \
-inline void F (size_t n, R *r, const X *x) \
+inline void F (size_t n, R *r, const X *x) throw () \
 { for (size_t i = 0; i < n; i++) r[i] OP x[i]; } \
 template <class R, class X> \
-inline void F (size_t n, R *r, X x) \
+inline void F (size_t n, R *r, X x) throw () \
 { for (size_t i = 0; i < n; i++) r[i] OP x; }
 
 DEFMXBINOPEQ (mx_inline_add2, +=)
@@ -97,13 +97,13 @@
 
 #define DEFMXCMPOP(F, OP) \
 template <class X, class Y> \
-inline void F (size_t n, bool *r, const X *x, const Y *y) \
+inline void F (size_t n, bool *r, const X *x, const Y *y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = x[i] OP y[i]; } \
 template <class X, class Y> \
-inline void F (size_t n, bool *r, const X *x, Y y) \
+inline void F (size_t n, bool *r, const X *x, Y y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = x[i] OP y; } \
 template <class X, class Y> \
-inline void F (size_t n, bool *r, X x, const Y *y) \
+inline void F (size_t n, bool *r, X x, const Y *y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = x OP y[i]; }
 
 DEFMXCMPOP (mx_inline_lt, <)
@@ -115,48 +115,39 @@
 
 // Convert to logical value, for logical op purposes.
 template <class T> inline bool logical_value (T x) { return x; }
+template <class T> inline bool logical_value (const std::complex<T>& x) 
+{ return x.real () != 0 && x.imag () != 0; }
 template <class T> inline bool logical_value (const octave_int<T>& x) 
 { return x.value (); }
 
-// NaNs in real data should generate an error. Doing it on-the-fly is faster.
-
-#define DEFLOGCHKNAN(ARG, ZERO) \
-inline bool logical_value (ARG x) \
-{ if (xisnan (x)) gripe_nan_to_logical_conversion (); return x != ZERO; }
-
-DEFLOGCHKNAN (double, 0.0)
-DEFLOGCHKNAN (const Complex&, 0.0)
-DEFLOGCHKNAN (float, 0.0f)
-DEFLOGCHKNAN (const FloatComplex&, 0.0f)
-
 template <class X>
-void mx_inline_not (size_t n, bool *r, const X* x)
+void mx_inline_not (size_t n, bool *r, const X* x) throw ()
 {
   for (size_t i = 0; i < n; i++)
     r[i] = ! logical_value (x[i]);
 }
 
-inline void mx_inline_not2 (size_t n, bool *r)
+inline void mx_inline_not2 (size_t n, bool *r) throw ()
 {
   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) \
+inline void F (size_t n, bool *r, const X *x, const Y *y) throw () \
 { \
   for (size_t i = 0; i < n; i++) \
     r[i] = (NOT1 logical_value (x[i])) OP (NOT2 logical_value (y[i])); \
 } \
 template <class X, class Y> \
-inline void F (size_t n, bool *r, const X *x, Y y) \
+inline void F (size_t n, bool *r, const X *x, Y y) throw () \
 { \
   const bool yy = (NOT2 logical_value (y)); \
   for (size_t i = 0; i < n; i++) \
     r[i] = (NOT1 logical_value (x[i])) OP yy; \
 } \
 template <class X, class Y> \
-inline void F (size_t n, bool *r, X x, const Y *y) \
+inline void F (size_t n, bool *r, X x, const Y *y) throw () \
 { \
   const bool xx = (NOT1 logical_value (x)); \
   for (size_t i = 0; i < n; i++) \
@@ -172,7 +163,7 @@
 
 #define DEFMXBOOLOPEQ(F, OP) \
 template <class X> \
-inline void F (size_t n, bool *r, const X *x) \
+inline void F (size_t n, bool *r, const X *x) throw () \
 { \
   for (size_t i = 0; i < n; i++) \
     r[i] OP logical_value (x[i]); \
@@ -183,7 +174,7 @@
 
 template <class T> 
 inline bool 
-mx_inline_any_nan (size_t n, const T* x) 
+mx_inline_any_nan (size_t n, const T* x)  throw ()
 {
   for (size_t i = 0; i < n; i++)
     {
@@ -196,7 +187,7 @@
 
 template <class T> 
 inline bool 
-mx_inline_any_negative (size_t n, const T* x) 
+mx_inline_any_negative (size_t n, const T* x) throw () 
 {
   for (size_t i = 0; i < n; i++)
     {
@@ -209,7 +200,7 @@
 
 template<class T>
 inline bool 
-mx_inline_all_real (size_t n, const std::complex<T>* x)
+mx_inline_all_real (size_t n, const std::complex<T>* x) throw ()
 {
   for (size_t i = 0; i < n; i++)
     {
@@ -222,26 +213,26 @@
 
 #define DEFMXMAPPER(F, FUN) \
 template <class T> \
-inline void F (size_t n, T *r, const T *x) \
+inline void F (size_t n, T *r, const T *x) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i]); }
 
 template<class T>
-inline void mx_inline_real (size_t n, T *r, const std::complex<T>* x)
+inline void mx_inline_real (size_t n, T *r, const std::complex<T>* x) throw ()
 { for (size_t i = 0; i < n; i++) r[i] = x[i].real (); }
 template<class T>
-inline void mx_inline_imag (size_t n, T *r, const std::complex<T>* x)
+inline void mx_inline_imag (size_t n, T *r, const std::complex<T>* x) throw ()
 { for (size_t i = 0; i < n; i++) r[i] = x[i].imag (); }
 
 // Pairwise minimums/maximums
 #define DEFMXMAPPER2(F, FUN) \
 template <class T> \
-inline void F (size_t n, T *r, const T *x, const T *y) \
+inline void F (size_t n, T *r, const T *x, const T *y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i], y[i]); } \
 template <class T> \
-inline void F (size_t n, T *r, const T *x, T y) \
+inline void F (size_t n, T *r, const T *x, T y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i], y); } \
 template <class T> \
-inline void F (size_t n, T *r, T x, const T *y) \
+inline void F (size_t n, T *r, T x, const T *y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = FUN (x, y[i]); }
 
 DEFMXMAPPER2 (mx_inline_xmin, xmin)
@@ -250,7 +241,7 @@
 // Specialize array-scalar max/min
 #define DEFMINMAXSPEC(T, F, OP) \
 template <> \
-inline void F<T> (size_t n, T *r, const T *x, T y) \
+inline void F<T> (size_t n, T *r, const T *x, T y) throw () \
 { \
   if (xisnan (y)) \
     std::memcpy (r, x, n * sizeof (T)); \
@@ -258,7 +249,7 @@
     for (size_t i = 0; i < n; i++) r[i] = (x[i] OP y) ? x[i] : y; \
 } \
 template <> \
-inline void F<T> (size_t n, T *r, T x, const T *y) \
+inline void F<T> (size_t n, T *r, T x, const T *y) throw () \
 { \
   if (xisnan (x)) \
     std::memcpy (r, y, n * sizeof (T)); \
@@ -274,13 +265,13 @@
 // Pairwise power
 #define DEFMXMAPPER2X(F, FUN) \
 template <class R, class X, class Y> \
-inline void F (size_t n, R *r, const X *x, const Y *y) \
+inline void F (size_t n, R *r, const X *x, const Y *y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i], y[i]); } \
 template <class R, class X, class Y> \
-inline void F (size_t n, R *r, const X *x, Y y) \
+inline void F (size_t n, R *r, const X *x, Y y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i], y); } \
 template <class R, class X, class Y> \
-inline void F (size_t n, R *r, X x, const Y *y) \
+inline void F (size_t n, R *r, X x, const Y *y) throw () \
 { for (size_t i = 0; i < n; i++) r[i] = FUN (x, y[i]); }
 
 DEFMXMAPPER2X (mx_inline_pow, std::pow)
@@ -288,11 +279,11 @@
 // Arbitrary function appliers. The function is a template parameter to enable
 // inlining.
 template <class R, class X, R fun (X x)>
-inline void mx_inline_map (size_t n, R *r, const X *x)
+inline void mx_inline_map (size_t n, R *r, const X *x) throw ()
 { for (size_t i = 0; i < n; i++) r[i] = fun (x[i]); }
 
 template <class R, class X, R fun (const X& x)>
-inline void mx_inline_map (size_t n, R *r, const X *x)
+inline void mx_inline_map (size_t n, R *r, const X *x) throw ()
 { for (size_t i = 0; i < n; i++) r[i] = fun (x[i]); }
 
 // Appliers. Since these call the operation just once, we pass it as
@@ -301,7 +292,7 @@
 template <class R, class X>
 inline Array<R> 
 do_mx_unary_op (const Array<X>& x,
-                void (*op) (size_t, R *, const X *))
+                void (*op) (size_t, R *, const X *) throw ())
 {
   Array<R> r (x.dims ());
   op (r.numel (), r.fortran_vec (), x.data ());
@@ -327,7 +318,7 @@
 template <class R>
 inline Array<R>&
 do_mx_inplace_op (Array<R>& r,
-                  void (*op) (size_t, R *))
+                  void (*op) (size_t, R *) throw ())
 {
   op (r.numel (), r.fortran_vec ());
   return r;
@@ -337,7 +328,7 @@
 template <class R, class X, class Y>
 inline Array<R> 
 do_mm_binary_op (const Array<X>& x, const Array<Y>& y,
-                 void (*op) (size_t, R *, const X *, const Y *),
+                 void (*op) (size_t, R *, const X *, const Y *) throw (),
                  const char *opname)
 {
   dim_vector dx = x.dims (), dy = y.dims ();
@@ -357,7 +348,7 @@
 template <class R, class X, class Y>
 inline Array<R> 
 do_ms_binary_op (const Array<X>& x, const Y& y,
-                 void (*op) (size_t, R *, const X *, Y))
+                 void (*op) (size_t, R *, const X *, Y) throw ())
 {
   Array<R> r (x.dims ());
   op (r.length (), r.fortran_vec (), x.data (), y);
@@ -367,7 +358,7 @@
 template <class R, class X, class Y>
 inline Array<R> 
 do_sm_binary_op (const X& x, const Array<Y>& y,
-                 void (*op) (size_t, R *, X, const Y *))
+                 void (*op) (size_t, R *, X, const Y *) throw ())
 {
   Array<R> r (y.dims ());
   op (r.length (), r.fortran_vec (), x, y.data ());
@@ -377,7 +368,7 @@
 template <class R, class X>
 inline Array<R>& 
 do_mm_inplace_op (Array<R>& r, const Array<X>& x,
-                  void (*op) (size_t, R *, const X *),
+                  void (*op) (size_t, R *, const X *) throw (),
                   const char *opname)
 {
   dim_vector dr = r.dims (), dx = x.dims ();
@@ -391,7 +382,7 @@
 template <class R, class X>
 inline Array<R>& 
 do_ms_inplace_op (Array<R>& r, const X& x,
-                  void (*op) (size_t, R *, X))
+                  void (*op) (size_t, R *, X) throw ())
 {
   op (r.length (), r.fortran_vec (), x);
   return r;
@@ -399,7 +390,7 @@
 
 template <class T1, class T2>
 inline bool
-mx_inline_equal (size_t n, const T1 *x, const T2 *y)
+mx_inline_equal (size_t n, const T1 *x, const T2 *y) throw ()
 {
   for (size_t i = 0; i < n; i++)
     if (x[i] != y[i])
@@ -407,9 +398,16 @@
   return true;
 }
 
-// FIXME: Due to a performance defect in g++ (<= 4.3), std::norm is slow unless
-// ffast-math is on (not by default even with -O3). The following helper function
-// gives the expected straightforward implementation of std::norm.
+template <class T>
+inline bool
+do_mx_check (const Array<T>& a, 
+             bool (*op) (size_t, const T *) throw ())
+{
+  return op (a.numel (), a.data ());
+}
+
+// NOTE: we don't use std::norm because it typically does some heavyweight
+// magic to avoid underflows, which we don't need here.
 template <class T>
 inline T cabsq (const std::complex<T>& c) 
 { return c.real () * c.real () + c.imag () * c.imag (); }
--- a/liboctave/mx-op-defs.h	Wed Mar 31 10:24:57 2010 +0200
+++ b/liboctave/mx-op-defs.h	Thu Apr 01 08:27:23 2010 +0200
@@ -29,6 +29,14 @@
 #include "mx-op-decl.h"
 #include "mx-inlines.cc"
 
+#define SNANCHK(s) \
+  if (xisnan (s)) \
+    gripe_nan_to_logical_conversion ()
+
+#define MNANCHK(m) \
+  if (do_mx_check (m, mx_inline_any_nan)) \
+    gripe_nan_to_logical_conversion ()
+
 // vector by scalar operations.
 
 #define VS_BIN_OP(R, F, OP, V, S) \
@@ -108,6 +116,8 @@
   boolMatrix \
   F (const M& m, const S& s) \
   { \
+    MNANCHK (m); \
+    SNANCHK (s); \
     return do_ms_binary_op<bool, M::element_type, S> (m, s, OP); \
   }
 
@@ -149,6 +159,8 @@
   boolMatrix \
   F (const S& s, const M& m) \
   { \
+    SNANCHK (s); \
+    MNANCHK (m); \
     return do_sm_binary_op<bool, S, M::element_type> (s, m, OP); \
   }
 
@@ -190,6 +202,8 @@
   boolMatrix \
   F (const M1& m1, const M2& m2) \
   { \
+    MNANCHK (m1); \
+    MNANCHK (m2); \
     return do_mm_binary_op<bool, M1::element_type, M2::element_type> (m1, m2, OP, #F); \
   }
 
@@ -231,6 +245,8 @@
   boolNDArray \
   F (const ND& m, const S& s) \
   { \
+    MNANCHK (m); \
+    SNANCHK (s); \
     return do_ms_binary_op<bool, ND::element_type, S> (m, s, OP); \
   }
 
@@ -276,6 +292,8 @@
   boolNDArray \
   F (const S& s, const ND& m) \
   { \
+    SNANCHK (s); \
+    MNANCHK (m); \
     return do_sm_binary_op<bool, S, ND::element_type> (s, m, OP); \
   }
 
@@ -321,6 +339,8 @@
   boolNDArray \
   F (const ND1& m1, const ND2& m2) \
   { \
+    MNANCHK (m1); \
+    MNANCHK (m2); \
     return do_mm_binary_op<bool, ND1::element_type, ND2::element_type> (m1, m2, OP, #F); \
   }