comparison libinterp/octave-value/ov-range.cc @ 15195:2fc554ffbc28

split libinterp from src * libinterp: New directory. Move all files from src directory here except Makefile.am, main.cc, main-cli.cc, mkoctfile.in.cc, mkoctfilr.in.sh, octave-config.in.cc, octave-config.in.sh. * libinterp/Makefile.am: New file, extracted from src/Makefile.am. * src/Makefile.am: Delete everything except targets and definitions needed to build and link main and utility programs. * Makefile.am (SUBDIRS): Include libinterp in the list. * autogen.sh: Run config-module.sh in libinterp/dldfcn directory, not src/dldfcn directory. * configure.ac (AC_CONFIG_SRCDIR): Use libinterp/octave.cc, not src/octave.cc. (DL_LDFLAGS, LIBOCTINTERP): Use libinterp, not src. (AC_CONFIG_FILES): Include libinterp/Makefile in the list. * find-docstring-files.sh: Look in libinterp, not src. * gui/src/Makefile.am (liboctgui_la_CPPFLAGS): Find header files in libinterp, not src.
author John W. Eaton <jwe@octave.org>
date Sat, 18 Aug 2012 16:23:39 -0400
parents src/octave-value/ov-range.cc@62a35ae7d6a2
children 0f143f68078d
comparison
equal deleted inserted replaced
15194:0f0b795044c3 15195:2fc554ffbc28
1 /*
2
3 Copyright (C) 1996-2012 John W. Eaton
4
5 This file is part of Octave.
6
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <iostream>
28
29 #include "lo-ieee.h"
30 #include "lo-utils.h"
31
32 #include "defun.h"
33 #include "variables.h"
34 #include "gripes.h"
35 #include "mxarray.h"
36 #include "ops.h"
37 #include "oct-obj.h"
38 #include "ov-range.h"
39 #include "ov-re-mat.h"
40 #include "ov-scalar.h"
41 #include "pr-output.h"
42
43 #include "byte-swap.h"
44 #include "ls-ascii-helper.h"
45 #include "ls-hdf5.h"
46 #include "ls-utils.h"
47
48 // If TRUE, allow ranges with non-integer elements as array indices.
49 bool Vallow_noninteger_range_as_index = false;
50
51 DEFINE_OCTAVE_ALLOCATOR (octave_range);
52
53 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_range, "range", "double");
54
55 static octave_base_value *
56 default_numeric_conversion_function (const octave_base_value& a)
57 {
58 CAST_CONV_ARG (const octave_range&);
59
60 return new octave_matrix (v.matrix_value ());
61 }
62
63 octave_base_value::type_conv_info
64 octave_range::numeric_conversion_function (void) const
65 {
66 return octave_base_value::type_conv_info (default_numeric_conversion_function,
67 octave_matrix::static_type_id ());
68 }
69
70 octave_base_value *
71 octave_range::try_narrowing_conversion (void)
72 {
73 octave_base_value *retval = 0;
74
75 switch (range.nelem ())
76 {
77 case 1:
78 retval = new octave_scalar (range.base ());
79 break;
80
81 case 0:
82 retval = new octave_matrix (Matrix (1, 0));
83 break;
84
85 case -2:
86 retval = new octave_matrix (range.matrix_value ());
87 break;
88
89 default:
90 break;
91 }
92
93 return retval;
94 }
95
96 octave_value
97 octave_range::subsref (const std::string& type,
98 const std::list<octave_value_list>& idx)
99 {
100 octave_value retval;
101
102 switch (type[0])
103 {
104 case '(':
105 retval = do_index_op (idx.front ());
106 break;
107
108 case '{':
109 case '.':
110 {
111 std::string nm = type_name ();
112 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
113 }
114 break;
115
116 default:
117 panic_impossible ();
118 }
119
120 return retval.next_subsref (type, idx);
121 }
122
123 octave_value
124 octave_range::do_index_op (const octave_value_list& idx, bool resize_ok)
125 {
126 if (idx.length () == 1 && ! resize_ok)
127 {
128 octave_value retval;
129
130 // The range can handle a single subscript.
131 idx_vector i = idx(0).index_vector ();
132 if (! error_state)
133 {
134 if (i.is_scalar () && i(0) < range.nelem ())
135 retval = range.elem (i(0));
136 else
137 retval = range.index (i);
138 }
139
140 return retval;
141 }
142 else
143 {
144 octave_value tmp (new octave_matrix (range.matrix_value ()));
145
146 return tmp.do_index_op (idx, resize_ok);
147 }
148 }
149
150 idx_vector
151 octave_range::index_vector (void) const
152 {
153 if (idx_cache)
154 return *idx_cache;
155 else
156 {
157 if (! Vallow_noninteger_range_as_index
158 || range.all_elements_are_ints ())
159 return set_idx_cache (idx_vector (range));
160 else
161 {
162 warning_with_id ("Octave:noninteger-range-as-index",
163 "non-integer range used as index");
164
165 return octave_value (matrix_value ()).round ().index_vector ();
166 }
167 }
168 }
169
170 double
171 octave_range::double_value (bool) const
172 {
173 double retval = lo_ieee_nan_value ();
174
175 octave_idx_type nel = range.nelem ();
176
177 if (nel > 0)
178 {
179 gripe_implicit_conversion ("Octave:array-to-scalar",
180 "range", "real scalar");
181
182 retval = range.base ();
183 }
184 else
185 gripe_invalid_conversion ("range", "real scalar");
186
187 return retval;
188 }
189
190 float
191 octave_range::float_value (bool) const
192 {
193 float retval = lo_ieee_float_nan_value ();
194
195 octave_idx_type nel = range.nelem ();
196
197 if (nel > 0)
198 {
199 gripe_implicit_conversion ("Octave:array-to-scalar",
200 "range", "real scalar");
201
202 retval = range.base ();
203 }
204 else
205 gripe_invalid_conversion ("range", "real scalar");
206
207 return retval;
208 }
209
210 charNDArray
211 octave_range::char_array_value (bool) const
212 {
213 const Matrix matrix = range.matrix_value ();
214 charNDArray retval (dims ());
215
216 octave_idx_type nel = numel ();
217
218 for (octave_idx_type i = 0; i < nel; i++)
219 retval.elem (i) = static_cast<char>(matrix.elem (i));
220
221 return retval;
222 }
223
224 octave_value
225 octave_range::all (int dim) const
226 {
227 // FIXME -- this is a potential waste of memory.
228
229 Matrix m = range.matrix_value ();
230
231 return m.all (dim);
232 }
233
234 octave_value
235 octave_range::any (int dim) const
236 {
237 // FIXME -- this is a potential waste of memory.
238
239 Matrix m = range.matrix_value ();
240
241 return m.any (dim);
242 }
243
244 octave_value
245 octave_range::diag (octave_idx_type k) const
246 {
247 return (k == 0
248 ? octave_value (DiagMatrix (DiagArray2<double> (range.matrix_value ())))
249 : octave_value (range.diag (k)));
250 }
251
252 octave_value
253 octave_range::diag (octave_idx_type m, octave_idx_type n) const
254 {
255 Matrix mat = range.matrix_value ();
256
257 return mat.diag (m, n);
258 }
259
260 bool
261 octave_range::is_true (void) const
262 {
263 bool retval = false;
264
265 if (range.nelem () != 0)
266 {
267 // FIXME -- this is a potential waste of memory.
268
269 Matrix m ((range.matrix_value () . all ()) . all ());
270
271 retval = (m.rows () == 1 && m.columns () == 1 && m (0, 0) != 0.0);
272 }
273
274 return retval;
275 }
276
277 Complex
278 octave_range::complex_value (bool) const
279 {
280 double tmp = lo_ieee_nan_value ();
281
282 Complex retval (tmp, tmp);
283
284 octave_idx_type nel = range.nelem ();
285
286 if (nel > 0)
287 {
288 gripe_implicit_conversion ("Octave:array-to-scalar",
289 "range", "complex scalar");
290
291 retval = range.base ();
292 }
293 else
294 gripe_invalid_conversion ("range", "complex scalar");
295
296 return retval;
297 }
298
299 FloatComplex
300 octave_range::float_complex_value (bool) const
301 {
302 float tmp = lo_ieee_float_nan_value ();
303
304 FloatComplex retval (tmp, tmp);
305
306 octave_idx_type nel = range.nelem ();
307
308 if (nel > 0)
309 {
310 gripe_implicit_conversion ("Octave:array-to-scalar",
311 "range", "complex scalar");
312
313 retval = range.base ();
314 }
315 else
316 gripe_invalid_conversion ("range", "complex scalar");
317
318 return retval;
319 }
320
321 boolNDArray
322 octave_range::bool_array_value (bool warn) const
323 {
324 Matrix m = range.matrix_value ();
325
326 if (m.any_element_is_nan ())
327 gripe_nan_to_logical_conversion ();
328 else if (warn && m.any_element_not_one_or_zero ())
329 gripe_logical_conversion ();
330
331 return boolNDArray (m);
332 }
333
334 octave_value
335 octave_range::resize (const dim_vector& dv, bool fill) const
336 {
337 NDArray retval = array_value ();
338 if (fill)
339 retval.resize (dv, 0);
340 else
341 retval.resize (dv);
342 return retval;
343 }
344
345 octave_value
346 octave_range::convert_to_str_internal (bool pad, bool force, char type) const
347 {
348 octave_value tmp (range.matrix_value ());
349 return tmp.convert_to_str (pad, force, type);
350 }
351
352 void
353 octave_range::print (std::ostream& os, bool pr_as_read_syntax) const
354 {
355 print_raw (os, pr_as_read_syntax);
356 newline (os);
357 }
358
359 void
360 octave_range::print_raw (std::ostream& os, bool pr_as_read_syntax) const
361 {
362 octave_print_internal (os, range, pr_as_read_syntax,
363 current_print_indent_level ());
364 }
365
366 bool
367 octave_range::print_name_tag (std::ostream& os, const std::string& name) const
368 {
369 bool retval = false;
370
371 octave_idx_type n = range.nelem ();
372
373 indent (os);
374
375 if (n == 0 || n == 1)
376 os << name << " = ";
377 else
378 {
379 os << name << " =";
380 newline (os);
381 if (! Vcompact_format)
382 newline (os);
383
384 retval = true;
385 }
386
387 return retval;
388 }
389
390 // Skip white space and comments on stream IS.
391
392 static void
393 skip_comments (std::istream& is)
394 {
395 char c = '\0';
396 while (is.get (c))
397 {
398 if (c == ' ' || c == '\t' || c == '\n')
399 ; // Skip whitespace on way to beginning of next line.
400 else
401 break;
402 }
403
404 skip_until_newline (is, false);
405 }
406
407 bool
408 octave_range::save_ascii (std::ostream& os)
409 {
410 Range r = range_value ();
411 double base = r.base ();
412 double limit = r.limit ();
413 double inc = r.inc ();
414 octave_idx_type len = r.nelem ();
415
416 if (inc != 0)
417 os << "# base, limit, increment\n";
418 else
419 os << "# base, length, increment\n";
420
421 octave_write_double (os, base);
422 os << " ";
423 if (inc != 0)
424 octave_write_double (os, limit);
425 else
426 os << len;
427 os << " ";
428 octave_write_double (os, inc);
429 os << "\n";
430
431 return true;
432 }
433
434 bool
435 octave_range::load_ascii (std::istream& is)
436 {
437 // # base, limit, range comment added by save ().
438 skip_comments (is);
439
440 double base, limit, inc;
441 is >> base >> limit >> inc;
442
443 if (!is)
444 {
445 error ("load: failed to load range constant");
446 return false;
447 }
448
449 if (inc != 0)
450 range = Range (base, limit, inc);
451 else
452 range = Range (base, inc, static_cast<octave_idx_type> (limit));
453
454 return true;
455 }
456
457 bool
458 octave_range::save_binary (std::ostream& os, bool& /* save_as_floats */)
459 {
460 char tmp = LS_DOUBLE;
461 os.write (reinterpret_cast<char *> (&tmp), 1);
462 Range r = range_value ();
463 double bas = r.base ();
464 double lim = r.limit ();
465 double inc = r.inc ();
466 if (inc == 0)
467 lim = r.nelem ();
468
469 os.write (reinterpret_cast<char *> (&bas), 8);
470 os.write (reinterpret_cast<char *> (&lim), 8);
471 os.write (reinterpret_cast<char *> (&inc), 8);
472
473 return true;
474 }
475
476 bool
477 octave_range::load_binary (std::istream& is, bool swap,
478 oct_mach_info::float_format /* fmt */)
479 {
480 char tmp;
481 if (! is.read (reinterpret_cast<char *> (&tmp), 1))
482 return false;
483 double bas, lim, inc;
484 if (! is.read (reinterpret_cast<char *> (&bas), 8))
485 return false;
486 if (swap)
487 swap_bytes<8> (&bas);
488 if (! is.read (reinterpret_cast<char *> (&lim), 8))
489 return false;
490 if (swap)
491 swap_bytes<8> (&lim);
492 if (! is.read (reinterpret_cast<char *> (&inc), 8))
493 return false;
494 if (swap)
495 swap_bytes<8> (&inc);
496 if (inc != 0)
497 range = Range (bas, lim, inc);
498 else
499 range = Range (bas, inc, static_cast<octave_idx_type> (lim));
500
501 return true;
502 }
503
504 #if defined (HAVE_HDF5)
505
506 // The following subroutines creates an HDF5 representation of the way
507 // we will store Octave range types (triplets of floating-point numbers).
508 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g.
509 // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary
510 // conversions are handled automatically by HDF5.
511
512 static hid_t
513 hdf5_make_range_type (hid_t num_type)
514 {
515 hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3);
516
517 H5Tinsert (type_id, "base", 0 * sizeof (double), num_type);
518 H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type);
519 H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type);
520
521 return type_id;
522 }
523
524 bool
525 octave_range::save_hdf5 (hid_t loc_id, const char *name,
526 bool /* save_as_floats */)
527 {
528 hsize_t dimens[3];
529 hid_t space_hid = -1, type_hid = -1, data_hid = -1;
530 bool retval = true;
531
532 space_hid = H5Screate_simple (0, dimens, 0);
533 if (space_hid < 0) return false;
534
535 type_hid = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
536 if (type_hid < 0)
537 {
538 H5Sclose (space_hid);
539 return false;
540 }
541 #if HAVE_HDF5_18
542 data_hid = H5Dcreate (loc_id, name, type_hid, space_hid,
543 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
544 #else
545 data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT);
546 #endif
547 if (data_hid < 0)
548 {
549 H5Sclose (space_hid);
550 H5Tclose (type_hid);
551 return false;
552 }
553
554 Range r = range_value ();
555 double range_vals[3];
556 range_vals[0] = r.base ();
557 range_vals[1] = r.inc () != 0 ? r.limit () : r.nelem ();
558 range_vals[2] = r.inc ();
559
560 if (H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
561 range_vals) >= 0)
562 {
563 octave_idx_type nel = r.nelem ();
564 retval = hdf5_add_scalar_attr (data_hid, H5T_NATIVE_IDX,
565 "OCTAVE_RANGE_NELEM", &nel) >= 0;
566 }
567 else
568 retval = false;
569
570 H5Dclose (data_hid);
571 H5Tclose (type_hid);
572 H5Sclose (space_hid);
573
574 return retval;
575 }
576
577 bool
578 octave_range::load_hdf5 (hid_t loc_id, const char *name)
579 {
580 bool retval = false;
581
582 #if HAVE_HDF5_18
583 hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
584 #else
585 hid_t data_hid = H5Dopen (loc_id, name);
586 #endif
587 hid_t type_hid = H5Dget_type (data_hid);
588
589 hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
590
591 if (! hdf5_types_compatible (type_hid, range_type))
592 {
593 H5Tclose (range_type);
594 H5Dclose (data_hid);
595 return false;
596 }
597
598 hid_t space_hid = H5Dget_space (data_hid);
599 hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
600
601 if (rank != 0)
602 {
603 H5Tclose (range_type);
604 H5Sclose (space_hid);
605 H5Dclose (data_hid);
606 return false;
607 }
608
609 double rangevals[3];
610 if (H5Dread (data_hid, range_type, H5S_ALL, H5S_ALL, H5P_DEFAULT,
611 rangevals) >= 0)
612 {
613 retval = true;
614 octave_idx_type nel;
615 if (hdf5_get_scalar_attr (data_hid, H5T_NATIVE_IDX,
616 "OCTAVE_RANGE_NELEM", &nel))
617 range = Range (rangevals[0], rangevals[2], nel);
618 else
619 {
620 if (rangevals[2] != 0)
621 range = Range (rangevals[0], rangevals[1], rangevals[2]);
622 else
623 range = Range (rangevals[0], rangevals[2],
624 static_cast<octave_idx_type> (rangevals[1]));
625 }
626 }
627
628 H5Tclose (range_type);
629 H5Sclose (space_hid);
630 H5Dclose (data_hid);
631
632 return retval;
633 }
634
635 #endif
636
637 mxArray *
638 octave_range::as_mxArray (void) const
639 {
640 mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
641
642 double *pr = static_cast<double *> (retval->get_data ());
643
644 mwSize nel = numel ();
645
646 Matrix m = matrix_value ();
647
648 const double *p = m.data ();
649
650 for (mwSize i = 0; i < nel; i++)
651 pr[i] = p[i];
652
653 return retval;
654 }
655
656 DEFUN (allow_noninteger_range_as_index, args, nargout,
657 "-*- texinfo -*-\n\
658 @deftypefn {Built-in Function} {@var{val} =} allow_noninteger_range_as_index ()\n\
659 @deftypefnx {Built-in Function} {@var{old_val} =} allow_noninteger_range_as_index (@var{new_val})\n\
660 @deftypefnx {Built-in Function} {} allow_noninteger_range_as_index (@var{new_val}, \"local\")\n\
661 Query or set the internal variable that controls whether non-integer\n\
662 ranges are allowed as indices. This might be useful for @sc{matlab}\n\
663 compatibility; however, it is still not entirely compatible because\n\
664 @sc{matlab} treats the range expression differently in different contexts.\n\
665 \n\
666 When called from inside a function with the \"local\" option, the variable is\n\
667 changed locally for the function and any subroutines it calls. The original\n\
668 variable value is restored when exiting the function.\n\
669 @end deftypefn")
670 {
671 return SET_INTERNAL_VARIABLE (allow_noninteger_range_as_index);
672 }
673
674 /*
675 %!test
676 %! x = 0:10;
677 %! save = allow_noninteger_range_as_index ();
678 %! warn_state = warning ("query", "Octave:noninteger-range-as-index");
679 %! unwind_protect
680 %! allow_noninteger_range_as_index (false);
681 %! fail ("x(2.1:5)");
682 %! assert (x(2:5), 1:4);
683 %! allow_noninteger_range_as_index (true);
684 %! warning ("off", "Octave:noninteger-range-as-index");
685 %! assert (x(2.49:5), 1:3);
686 %! assert (x(2.5:5), 2:4);
687 %! assert (x(2.51:5), 2:4);
688 %! unwind_protect_cleanup
689 %! allow_noninteger_range_as_index (save);
690 %! warning (warn_state.state, warn_state.identifier);
691 %! end_unwind_protect
692 */