changeset 9840:c0b54271904b

improve safe numel() calculation for arrays
author Jaroslav Hajek <highegg@gmail.com>
date Thu, 19 Nov 2009 15:48:33 +0100
parents 3e8b4c80ae63
children 6f1ea8241c99
files liboctave/Array.cc liboctave/Array.h liboctave/Array2.h liboctave/Array3.h liboctave/ChangeLog liboctave/dim-vector.h
diffstat 6 files changed, 40 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/Array.cc	Thu Nov 19 14:40:17 2009 +0100
+++ b/liboctave/Array.cc	Thu Nov 19 15:48:33 2009 +0100
@@ -102,7 +102,7 @@
   if (--rep->count <= 0)
     delete rep;
 
-  rep = new ArrayRep (get_size (dv));
+  rep = new ArrayRep (dv.safe_numel ());
   slice_data = rep->data;
   slice_len = rep->len;
 
@@ -162,135 +162,6 @@
   return retval;
 }
 
-// KLUGE
-
-// The following get_size functions will throw a std::bad_alloc ()
-// exception if the requested size is larger than can be indexed by
-// octave_idx_type.  This may be smaller than the actual amount of
-// memory that can be safely allocated on a system.  However, if we
-// don't fail here, we can end up with a mysterious crash inside a
-// function that is iterating over an array using octave_idx_type
-// indices.
-
-// A guess (should be quite conservative).
-#define MALLOC_OVERHEAD 1024
-
-template <class T>
-octave_idx_type
-Array<T>::get_size (octave_idx_type r, octave_idx_type c)
-{
-  static int nl;
-  static double dl
-    = frexp (static_cast<double> 
-	(std::numeric_limits<octave_idx_type>::max() - MALLOC_OVERHEAD) / sizeof (T), &nl);
-
-  int nr, nc;
-  double dr = frexp (static_cast<double> (r), &nr);   // r = dr * 2^nr
-  double dc = frexp (static_cast<double> (c), &nc);   // c = dc * 2^nc
-
-  int nt = nr + nc;
-  double dt = dr * dc;
-
-  if (dt < 0.5)
-    {
-      nt--;
-      dt *= 2;
-    }
-
-  if (nt < nl || (nt == nl && dt < dl))
-    return r * c;
-  else
-    {
-      throw std::bad_alloc ();
-      return 0;
-    }
-}
-
-template <class T>
-octave_idx_type
-Array<T>::get_size (octave_idx_type r, octave_idx_type c, octave_idx_type p)
-{
-  static int nl;
-  static double dl
-    = frexp (static_cast<double>
-	(std::numeric_limits<octave_idx_type>::max() - MALLOC_OVERHEAD) / sizeof (T), &nl);
-
-  int nr, nc, np;
-  double dr = frexp (static_cast<double> (r), &nr);
-  double dc = frexp (static_cast<double> (c), &nc);
-  double dp = frexp (static_cast<double> (p), &np);
-
-  int nt = nr + nc + np;
-  double dt = dr * dc * dp;
-
-  if (dt < 0.5)
-    {
-      nt--;
-      dt *= 2;
-
-      if (dt < 0.5)
-	{
-	  nt--;
-	  dt *= 2;
-	}
-    }
-
-  if (nt < nl || (nt == nl && dt < dl))
-    return r * c * p;
-  else
-    {
-      throw std::bad_alloc ();
-      return 0;
-    }
-}
-
-template <class T>
-octave_idx_type
-Array<T>::get_size (const dim_vector& ra_idx)
-{
-  static int nl;
-  static double dl
-    = frexp (static_cast<double>
-	(std::numeric_limits<octave_idx_type>::max() - MALLOC_OVERHEAD) / sizeof (T), &nl);
-
-  int n = ra_idx.length ();
-
-  int nt = 0;
-  double dt = 1;
-
-  for (int i = 0; i < n; i++)
-    {
-      int nra_idx;
-      double dra_idx = frexp (static_cast<double> (ra_idx(i)), &nra_idx);
-
-      nt += nra_idx;
-      dt *= dra_idx;
-
-      if (dt < 0.5)
-	{
-	  nt--;
-	  dt *= 2;
-	}
-    }
-
-  if (nt < nl || (nt == nl && dt < dl))
-    {
-      octave_idx_type retval = 1;
-
-      for (int i = 0; i < n; i++)
-	retval *= ra_idx(i);
-
-      return retval;
-    }
-  else
-    {
-      throw std::bad_alloc ();
-      return 0;
-    }
-}
-
-#undef MALLOC_OVERHEAD
-
 template <class T>
 octave_idx_type
 Array<T>::compute_index (const Array<octave_idx_type>& ra_idx) const
--- a/liboctave/Array.h	Thu Nov 19 14:40:17 2009 +0100
+++ b/liboctave/Array.h	Thu Nov 19 15:48:33 2009 +0100
@@ -138,7 +138,7 @@
     }
 
   Array (T *d, const dim_vector& dv)
-    : rep (new typename Array<T>::ArrayRep (d, get_size (dv))),
+    : rep (new typename Array<T>::ArrayRep (d, dv.numel ())),
       dimensions (dv) 
     { 
       slice_data = rep->data;
@@ -224,7 +224,7 @@
 public:
 
   Array (const dim_vector& dv)
-    : rep (new typename Array<T>::ArrayRep (get_size (dv))),
+    : rep (new typename Array<T>::ArrayRep (dv.safe_numel ())),
       dimensions (dv) 
     { 
       slice_data = rep->data;
@@ -232,7 +232,7 @@
     }
 
   Array (const dim_vector& dv, const T& val)
-    : rep (new typename Array<T>::ArrayRep (get_size (dv))),
+    : rep (new typename Array<T>::ArrayRep (dv.safe_numel ())),
       dimensions (dv)
     {
       slice_data = rep->data;
@@ -301,10 +301,6 @@
   void chop_trailing_singletons (void) 
   { dimensions.chop_trailing_singletons (); }
   
-  static octave_idx_type get_size (octave_idx_type r, octave_idx_type c);
-  static octave_idx_type get_size (octave_idx_type r, octave_idx_type c, octave_idx_type p);
-  static octave_idx_type get_size (const dim_vector& dv);
-
   octave_idx_type compute_index (const Array<octave_idx_type>& ra_idx) const;
 
   T range_error (const char *fcn, octave_idx_type n) const;
--- a/liboctave/Array2.h	Thu Nov 19 14:40:17 2009 +0100
+++ b/liboctave/Array2.h	Thu Nov 19 15:48:33 2009 +0100
@@ -43,8 +43,6 @@
 {
 protected:
 
-  static octave_idx_type get_size (octave_idx_type r, octave_idx_type c) { return Array<T>::get_size (r, c); }
-
   Array2 (T *d, octave_idx_type r, octave_idx_type c) : Array<T> (d, dim_vector (r, c)) { }
 
 public:
--- a/liboctave/Array3.h	Thu Nov 19 14:40:17 2009 +0100
+++ b/liboctave/Array3.h	Thu Nov 19 15:48:33 2009 +0100
@@ -41,9 +41,6 @@
 {
 protected:
 
-  static octave_idx_type get_size (octave_idx_type r, octave_idx_type c, octave_idx_type p)
-    { return Array<T>::get_size (r, c, p); }
-
   Array3 (T *d, octave_idx_type r, octave_idx_type c, octave_idx_type p) : Array<T> (d, dim_vector (r, c, p)) { }
 
 public:
--- a/liboctave/ChangeLog	Thu Nov 19 14:40:17 2009 +0100
+++ b/liboctave/ChangeLog	Thu Nov 19 15:48:33 2009 +0100
@@ -1,3 +1,14 @@
+2009-11-19  Jaroslav Hajek  <highegg@gmail.com>
+
+	* dim-vector.h (dim_vector::safe_numel): New method.
+	* Array.h (Array<T>::Array (const dim_vector&),
+	Array<T>::Array (const dim_vector&, const T&),
+	Array<T>::Array (T *, const dim_vector&)): Use it here.
+	* Array.cc (Array<T>::clear (const dim_vector&)): Also here.
+	(Array<T>::get_size): Remove.
+	* Array2.h (Array2::get_size): Remove.
+	* Array3.h (Array3::get_size): Remove.
+
 2009-11-19  Jaroslav Hajek  <highegg@gmail.com>
 
 	* Array.cc (Array::clear (const dim_vector&)): Use get_size.
--- a/liboctave/dim-vector.h	Thu Nov 19 14:40:17 2009 +0100
+++ b/liboctave/dim-vector.h	Thu Nov 19 15:48:33 2009 +0100
@@ -25,6 +25,7 @@
 #define octave_dim_vector_h 1
 
 #include <cassert>
+#include <limits>
 
 #include <sstream>
 #include <string>
@@ -327,6 +328,30 @@
     return retval;
   }
 
+  // The following function will throw a std::bad_alloc ()
+  // exception if the requested size is larger than can be indexed by
+  // octave_idx_type. This may be smaller than the actual amount of
+  // memory that can be safely allocated on a system.  However, if we
+  // don't fail here, we can end up with a mysterious crash inside a
+  // function that is iterating over an array using octave_idx_type
+  // indices.
+
+  octave_idx_type safe_numel (void) const
+  {
+    octave_idx_type idx_max = std::numeric_limits<octave_idx_type>::max () - 1;
+    octave_idx_type n = 1;
+    int n_dims = length ();
+    for (int i = 0; i < n_dims; i++)
+      {
+        n *= rep[i];
+        if (rep[i] != 0)
+          idx_max /= rep[i];
+        if (idx_max <= 0)
+          throw std::bad_alloc ();
+      }
+    return n;
+  }
+
   bool any_neg (void) const
   {
     int n_dims = length (), i;