diff liboctave/oct-inttypes.h @ 8039:cd90e2842080

Add additional integer math and conversion warnings, set their default state to be off and add the intwarning function
author David Bateman <dbateman@free.fr>
date Tue, 19 Aug 2008 14:46:35 -0400
parents f7f2d867c523
children fc45357bf50c
line wrap: on
line diff
--- a/liboctave/oct-inttypes.h
+++ b/liboctave/oct-inttypes.h
@@ -124,16 +124,26 @@
 
 template <class T1, class T2>
 inline T2
-octave_int_fit_to_range (const T1& x, const T2& mn, const T2& mx)
+octave_int_fit_to_range (const T1& x, const T2& mn, const T2& mx,
+			 int& conv_flag, int math_truncate)
 {
-  return (x > mx ? mx : (x < mn ? mn : T2 (x)));
+  bool out_of_range_max = x > mx;
+  bool out_of_range_min = x < mn;
+  conv_flag |= (out_of_range_max || out_of_range_min ? math_truncate : 0);
+  return (out_of_range_max ? mx : (out_of_range_min ? mn : T2 (x)));
 }
 
 template <typename T>
 inline T
-octave_int_fit_to_range (const double& x, const T& mn, const T& mx)
+octave_int_fit_to_range (const double& x, const T& mn, const T& mx,
+			 int& conv_flag, int math_truncate)
 {
-  return (__lo_ieee_isnan (x) ? 0 : (x > mx ? mx : (x < mn ? mn : static_cast<T> (x))));
+  bool out_of_range_max = x > mx;
+  bool out_of_range_min = x < mn;
+  conv_flag |= (out_of_range_max || out_of_range_min ? math_truncate : 0);
+  return (__lo_ieee_isnan (x)
+	  ? 0 : (out_of_range_max
+		 ? mx : (out_of_range_min ? mn : static_cast<T> (x))));
 }
 
 // If X is unsigned and the new type is signed, then we only have to
@@ -145,9 +155,12 @@
 #define OCTAVE_US_S_FTR(T1, T2, TC) \
   template <> \
   inline T2 \
-  octave_int_fit_to_range<T1, T2> (const T1& x, const T2&, const T2& mx) \
+  octave_int_fit_to_range<T1, T2> (const T1& x, const T2&, const T2& mx, \
+				   int& conv_flag, int math_truncate) \
   { \
-    return x > static_cast<TC> (mx) ? mx : x; \
+    bool out_of_range = x > static_cast<TC> (mx); \
+    conv_flag |= (out_of_range ? math_truncate : 0); \
+    return out_of_range ? mx : x; \
   }
 
 #define OCTAVE_US_S_FTR_FCNS(T) \
@@ -172,10 +185,13 @@
 #define OCTAVE_S_US_FTR(T1, T2) \
   template <> \
   inline T2 \
-  octave_int_fit_to_range<T1, T2> (const T1& x, const T2&, const T2&) \
+  octave_int_fit_to_range<T1, T2> (const T1& x, const T2&, const T2&, \
+				   int& conv_flag, int math_truncate) \
   { \
+    bool out_of_range = x < 0; \
+    conv_flag |= (out_of_range ? math_truncate : 0); \
     return x <= 0 ? 0 : x; \
-  }
+   }
 
 #define OCTAVE_S_US_FTR_FCNS(T) \
   OCTAVE_S_US_FTR (T, unsigned char) \
@@ -191,10 +207,19 @@
 OCTAVE_S_US_FTR_FCNS (long)
 OCTAVE_S_US_FTR_FCNS (long long)
 
+#define OCTAVE_INT_CONV_FIT_TO_RANGE(r, T) \
+  octave_int_fit_to_range (r, \
+                           std::numeric_limits<T>::min (), \
+                           std::numeric_limits<T>::max (), \
+			   octave_int<T>::conv_flag, \
+			   octave_int<T>::int_truncate)
+
 #define OCTAVE_INT_FIT_TO_RANGE(r, T) \
   octave_int_fit_to_range (r, \
                            std::numeric_limits<T>::min (), \
-                           std::numeric_limits<T>::max ())
+                           std::numeric_limits<T>::max (), \
+			   octave_int<T>::conv_flag, \
+			   octave_int<T>::math_truncate)
 
 #define OCTAVE_INT_MIN_VAL2(T1, T2) \
   std::numeric_limits<typename octave_int_binop_traits<T1, T2>::TR>::min ()
@@ -205,7 +230,9 @@
 #define OCTAVE_INT_FIT_TO_RANGE2(r, T1, T2) \
   octave_int_fit_to_range (r, \
                            OCTAVE_INT_MIN_VAL2 (T1, T2), \
-                           OCTAVE_INT_MAX_VAL2 (T1, T2))
+                           OCTAVE_INT_MAX_VAL2 (T1, T2), \
+			   octave_int<typename octave_int_binop_traits<T1, T2>::TR>::conv_flag, \
+			   octave_int<typename octave_int_binop_traits<T1, T2>::TR>::math_truncate)
 
 // We have all the machinery below (octave_int_helper) to avoid a few
 // warnings from GCC about comparisons always false due to limited
@@ -268,24 +295,34 @@
 octave_int
 {
 public:
+  enum conv_error_type
+    {
+      int_truncate = 1,
+      conv_nan = 2,
+      conv_non_int = 4,
+      math_truncate = 8
+    };
 
   typedef T val_type;
 
   octave_int (void) : ival () { }
 
   template <class U>
-  octave_int (U i) : ival (OCTAVE_INT_FIT_TO_RANGE (i, T)) { }
+  octave_int (U i) : ival (OCTAVE_INT_CONV_FIT_TO_RANGE (i, T)) { }
 
-  octave_int (double d) : ival (OCTAVE_INT_FIT_TO_RANGE (xround (d), T)) { }
+  octave_int (double d) : ival (OCTAVE_INT_CONV_FIT_TO_RANGE (xround (d), T)) 
+    { 
+      if (xisnan (d))
+	conv_flag |= conv_nan;
+      else
+	conv_flag |= (d != xround (d) ? conv_non_int : 0);
+    }
 
   octave_int (bool b) : ival (b) { }
 
   template <class U>
   octave_int (const octave_int<U>& i)
-    : ival (OCTAVE_INT_FIT_TO_RANGE (i.value (), T)) 
-    { 
-      trunc_flag = trunc_flag || (ival != i.value ());
-    }
+    : ival (OCTAVE_INT_CONV_FIT_TO_RANGE (i.value (), T)) { }
 
   octave_int (const octave_int<T>& i) : ival (i.ival) { }
 
@@ -312,9 +349,13 @@
     // symmetric, which causes things like -intmin("int32") to be the
     // same as intmin("int32") instead of intmax("int32") (which is
     // what we should get with saturation semantics).
-
-    return std::numeric_limits<T>::is_signed ?
-      OCTAVE_INT_FIT_TO_RANGE (- static_cast<double> (ival), T) : 0;
+    if (std::numeric_limits<T>::is_signed)
+      return OCTAVE_INT_FIT_TO_RANGE (- static_cast<double> (ival), T);
+    else
+      {
+	conv_flag |= math_truncate;
+	return 0;
+      }
   }
 
   bool bool_value (void) const { return static_cast<bool> (value ()); }
@@ -402,8 +443,12 @@
 
   static int byte_size (void) { return sizeof(T); }
 
-  static bool get_trunc_flag () { return trunc_flag; }
-  static void clear_trunc_flag () { trunc_flag = false; }
+  static int get_conv_flag () { return conv_flag; }
+  static bool get_trunc_flag () { return (conv_flag & int_truncate); }
+  static bool get_nan_flag () { return (conv_flag & conv_nan); }
+  static bool get_non_int_flag () { return (conv_flag & conv_non_int); }
+  static bool get_math_trunc_flag () { return (conv_flag & math_truncate); }
+  static void clear_conv_flag () { conv_flag = 0; }
 
   static const char *type_name () { return "unknown type"; }
 
@@ -411,13 +456,14 @@
   // You should not use it anywhere else.
   void *mex_get_data (void) const { return const_cast<T *> (&ival); }
 
+  static int conv_flag;
+
 private:
 
-  static bool trunc_flag;
   T ival;
 };
 
-template<class T> bool octave_int<T>::trunc_flag = false; 
+template<class T> int octave_int<T>::conv_flag = 0;
 
 template <class T>
 bool
@@ -484,6 +530,26 @@
 }
 
 template <class T>
+octave_int<T>
+powf (float a, const octave_int<T>& b)
+{
+  float tb = static_cast<float> (b.value ());
+  float r = powf (a, tb);
+  r = __lo_ieee_float_isnan (r) ? 0 : xround (r);
+  return OCTAVE_INT_FIT_TO_RANGE (r, T);
+}
+
+template <class T>
+octave_int<T>
+powf (const octave_int<T>& a, float b)
+{
+  float ta = static_cast<float> (a.value ());
+  float r = pow (ta, b);
+  r = __lo_ieee_float_isnan (r) ? 0 : xround (r);
+  return OCTAVE_INT_FIT_TO_RANGE (r, T);
+}
+
+template <class T>
 std::ostream&
 operator << (std::ostream& os, const octave_int<T>& ival)
 {