Mercurial > hg > octave-avbm
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 +++ b/liboctave/Array.cc @@ -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 +++ b/liboctave/Array.h @@ -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 +++ b/liboctave/Array2.h @@ -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 +++ b/liboctave/Array3.h @@ -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 +++ b/liboctave/ChangeLog @@ -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 +++ b/liboctave/dim-vector.h @@ -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;