Mercurial > octave-nkf
comparison liboctave/util/lo-array-gripes.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 | 4197fc428c7d |
children | e54ecb33727e |
comparison
equal
deleted
inserted
replaced
20573:e3c0fee87493 | 20574:dd6345fd8a97 |
---|---|
23 | 23 |
24 #ifdef HAVE_CONFIG_H | 24 #ifdef HAVE_CONFIG_H |
25 #include <config.h> | 25 #include <config.h> |
26 #endif | 26 #endif |
27 | 27 |
28 #include <string.h> | |
28 #include "lo-array-gripes.h" | 29 #include "lo-array-gripes.h" |
29 #include "lo-error.h" | 30 #include "lo-error.h" |
30 | 31 |
31 const char *error_id_nonconformant_args = "Octave:nonconformant-args"; | 32 const char *error_id_nonconformant_args = "Octave:nonconformant-args"; |
32 | 33 |
88 (err_id, "%s: nonconformant arguments (op1 is %s, op2 is %s)", | 89 (err_id, "%s: nonconformant arguments (op1 is %s, op2 is %s)", |
89 op, op1_dims_str.c_str (), op2_dims_str.c_str ()); | 90 op, op1_dims_str.c_str (), op2_dims_str.c_str ()); |
90 } | 91 } |
91 | 92 |
92 void | 93 void |
94 gripe_del_index_out_of_range (bool is1d, octave_idx_type idx, | |
95 octave_idx_type ext) | |
96 { | |
97 const char *err_id = error_id_index_out_of_bounds; | |
98 | |
99 (*current_liboctave_error_with_id_handler) | |
100 (err_id, "A(%s) = []: index out of bounds; value %d out of bound %d", | |
101 is1d ? "I" : "..,I,..", idx, ext); | |
102 } | |
103 | |
104 | |
105 | |
106 // Common procedures of base class index_exception, thrown whenever an | |
107 // object is indexed incorrectly, such as by an index that is out of | |
108 // range, negative, fractional, complex, or of a non-numeric type. | |
109 | |
110 const char * | |
111 index_exception::err (void) throw () | |
112 { | |
113 msg = access () + "; " + explain (); | |
114 return msg.c_str (); | |
115 } | |
116 | |
117 // Show what was illegally accessed, e.g., "A(-1,_)", "A(0+1i)", "A(_,3)" | |
118 // Show how many indices come before/after the offending one, | |
119 // e.g., (<error>), (<error>,_), or (_,<error>,...[x5]...) | |
120 | |
121 std::string | |
122 index_exception:: access (void) const | |
123 { | |
124 // FIXME: don't use a fixed size buffer! | |
125 | |
126 int buf_len = 300; | |
127 | |
128 char output [buf_len]; | |
129 char pre [buf_len]; | |
130 char post [buf_len]; | |
131 | |
132 // dim == 0 if position not yet given, or | |
133 // <static_cast unsigned int>(-1) if explicitly shown to be unknown | |
134 // both are caught by this condition | |
135 | |
136 if (static_cast <unsigned int> (dim-1) > 100000) | |
137 { | |
138 // No parentheses are given if the dimension is not known. | |
139 pre[0] = post[0] = '\0'; | |
140 } | |
141 else | |
142 { | |
143 if (dim < 5) | |
144 { | |
145 pre[0] = '('; | |
146 octave_idx_type i; | |
147 | |
148 for (i = 1; i < dim; i++) | |
149 { | |
150 pre[2*i-1] = '_'; | |
151 pre[2*i] = ','; | |
152 } | |
153 | |
154 pre[2*i-1] = '\0'; // i == min (1, dim) | |
155 } | |
156 else | |
157 { | |
158 sprintf (pre, "(...[x%d]...", dim-1); | |
159 } | |
160 | |
161 if (static_cast <unsigned int> (nd-dim) < 5) | |
162 { | |
163 for (octave_idx_type i = 0; i < nd-dim; i++) | |
164 { | |
165 post[2*i] = ','; | |
166 post[2*i+1] = '_'; | |
167 } | |
168 | |
169 if (nd >= dim) | |
170 { | |
171 post[2*(nd-dim)] = ')'; | |
172 post[2*(nd-dim)+1] = '\0'; | |
173 } | |
174 } | |
175 else | |
176 sprintf (post, "...[x%d]...)", nd-dim); | |
177 } | |
178 | |
179 const char *v; | |
180 | |
181 if (var[0] == '\0' || var == "<unknown>") | |
182 v = "index "; | |
183 else | |
184 v = var.c_str (); | |
185 | |
186 snprintf (output, buf_len, "%s%s%s%s", v, pre, idx(), post); | |
187 | |
188 return output; | |
189 } | |
190 | |
191 class invalid_index : public index_exception | |
192 { | |
193 public: | |
194 | |
195 invalid_index (const char *value, octave_idx_type ndim, | |
196 octave_idx_type dimen) | |
197 : index_exception (value, ndim, dimen) | |
198 { } | |
199 | |
200 const char* explain (void) const | |
201 { | |
202 #ifdef USE_64_BIT_IDX_T | |
203 return "subscripts must be either integers 1 to (2^63)-1 or logicals"; | |
204 #else | |
205 return "subscripts must be either integers 1 to (2^31)-1 or logicals"; | |
206 #endif | |
207 } | |
208 | |
209 // ID of error to throw | |
210 const char* id (void) const | |
211 { | |
212 return error_id_invalid_index; | |
213 } | |
214 }; | |
215 | |
216 // Complain of an index that is: negative, fractional, or too big. | |
217 | |
218 void | |
219 gripe_invalid_index (const char *idx, octave_idx_type nd, | |
220 octave_idx_type dim, const char * /* var */) | |
221 { | |
222 invalid_index e (idx, nd, dim); | |
223 | |
224 throw e; | |
225 } | |
226 | |
227 void | |
228 gripe_invalid_index (octave_idx_type n, octave_idx_type nd, | |
229 octave_idx_type dim, const char *var) | |
230 { | |
231 // FIXME: don't use a fixed size buffer! | |
232 char buf [100]; | |
233 | |
234 sprintf (buf, "%d", n+1); | |
235 | |
236 gripe_invalid_index (buf, nd, dim, var); | |
237 } | |
238 | |
239 void | |
240 gripe_invalid_index (double n, octave_idx_type nd, octave_idx_type dim, | |
241 const char *var) | |
242 { | |
243 // FIXME: don't use a fixed size buffer! | |
244 char buf [100]; | |
245 | |
246 sprintf (buf, "%g", n+1); | |
247 | |
248 gripe_invalid_index (buf, nd, dim, var); | |
249 } | |
250 | |
251 | |
252 // Gripe and exception for read access beyond the bounds of an array. | |
253 | |
254 class out_of_range : public index_exception | |
255 { | |
256 public: | |
257 | |
258 out_of_range (const char *value, octave_idx_type nd_in,octave_idx_type dim_in) | |
259 : index_exception (value, nd_in, dim_in), extent(0) | |
260 { } | |
261 | |
262 const char* explain (void) const | |
263 { | |
264 static std::string expl; // should probably be member variable, but | |
265 // then explain() can't be const. | |
266 | |
267 if (nd >= size.length ()) // if not an index slice | |
268 { | |
269 if (var != "") | |
270 expl = "but " + var + " has size "; | |
271 else | |
272 expl = "but object has size "; | |
273 | |
274 expl = expl + size.str ('x'); | |
275 } | |
276 else | |
277 { | |
278 // FIXME: don't use a fixed size buffer! | |
279 char buf [100]; | |
280 sprintf (buf, "%d", extent); | |
281 expl = "out of bound " + std::string (buf); | |
282 } | |
283 | |
284 return expl.c_str (); | |
285 } | |
286 | |
287 // ID of error to throw. | |
288 const char* id (void) const | |
289 { | |
290 return (error_id_index_out_of_bounds); | |
291 } | |
292 | |
293 void set_size (const dim_vector& size_in) { size = size_in; } | |
294 | |
295 void set_extent (octave_idx_type ext) { extent = ext; } | |
296 | |
297 private: | |
298 | |
299 dim_vector size; // dimension of object being accessed | |
300 | |
301 octave_idx_type extent; // length of dimension being accessed | |
302 }; | |
303 | |
304 // Complain of an index that is out of range, but we don't know matrix size | |
305 void | |
93 gripe_index_out_of_range (int nd, int dim, octave_idx_type idx, | 306 gripe_index_out_of_range (int nd, int dim, octave_idx_type idx, |
94 octave_idx_type ext) | 307 octave_idx_type ext) |
95 { | 308 { |
96 const char *err_id = error_id_index_out_of_bounds; | 309 char buf [100]; |
97 | 310 sprintf (buf, "%d", idx); |
98 switch (nd) | 311 out_of_range e (buf, nd, dim); |
99 { | 312 |
100 case 1: | 313 e.set_extent (ext); |
101 (*current_liboctave_error_with_id_handler) | 314 dim_vector d (1,1,1,1,1,1,1); // make explain() give extent not size |
102 (err_id, "A(I): index out of bounds; value %d out of bound %d", | 315 e.set_size (d); |
103 idx, ext); | 316 throw e; |
104 break; | 317 } |
105 | 318 |
106 case 2: | 319 // Complain of an index that is out of range |
107 (*current_liboctave_error_with_id_handler) | 320 void |
108 (err_id, "A(I,J): %s index out of bounds; value %d out of bound %d", | 321 gripe_index_out_of_range (int nd, int dim, octave_idx_type idx, |
109 (dim == 1) ? "row" : "column", idx, ext); | 322 octave_idx_type ext, const dim_vector& d) |
110 break; | 323 { |
111 | 324 char buf [100]; |
112 default: | 325 sprintf (buf, "%d", idx); |
113 (*current_liboctave_error_with_id_handler) | 326 out_of_range e (buf, nd, dim); |
114 (err_id, "A(I,J,...): index to dimension %d out of bounds; value %d out of bound %d", | 327 |
115 dim, idx, ext); | 328 e.set_extent (ext); |
116 break; | 329 e.set_size (d); |
117 } | 330 throw e; |
118 } | 331 } |
119 | |
120 void | |
121 gripe_del_index_out_of_range (bool is1d, octave_idx_type idx, | |
122 octave_idx_type ext) | |
123 { | |
124 const char *err_id = error_id_index_out_of_bounds; | |
125 | |
126 (*current_liboctave_error_with_id_handler) | |
127 (err_id, "A(%s) = []: index out of bounds; value %d out of bound %d", | |
128 is1d ? "I" : "..,I,..", idx, ext); | |
129 } | |
130 | |
131 void | |
132 gripe_invalid_index (void) | |
133 { | |
134 const char *err_id = error_id_invalid_index; | |
135 | |
136 (*current_liboctave_error_with_id_handler) | |
137 #ifdef USE_64_BIT_IDX_T | |
138 (err_id, "subscript indices must be either positive integers less than 2^63 or logicals"); | |
139 #else | |
140 (err_id, "subscript indices must be either positive integers less than 2^31 or logicals"); | |
141 #endif | |
142 } | |
143 | |
144 // FIXME: the following is a common error message to resize, | |
145 // regardless of whether it's called from assign or elsewhere. It | |
146 // seems OK to me, but eventually the gripe can be specialized. | |
147 // Anyway, propagating various error messages into procedure is, IMHO, | |
148 // a nonsense. If anything, we should change error handling here (and | |
149 // throughout liboctave) to allow custom handling of errors | |
150 | 332 |
151 void | 333 void |
152 gripe_invalid_resize (void) | 334 gripe_invalid_resize (void) |
153 { | 335 { |
154 (*current_liboctave_error_with_id_handler) | 336 (*current_liboctave_error_with_id_handler) |
155 ("Octave:invalid-resize", | 337 ("Octave:invalid-resize", |
156 "Invalid resizing operation or ambiguous assignment to an out-of-bounds array element"); | 338 "Invalid resizing operation or ambiguous assignment to an out-of-bounds array element"); |
157 } | |
158 | |
159 void | |
160 gripe_invalid_assignment_size (void) | |
161 { | |
162 (*current_liboctave_error_handler) | |
163 ("A(I) = X: X must have the same size as I"); | |
164 } | |
165 | |
166 void | |
167 gripe_assignment_dimension_mismatch (void) | |
168 { | |
169 (*current_liboctave_error_handler) | |
170 ("A(I,J,...) = X: dimensions mismatch"); | |
171 } | 339 } |
172 | 340 |
173 void | 341 void |
174 gripe_singular_matrix (double rcond) | 342 gripe_singular_matrix (double rcond) |
175 { | 343 { |
184 (*current_liboctave_warning_with_id_handler) | 352 (*current_liboctave_warning_with_id_handler) |
185 (warning_id_nearly_singular_matrix, | 353 (warning_id_nearly_singular_matrix, |
186 "matrix singular to machine precision, rcond = %g", rcond); | 354 "matrix singular to machine precision, rcond = %g", rcond); |
187 } | 355 } |
188 } | 356 } |
357 | |
358 /* Tests in test/index.tst */ |