comparison liboctave/Array.cc @ 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 ead4f9c82a9a
comparison
equal deleted inserted replaced
9839:3e8b4c80ae63 9840:c0b54271904b
100 Array<T>::clear (const dim_vector& dv) 100 Array<T>::clear (const dim_vector& dv)
101 { 101 {
102 if (--rep->count <= 0) 102 if (--rep->count <= 0)
103 delete rep; 103 delete rep;
104 104
105 rep = new ArrayRep (get_size (dv)); 105 rep = new ArrayRep (dv.safe_numel ());
106 slice_data = rep->data; 106 slice_data = rep->data;
107 slice_len = rep->len; 107 slice_len = rep->len;
108 108
109 dimensions = dv; 109 dimensions = dv;
110 } 110 }
159 retval = Array<T> (*this, new_dimensions); 159 retval = Array<T> (*this, new_dimensions);
160 } 160 }
161 161
162 return retval; 162 return retval;
163 } 163 }
164
165 // KLUGE
166
167 // The following get_size functions will throw a std::bad_alloc ()
168 // exception if the requested size is larger than can be indexed by
169 // octave_idx_type. This may be smaller than the actual amount of
170 // memory that can be safely allocated on a system. However, if we
171 // don't fail here, we can end up with a mysterious crash inside a
172 // function that is iterating over an array using octave_idx_type
173 // indices.
174
175 // A guess (should be quite conservative).
176 #define MALLOC_OVERHEAD 1024
177
178 template <class T>
179 octave_idx_type
180 Array<T>::get_size (octave_idx_type r, octave_idx_type c)
181 {
182 static int nl;
183 static double dl
184 = frexp (static_cast<double>
185 (std::numeric_limits<octave_idx_type>::max() - MALLOC_OVERHEAD) / sizeof (T), &nl);
186
187 int nr, nc;
188 double dr = frexp (static_cast<double> (r), &nr); // r = dr * 2^nr
189 double dc = frexp (static_cast<double> (c), &nc); // c = dc * 2^nc
190
191 int nt = nr + nc;
192 double dt = dr * dc;
193
194 if (dt < 0.5)
195 {
196 nt--;
197 dt *= 2;
198 }
199
200 if (nt < nl || (nt == nl && dt < dl))
201 return r * c;
202 else
203 {
204 throw std::bad_alloc ();
205 return 0;
206 }
207 }
208
209 template <class T>
210 octave_idx_type
211 Array<T>::get_size (octave_idx_type r, octave_idx_type c, octave_idx_type p)
212 {
213 static int nl;
214 static double dl
215 = frexp (static_cast<double>
216 (std::numeric_limits<octave_idx_type>::max() - MALLOC_OVERHEAD) / sizeof (T), &nl);
217
218 int nr, nc, np;
219 double dr = frexp (static_cast<double> (r), &nr);
220 double dc = frexp (static_cast<double> (c), &nc);
221 double dp = frexp (static_cast<double> (p), &np);
222
223 int nt = nr + nc + np;
224 double dt = dr * dc * dp;
225
226 if (dt < 0.5)
227 {
228 nt--;
229 dt *= 2;
230
231 if (dt < 0.5)
232 {
233 nt--;
234 dt *= 2;
235 }
236 }
237
238 if (nt < nl || (nt == nl && dt < dl))
239 return r * c * p;
240 else
241 {
242 throw std::bad_alloc ();
243 return 0;
244 }
245 }
246
247 template <class T>
248 octave_idx_type
249 Array<T>::get_size (const dim_vector& ra_idx)
250 {
251 static int nl;
252 static double dl
253 = frexp (static_cast<double>
254 (std::numeric_limits<octave_idx_type>::max() - MALLOC_OVERHEAD) / sizeof (T), &nl);
255
256 int n = ra_idx.length ();
257
258 int nt = 0;
259 double dt = 1;
260
261 for (int i = 0; i < n; i++)
262 {
263 int nra_idx;
264 double dra_idx = frexp (static_cast<double> (ra_idx(i)), &nra_idx);
265
266 nt += nra_idx;
267 dt *= dra_idx;
268
269 if (dt < 0.5)
270 {
271 nt--;
272 dt *= 2;
273 }
274 }
275
276 if (nt < nl || (nt == nl && dt < dl))
277 {
278 octave_idx_type retval = 1;
279
280 for (int i = 0; i < n; i++)
281 retval *= ra_idx(i);
282
283 return retval;
284 }
285 else
286 {
287 throw std::bad_alloc ();
288 return 0;
289 }
290 }
291
292 #undef MALLOC_OVERHEAD
293 164
294 template <class T> 165 template <class T>
295 octave_idx_type 166 octave_idx_type
296 Array<T>::compute_index (const Array<octave_idx_type>& ra_idx) const 167 Array<T>::compute_index (const Array<octave_idx_type>& ra_idx) const
297 { 168 {