comparison libinterp/octave-value/ov-base-mat.cc @ 20574:dd6345fd8a97

use exceptions for better invalid index error reporting (bug #45957) * lo-array-gripes.h, lo-array-gripes.cc (index_exception): New base class for indexing errors. (invalid_index, out_of_range): New classes. (gripe_index_out_of_range): New overloaded function. (gripe_invalid_index): New overloaded functions. Delete version with no arguments. (gripe_invalid_assignment_size, gripe_assignment_dimension_mismatch): Delete. Change uses of gripe functions as needed. * Cell.cc (Cell::index, Cell::assign, Cell::delete_elements): Use exceptions to collect error info about and handle indexing errors. * data.cc (Fnth_element, do_accumarray_sum, F__accumarray_sum__, do_accumarray_minmax, do_accumarray_minmax_fun, F__accumdim_sum__): Likewise. * oct-map.cc (octave_map::index, octave_map::assign, octave_map::delete_elements): Likewise. * sparse.cc (Fsparse): Likewise. * sub2ind.cc (Fsub2ind, Find2sub): Likewise. New tests. * utils.cc (dims_to_numel): Likewise. * ov-base-diag.cc (octave_base_diag<DMT, MT>::do_index_op, octave_base_diag<DMT, MT>::subsasgn): Likewise. * ov-base-mat.cc (octave_base_matrix<MT>::subsref, octave_base_matrix<MT>::assign): Likewise. * ov-base-sparse.cc (octave_base_sparse<T>::do_index_op, octave_base_sparse<T>::assign, octave_base_sparse<MT>::delete_elements): Likewise. * ov-classdef.cc (cdef_object_array::subsref, cdef_object_array::subsasgn): Likewise. * ov-java.cc (make_java_index): Likewise. * ov-perm.cc (octave_perm_matrix::do_index_op): Likewise. * ov-range.cc (octave_range::do_index_op): Likewise. * ov-re-diag.cc (octave_diag_matrix::do_index_op): Likewise. * ov-str-mat.cc (octave_char_matrix_str::do_index_op_internal): Likewise. * pt-assign.cc (tree_simple_assignment::rvalue1): Likewise. * pt-idx.cc (tree_index_expression::rvalue, tree_index_expression::lvalue): Likewise. * Array-util.cc (sub2ind): Likewise. * toplev.cc (main_loop): Also catch unhandled index_exception exceptions. * ov-base.cc (octave_base_value::index_vector): Improve error message. * ov-re-sparse.cc (octave_sparse_matrix::index_vector): Likewise. * ov-complex.cc (complex_index): New class. (gripe_complex_index): New function. (octave_complex::index_vector): Use it. * pt-id.h, pt-id.cc (tree_identifier::is_variable, tree_black_hole::is_variable): Now const. * pt-idx.cc (final_index_error): New static function. (tree_index_expression::rvalue, tree_index_expression::lvalue): Use it. * index.tst: New tests.
author Lachlan Andrew <lachlanbis@gmail.com>
date Fri, 02 Oct 2015 15:07:37 -0400
parents b2100e1659ac
children 1a0a433c8263
comparison
equal deleted inserted replaced
20573:e3c0fee87493 20574:dd6345fd8a97
34 #include "oct-map.h" 34 #include "oct-map.h"
35 #include "ov-base.h" 35 #include "ov-base.h"
36 #include "ov-base-mat.h" 36 #include "ov-base-mat.h"
37 #include "ov-base-scalar.h" 37 #include "ov-base-scalar.h"
38 #include "pr-output.h" 38 #include "pr-output.h"
39 39
40 template <class MT> 40 template <class MT>
41 octave_value 41 octave_value
42 octave_base_matrix<MT>::subsref (const std::string& type, 42 octave_base_matrix<MT>::subsref (const std::string& type,
43 const std::list<octave_value_list>& idx) 43 const std::list<octave_value_list>& idx)
44 { 44 {
138 octave_idx_type n_idx = idx.length (); 138 octave_idx_type n_idx = idx.length ();
139 139
140 int nd = matrix.ndims (); 140 int nd = matrix.ndims ();
141 const MT& cmatrix = matrix; 141 const MT& cmatrix = matrix;
142 142
143 switch (n_idx) 143 // If we catch an indexing error in index_vector, we flag an error in
144 { 144 // index k. Ensure it is the right value befor each idx_vector call.
145 case 0: 145 // Same variable as used in the for loop in the default case.
146 retval = matrix; 146
147 break; 147 octave_idx_type k = 0;
148 148
149 case 1: 149 try
150 { 150 {
151 idx_vector i = idx (0).index_vector (); 151 switch (n_idx)
152 152 {
153 if (! error_state) 153 case 0:
154 { 154 retval = matrix;
155 // optimize single scalar index. 155 break;
156 if (! resize_ok && i.is_scalar ()) 156
157 retval = cmatrix.checkelem (i(0)); 157 case 1:
158 else 158 {
159 retval = MT (matrix.index (i, resize_ok)); 159 idx_vector i = idx (0).index_vector ();
160 }
161 }
162 break;
163
164 case 2:
165 {
166 idx_vector i = idx (0).index_vector ();
167
168 if (! error_state)
169 {
170 idx_vector j = idx (1).index_vector ();
171 160
172 if (! error_state) 161 if (! error_state)
173 { 162 {
174 // optimize two scalar indices. 163 // optimize single scalar index.
175 if (! resize_ok && i.is_scalar () && j.is_scalar ()) 164 if (! resize_ok && i.is_scalar ())
176 retval = cmatrix.checkelem (i(0), j(0)); 165 retval = cmatrix.checkelem (i(0));
177 else 166 else
178 retval = MT (matrix.index (i, j, resize_ok)); 167 retval = MT (matrix.index (i, resize_ok));
179 } 168 }
180 } 169 }
181 } 170 break;
182 break; 171
183 172 case 2:
184 default: 173 {
185 { 174 idx_vector i = idx (0).index_vector ();
186 Array<idx_vector> idx_vec (dim_vector (n_idx, 1)); 175
187 bool scalar_opt = n_idx == nd && ! resize_ok; 176 if (! error_state)
188 const dim_vector dv = matrix.dims (); 177 {
189 178 k=1;
190 for (octave_idx_type i = 0; i < n_idx; i++) 179 idx_vector j = idx (1).index_vector ();
191 { 180
192 idx_vec(i) = idx(i).index_vector (); 181 if (! error_state)
193 182 {
194 if (error_state) 183 // optimize two scalar indices.
195 break; 184 if (! resize_ok && i.is_scalar () && j.is_scalar ())
196 185 retval = cmatrix.checkelem (i(0), j(0));
197 scalar_opt = (scalar_opt && idx_vec(i).is_scalar ()); 186 else
198 } 187 retval = MT (matrix.index (i, j, resize_ok));
199 188 }
200 if (! error_state) 189 }
201 { 190 }
202 if (scalar_opt) 191 break;
203 retval = cmatrix.checkelem (conv_to_int_array (idx_vec)); 192
204 else 193 default:
205 retval = MT (matrix.index (idx_vec, resize_ok)); 194 {
206 } 195 Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
207 } 196 bool scalar_opt = n_idx == nd && ! resize_ok;
208 break; 197 const dim_vector dv = matrix.dims ();
198
199 for (k = 0; k < n_idx; k++)
200 {
201 idx_vec(k) = idx(k).index_vector ();
202
203 if (error_state)
204 break;
205
206 scalar_opt = (scalar_opt && idx_vec(k).is_scalar ());
207 }
208
209 if (! error_state)
210 {
211 if (scalar_opt)
212 retval = cmatrix.checkelem (conv_to_int_array (idx_vec));
213 else
214 retval = MT (matrix.index (idx_vec, resize_ok));
215 }
216 }
217 break;
218 }
219 }
220 catch (index_exception& e)
221 {
222 // Rethrow to allow more info to be reported later.
223 e.set_pos_if_unset (n_idx, k+1);
224 throw;
209 } 225 }
210 226
211 return retval; 227 return retval;
212 } 228 }
213 229
215 void 231 void
216 octave_base_matrix<MT>::assign (const octave_value_list& idx, const MT& rhs) 232 octave_base_matrix<MT>::assign (const octave_value_list& idx, const MT& rhs)
217 { 233 {
218 octave_idx_type n_idx = idx.length (); 234 octave_idx_type n_idx = idx.length ();
219 235
220 switch (n_idx) 236 // If we catch an indexing error in index_vector, we flag an error in
221 { 237 // index k. Ensure it is the right value befor each idx_vector call.
222 case 0: 238 // Same variable as used in the for loop in the default case.
223 panic_impossible (); 239
224 break; 240 octave_idx_type k = 0;
225 241
226 case 1: 242 try
227 { 243 {
228 idx_vector i = idx (0).index_vector (); 244 switch (n_idx)
229 245 {
230 if (! error_state) 246 case 0:
231 matrix.assign (i, rhs); 247 panic_impossible ();
232 } 248 break;
233 break; 249
234 250 case 1:
235 case 2: 251 {
236 { 252 idx_vector i = idx (0).index_vector ();
237 idx_vector i = idx (0).index_vector (); 253
238 254 if (! error_state)
239 if (! error_state) 255 matrix.assign (i, rhs);
240 { 256 }
241 idx_vector j = idx (1).index_vector (); 257 break;
242 258
243 if (! error_state) 259 case 2:
244 matrix.assign (i, j, rhs); 260 {
245 } 261 idx_vector i = idx (0).index_vector ();
246 } 262
247 break; 263 if (! error_state)
248 264 {
249 default: 265 k = 1;
250 { 266 idx_vector j = idx (1).index_vector ();
251 Array<idx_vector> idx_vec (dim_vector (n_idx, 1)); 267
252 268 if (! error_state)
253 for (octave_idx_type i = 0; i < n_idx; i++) 269 matrix.assign (i, j, rhs);
254 { 270 }
255 idx_vec(i) = idx(i).index_vector (); 271 }
256 272 break;
257 if (error_state) 273
258 break; 274 default:
259 } 275 {
260 276 Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
261 if (! error_state) 277
262 matrix.assign (idx_vec, rhs); 278 for (k = 0; k < n_idx; k++)
263 } 279 {
264 break; 280 idx_vec(k) = idx(k).index_vector ();
281
282 if (error_state)
283 break;
284 }
285
286 if (! error_state)
287 matrix.assign (idx_vec, rhs);
288 }
289 break;
290 }
291 }
292 catch (index_exception& e)
293 {
294 gripe_invalid_index (e.idx(), n_idx, k+1);
265 } 295 }
266 296
267 // Clear cache. 297 // Clear cache.
268 clear_cached_info (); 298 clear_cached_info ();
269 } 299 }
286 316
287 int nd = matrix.ndims (); 317 int nd = matrix.ndims ();
288 318
289 MT mrhs (dim_vector (1, 1), rhs); 319 MT mrhs (dim_vector (1, 1), rhs);
290 320
291 switch (n_idx) 321 // If we catch an indexing error in index_vector, we flag an error in
292 { 322 // index k. Ensure it is the right value befor each idx_vector call.
293 case 0: 323 // Same variable as used in the for loop in the default case.
294 panic_impossible (); 324
295 break; 325 octave_idx_type k = 0;
296 326
297 case 1: 327 try
298 { 328 {
299 idx_vector i = idx (0).index_vector (); 329 switch (n_idx)
300 330 {
301 if (! error_state) 331 case 0:
302 { 332 panic_impossible ();
303 // optimize single scalar index. 333 break;
304 if (i.is_scalar () && i(0) < matrix.numel ()) 334
305 matrix(i(0)) = rhs; 335 case 1:
306 else 336 {
307 matrix.assign (i, mrhs); 337 idx_vector i = idx (0).index_vector ();
308 }
309 }
310 break;
311
312 case 2:
313 {
314 idx_vector i = idx (0).index_vector ();
315
316 if (! error_state)
317 {
318 idx_vector j = idx (1).index_vector ();
319 338
320 if (! error_state) 339 if (! error_state)
321 { 340 {
322 // optimize two scalar indices. 341 // optimize single scalar index.
323 if (i.is_scalar () && j.is_scalar () && nd == 2 342 if (i.is_scalar () && i(0) < matrix.numel ())
324 && i(0) < matrix.rows () && j(0) < matrix.columns ()) 343 matrix(i(0)) = rhs;
325 matrix(i(0), j(0)) = rhs;
326 else 344 else
327 matrix.assign (i, j, mrhs); 345 matrix.assign (i, mrhs);
328 } 346 }
329 } 347 }
330 } 348 break;
331 break; 349
332 350 case 2:
333 default: 351 {
334 { 352 idx_vector i = idx (0).index_vector ();
335 Array<idx_vector> idx_vec (dim_vector (n_idx, 1)); 353
336 bool scalar_opt = n_idx == nd; 354 if (! error_state)
337 const dim_vector dv = matrix.dims ().redim (n_idx); 355 {
338 356 k = 1;
339 for (octave_idx_type i = 0; i < n_idx; i++) 357 idx_vector j = idx (1).index_vector ();
340 { 358
341 idx_vec(i) = idx(i).index_vector (); 359 if (! error_state)
342
343 if (error_state)
344 break;
345
346 scalar_opt = (scalar_opt && idx_vec(i).is_scalar ()
347 && idx_vec(i)(0) < dv(i));
348 }
349
350 if (! error_state)
351 {
352 if (scalar_opt)
353 {
354 // optimize all scalar indices. Don't construct an index array,
355 // but rather calc a scalar index directly.
356 octave_idx_type k = 1;
357 octave_idx_type j = 0;
358 for (octave_idx_type i = 0; i < n_idx; i++)
359 { 360 {
360 j += idx_vec(i)(0) * k; 361 // optimize two scalar indices.
361 k *= dv(i); 362 if (i.is_scalar () && j.is_scalar () && nd == 2
363 && i(0) < matrix.rows () && j(0) < matrix.columns ())
364 matrix(i(0), j(0)) = rhs;
365 else
366 matrix.assign (i, j, mrhs);
362 } 367 }
363 matrix(j) = rhs; 368 }
364 } 369 }
365 else 370 break;
366 matrix.assign (idx_vec, mrhs); 371
367 } 372 default:
368 } 373 {
369 break; 374 Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
370 } 375 bool scalar_opt = n_idx == nd;
376 const dim_vector dv = matrix.dims ().redim (n_idx);
377
378 for (k = 0; k < n_idx; k++)
379 {
380 idx_vec(k) = idx(k).index_vector ();
381
382 if (error_state)
383 break;
384
385 scalar_opt = (scalar_opt && idx_vec(k).is_scalar ()
386 && idx_vec(k)(0) < dv(k));
387 }
388
389 if (! error_state)
390 {
391 if (scalar_opt)
392 {
393 // optimize all scalar indices. Don't construct
394 // an index array, but rather calc a scalar index directly.
395 octave_idx_type n = 1;
396 octave_idx_type j = 0;
397 for (octave_idx_type i = 0; i < n_idx; i++)
398 {
399 j += idx_vec(i)(0) * n;
400 n *= dv (i);
401 }
402 matrix(j) = rhs;
403 }
404 else
405 matrix.assign (idx_vec, mrhs);
406 }
407 }
408 break;
409 }
410 }
411 catch (const index_exception& e)
412 {
413 gripe_invalid_index (e.idx(), n_idx, k+1);
414 }
371 415
372 // Clear cache. 416 // Clear cache.
373 clear_cached_info (); 417 clear_cached_info ();
374 } 418 }
375 419