changeset 7997:2b8952e133c9

implement checked conversions between integers
author Jaroslav Hajek <highegg@gmail.com>
date Wed, 30 Jul 2008 15:20:13 +0200
parents 6a7db240b3a3
children a4acda9fc3e7
files liboctave/ChangeLog liboctave/oct-inttypes.h src/ChangeLog src/gripes.cc src/gripes.h src/ops.h src/ov-intx.h src/ov.cc
diffstat 8 files changed, 200 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog	Wed Jul 30 14:13:45 2008 -0400
+++ b/liboctave/ChangeLog	Wed Jul 30 15:20:13 2008 +0200
@@ -1,3 +1,12 @@
+2008-07-30  Jaroslav Hajek <highegg@gmail.com>
+
+	* oct-inttypes.h (octave_int<T>::trunc_flag): New member static field.
+	(octave_int<T>::get_trunc_flag, octave_int<T>::clear_trunc_flag): New
+	member functions.
+	(octave_int<T>::octave_int (const octave_int<U>&)): set trunc_flag on truncation.
+	(SPECIALIZE_WIDENING_CONVERSION): New macro.
+	(DECLARE_OCTAVE_INT_TYPENAME): New macro.
+
 2008-07-29  David Bateman  <dbateman@free.fr>
 
 	* lo-ieee.h (LO_IEEE_NA_HW, LO_IEEE_NA_LW, LO_IEEE_NA_FLOAT):
--- a/liboctave/oct-inttypes.h	Wed Jul 30 14:13:45 2008 -0400
+++ b/liboctave/oct-inttypes.h	Wed Jul 30 15:20:13 2008 +0200
@@ -1,6 +1,7 @@
 /*
 
 Copyright (C) 2004, 2005, 2006, 2007 John W. Eaton
+Copyright (C) 2008 Jaroslav Hajek <highegg@gmail.com>
 
 This file is part of Octave.
 
@@ -281,7 +282,10 @@
 
   template <class U>
   octave_int (const octave_int<U>& i)
-    : ival (OCTAVE_INT_FIT_TO_RANGE (i.value (), T)) { }
+    : ival (OCTAVE_INT_FIT_TO_RANGE (i.value (), T)) 
+    { 
+      trunc_flag = trunc_flag || (ival != i.value ());
+    }
 
   octave_int (const octave_int<T>& i) : ival (i.ival) { }
 
@@ -398,15 +402,23 @@
 
   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 const char *type_name () { return "unknown type"; }
+
   // Unsafe.  This function exists to support the MEX interface.
   // You should not use it anywhere else.
   void *mex_get_data (void) const { return const_cast<T *> (&ival); }
 
 private:
 
+  static bool trunc_flag;
   T ival;
 };
 
+template<class T> bool octave_int<T>::trunc_flag = false; 
+
 template <class T>
 bool
 xisnan (const octave_int<T>&)
@@ -489,6 +501,43 @@
   return is;
 }
 
+// specialize the widening conversions to make them faster
+// gosh. the syntax is tricky!
+
+#define SPECIALIZE_WIDENING_CONVERSION(T1, T2) \
+  template <> template <> \
+  inline octave_int<T2>::octave_int (T1 i) : ival (i) {} \
+  template <> template <> \
+  inline octave_int<T2>::octave_int (const octave_int<T1>& i) : ival (i.value ()) {}
+
+SPECIALIZE_WIDENING_CONVERSION(int8_t, int16_t)
+SPECIALIZE_WIDENING_CONVERSION(int8_t, int32_t)
+SPECIALIZE_WIDENING_CONVERSION(int8_t, int64_t)
+SPECIALIZE_WIDENING_CONVERSION(int16_t, int32_t)
+SPECIALIZE_WIDENING_CONVERSION(int16_t, int64_t)
+SPECIALIZE_WIDENING_CONVERSION(int32_t, int64_t)
+SPECIALIZE_WIDENING_CONVERSION(uint8_t, uint16_t)
+SPECIALIZE_WIDENING_CONVERSION(uint8_t, uint32_t)
+SPECIALIZE_WIDENING_CONVERSION(uint8_t, uint64_t)
+SPECIALIZE_WIDENING_CONVERSION(uint16_t, uint32_t)
+SPECIALIZE_WIDENING_CONVERSION(uint16_t, uint64_t)
+SPECIALIZE_WIDENING_CONVERSION(uint32_t, uint64_t)
+
+// declare type names
+#define DECLARE_OCTAVE_INT_TYPENAME(TYPE, TYPENAME) \
+  template<> \
+  inline const char * \
+  octave_int<TYPE>::type_name () { return TYPENAME; }
+
+DECLARE_OCTAVE_INT_TYPENAME(int8_t, "int8")
+DECLARE_OCTAVE_INT_TYPENAME(int16_t, "int16")
+DECLARE_OCTAVE_INT_TYPENAME(int32_t, "int32")
+DECLARE_OCTAVE_INT_TYPENAME(int64_t, "int64")
+DECLARE_OCTAVE_INT_TYPENAME(uint8_t, "uint8")
+DECLARE_OCTAVE_INT_TYPENAME(uint16_t, "uint16")
+DECLARE_OCTAVE_INT_TYPENAME(uint32_t, "uint32")
+DECLARE_OCTAVE_INT_TYPENAME(uint64_t, "uint64")
+
 typedef octave_int<int8_t> octave_int8;
 typedef octave_int<int16_t> octave_int16;
 typedef octave_int<int32_t> octave_int32;
--- a/src/ChangeLog	Wed Jul 30 14:13:45 2008 -0400
+++ b/src/ChangeLog	Wed Jul 30 15:20:13 2008 +0200
@@ -1,3 +1,18 @@
+2008-07-30  Jaroslav Hajek <highegg@gmail.com>
+
+	* gripes.cc (gripe_truncated_conversion): New function.
+	* gripes.h (gripe_truncated_conversion): Declare it.
+	* ops.h (DEFCONVFNX2): New macro.
+	(DEFCONVFN, DEFCONVFN2): Call DEFCONVFNX2 instead of DEFCONVFNX.
+	* ov-intx.h (OCTAVE_VALUE_INT_MATRIX_T::convert_gripe): New member
+	function.
+	(OCTAVE_VALUE_INT_MATRIX_T::int*_array_value): Call convert_gripe.
+	(OCTAVE_VALUE_INT_SCALAR_T::convert_gripe): New member function.
+	(OCTAVE_VALUE_INT_SCALAR_T::int*_scalar_value): Call convert_gripe.
+	(OCTAVE_VALUE_INT_SCALAR_T::int*_array_value): Call int*_scalar_value.
+	* ov.cc (convert_to_int_array): New function.
+	(int_vector_value): Call convert_to_int_array.
+
 2008-07-30  John W. Eaton  <jwe@octave.org>
 
 	* defun-dld.h (DEFUNX_DLD): Eliminate fsname arg.
--- a/src/gripes.cc	Wed Jul 30 14:13:45 2008 -0400
+++ b/src/gripes.cc	Wed Jul 30 15:20:13 2008 +0200
@@ -204,6 +204,14 @@
 		   "value not equal to 1 or 0 converted to logical 1");
 }
 
+extern void
+gripe_truncated_conversion (const char *srctype, const char *desttype)
+{
+  warning_with_id ("Octave:truncated_conversion", 
+                   "data truncated converting from %s to %s",
+                   srctype, desttype);
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/gripes.h	Wed Jul 30 14:13:45 2008 -0400
+++ b/src/gripes.h	Wed Jul 30 15:20:13 2008 +0200
@@ -108,6 +108,9 @@
 			   const std::string& to);
 
 extern OCTINTERP_API void
+gripe_truncated_conversion (const char *srctype, const char *desttype);
+
+extern OCTINTERP_API void
 gripe_divide_by_zero (void);
 
 extern OCTINTERP_API void
--- a/src/ops.h	Wed Jul 30 14:13:45 2008 -0400
+++ b/src/ops.h	Wed Jul 30 15:20:13 2008 +0200
@@ -207,6 +207,14 @@
     return new octave_ ## ovtto (tto ## NDArray (v.e ## array_value ())); \
   }
 
+#define DEFCONVFNX2(name, tfrom, ovtto, e) \
+  CONVDECL (name) \
+  { \
+    CAST_CONV_ARG (const octave_ ## tfrom&); \
+ \
+    return new octave_ ## ovtto (v.e ## array_value ()); \
+  }
+
 #define DEFDBLCONVFN(name, ovtfrom, e) \
   CONVDECL (name) \
   { \
@@ -222,10 +230,10 @@
   DEFCONVFNX(name, tfrom, matrix, , char_)
 
 #define DEFCONVFN(name, tfrom, tto) \
-  DEFCONVFNX (name, tfrom, tto ## _matrix, tto, )
+  DEFCONVFNX2 (name, tfrom, tto ## _matrix, tto ## _)
 
 #define DEFCONVFN2(name, tfrom, sm, tto) \
-  DEFCONVFNX (name, tfrom ## _ ## sm, tto ## _matrix, tto, tfrom ## _)
+  DEFCONVFNX2 (name, tfrom ## _ ## sm, tto ## _matrix, tto ## _)
 
 #define UNOPDECL(name, a) \
   static octave_value \
--- a/src/ov-intx.h	Wed Jul 30 14:13:45 2008 -0400
+++ b/src/ov-intx.h	Wed Jul 30 15:20:13 2008 +0200
@@ -67,29 +67,51 @@
 
   bool is_integer_type (void) const { return true; }
 
+private:
+
+  template <class _int_matrix>
+  _int_matrix convert_gripe () const
+    {
+      typedef typename _int_matrix::element_type dest_el_type;
+      typedef OCTAVE_INT_NDARRAY_T::element_type src_el_type;
+      dest_el_type::clear_trunc_flag ();
+      _int_matrix retval (matrix);
+      if (dest_el_type::get_trunc_flag ())
+        {
+          gripe_truncated_conversion (src_el_type::type_name (),
+                                      dest_el_type::type_name ());
+          dest_el_type::clear_trunc_flag ();
+
+        }
+
+      return retval;
+    }
+
+public:
+
   int8NDArray
-  int8_array_value (void) const { return int8NDArray (matrix); }
+  int8_array_value (void) const { return convert_gripe<int8NDArray> (); }
 
   int16NDArray
-  int16_array_value (void) const { return int16NDArray (matrix); }
+  int16_array_value (void) const { return convert_gripe<int16NDArray> (); }
 
   int32NDArray
-  int32_array_value (void) const { return int32NDArray (matrix); }
+  int32_array_value (void) const { return convert_gripe<int32NDArray> (); }
 
   int64NDArray
-  int64_array_value (void) const { return int64NDArray (matrix); }
+  int64_array_value (void) const { return convert_gripe<int64NDArray> (); }
 
   uint8NDArray
-  uint8_array_value (void) const { return uint8NDArray (matrix); }
+  uint8_array_value (void) const { return convert_gripe<uint8NDArray> (); }
 
   uint16NDArray
-  uint16_array_value (void) const { return uint16NDArray (matrix); }
+  uint16_array_value (void) const { return convert_gripe<uint16NDArray> (); }
 
   uint32NDArray
-  uint32_array_value (void) const { return uint32NDArray (matrix); }
+  uint32_array_value (void) const { return convert_gripe<uint32NDArray> (); }
 
   uint64NDArray
-  uint64_array_value (void) const { return uint64NDArray (matrix); }
+  uint64_array_value (void) const { return convert_gripe<uint64NDArray> (); }
 
   double
   double_value (bool = false) const
@@ -405,61 +427,83 @@
 
   bool is_integer_type (void) const { return true; }
 
+private:
+
+  template <class _int_scalar>
+  _int_scalar convert_gripe () const
+    {
+      typedef _int_scalar dest_el_type;
+      typedef OCTAVE_INT_T src_el_type;
+      dest_el_type::clear_trunc_flag ();
+      _int_scalar retval (scalar);
+      if (dest_el_type::get_trunc_flag ())
+        {
+          gripe_truncated_conversion (src_el_type::type_name (),
+                                      dest_el_type::type_name ());
+          dest_el_type::clear_trunc_flag ();
+
+        }
+
+      return retval;
+    }
+
+public:
+
   octave_int8
-  int8_scalar_value (void) const { return octave_int8 (scalar); }
+  int8_scalar_value (void) const { return convert_gripe<octave_int8> (); }
 
   octave_int16
-  int16_scalar_value (void) const { return octave_int16 (scalar); }
+  int16_scalar_value (void) const { return convert_gripe<octave_int16> (); }
 
   octave_int32
-  int32_scalar_value (void) const { return octave_int32 (scalar); }
+  int32_scalar_value (void) const { return convert_gripe<octave_int32> (); }
 
   octave_int64
-  int64_scalar_value (void) const { return octave_int64 (scalar); }
+  int64_scalar_value (void) const { return convert_gripe<octave_int64> (); }
 
   octave_uint8
-  uint8_scalar_value (void) const { return octave_uint8 (scalar); }
+  uint8_scalar_value (void) const { return convert_gripe<octave_uint8> (); }
 
   octave_uint16
-  uint16_scalar_value (void) const { return octave_uint16 (scalar); }
+  uint16_scalar_value (void) const { return convert_gripe<octave_uint16> (); }
 
   octave_uint32
-  uint32_scalar_value (void) const { return octave_uint32 (scalar); }
+  uint32_scalar_value (void) const { return convert_gripe<octave_uint32> (); }
 
   octave_uint64
-  uint64_scalar_value (void) const { return octave_uint64 (scalar); }
+  uint64_scalar_value (void) const { return convert_gripe<octave_uint64> (); }
 
   int8NDArray
   int8_array_value (void) const
-    { return int8NDArray (dim_vector (1, 1), scalar); }
+    { return int8NDArray (dim_vector (1, 1), int8_scalar_value ()); }
 
   int16NDArray
   int16_array_value (void) const
-    { return int16NDArray (dim_vector (1, 1), scalar); }
+    { return int16NDArray (dim_vector (1, 1), int16_scalar_value ()); }
 
   int32NDArray
   int32_array_value (void) const
-    { return int32NDArray (dim_vector (1, 1), scalar); }
+    { return int32NDArray (dim_vector (1, 1), int32_scalar_value ()); }
 
   int64NDArray
   int64_array_value (void) const
-    { return int64NDArray (dim_vector (1, 1), scalar); }
+    { return int64NDArray (dim_vector (1, 1), int64_scalar_value ()); }
 
   uint8NDArray
   uint8_array_value (void) const
-    { return uint8NDArray (dim_vector (1, 1), scalar); }
+    { return uint8NDArray (dim_vector (1, 1), uint8_scalar_value ()); }
 
   uint16NDArray
   uint16_array_value (void) const
-    { return uint16NDArray (dim_vector (1, 1), scalar); }
+    { return uint16NDArray (dim_vector (1, 1), uint16_scalar_value ()); }
 
   uint32NDArray
   uint32_array_value (void) const
-    { return uint32NDArray (dim_vector (1, 1), scalar); }
+    { return uint32NDArray (dim_vector (1, 1), uint32_scalar_value ()); }
 
   uint64NDArray
   uint64_array_value (void) const
-    { return uint64NDArray (dim_vector (1, 1), scalar); }
+    { return uint64NDArray (dim_vector (1, 1), uint64_scalar_value ()); }
 
   octave_value resize (const dim_vector& dv, bool fill = false) const
     {
--- a/src/ov.cc	Wed Jul 30 14:13:45 2008 -0400
+++ b/src/ov.cc	Wed Jul 30 15:20:13 2008 +0200
@@ -1346,6 +1346,25 @@
                                              type_name (), "real vector"));
 }
 
+template <class T>
+static Array<int>
+convert_to_int_array (const Array<octave_int<T> >& A)
+{
+  Array<int> O (A.dims ());
+  octave_idx_type n = A.numel ();
+
+  octave_int<int>::clear_trunc_flag ();
+  for (octave_idx_type i = 0; i < n; i++)
+    O.xelem (i) = octave_int<int> (A.xelem (i));
+  if (octave_int<int>::get_trunc_flag ())
+    {
+      gripe_truncated_conversion (octave_int<T>::type_name (), "int");
+      octave_int<int>::clear_trunc_flag ();
+    }
+
+  return O;
+}
+
 Array<int>
 octave_value::int_vector_value (bool force_string_conv, bool require_int,
 				bool force_vector_conversion) const
@@ -1354,14 +1373,24 @@
 
   if (is_integer_type ())
     {
-      // query for the first type that is wide enough
-#if SIZEOF_INT == 2
-      retval = int16_array_value ();
-#elif SIZEOF_INT == 4
-      retval = int32_array_value ();
-#else
-      retval = int64_array_value ();
-#endif
+      if (is_int32_type ())
+        retval = convert_to_int_array (int32_array_value ());
+      else if (is_int64_type ())
+        retval = convert_to_int_array (int64_array_value ());
+      else if (is_int16_type ())
+        retval = convert_to_int_array (int16_array_value ());
+      else if (is_int8_type ())
+        retval = convert_to_int_array (int8_array_value ());
+      else if (is_uint32_type ())
+        retval = convert_to_int_array (uint32_array_value ());
+      else if (is_uint64_type ())
+        retval = convert_to_int_array (uint64_array_value ());
+      else if (is_uint16_type ())
+        retval = convert_to_int_array (uint16_array_value ());
+      else if (is_uint8_type ())
+        retval = convert_to_int_array (uint8_array_value ());
+      else
+        retval = array_value (force_string_conv);
     }
   else 
     {