comparison libinterp/octave-value/ov-legacy-range.cc @ 30857:95725e6ad9c1 stable

restore part of the old octave_range class as octave_legacy_range This change allows old range objects to be loaded from data files and then converted to the new range type or other numeric types. * libinterp/octave-value/ov-legacy-range.h, libinterp/octave-value/ov-legacy-range.cc: New files restored from old versions of ov-range.h and ov-range.cc. Only provide enough support to load "range" objects from data files. * libinterp/octave-value/module.mk: Update. * ov.h, ov.cc: Update tests. (octave_value::is_legacy_object): New function. (octave_value::load_ascii, octave_value::load_binary, octave_value::load_hdf5): If loaded value is a legacy object, call maybe_mutate to allow conversion to a currently supported data type. (install_types): Register octave_legacy_range objects. (octave_value::make_range_rep_deprecated): Convert to Don't allow (const Range& r, bool force_range) (octave_value::make_range_rep_deprecated): Use Range constructor. Allow mutation to handle conversion to new range object or other numeric types. * ov-base.h (octave_base_value::is_legacy_object): New function * ov-range.cc: Rename ov_range<double> data type from "range" to "double_range". * Range.h (Range::Range): Always provide deprecated Range constructors. * ov-typeinfo.cc: Update test. * mk-conv-tst.sh: Update tests.
author John W. Eaton <jwe@octave.org>
date Mon, 21 Mar 2022 23:58:35 -0400
parents
children
comparison
equal deleted inserted replaced
30855:82c1554c4a64 30857:95725e6ad9c1
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2022 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29
30 #include <istream>
31 #include <ostream>
32 #include <sstream>
33
34 #include "lo-ieee.h"
35 #include "lo-utils.h"
36
37 #include "variables.h"
38 #include "error.h"
39 #include "ovl.h"
40 #include "oct-hdf5.h"
41 #include "ov-legacy-range.h"
42 #include "ov-range.h"
43 #include "ov-re-mat.h"
44 #include "ov-scalar.h"
45 #include "pr-output.h"
46
47 #include "byte-swap.h"
48 #include "ls-ascii-helper.h"
49 #include "ls-hdf5.h"
50 #include "ls-utils.h"
51
52 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
53 # pragma GCC diagnostic push
54 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
55 #endif
56
57 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_legacy_range, "range", "double");
58
59 octave_legacy_range::octave_legacy_range (void)
60 : octave_base_value (), range () { }
61
62 octave_legacy_range::octave_legacy_range (const Range& r)
63 : octave_base_value (), range (r)
64 {
65 if (range.numel () < 0 && range.numel () != -2)
66 error ("invalid range");
67 }
68
69 static octave_base_value *
70 default_numeric_conversion_function (const octave_base_value& a)
71 {
72 const octave_legacy_range& v = dynamic_cast<const octave_legacy_range&> (a);
73
74 return new octave_matrix (v.matrix_value ());
75 }
76
77 octave_base_value::type_conv_info
78 octave_legacy_range::numeric_conversion_function (void) const
79 {
80 return octave_base_value::type_conv_info (default_numeric_conversion_function,
81 octave_matrix::static_type_id ());
82 }
83
84 octave_base_value *
85 octave_legacy_range::try_narrowing_conversion (void)
86 {
87 octave_base_value *retval = nullptr;
88
89 switch (range.numel ())
90 {
91 case 1:
92 retval = new octave_scalar (range.base ());
93 break;
94
95 case 0:
96 retval = new octave_matrix (Matrix (1, 0));
97 break;
98
99 case -2:
100 retval = new octave_matrix (range.matrix_value ());
101 break;
102
103 default:
104 {
105 if (range.increment () == 0)
106 retval = new octave_matrix (range.matrix_value ());
107 else
108 retval = new octave_range
109 (octave::range<double> (range.base (), range.increment (),
110 range.limit (), range.numel ()));
111 }
112 break;
113 }
114
115 return retval;
116 }
117
118 // Skip white space and comments on stream IS.
119
120 static void
121 skip_comments (std::istream& is)
122 {
123 char c = '\0';
124 while (is.get (c))
125 {
126 if (c == ' ' || c == '\t' || c == '\n')
127 ; // Skip whitespace on way to beginning of next line.
128 else
129 break;
130 }
131
132 octave::skip_until_newline (is, false);
133 }
134
135 bool
136 octave_legacy_range::load_ascii (std::istream& is)
137 {
138 // # base, limit, range comment added by save ().
139 skip_comments (is);
140
141 double base, limit, inc;
142 is >> base >> limit >> inc;
143
144 if (! is)
145 error ("load: failed to load range constant");
146
147 if (inc != 0)
148 range = Range (base, limit, inc);
149 else
150 range = Range (base, inc, static_cast<octave_idx_type> (limit));
151
152 return true;
153 }
154
155 bool
156 octave_legacy_range::load_binary (std::istream& is, bool swap,
157 octave::mach_info::float_format /* fmt */)
158 {
159 char tmp;
160 if (! is.read (reinterpret_cast<char *> (&tmp), 1))
161 return false;
162 double bas, lim, inc;
163 if (! is.read (reinterpret_cast<char *> (&bas), 8))
164 return false;
165 if (swap)
166 swap_bytes<8> (&bas);
167 if (! is.read (reinterpret_cast<char *> (&lim), 8))
168 return false;
169 if (swap)
170 swap_bytes<8> (&lim);
171 if (! is.read (reinterpret_cast<char *> (&inc), 8))
172 return false;
173 if (swap)
174 swap_bytes<8> (&inc);
175 if (inc != 0)
176 range = Range (bas, lim, inc);
177 else
178 range = Range (bas, inc, static_cast<octave_idx_type> (lim));
179
180 return true;
181 }
182
183 #if defined (HAVE_HDF5)
184
185 // The following subroutines creates an HDF5 representation of the way
186 // we will store Octave range types (triplets of floating-point numbers).
187 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g.
188 // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary
189 // conversions are handled automatically by HDF5.
190
191 static hid_t
192 hdf5_make_range_type (hid_t num_type)
193 {
194 hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3);
195
196 H5Tinsert (type_id, "base", 0 * sizeof (double), num_type);
197 H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type);
198 H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type);
199
200 return type_id;
201 }
202
203 #endif
204
205 bool
206 octave_legacy_range::load_hdf5 (octave_hdf5_id loc_id, const char *name)
207 {
208 bool retval = false;
209
210 #if defined (HAVE_HDF5)
211
212 #if defined (HAVE_HDF5_18)
213 hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
214 #else
215 hid_t data_hid = H5Dopen (loc_id, name);
216 #endif
217 hid_t type_hid = H5Dget_type (data_hid);
218
219 hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
220
221 if (! hdf5_types_compatible (type_hid, range_type))
222 {
223 H5Tclose (range_type);
224 H5Dclose (data_hid);
225 return false;
226 }
227
228 hid_t space_hid = H5Dget_space (data_hid);
229 hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
230
231 if (rank != 0)
232 {
233 H5Tclose (range_type);
234 H5Sclose (space_hid);
235 H5Dclose (data_hid);
236 return false;
237 }
238
239 double rangevals[3];
240 if (H5Dread (data_hid, range_type, octave_H5S_ALL, octave_H5S_ALL,
241 octave_H5P_DEFAULT, rangevals)
242 >= 0)
243 {
244 retval = true;
245 octave_idx_type nel;
246 if (hdf5_get_scalar_attr (data_hid, H5T_NATIVE_IDX,
247 "OCTAVE_RANGE_NELEM", &nel))
248 range = Range (rangevals[0], rangevals[2], nel);
249 else
250 {
251 if (rangevals[2] != 0)
252 range = Range (rangevals[0], rangevals[1], rangevals[2]);
253 else
254 range = Range (rangevals[0], rangevals[2],
255 static_cast<octave_idx_type> (rangevals[1]));
256 }
257 }
258
259 H5Tclose (range_type);
260 H5Sclose (space_hid);
261 H5Dclose (data_hid);
262
263 #else
264 octave_unused_parameter (loc_id);
265 octave_unused_parameter (name);
266
267 warn_load ("hdf5");
268 #endif
269
270 return retval;
271 }
272
273 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
274 # pragma GCC diagnostic pop
275 #endif