Mercurial > hg > octave-nkf
comparison src/octave-value/ov-struct.cc @ 15057:46b19589b593
maint: Partition src/ directory with more code in subdirs.
Create new octave-value dir for ov* code.
Create new parse-tre dir for pt* code.
Move OPERATORS and TEMPLATE-INST directories to lowercase names
* octave-value/module.mk: Hook code in octave-value dir into build system.
* octave-value/ov-base-diag.cc,
octave-value/ov-base-diag.h, octave-value/ov-base-int.cc,
octave-value/ov-base-int.h, octave-value/ov-base-mat.cc,
octave-value/ov-base-mat.h, octave-value/ov-base-scalar.cc,
octave-value/ov-base-scalar.h, octave-value/ov-base-sparse.cc,
octave-value/ov-base-sparse.h, octave-value/ov-base.cc, octave-value/ov-base.h,
octave-value/ov-bool-mat.cc, octave-value/ov-bool-mat.h,
octave-value/ov-bool-sparse.cc, octave-value/ov-bool-sparse.h,
octave-value/ov-bool.cc, octave-value/ov-bool.h, octave-value/ov-builtin.cc,
octave-value/ov-builtin.h, octave-value/ov-cell.cc, octave-value/ov-cell.h,
octave-value/ov-ch-mat.cc, octave-value/ov-ch-mat.h, octave-value/ov-class.cc,
octave-value/ov-class.h, octave-value/ov-colon.cc, octave-value/ov-colon.h,
octave-value/ov-complex.cc, octave-value/ov-complex.h,
octave-value/ov-cs-list.cc, octave-value/ov-cs-list.h,
octave-value/ov-cx-diag.cc, octave-value/ov-cx-diag.h,
octave-value/ov-cx-mat.cc, octave-value/ov-cx-mat.h,
octave-value/ov-cx-sparse.cc, octave-value/ov-cx-sparse.h,
octave-value/ov-dld-fcn.cc, octave-value/ov-dld-fcn.h,
octave-value/ov-fcn-handle.cc, octave-value/ov-fcn-handle.h,
octave-value/ov-fcn-inline.cc, octave-value/ov-fcn-inline.h,
octave-value/ov-fcn.cc, octave-value/ov-fcn.h, octave-value/ov-float.cc,
octave-value/ov-float.h, octave-value/ov-flt-complex.cc,
octave-value/ov-flt-complex.h, octave-value/ov-flt-cx-diag.cc,
octave-value/ov-flt-cx-diag.h, octave-value/ov-flt-cx-mat.cc,
octave-value/ov-flt-cx-mat.h, octave-value/ov-flt-re-diag.cc,
octave-value/ov-flt-re-diag.h, octave-value/ov-flt-re-mat.cc,
octave-value/ov-flt-re-mat.h, octave-value/ov-int-traits.h,
octave-value/ov-int16.cc, octave-value/ov-int16.h, octave-value/ov-int32.cc,
octave-value/ov-int32.h, octave-value/ov-int64.cc, octave-value/ov-int64.h,
octave-value/ov-int8.cc, octave-value/ov-int8.h, octave-value/ov-intx.h,
octave-value/ov-lazy-idx.cc, octave-value/ov-lazy-idx.h,
octave-value/ov-mex-fcn.cc, octave-value/ov-mex-fcn.h,
octave-value/ov-null-mat.cc, octave-value/ov-null-mat.h,
octave-value/ov-oncleanup.cc, octave-value/ov-oncleanup.h,
octave-value/ov-perm.cc, octave-value/ov-perm.h, octave-value/ov-range.cc,
octave-value/ov-range.h, octave-value/ov-re-diag.cc, octave-value/ov-re-diag.h,
octave-value/ov-re-mat.cc, octave-value/ov-re-mat.h,
octave-value/ov-re-sparse.cc, octave-value/ov-re-sparse.h,
octave-value/ov-scalar.cc, octave-value/ov-scalar.h,
octave-value/ov-str-mat.cc, octave-value/ov-str-mat.h,
octave-value/ov-struct.cc, octave-value/ov-struct.h,
octave-value/ov-type-conv.h, octave-value/ov-typeinfo.cc,
octave-value/ov-typeinfo.h, octave-value/ov-uint16.cc,
octave-value/ov-uint16.h, octave-value/ov-uint32.cc, octave-value/ov-uint32.h,
octave-value/ov-uint64.cc, octave-value/ov-uint64.h, octave-value/ov-uint8.cc,
octave-value/ov-uint8.h, octave-value/ov-usr-fcn.cc, octave-value/ov-usr-fcn.h,
octave-value/ov.cc, octave-value/ov.h: Moved from src/ dir to octave-value dir.
* operators/module.mk, operators/op-b-b.cc, operators/op-b-bm.cc,
operators/op-b-sbm.cc, operators/op-bm-b.cc, operators/op-bm-bm.cc,
operators/op-bm-sbm.cc, operators/op-cdm-cdm.cc, operators/op-cdm-cm.cc,
operators/op-cdm-cs.cc, operators/op-cdm-dm.cc, operators/op-cdm-m.cc,
operators/op-cdm-s.cc, operators/op-cell.cc, operators/op-chm.cc,
operators/op-class.cc, operators/op-cm-cdm.cc, operators/op-cm-cm.cc,
operators/op-cm-cs.cc, operators/op-cm-dm.cc, operators/op-cm-m.cc,
operators/op-cm-pm.cc, operators/op-cm-s.cc, operators/op-cm-scm.cc,
operators/op-cm-sm.cc, operators/op-cs-cm.cc, operators/op-cs-cs.cc,
operators/op-cs-m.cc, operators/op-cs-s.cc, operators/op-cs-scm.cc,
operators/op-cs-sm.cc, operators/op-dm-cdm.cc, operators/op-dm-cm.cc,
operators/op-dm-cs.cc, operators/op-dm-dm.cc, operators/op-dm-m.cc,
operators/op-dm-s.cc, operators/op-dm-scm.cc, operators/op-dm-sm.cc,
operators/op-dm-template.cc, operators/op-dms-template.cc,
operators/op-double-conv.cc, operators/op-fcdm-fcdm.cc,
operators/op-fcdm-fcm.cc, operators/op-fcdm-fcs.cc, operators/op-fcdm-fdm.cc,
operators/op-fcdm-fm.cc, operators/op-fcdm-fs.cc, operators/op-fcm-fcdm.cc,
operators/op-fcm-fcm.cc, operators/op-fcm-fcs.cc, operators/op-fcm-fdm.cc,
operators/op-fcm-fm.cc, operators/op-fcm-fs.cc, operators/op-fcm-pm.cc,
operators/op-fcn.cc, operators/op-fcs-fcm.cc, operators/op-fcs-fcs.cc,
operators/op-fcs-fm.cc, operators/op-fcs-fs.cc, operators/op-fdm-fcdm.cc,
operators/op-fdm-fcm.cc, operators/op-fdm-fcs.cc, operators/op-fdm-fdm.cc,
operators/op-fdm-fm.cc, operators/op-fdm-fs.cc, operators/op-float-conv.cc,
operators/op-fm-fcdm.cc, operators/op-fm-fcm.cc, operators/op-fm-fcs.cc,
operators/op-fm-fdm.cc, operators/op-fm-fm.cc, operators/op-fm-fs.cc,
operators/op-fm-pm.cc, operators/op-fs-fcm.cc, operators/op-fs-fcs.cc,
operators/op-fs-fm.cc, operators/op-fs-fs.cc, operators/op-i16-i16.cc,
operators/op-i32-i32.cc, operators/op-i64-i64.cc, operators/op-i8-i8.cc,
operators/op-int-concat.cc, operators/op-int-conv.cc, operators/op-int.h,
operators/op-m-cdm.cc, operators/op-m-cm.cc, operators/op-m-cs.cc,
operators/op-m-dm.cc, operators/op-m-m.cc, operators/op-m-pm.cc,
operators/op-m-s.cc, operators/op-m-scm.cc, operators/op-m-sm.cc,
operators/op-pm-cm.cc, operators/op-pm-fcm.cc, operators/op-pm-fm.cc,
operators/op-pm-m.cc, operators/op-pm-pm.cc, operators/op-pm-scm.cc,
operators/op-pm-sm.cc, operators/op-pm-template.cc, operators/op-range.cc,
operators/op-s-cm.cc, operators/op-s-cs.cc, operators/op-s-m.cc,
operators/op-s-s.cc, operators/op-s-scm.cc, operators/op-s-sm.cc,
operators/op-sbm-b.cc, operators/op-sbm-bm.cc, operators/op-sbm-sbm.cc,
operators/op-scm-cm.cc, operators/op-scm-cs.cc, operators/op-scm-m.cc,
operators/op-scm-s.cc, operators/op-scm-scm.cc, operators/op-scm-sm.cc,
operators/op-sm-cm.cc, operators/op-sm-cs.cc, operators/op-sm-m.cc,
operators/op-sm-s.cc, operators/op-sm-scm.cc, operators/op-sm-sm.cc,
operators/op-str-m.cc, operators/op-str-s.cc, operators/op-str-str.cc,
operators/op-struct.cc, operators/op-ui16-ui16.cc, operators/op-ui32-ui32.cc,
operators/op-ui64-ui64.cc, operators/op-ui8-ui8.cc: Moved from OPERATORS/
dir to operators/ directory.
* mkops: Correctly print comment in generated file ops.cc that it is made by
mkops. Change sed expression for OPERATORS/ to operators/.
* parse-tree/module.mk: Hook code in parse-tree dir into build system.
* parse-tree/pt-all.h, parse-tree/pt-arg-list.cc, parse-tree/pt-arg-list.h,
parse-tree/pt-assign.cc, parse-tree/pt-assign.h, parse-tree/pt-binop.cc,
parse-tree/pt-binop.h, parse-tree/pt-bp.cc, parse-tree/pt-bp.h,
parse-tree/pt-cbinop.cc, parse-tree/pt-cbinop.h, parse-tree/pt-cell.cc,
parse-tree/pt-cell.h, parse-tree/pt-check.cc, parse-tree/pt-check.h,
parse-tree/pt-cmd.cc, parse-tree/pt-cmd.h, parse-tree/pt-colon.cc,
parse-tree/pt-colon.h, parse-tree/pt-const.cc, parse-tree/pt-const.h,
parse-tree/pt-decl.cc, parse-tree/pt-decl.h, parse-tree/pt-eval.cc,
parse-tree/pt-eval.h, parse-tree/pt-except.cc, parse-tree/pt-except.h,
parse-tree/pt-exp.cc, parse-tree/pt-exp.h, parse-tree/pt-fcn-handle.cc,
parse-tree/pt-fcn-handle.h, parse-tree/pt-id.cc, parse-tree/pt-id.h,
parse-tree/pt-idx.cc, parse-tree/pt-idx.h, parse-tree/pt-jump.cc,
parse-tree/pt-jump.h, parse-tree/pt-loop.cc, parse-tree/pt-loop.h,
parse-tree/pt-mat.cc, parse-tree/pt-mat.h, parse-tree/pt-misc.cc,
parse-tree/pt-misc.h, parse-tree/pt-pr-code.cc, parse-tree/pt-pr-code.h,
parse-tree/pt-select.cc, parse-tree/pt-select.h, parse-tree/pt-stmt.cc,
parse-tree/pt-stmt.h, parse-tree/pt-unop.cc, parse-tree/pt-unop.h,
parse-tree/pt-walk.h, parse-tree/pt.cc, parse-tree/pt.h:
Moved from src/ dir to parse-tree dir.
* template-inst/Array-jit.cc, template-inst/Array-os.cc,
template-inst/Array-sym.cc, template-inst/Array-tc.cc, template-inst/module.mk:
Moved from TEMPLATE-INST dir to template-inst/ directory.
* src/Makefile.am: Add new directories to build system.
* corefcn/module.mk: Use COREFCN_SRC with all capitals to indicate it is not an
Automake special target.
author | Rik <rik@octave.org> |
---|---|
date | Mon, 30 Jul 2012 15:29:19 -0700 |
parents | src/ov-struct.cc@f7afecdd87ef |
children | 62a35ae7d6a2 |
comparison
equal
deleted
inserted
replaced
15056:bc32288f4a42 | 15057:46b19589b593 |
---|---|
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 "Cell.h" | |
30 #include "defun.h" | |
31 #include "error.h" | |
32 #include "gripes.h" | |
33 #include "oct-lvalue.h" | |
34 #include "ov-struct.h" | |
35 #include "unwind-prot.h" | |
36 #include "utils.h" | |
37 #include "variables.h" | |
38 | |
39 #include "Array-util.h" | |
40 #include "oct-locbuf.h" | |
41 | |
42 #include "byte-swap.h" | |
43 #include "ls-oct-ascii.h" | |
44 #include "ls-oct-binary.h" | |
45 #include "ls-hdf5.h" | |
46 #include "ls-utils.h" | |
47 #include "pr-output.h" | |
48 | |
49 DEFINE_OCTAVE_ALLOCATOR(octave_struct); | |
50 | |
51 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct"); | |
52 | |
53 // How many levels of structure elements should we print? | |
54 static int Vstruct_levels_to_print = 2; | |
55 | |
56 // TRUE means print struct array contents, up to the number of levels | |
57 // specified by struct_levels_to_print. | |
58 static bool Vprint_struct_array_contents = false; | |
59 | |
60 octave_base_value * | |
61 octave_struct::try_narrowing_conversion (void) | |
62 { | |
63 octave_base_value *retval = 0; | |
64 | |
65 if (numel () == 1) | |
66 retval = new octave_scalar_struct (map.checkelem (0)); | |
67 | |
68 return retval; | |
69 } | |
70 | |
71 Cell | |
72 octave_struct::dotref (const octave_value_list& idx, bool auto_add) | |
73 { | |
74 Cell retval; | |
75 | |
76 assert (idx.length () == 1); | |
77 | |
78 std::string nm = idx(0).string_value (); | |
79 | |
80 octave_map::const_iterator p = map.seek (nm); | |
81 | |
82 if (p != map.end ()) | |
83 retval = map.contents (p); | |
84 else if (auto_add) | |
85 retval = (numel () == 0) ? Cell (dim_vector (1, 1)) : Cell (dims ()); | |
86 else | |
87 error ("structure has no member `%s'", nm.c_str ()); | |
88 | |
89 return retval; | |
90 } | |
91 | |
92 #if 0 | |
93 static void | |
94 gripe_invalid_index1 (void) | |
95 { | |
96 error ("invalid index for structure array"); | |
97 } | |
98 #endif | |
99 | |
100 static void | |
101 gripe_invalid_index_for_assignment (void) | |
102 { | |
103 error ("invalid index for structure array assignment"); | |
104 } | |
105 | |
106 static void | |
107 gripe_invalid_index_type (const std::string& nm, char t) | |
108 { | |
109 error ("%s cannot be indexed with %c", nm.c_str (), t); | |
110 } | |
111 | |
112 static void | |
113 gripe_failed_assignment (void) | |
114 { | |
115 error ("assignment to structure element failed"); | |
116 } | |
117 | |
118 octave_value_list | |
119 octave_struct::subsref (const std::string& type, | |
120 const std::list<octave_value_list>& idx, | |
121 int nargout) | |
122 { | |
123 octave_value_list retval; | |
124 | |
125 int skip = 1; | |
126 | |
127 switch (type[0]) | |
128 { | |
129 case '(': | |
130 { | |
131 if (type.length () > 1 && type[1] == '.') | |
132 { | |
133 std::list<octave_value_list>::const_iterator p = idx.begin (); | |
134 octave_value_list key_idx = *++p; | |
135 | |
136 const Cell tmp = dotref (key_idx); | |
137 | |
138 if (! error_state) | |
139 { | |
140 const Cell t = tmp.index (idx.front ()); | |
141 | |
142 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true); | |
143 | |
144 // We handled two index elements, so tell | |
145 // next_subsref to skip both of them. | |
146 | |
147 skip++; | |
148 } | |
149 } | |
150 else | |
151 retval(0) = do_index_op (idx.front ()); | |
152 } | |
153 break; | |
154 | |
155 case '.': | |
156 { | |
157 if (map.numel () > 0) | |
158 { | |
159 const Cell t = dotref (idx.front ()); | |
160 | |
161 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true); | |
162 } | |
163 } | |
164 break; | |
165 | |
166 case '{': | |
167 gripe_invalid_index_type (type_name (), type[0]); | |
168 break; | |
169 | |
170 default: | |
171 panic_impossible (); | |
172 } | |
173 | |
174 // FIXME -- perhaps there should be an | |
175 // octave_value_list::next_subsref member function? See also | |
176 // octave_user_function::subsref. | |
177 | |
178 if (idx.size () > 1) | |
179 retval = retval(0).next_subsref (nargout, type, idx, skip); | |
180 | |
181 return retval; | |
182 } | |
183 | |
184 octave_value | |
185 octave_struct::subsref (const std::string& type, | |
186 const std::list<octave_value_list>& idx, | |
187 bool auto_add) | |
188 { | |
189 octave_value retval; | |
190 | |
191 int skip = 1; | |
192 | |
193 switch (type[0]) | |
194 { | |
195 case '(': | |
196 { | |
197 if (type.length () > 1 && type[1] == '.') | |
198 { | |
199 std::list<octave_value_list>::const_iterator p = idx.begin (); | |
200 octave_value_list key_idx = *++p; | |
201 | |
202 const Cell tmp = dotref (key_idx, auto_add); | |
203 | |
204 if (! error_state) | |
205 { | |
206 const Cell t = tmp.index (idx.front (), auto_add); | |
207 | |
208 retval = (t.length () == 1) ? t(0) : octave_value (t, true); | |
209 | |
210 // We handled two index elements, so tell | |
211 // next_subsref to skip both of them. | |
212 | |
213 skip++; | |
214 } | |
215 } | |
216 else | |
217 retval = do_index_op (idx.front (), auto_add); | |
218 } | |
219 break; | |
220 | |
221 case '.': | |
222 { | |
223 if (map.numel () > 0) | |
224 { | |
225 const Cell t = dotref (idx.front (), auto_add); | |
226 | |
227 retval = (t.length () == 1) ? t(0) : octave_value (t, true); | |
228 } | |
229 } | |
230 break; | |
231 | |
232 case '{': | |
233 gripe_invalid_index_type (type_name (), type[0]); | |
234 break; | |
235 | |
236 default: | |
237 panic_impossible (); | |
238 } | |
239 | |
240 // FIXME -- perhaps there should be an | |
241 // octave_value_list::next_subsref member function? See also | |
242 // octave_user_function::subsref. | |
243 | |
244 if (idx.size () > 1) | |
245 retval = retval.next_subsref (auto_add, type, idx, skip); | |
246 | |
247 return retval; | |
248 } | |
249 | |
250 /* | |
251 %!test | |
252 %! x(1).a.a = 1; | |
253 %! x(2).a.a = 2; | |
254 %! assert (size (x), [1, 2]); | |
255 %! assert (x(1).a.a, 1); | |
256 %! assert (x(2).a.a, 2); | |
257 */ | |
258 | |
259 octave_value | |
260 octave_struct::numeric_conv (const octave_value& val, | |
261 const std::string& type) | |
262 { | |
263 octave_value retval; | |
264 | |
265 if (type.length () > 0 && type[0] == '.' && ! val.is_map ()) | |
266 retval = octave_map (); | |
267 else | |
268 retval = val; | |
269 | |
270 return retval; | |
271 } | |
272 | |
273 octave_value | |
274 octave_struct::subsasgn (const std::string& type, | |
275 const std::list<octave_value_list>& idx, | |
276 const octave_value& rhs) | |
277 { | |
278 octave_value retval; | |
279 | |
280 int n = type.length (); | |
281 | |
282 octave_value t_rhs = rhs; | |
283 | |
284 if (idx.front ().empty ()) | |
285 { | |
286 error ("missing index in indexed assignment"); | |
287 return retval; | |
288 } | |
289 | |
290 if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.')) | |
291 { | |
292 switch (type[0]) | |
293 { | |
294 case '(': | |
295 { | |
296 if (type.length () > 1 && type[1] == '.') | |
297 { | |
298 std::list<octave_value_list>::const_iterator p = idx.begin (); | |
299 octave_value_list t_idx = *p; | |
300 | |
301 octave_value_list key_idx = *++p; | |
302 | |
303 assert (key_idx.length () == 1); | |
304 | |
305 std::string key = key_idx(0).string_value (); | |
306 | |
307 std::list<octave_value_list> next_idx (idx); | |
308 | |
309 // We handled two index elements, so subsasgn to | |
310 // needs to skip both of them. | |
311 | |
312 next_idx.erase (next_idx.begin ()); | |
313 next_idx.erase (next_idx.begin ()); | |
314 | |
315 std::string next_type = type.substr (2); | |
316 | |
317 Cell tmpc (1, 1); | |
318 octave_map::iterator pkey = map.seek (key); | |
319 if (pkey != map.end ()) | |
320 { | |
321 map.contents (pkey).make_unique (); | |
322 tmpc = map.contents (pkey).index (idx.front (), true); | |
323 } | |
324 | |
325 // FIXME: better code reuse? cf. octave_cell::subsasgn and the case below. | |
326 if (! error_state) | |
327 { | |
328 if (tmpc.numel () == 1) | |
329 { | |
330 octave_value& tmp = tmpc(0); | |
331 | |
332 bool orig_undefined = tmp.is_undefined (); | |
333 | |
334 if (orig_undefined || tmp.is_zero_by_zero ()) | |
335 { | |
336 tmp = octave_value::empty_conv (next_type, rhs); | |
337 tmp.make_unique (); // probably a no-op. | |
338 } | |
339 else | |
340 // optimization: ignore the copy still stored inside our map. | |
341 tmp.make_unique (1); | |
342 | |
343 if (! error_state) | |
344 t_rhs = (orig_undefined | |
345 ? tmp.undef_subsasgn (next_type, next_idx, rhs) | |
346 : tmp.subsasgn (next_type, next_idx, rhs)); | |
347 } | |
348 else | |
349 gripe_indexed_cs_list (); | |
350 } | |
351 } | |
352 else | |
353 gripe_invalid_index_for_assignment (); | |
354 } | |
355 break; | |
356 | |
357 case '.': | |
358 { | |
359 octave_value_list key_idx = idx.front (); | |
360 | |
361 assert (key_idx.length () == 1); | |
362 | |
363 std::string key = key_idx(0).string_value (); | |
364 | |
365 std::list<octave_value_list> next_idx (idx); | |
366 | |
367 next_idx.erase (next_idx.begin ()); | |
368 | |
369 std::string next_type = type.substr (1); | |
370 | |
371 Cell tmpc (1, 1); | |
372 octave_map::iterator pkey = map.seek (key); | |
373 if (pkey != map.end ()) | |
374 { | |
375 map.contents (pkey).make_unique (); | |
376 tmpc = map.contents (pkey); | |
377 } | |
378 | |
379 // FIXME: better code reuse? | |
380 if (! error_state) | |
381 { | |
382 if (tmpc.numel () == 1) | |
383 { | |
384 octave_value& tmp = tmpc(0); | |
385 | |
386 bool orig_undefined = tmp.is_undefined (); | |
387 | |
388 if (orig_undefined || tmp.is_zero_by_zero ()) | |
389 { | |
390 tmp = octave_value::empty_conv (next_type, rhs); | |
391 tmp.make_unique (); // probably a no-op. | |
392 } | |
393 else | |
394 // optimization: ignore the copy still stored inside our map. | |
395 tmp.make_unique (1); | |
396 | |
397 if (! error_state) | |
398 t_rhs = (orig_undefined | |
399 ? tmp.undef_subsasgn (next_type, next_idx, rhs) | |
400 : tmp.subsasgn (next_type, next_idx, rhs)); | |
401 } | |
402 else | |
403 gripe_indexed_cs_list (); | |
404 } | |
405 } | |
406 break; | |
407 | |
408 case '{': | |
409 gripe_invalid_index_type (type_name (), type[0]); | |
410 break; | |
411 | |
412 default: | |
413 panic_impossible (); | |
414 } | |
415 } | |
416 | |
417 if (! error_state) | |
418 { | |
419 switch (type[0]) | |
420 { | |
421 case '(': | |
422 { | |
423 if (n > 1 && type[1] == '.') | |
424 { | |
425 std::list<octave_value_list>::const_iterator p = idx.begin (); | |
426 octave_value_list key_idx = *++p; | |
427 octave_value_list idxf = idx.front (); | |
428 | |
429 assert (key_idx.length () == 1); | |
430 | |
431 std::string key = key_idx(0).string_value (); | |
432 | |
433 if (! error_state) | |
434 { | |
435 if (t_rhs.is_cs_list ()) | |
436 { | |
437 Cell tmp_cell = Cell (t_rhs.list_value ()); | |
438 | |
439 // Inquire the proper shape of the RHS. | |
440 | |
441 dim_vector didx = dims ().redim (idxf.length ()); | |
442 for (octave_idx_type k = 0; k < idxf.length (); k++) | |
443 if (! idxf(k).is_magic_colon ()) didx(k) = idxf(k).numel (); | |
444 | |
445 if (didx.numel () == tmp_cell.numel ()) | |
446 tmp_cell = tmp_cell.reshape (didx); | |
447 | |
448 | |
449 map.assign (idxf, key, tmp_cell); | |
450 | |
451 if (! error_state) | |
452 { | |
453 count++; | |
454 retval = octave_value (this); | |
455 } | |
456 else | |
457 gripe_failed_assignment (); | |
458 } | |
459 else | |
460 { | |
461 const octave_map& cmap = const_cast<const octave_map &> (map); | |
462 // cast map to const reference to avoid forced key insertion. | |
463 if (idxf.all_scalars () | |
464 || cmap.contents (key).index (idxf, true).numel () == 1) | |
465 { | |
466 map.assign (idxf, key, Cell (t_rhs.storable_value ())); | |
467 if (! error_state) | |
468 { | |
469 count++; | |
470 retval = octave_value (this); | |
471 } | |
472 else | |
473 gripe_failed_assignment (); | |
474 } | |
475 else if (! error_state) | |
476 gripe_nonbraced_cs_list_assignment (); | |
477 } | |
478 } | |
479 else | |
480 gripe_failed_assignment (); | |
481 } | |
482 else | |
483 { | |
484 if (t_rhs.is_map () || t_rhs.is_object ()) | |
485 { | |
486 octave_map rhs_map = t_rhs.map_value (); | |
487 | |
488 if (! error_state) | |
489 { | |
490 map.assign (idx.front (), rhs_map); | |
491 | |
492 if (! error_state) | |
493 { | |
494 count++; | |
495 retval = octave_value (this); | |
496 } | |
497 else | |
498 gripe_failed_assignment (); | |
499 } | |
500 else | |
501 error ("invalid structure assignment"); | |
502 } | |
503 else | |
504 { | |
505 if (t_rhs.is_null_value ()) | |
506 { | |
507 map.delete_elements (idx.front ()); | |
508 | |
509 if (! error_state) | |
510 { | |
511 count++; | |
512 retval = octave_value (this); | |
513 } | |
514 else | |
515 gripe_failed_assignment (); | |
516 } | |
517 else | |
518 error ("invalid structure assignment"); | |
519 } | |
520 } | |
521 } | |
522 break; | |
523 | |
524 case '.': | |
525 { | |
526 octave_value_list key_idx = idx.front (); | |
527 | |
528 assert (key_idx.length () == 1); | |
529 | |
530 std::string key = key_idx(0).string_value (); | |
531 | |
532 if (t_rhs.is_cs_list ()) | |
533 { | |
534 Cell tmp_cell = Cell (t_rhs.list_value ()); | |
535 | |
536 // The shape of the RHS is irrelevant, we just want | |
537 // the number of elements to agree and to preserve the | |
538 // shape of the left hand side of the assignment. | |
539 | |
540 if (numel () == tmp_cell.numel ()) | |
541 tmp_cell = tmp_cell.reshape (dims ()); | |
542 | |
543 map.setfield (key, tmp_cell); | |
544 } | |
545 else | |
546 { | |
547 Cell tmp_cell(1, 1); | |
548 tmp_cell(0) = t_rhs.storable_value (); | |
549 map.setfield (key, tmp_cell); | |
550 } | |
551 | |
552 if (! error_state) | |
553 { | |
554 count++; | |
555 retval = octave_value (this); | |
556 } | |
557 else | |
558 gripe_failed_assignment (); | |
559 } | |
560 break; | |
561 | |
562 case '{': | |
563 gripe_invalid_index_type (type_name (), type[0]); | |
564 break; | |
565 | |
566 default: | |
567 panic_impossible (); | |
568 } | |
569 } | |
570 else | |
571 gripe_failed_assignment (); | |
572 | |
573 retval.maybe_mutate (); | |
574 | |
575 return retval; | |
576 } | |
577 | |
578 octave_value | |
579 octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok) | |
580 { | |
581 // octave_map handles indexing itself. | |
582 return map.index (idx, resize_ok); | |
583 } | |
584 | |
585 size_t | |
586 octave_struct::byte_size (void) const | |
587 { | |
588 // Neglect the size of the fieldnames. | |
589 | |
590 size_t retval = 0; | |
591 | |
592 for (octave_map::const_iterator p = map.begin (); p != map.end (); p++) | |
593 { | |
594 std::string key = map.key (p); | |
595 | |
596 octave_value val = octave_value (map.contents (p)); | |
597 | |
598 retval += val.byte_size (); | |
599 } | |
600 | |
601 return retval; | |
602 } | |
603 | |
604 void | |
605 octave_struct::print (std::ostream& os, bool) const | |
606 { | |
607 print_raw (os); | |
608 } | |
609 | |
610 void | |
611 octave_struct::print_raw (std::ostream& os, bool) const | |
612 { | |
613 unwind_protect frame; | |
614 | |
615 frame.protect_var (Vstruct_levels_to_print); | |
616 | |
617 if (Vstruct_levels_to_print >= 0) | |
618 { | |
619 bool max_depth_reached = Vstruct_levels_to_print-- == 0; | |
620 | |
621 bool print_fieldnames_only | |
622 = (max_depth_reached || ! Vprint_struct_array_contents); | |
623 | |
624 increment_indent_level (); | |
625 | |
626 newline (os); | |
627 indent (os); | |
628 dim_vector dv = dims (); | |
629 os << dv.str () << " struct array containing the fields:"; | |
630 newline (os); | |
631 | |
632 increment_indent_level (); | |
633 | |
634 string_vector key_list = map.fieldnames (); | |
635 | |
636 for (octave_idx_type i = 0; i < key_list.length (); i++) | |
637 { | |
638 std::string key = key_list[i]; | |
639 | |
640 Cell val = map.contents (key); | |
641 | |
642 newline (os); | |
643 | |
644 if (print_fieldnames_only) | |
645 { | |
646 indent (os); | |
647 os << key; | |
648 } | |
649 else | |
650 { | |
651 octave_value tmp (val); | |
652 tmp.print_with_name (os, key); | |
653 } | |
654 } | |
655 | |
656 if (print_fieldnames_only) | |
657 newline (os); | |
658 | |
659 decrement_indent_level (); | |
660 decrement_indent_level (); | |
661 } | |
662 else | |
663 { | |
664 indent (os); | |
665 os << "<structure>"; | |
666 newline (os); | |
667 } | |
668 } | |
669 | |
670 bool | |
671 octave_struct::print_name_tag (std::ostream& os, const std::string& name) const | |
672 { | |
673 bool retval = false; | |
674 | |
675 indent (os); | |
676 | |
677 if (Vstruct_levels_to_print < 0) | |
678 os << name << " = "; | |
679 else | |
680 { | |
681 os << name << " ="; | |
682 newline (os); | |
683 retval = true; | |
684 } | |
685 | |
686 return retval; | |
687 } | |
688 | |
689 static bool | |
690 scalar (const dim_vector& dims) | |
691 { | |
692 return dims.length () == 2 && dims (0) == 1 && dims (1) == 1; | |
693 } | |
694 | |
695 | |
696 bool | |
697 octave_struct::save_ascii (std::ostream& os) | |
698 { | |
699 octave_map m = map_value (); | |
700 | |
701 octave_idx_type nf = m.nfields (); | |
702 | |
703 const dim_vector dv = dims (); | |
704 | |
705 os << "# ndims: " << dv.length () << "\n"; | |
706 | |
707 for (int i = 0; i < dv.length (); i++) | |
708 os << " " << dv (i); | |
709 os << "\n"; | |
710 | |
711 os << "# length: " << nf << "\n"; | |
712 | |
713 // Iterating over the list of keys will preserve the order of the | |
714 // fields. | |
715 string_vector keys = m.fieldnames (); | |
716 | |
717 for (octave_idx_type i = 0; i < nf; i++) | |
718 { | |
719 std::string key = keys(i); | |
720 | |
721 octave_value val = map.contents (key); | |
722 | |
723 bool b = save_ascii_data (os, val, key, false, 0); | |
724 | |
725 if (! b) | |
726 return os; | |
727 } | |
728 | |
729 return true; | |
730 } | |
731 | |
732 bool | |
733 octave_struct::load_ascii (std::istream& is) | |
734 { | |
735 octave_idx_type len = 0; | |
736 dim_vector dv (1, 1); | |
737 bool success = true; | |
738 | |
739 // KLUGE: earlier Octave versions did not save extra dimensions with struct, | |
740 // and as a result did not preserve dimensions for empty structs. | |
741 // The default dimensions were 1x1, which we want to preserve. | |
742 string_vector keywords(2); | |
743 | |
744 keywords[0] = "ndims"; | |
745 keywords[1] = "length"; | |
746 | |
747 std::string kw; | |
748 | |
749 if (extract_keyword (is, keywords, kw, len, true)) | |
750 { | |
751 if (kw == keywords[0]) | |
752 { | |
753 int mdims = std::max (static_cast<int> (len), 2); | |
754 dv.resize (mdims); | |
755 for (int i = 0; i < mdims; i++) | |
756 is >> dv(i); | |
757 | |
758 success = extract_keyword (is, keywords[1], len); | |
759 } | |
760 } | |
761 else | |
762 success = false; | |
763 | |
764 if (success && len >= 0) | |
765 { | |
766 if (len > 0) | |
767 { | |
768 octave_map m (dv); | |
769 | |
770 for (octave_idx_type j = 0; j < len; j++) | |
771 { | |
772 octave_value t2; | |
773 bool dummy; | |
774 | |
775 // recurse to read cell elements | |
776 std::string nm | |
777 = read_ascii_data (is, std::string (), dummy, t2, j); | |
778 | |
779 if (!is) | |
780 break; | |
781 | |
782 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); | |
783 | |
784 if (error_state) | |
785 { | |
786 error ("load: internal error loading struct elements"); | |
787 return false; | |
788 } | |
789 | |
790 m.setfield (nm, tcell); | |
791 } | |
792 | |
793 if (is) | |
794 map = m; | |
795 else | |
796 { | |
797 error ("load: failed to load structure"); | |
798 success = false; | |
799 } | |
800 } | |
801 else if (len == 0 ) | |
802 map = octave_map (dv); | |
803 else | |
804 panic_impossible (); | |
805 } | |
806 else { | |
807 error ("load: failed to extract number of elements in structure"); | |
808 success = false; | |
809 } | |
810 | |
811 return success; | |
812 } | |
813 | |
814 bool | |
815 octave_struct::save_binary (std::ostream& os, bool& save_as_floats) | |
816 { | |
817 octave_map m = map_value (); | |
818 | |
819 octave_idx_type nf = m.nfields (); | |
820 | |
821 dim_vector d = dims (); | |
822 if (d.length () < 1) | |
823 return false; | |
824 | |
825 // Use negative value for ndims | |
826 int32_t di = - d.length (); | |
827 os.write (reinterpret_cast<char *> (&di), 4); | |
828 for (int i = 0; i < d.length (); i++) | |
829 { | |
830 di = d(i); | |
831 os.write (reinterpret_cast<char *> (&di), 4); | |
832 } | |
833 | |
834 int32_t len = nf; | |
835 os.write (reinterpret_cast<char *> (&len), 4); | |
836 | |
837 // Iterating over the list of keys will preserve the order of the | |
838 // fields. | |
839 string_vector keys = m.fieldnames (); | |
840 | |
841 for (octave_idx_type i = 0; i < nf; i++) | |
842 { | |
843 std::string key = keys(i); | |
844 | |
845 octave_value val = map.contents (key); | |
846 | |
847 bool b = save_binary_data (os, val, key, "", 0, save_as_floats); | |
848 | |
849 if (! b) | |
850 return os; | |
851 } | |
852 | |
853 return true; | |
854 } | |
855 | |
856 bool | |
857 octave_struct::load_binary (std::istream& is, bool swap, | |
858 oct_mach_info::float_format fmt) | |
859 { | |
860 bool success = true; | |
861 int32_t len; | |
862 if (! is.read (reinterpret_cast<char *> (&len), 4)) | |
863 return false; | |
864 if (swap) | |
865 swap_bytes<4> (&len); | |
866 | |
867 dim_vector dv (1, 1); | |
868 | |
869 if (len < 0) | |
870 { | |
871 // We have explicit dimensions. | |
872 int mdims = -len; | |
873 | |
874 int32_t di; | |
875 dv.resize (mdims); | |
876 | |
877 for (int i = 0; i < mdims; i++) | |
878 { | |
879 if (! is.read (reinterpret_cast<char *> (&di), 4)) | |
880 return false; | |
881 if (swap) | |
882 swap_bytes<4> (&di); | |
883 dv(i) = di; | |
884 } | |
885 | |
886 if (! is.read (reinterpret_cast<char *> (&len), 4)) | |
887 return false; | |
888 if (swap) | |
889 swap_bytes<4> (&len); | |
890 } | |
891 | |
892 if (len > 0) | |
893 { | |
894 octave_map m (dv); | |
895 | |
896 for (octave_idx_type j = 0; j < len; j++) | |
897 { | |
898 octave_value t2; | |
899 bool dummy; | |
900 std::string doc; | |
901 | |
902 // recurse to read cell elements | |
903 std::string nm = read_binary_data (is, swap, fmt, std::string (), | |
904 dummy, t2, doc); | |
905 | |
906 if (!is) | |
907 break; | |
908 | |
909 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); | |
910 | |
911 if (error_state) | |
912 { | |
913 error ("load: internal error loading struct elements"); | |
914 return false; | |
915 } | |
916 | |
917 m.setfield (nm, tcell); | |
918 } | |
919 | |
920 if (is) | |
921 map = m; | |
922 else | |
923 { | |
924 error ("load: failed to load structure"); | |
925 success = false; | |
926 } | |
927 } | |
928 else if (len == 0) | |
929 map = octave_map (dv); | |
930 else | |
931 success = false; | |
932 | |
933 return success; | |
934 } | |
935 | |
936 #if defined (HAVE_HDF5) | |
937 | |
938 bool | |
939 octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) | |
940 { | |
941 hid_t data_hid = -1; | |
942 | |
943 #if HAVE_HDF5_18 | |
944 data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); | |
945 #else | |
946 data_hid = H5Gcreate (loc_id, name, 0); | |
947 #endif | |
948 if (data_hid < 0) return false; | |
949 | |
950 // recursively add each element of the structure to this group | |
951 octave_map m = map_value (); | |
952 | |
953 octave_idx_type nf = m.nfields (); | |
954 | |
955 // Iterating over the list of keys will preserve the order of the | |
956 // fields. | |
957 string_vector keys = m.fieldnames (); | |
958 | |
959 for (octave_idx_type i = 0; i < nf; i++) | |
960 { | |
961 std::string key = keys(i); | |
962 | |
963 octave_value val = map.contents (key); | |
964 | |
965 bool retval2 = add_hdf5_data (data_hid, val, key, "", false, | |
966 save_as_floats); | |
967 | |
968 if (! retval2) | |
969 break; | |
970 } | |
971 | |
972 H5Gclose (data_hid); | |
973 | |
974 return true; | |
975 } | |
976 | |
977 bool | |
978 octave_struct::load_hdf5 (hid_t loc_id, const char *name) | |
979 { | |
980 bool retval = false; | |
981 | |
982 hdf5_callback_data dsub; | |
983 | |
984 herr_t retval2 = 0; | |
985 octave_map m (dim_vector (1, 1)); | |
986 int current_item = 0; | |
987 hsize_t num_obj = 0; | |
988 #if HAVE_HDF5_18 | |
989 hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT); | |
990 #else | |
991 hid_t group_id = H5Gopen (loc_id, name); | |
992 #endif | |
993 H5Gget_num_objs (group_id, &num_obj); | |
994 H5Gclose (group_id); | |
995 | |
996 // FIXME -- fields appear to be sorted alphabetically on loading. | |
997 // Why is that happening? | |
998 | |
999 while (current_item < static_cast<int> (num_obj) | |
1000 && (retval2 = H5Giterate (loc_id, name, ¤t_item, | |
1001 hdf5_read_next_data, &dsub)) > 0) | |
1002 { | |
1003 octave_value t2 = dsub.tc; | |
1004 | |
1005 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); | |
1006 | |
1007 if (error_state) | |
1008 { | |
1009 error ("load: internal error loading struct elements"); | |
1010 return false; | |
1011 } | |
1012 | |
1013 m.setfield (dsub.name, tcell); | |
1014 | |
1015 } | |
1016 | |
1017 if (retval2 >= 0) | |
1018 { | |
1019 map = m; | |
1020 retval = true; | |
1021 } | |
1022 | |
1023 return retval; | |
1024 } | |
1025 | |
1026 #endif | |
1027 | |
1028 mxArray * | |
1029 octave_struct::as_mxArray (void) const | |
1030 { | |
1031 int nf = nfields (); | |
1032 string_vector kv = map_keys (); | |
1033 | |
1034 OCTAVE_LOCAL_BUFFER (const char *, f, nf); | |
1035 | |
1036 for (int i = 0; i < nf; i++) | |
1037 f[i] = kv[i].c_str (); | |
1038 | |
1039 mxArray *retval = new mxArray (dims (), nf, f); | |
1040 | |
1041 mxArray **elts = static_cast<mxArray **> (retval->get_data ()); | |
1042 | |
1043 mwSize nel = numel (); | |
1044 | |
1045 mwSize ntot = nf * nel; | |
1046 | |
1047 for (int i = 0; i < nf; i++) | |
1048 { | |
1049 Cell c = map.contents (kv[i]); | |
1050 | |
1051 const octave_value *p = c.data (); | |
1052 | |
1053 mwIndex k = 0; | |
1054 for (mwIndex j = i; j < ntot; j += nf) | |
1055 elts[j] = new mxArray (p[k++]); | |
1056 } | |
1057 | |
1058 return retval; | |
1059 } | |
1060 | |
1061 octave_value | |
1062 octave_struct::fast_elem_extract (octave_idx_type n) const | |
1063 { | |
1064 if (n < map.numel ()) | |
1065 return map.checkelem (n); | |
1066 else | |
1067 return octave_value (); | |
1068 } | |
1069 | |
1070 bool | |
1071 octave_struct::fast_elem_insert (octave_idx_type n, | |
1072 const octave_value& x) | |
1073 { | |
1074 bool retval = false; | |
1075 | |
1076 if (n < map.numel ()) | |
1077 { | |
1078 // To avoid copying the scalar struct, it just stores a pointer to | |
1079 // itself. | |
1080 const octave_scalar_map *sm_ptr; | |
1081 void *here = reinterpret_cast<void *>(&sm_ptr); | |
1082 return (x.get_rep ().fast_elem_insert_self (here, btyp_struct) | |
1083 && map.fast_elem_insert (n, *sm_ptr)); | |
1084 } | |
1085 | |
1086 return retval; | |
1087 } | |
1088 DEFINE_OCTAVE_ALLOCATOR(octave_scalar_struct); | |
1089 | |
1090 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_scalar_struct, "scalar struct", "struct"); | |
1091 | |
1092 octave_value | |
1093 octave_scalar_struct::dotref (const octave_value_list& idx, bool auto_add) | |
1094 { | |
1095 assert (idx.length () == 1); | |
1096 | |
1097 std::string nm = idx(0).string_value (); | |
1098 | |
1099 octave_value retval = map.getfield (nm); | |
1100 | |
1101 if (! auto_add && retval.is_undefined ()) | |
1102 error ("structure has no member `%s'", nm.c_str ()); | |
1103 | |
1104 return retval; | |
1105 } | |
1106 | |
1107 octave_value | |
1108 octave_scalar_struct::subsref (const std::string& type, | |
1109 const std::list<octave_value_list>& idx) | |
1110 { | |
1111 octave_value retval; | |
1112 | |
1113 if (type[0] == '.') | |
1114 { | |
1115 int skip = 1; | |
1116 | |
1117 retval = dotref (idx.front ()); | |
1118 | |
1119 if (idx.size () > 1) | |
1120 retval = retval.next_subsref (type, idx, skip); | |
1121 } | |
1122 else | |
1123 retval = to_array ().subsref (type, idx); | |
1124 | |
1125 return retval; | |
1126 } | |
1127 | |
1128 octave_value_list | |
1129 octave_scalar_struct::subsref (const std::string& type, | |
1130 const std::list<octave_value_list>& idx, | |
1131 int nargout) | |
1132 { | |
1133 octave_value_list retval; | |
1134 | |
1135 if (type[0] == '.') | |
1136 { | |
1137 int skip = 1; | |
1138 | |
1139 retval(0) = dotref (idx.front ()); | |
1140 | |
1141 if (idx.size () > 1) | |
1142 retval = retval(0).next_subsref (nargout, type, idx, skip); | |
1143 } | |
1144 else | |
1145 retval = to_array ().subsref (type, idx, nargout); | |
1146 | |
1147 return retval; | |
1148 } | |
1149 | |
1150 octave_value | |
1151 octave_scalar_struct::subsref (const std::string& type, | |
1152 const std::list<octave_value_list>& idx, | |
1153 bool auto_add) | |
1154 { | |
1155 octave_value retval; | |
1156 | |
1157 if (type[0] == '.') | |
1158 { | |
1159 int skip = 1; | |
1160 | |
1161 retval = dotref (idx.front (), auto_add); | |
1162 | |
1163 if (idx.size () > 1) | |
1164 retval = retval.next_subsref (auto_add, type, idx, skip); | |
1165 } | |
1166 else | |
1167 retval = to_array ().subsref (type, idx, auto_add); | |
1168 | |
1169 return retval; | |
1170 } | |
1171 | |
1172 /* | |
1173 %!test | |
1174 %! x(1).a.a = 1; | |
1175 %! x(2).a.a = 2; | |
1176 %! assert (size (x), [1, 2]); | |
1177 %! assert (x(1).a.a, 1); | |
1178 %! assert (x(2).a.a, 2); | |
1179 */ | |
1180 | |
1181 octave_value | |
1182 octave_scalar_struct::numeric_conv (const octave_value& val, | |
1183 const std::string& type) | |
1184 { | |
1185 octave_value retval; | |
1186 | |
1187 if (type.length () > 0 && type[0] == '.' && ! val.is_map ()) | |
1188 retval = octave_map (); | |
1189 else | |
1190 retval = val; | |
1191 | |
1192 return retval; | |
1193 } | |
1194 | |
1195 octave_value | |
1196 octave_scalar_struct::subsasgn (const std::string& type, | |
1197 const std::list<octave_value_list>& idx, | |
1198 const octave_value& rhs) | |
1199 { | |
1200 octave_value retval; | |
1201 | |
1202 if (idx.front ().empty ()) | |
1203 { | |
1204 error ("missing index in indexed assignment"); | |
1205 return retval; | |
1206 } | |
1207 | |
1208 if (type[0] == '.') | |
1209 { | |
1210 int n = type.length (); | |
1211 | |
1212 octave_value t_rhs = rhs; | |
1213 | |
1214 octave_value_list key_idx = idx.front (); | |
1215 | |
1216 assert (key_idx.length () == 1); | |
1217 | |
1218 std::string key = key_idx(0).string_value (); | |
1219 | |
1220 if (n > 1) | |
1221 { | |
1222 std::list<octave_value_list> next_idx (idx); | |
1223 | |
1224 next_idx.erase (next_idx.begin ()); | |
1225 | |
1226 std::string next_type = type.substr (1); | |
1227 | |
1228 octave_value tmp; | |
1229 octave_map::iterator pkey = map.seek (key); | |
1230 if (pkey != map.end ()) | |
1231 { | |
1232 map.contents (pkey).make_unique (); | |
1233 tmp = map.contents (pkey); | |
1234 } | |
1235 | |
1236 if (! error_state) | |
1237 { | |
1238 bool orig_undefined = tmp.is_undefined (); | |
1239 | |
1240 if (orig_undefined || tmp.is_zero_by_zero ()) | |
1241 { | |
1242 tmp = octave_value::empty_conv (next_type, rhs); | |
1243 tmp.make_unique (); // probably a no-op. | |
1244 } | |
1245 else | |
1246 // optimization: ignore the copy still stored inside our map. | |
1247 tmp.make_unique (1); | |
1248 | |
1249 if (! error_state) | |
1250 t_rhs = (orig_undefined | |
1251 ? tmp.undef_subsasgn (next_type, next_idx, rhs) | |
1252 : tmp.subsasgn (next_type, next_idx, rhs)); | |
1253 } | |
1254 } | |
1255 | |
1256 if (! error_state) | |
1257 map.setfield (key, t_rhs.storable_value ()); | |
1258 else | |
1259 gripe_failed_assignment (); | |
1260 | |
1261 count++; | |
1262 retval = this; | |
1263 } | |
1264 else | |
1265 { | |
1266 // Forward this case to octave_struct. | |
1267 octave_value tmp (new octave_struct (octave_map (map))); | |
1268 retval = tmp.subsasgn (type, idx, rhs); | |
1269 } | |
1270 | |
1271 return retval; | |
1272 } | |
1273 | |
1274 octave_value | |
1275 octave_scalar_struct::do_index_op (const octave_value_list& idx, bool resize_ok) | |
1276 { | |
1277 // octave_map handles indexing itself. | |
1278 return octave_map (map).index (idx, resize_ok); | |
1279 } | |
1280 | |
1281 size_t | |
1282 octave_scalar_struct::byte_size (void) const | |
1283 { | |
1284 // Neglect the size of the fieldnames. | |
1285 | |
1286 size_t retval = 0; | |
1287 | |
1288 for (octave_map::const_iterator p = map.begin (); p != map.end (); p++) | |
1289 { | |
1290 std::string key = map.key (p); | |
1291 | |
1292 octave_value val = octave_value (map.contents (p)); | |
1293 | |
1294 retval += val.byte_size (); | |
1295 } | |
1296 | |
1297 return retval; | |
1298 } | |
1299 | |
1300 void | |
1301 octave_scalar_struct::print (std::ostream& os, bool) const | |
1302 { | |
1303 print_raw (os); | |
1304 } | |
1305 | |
1306 void | |
1307 octave_scalar_struct::print_raw (std::ostream& os, bool) const | |
1308 { | |
1309 unwind_protect frame; | |
1310 | |
1311 frame.protect_var (Vstruct_levels_to_print); | |
1312 | |
1313 if (Vstruct_levels_to_print >= 0) | |
1314 { | |
1315 bool max_depth_reached = Vstruct_levels_to_print-- == 0; | |
1316 | |
1317 bool print_fieldnames_only = max_depth_reached; | |
1318 | |
1319 increment_indent_level (); | |
1320 | |
1321 if (! Vcompact_format) | |
1322 newline (os); | |
1323 | |
1324 indent (os); | |
1325 os << "scalar structure containing the fields:"; | |
1326 newline (os); | |
1327 if (! Vcompact_format) | |
1328 newline (os); | |
1329 | |
1330 increment_indent_level (); | |
1331 | |
1332 string_vector key_list = map.fieldnames (); | |
1333 | |
1334 for (octave_idx_type i = 0; i < key_list.length (); i++) | |
1335 { | |
1336 std::string key = key_list[i]; | |
1337 | |
1338 octave_value val = map.contents (key); | |
1339 | |
1340 if (print_fieldnames_only) | |
1341 { | |
1342 indent (os); | |
1343 os << key; | |
1344 dim_vector dv = val.dims (); | |
1345 os << ": " << dv.str () << " " << val.type_name (); | |
1346 newline (os); | |
1347 } | |
1348 else | |
1349 val.print_with_name (os, key); | |
1350 } | |
1351 | |
1352 decrement_indent_level (); | |
1353 decrement_indent_level (); | |
1354 } | |
1355 else | |
1356 { | |
1357 indent (os); | |
1358 os << "<structure>"; | |
1359 newline (os); | |
1360 } | |
1361 } | |
1362 | |
1363 bool | |
1364 octave_scalar_struct::print_name_tag (std::ostream& os, const std::string& name) const | |
1365 { | |
1366 bool retval = false; | |
1367 | |
1368 indent (os); | |
1369 | |
1370 if (Vstruct_levels_to_print < 0) | |
1371 os << name << " = "; | |
1372 else | |
1373 { | |
1374 os << name << " ="; | |
1375 newline (os); | |
1376 retval = true; | |
1377 } | |
1378 | |
1379 return retval; | |
1380 } | |
1381 | |
1382 bool | |
1383 octave_scalar_struct::save_ascii (std::ostream& os) | |
1384 { | |
1385 octave_map m = map_value (); | |
1386 | |
1387 octave_idx_type nf = m.nfields (); | |
1388 | |
1389 const dim_vector dv = dims (); | |
1390 | |
1391 os << "# ndims: " << dv.length () << "\n"; | |
1392 | |
1393 for (int i = 0; i < dv.length (); i++) | |
1394 os << " " << dv (i); | |
1395 os << "\n"; | |
1396 | |
1397 os << "# length: " << nf << "\n"; | |
1398 | |
1399 // Iterating over the list of keys will preserve the order of the | |
1400 // fields. | |
1401 string_vector keys = m.fieldnames (); | |
1402 | |
1403 for (octave_idx_type i = 0; i < nf; i++) | |
1404 { | |
1405 std::string key = keys(i); | |
1406 | |
1407 octave_value val = map.contents (key); | |
1408 | |
1409 bool b = save_ascii_data (os, val, key, false, 0); | |
1410 | |
1411 if (! b) | |
1412 return os; | |
1413 } | |
1414 | |
1415 return true; | |
1416 } | |
1417 | |
1418 bool | |
1419 octave_scalar_struct::load_ascii (std::istream& is) | |
1420 { | |
1421 bool success = true; | |
1422 octave_idx_type len = 0; | |
1423 | |
1424 if (extract_keyword (is, "length", len) && len >= 0) | |
1425 { | |
1426 if (len > 0) | |
1427 { | |
1428 octave_scalar_map m; | |
1429 | |
1430 for (octave_idx_type j = 0; j < len; j++) | |
1431 { | |
1432 octave_value t2; | |
1433 bool dummy; | |
1434 | |
1435 // recurse to read cell elements | |
1436 std::string nm | |
1437 = read_ascii_data (is, std::string (), dummy, t2, j); | |
1438 | |
1439 if (!is) | |
1440 break; | |
1441 | |
1442 if (error_state) | |
1443 { | |
1444 error ("load: internal error loading struct elements"); | |
1445 return false; | |
1446 } | |
1447 | |
1448 m.setfield (nm, t2); | |
1449 } | |
1450 | |
1451 if (is) | |
1452 map = m; | |
1453 else | |
1454 { | |
1455 error ("load: failed to load structure"); | |
1456 success = false; | |
1457 } | |
1458 } | |
1459 else if (len == 0) | |
1460 map = octave_scalar_map (); | |
1461 else | |
1462 panic_impossible (); | |
1463 } | |
1464 else { | |
1465 error ("load: failed to extract number of elements in structure"); | |
1466 success = false; | |
1467 } | |
1468 | |
1469 return success; | |
1470 } | |
1471 | |
1472 bool | |
1473 octave_scalar_struct::save_binary (std::ostream& os, bool& save_as_floats) | |
1474 { | |
1475 octave_map m = map_value (); | |
1476 | |
1477 octave_idx_type nf = m.nfields (); | |
1478 | |
1479 int32_t len = nf; | |
1480 os.write (reinterpret_cast<char *> (&len), 4); | |
1481 | |
1482 // Iterating over the list of keys will preserve the order of the | |
1483 // fields. | |
1484 string_vector keys = m.fieldnames (); | |
1485 | |
1486 for (octave_idx_type i = 0; i < nf; i++) | |
1487 { | |
1488 std::string key = keys(i); | |
1489 | |
1490 octave_value val = map.contents (key); | |
1491 | |
1492 bool b = save_binary_data (os, val, key, "", 0, save_as_floats); | |
1493 | |
1494 if (! b) | |
1495 return os; | |
1496 } | |
1497 | |
1498 return true; | |
1499 } | |
1500 | |
1501 bool | |
1502 octave_scalar_struct::load_binary (std::istream& is, bool swap, | |
1503 oct_mach_info::float_format fmt) | |
1504 { | |
1505 bool success = true; | |
1506 int32_t len; | |
1507 if (! is.read (reinterpret_cast<char *> (&len), 4)) | |
1508 return false; | |
1509 if (swap) | |
1510 swap_bytes<4> (&len); | |
1511 | |
1512 dim_vector dv (1, 1); | |
1513 | |
1514 if (len > 0) | |
1515 { | |
1516 octave_scalar_map m; | |
1517 | |
1518 for (octave_idx_type j = 0; j < len; j++) | |
1519 { | |
1520 octave_value t2; | |
1521 bool dummy; | |
1522 std::string doc; | |
1523 | |
1524 // recurse to read cell elements | |
1525 std::string nm = read_binary_data (is, swap, fmt, std::string (), | |
1526 dummy, t2, doc); | |
1527 | |
1528 if (!is) | |
1529 break; | |
1530 | |
1531 if (error_state) | |
1532 { | |
1533 error ("load: internal error loading struct elements"); | |
1534 return false; | |
1535 } | |
1536 | |
1537 m.setfield (nm, t2); | |
1538 } | |
1539 | |
1540 if (is) | |
1541 map = m; | |
1542 else | |
1543 { | |
1544 error ("load: failed to load structure"); | |
1545 success = false; | |
1546 } | |
1547 } | |
1548 else if (len == 0) | |
1549 map = octave_scalar_map (); | |
1550 else | |
1551 success = false; | |
1552 | |
1553 return success; | |
1554 } | |
1555 | |
1556 #if defined (HAVE_HDF5) | |
1557 | |
1558 bool | |
1559 octave_scalar_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) | |
1560 { | |
1561 hid_t data_hid = -1; | |
1562 | |
1563 #if HAVE_HDF5_18 | |
1564 data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); | |
1565 #else | |
1566 data_hid = H5Gcreate (loc_id, name, 0); | |
1567 #endif | |
1568 if (data_hid < 0) return false; | |
1569 | |
1570 // recursively add each element of the structure to this group | |
1571 octave_scalar_map m = scalar_map_value (); | |
1572 | |
1573 octave_idx_type nf = m.nfields (); | |
1574 | |
1575 // Iterating over the list of keys will preserve the order of the | |
1576 // fields. | |
1577 string_vector keys = m.fieldnames (); | |
1578 | |
1579 for (octave_idx_type i = 0; i < nf; i++) | |
1580 { | |
1581 std::string key = keys(i); | |
1582 | |
1583 octave_value val = map.contents (key); | |
1584 | |
1585 bool retval2 = add_hdf5_data (data_hid, val, key, "", false, | |
1586 save_as_floats); | |
1587 | |
1588 if (! retval2) | |
1589 break; | |
1590 } | |
1591 | |
1592 H5Gclose (data_hid); | |
1593 | |
1594 return true; | |
1595 } | |
1596 | |
1597 bool | |
1598 octave_scalar_struct::load_hdf5 (hid_t loc_id, const char *name) | |
1599 { | |
1600 bool retval = false; | |
1601 | |
1602 hdf5_callback_data dsub; | |
1603 | |
1604 herr_t retval2 = 0; | |
1605 octave_scalar_map m; | |
1606 int current_item = 0; | |
1607 hsize_t num_obj = 0; | |
1608 #if HAVE_HDF5_18 | |
1609 hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT); | |
1610 #else | |
1611 hid_t group_id = H5Gopen (loc_id, name); | |
1612 #endif | |
1613 H5Gget_num_objs (group_id, &num_obj); | |
1614 H5Gclose (group_id); | |
1615 | |
1616 // FIXME -- fields appear to be sorted alphabetically on loading. | |
1617 // Why is that happening? | |
1618 | |
1619 while (current_item < static_cast<int> (num_obj) | |
1620 && (retval2 = H5Giterate (loc_id, name, ¤t_item, | |
1621 hdf5_read_next_data, &dsub)) > 0) | |
1622 { | |
1623 octave_value t2 = dsub.tc; | |
1624 | |
1625 if (error_state) | |
1626 { | |
1627 error ("load: internal error loading struct elements"); | |
1628 return false; | |
1629 } | |
1630 | |
1631 m.setfield (dsub.name, t2); | |
1632 | |
1633 } | |
1634 | |
1635 if (retval2 >= 0) | |
1636 { | |
1637 map = m; | |
1638 retval = true; | |
1639 } | |
1640 | |
1641 return retval; | |
1642 } | |
1643 | |
1644 #endif | |
1645 | |
1646 mxArray * | |
1647 octave_scalar_struct::as_mxArray (void) const | |
1648 { | |
1649 int nf = nfields (); | |
1650 string_vector kv = map_keys (); | |
1651 | |
1652 OCTAVE_LOCAL_BUFFER (const char *, f, nf); | |
1653 | |
1654 for (int i = 0; i < nf; i++) | |
1655 f[i] = kv[i].c_str (); | |
1656 | |
1657 mxArray *retval = new mxArray (dims (), nf, f); | |
1658 | |
1659 mxArray **elts = static_cast<mxArray **> (retval->get_data ()); | |
1660 | |
1661 mwSize nel = numel (); | |
1662 | |
1663 mwSize ntot = nf * nel; | |
1664 | |
1665 for (int i = 0; i < nf; i++) | |
1666 { | |
1667 Cell c = map.contents (kv[i]); | |
1668 | |
1669 const octave_value *p = c.data (); | |
1670 | |
1671 mwIndex k = 0; | |
1672 for (mwIndex j = i; j < ntot; j += nf) | |
1673 elts[j] = new mxArray (p[k++]); | |
1674 } | |
1675 | |
1676 return retval; | |
1677 } | |
1678 | |
1679 | |
1680 octave_value | |
1681 octave_scalar_struct::to_array (void) | |
1682 { | |
1683 return new octave_struct (octave_map (map)); | |
1684 } | |
1685 | |
1686 bool | |
1687 octave_scalar_struct::fast_elem_insert_self (void *where, builtin_type_t btyp) const | |
1688 { | |
1689 | |
1690 if (btyp == btyp_struct) | |
1691 { | |
1692 *(reinterpret_cast<const octave_scalar_map **>(where)) = ↦ | |
1693 return true; | |
1694 } | |
1695 else | |
1696 return false; | |
1697 } | |
1698 | |
1699 DEFUN (struct, args, , | |
1700 "-*- texinfo -*-\n\ | |
1701 @deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\ | |
1702 \n\ | |
1703 Create a structure and initialize its value.\n\ | |
1704 \n\ | |
1705 If the values are cell arrays, create a structure array and initialize\n\ | |
1706 its values. The dimensions of each cell array of values must match.\n\ | |
1707 Singleton cells and non-cell values are repeated so that they fill\n\ | |
1708 the entire array. If the cells are empty, create an empty structure\n\ | |
1709 array with the specified field names.\n\ | |
1710 \n\ | |
1711 If the argument is an object, return the underlying struct.\n\ | |
1712 @end deftypefn") | |
1713 { | |
1714 octave_value retval; | |
1715 | |
1716 int nargin = args.length (); | |
1717 | |
1718 // struct ([]) returns an empty struct. | |
1719 | |
1720 // struct (empty_matrix) returns an empty struct with the same | |
1721 // dimensions as the empty matrix. | |
1722 | |
1723 // Note that struct () creates a 1x1 struct with no fields for | |
1724 // compatibility with Matlab. | |
1725 | |
1726 if (nargin == 1 && args(0).is_map ()) | |
1727 return args(0); | |
1728 | |
1729 if (nargin == 1 && args(0).is_object ()) | |
1730 { | |
1731 retval = args(0).map_value (); | |
1732 | |
1733 return retval; | |
1734 } | |
1735 | |
1736 if ((nargin == 1 || nargin == 2) | |
1737 && args(0).is_empty () && args(0).is_real_matrix ()) | |
1738 { | |
1739 Cell fields; | |
1740 | |
1741 if (nargin == 2) | |
1742 { | |
1743 if (args(1).is_cellstr ()) | |
1744 retval = octave_map (args(0).dims (), args(1).cellstr_value ()); | |
1745 else | |
1746 error ("struct: expecting cell array of field names as second argument"); | |
1747 } | |
1748 else | |
1749 retval = octave_map (args(0).dims ()); | |
1750 | |
1751 return retval; | |
1752 } | |
1753 | |
1754 // Check for "field", VALUE pairs. | |
1755 | |
1756 for (int i = 0; i < nargin; i += 2) | |
1757 { | |
1758 if (! args(i).is_string () || i + 1 >= nargin) | |
1759 { | |
1760 error ("struct: expecting alternating \"field\", VALUE pairs"); | |
1761 return retval; | |
1762 } | |
1763 } | |
1764 | |
1765 // Check that the dimensions of the values correspond. | |
1766 | |
1767 dim_vector dims (1, 1); | |
1768 | |
1769 int first_dimensioned_value = 0; | |
1770 | |
1771 for (int i = 1; i < nargin; i += 2) | |
1772 { | |
1773 if (args(i).is_cell ()) | |
1774 { | |
1775 dim_vector argdims (args(i).dims ()); | |
1776 | |
1777 if (! scalar (argdims)) | |
1778 { | |
1779 if (! first_dimensioned_value) | |
1780 { | |
1781 dims = argdims; | |
1782 first_dimensioned_value = i + 1; | |
1783 } | |
1784 else if (dims != argdims) | |
1785 { | |
1786 error ("struct: dimensions of parameter %d do not match those of parameter %d", | |
1787 first_dimensioned_value, i+1); | |
1788 return retval; | |
1789 } | |
1790 } | |
1791 } | |
1792 } | |
1793 | |
1794 // Create the return value. | |
1795 | |
1796 octave_map map (dims); | |
1797 | |
1798 for (int i = 0; i < nargin; i+= 2) | |
1799 { | |
1800 // Get key. | |
1801 | |
1802 std::string key (args(i).string_value ()); | |
1803 | |
1804 if (error_state) | |
1805 return retval; | |
1806 | |
1807 if (! valid_identifier (key)) | |
1808 { | |
1809 error ("struct: invalid structure field name `%s'", key.c_str ()); | |
1810 return retval; | |
1811 } | |
1812 | |
1813 // Value may be v, { v }, or { v1, v2, ... } | |
1814 // In the first two cases, we need to create a cell array of | |
1815 // the appropriate dimensions filled with v. In the last case, | |
1816 // the cell array has already been determined to be of the | |
1817 // correct dimensions. | |
1818 | |
1819 if (args(i+1).is_cell ()) | |
1820 { | |
1821 const Cell c (args(i+1).cell_value ()); | |
1822 | |
1823 if (error_state) | |
1824 return retval; | |
1825 | |
1826 if (scalar (c.dims ())) | |
1827 map.setfield (key, Cell (dims, c(0))); | |
1828 else | |
1829 map.setfield (key, c); | |
1830 } | |
1831 else | |
1832 map.setfield (key, Cell (dims, args(i+1))); | |
1833 | |
1834 if (error_state) | |
1835 return retval; | |
1836 } | |
1837 | |
1838 return octave_value (map); | |
1839 } | |
1840 | |
1841 /* | |
1842 %!shared x | |
1843 %! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3; | |
1844 %!assert (struct ("a",1, "b",3), x(1)) | |
1845 %!assert (isempty (x([]))) | |
1846 %!assert (isempty (struct ("a",{}, "b",{}))) | |
1847 %!assert (struct ("a",{1,2}, "b",{3,3}), x) | |
1848 %!assert (struct ("a",{1,2}, "b",3), x) | |
1849 %!assert (struct ("a",{1,2}, "b",{3}), x) | |
1850 %!assert (struct ("b",3, "a",{1,2}), x) | |
1851 %!assert (struct ("b",{3}, "a",{1,2}), x) | |
1852 %!test x = struct ([]); | |
1853 %!assert (size (x), [0,0]) | |
1854 %!assert (isstruct (x)) | |
1855 %!assert (isempty (fieldnames (x))) | |
1856 %!fail ('struct ("a",{1,2},"b",{1,2,3})', 'dimensions of parameter 2 do not match those of parameter 4') | |
1857 %!fail ('struct (1,2,3,4)', 'struct: expecting alternating "field", VALUE pairs') | |
1858 %!fail ('struct ("1",2,"3")', 'struct: expecting alternating "field", VALUE pairs') | |
1859 */ | |
1860 | |
1861 DEFUN (isstruct, args, , | |
1862 "-*- texinfo -*-\n\ | |
1863 @deftypefn {Built-in Function} {} isstruct (@var{x})\n\ | |
1864 Return true if @var{x} is a structure or a structure array.\n\ | |
1865 @seealso{ismatrix, iscell, isa}\n\ | |
1866 @end deftypefn") | |
1867 { | |
1868 octave_value retval; | |
1869 | |
1870 if (args.length () == 1) | |
1871 retval = args(0).is_map (); | |
1872 else | |
1873 print_usage (); | |
1874 | |
1875 return retval; | |
1876 } | |
1877 | |
1878 DEFUN (fieldnames, args, , | |
1879 "-*- texinfo -*-\n\ | |
1880 @deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\ | |
1881 Return a cell array of strings naming the elements of the structure\n\ | |
1882 @var{struct}. It is an error to call @code{fieldnames} with an\n\ | |
1883 argument that is not a structure.\n\ | |
1884 @end deftypefn") | |
1885 { | |
1886 octave_value retval; | |
1887 | |
1888 int nargin = args.length (); | |
1889 | |
1890 if (nargin == 1) | |
1891 { | |
1892 octave_value arg = args(0); | |
1893 | |
1894 if (arg.is_map () || arg.is_object ()) | |
1895 { | |
1896 octave_map m = arg.map_value (); | |
1897 | |
1898 string_vector keys = m.fieldnames (); | |
1899 | |
1900 if (keys.length () == 0) | |
1901 retval = Cell (0, 1); | |
1902 else | |
1903 retval = Cell (keys); | |
1904 } | |
1905 else | |
1906 gripe_wrong_type_arg ("fieldnames", args(0)); | |
1907 } | |
1908 else | |
1909 print_usage (); | |
1910 | |
1911 return retval; | |
1912 } | |
1913 | |
1914 /* | |
1915 ## test preservation of fieldname order | |
1916 %!test | |
1917 %! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; | |
1918 %! assert (fieldnames (x), {"d"; "a"; "b"; "c"}); | |
1919 */ | |
1920 | |
1921 DEFUN (isfield, args, , | |
1922 "-*- texinfo -*-\n\ | |
1923 @deftypefn {Built-in Function} {} isfield (@var{x}, @var{name})\n\ | |
1924 Return true if the @var{x} is a structure and it\n\ | |
1925 includes an element named @var{name}. If @var{name} is a cell\n\ | |
1926 array of strings then a logical array of equal dimension is returned.\n\ | |
1927 @end deftypefn") | |
1928 { | |
1929 octave_value retval; | |
1930 | |
1931 int nargin = args.length (); | |
1932 | |
1933 if (nargin == 2) | |
1934 { | |
1935 retval = false; | |
1936 | |
1937 if (args(0).is_map ()) | |
1938 { | |
1939 octave_map m = args(0).map_value (); | |
1940 | |
1941 // FIXME -- should this work for all types that can do | |
1942 // structure reference operations? | |
1943 | |
1944 if (args(1).is_string ()) | |
1945 { | |
1946 std::string key = args(1).string_value (); | |
1947 | |
1948 retval = m.isfield (key); | |
1949 } | |
1950 else if (args(1).is_cell ()) | |
1951 { | |
1952 Cell c = args(1).cell_value (); | |
1953 boolNDArray bm (c.dims ()); | |
1954 octave_idx_type n = bm.numel (); | |
1955 | |
1956 for (octave_idx_type i = 0; i < n; i++) | |
1957 { | |
1958 if (c(i).is_string ()) | |
1959 { | |
1960 std::string key = c(i).string_value (); | |
1961 | |
1962 bm(i) = m.isfield (key); | |
1963 } | |
1964 else | |
1965 bm(i) = false; | |
1966 } | |
1967 | |
1968 retval = bm; | |
1969 } | |
1970 } | |
1971 } | |
1972 else | |
1973 print_usage (); | |
1974 | |
1975 return retval; | |
1976 } | |
1977 | |
1978 DEFUN (nfields, args, , | |
1979 "-*- texinfo -*-\n\ | |
1980 @deftypefn {Built-in Function} {} nfields (@var{s})\n\ | |
1981 Return the number of fields of the structure @var{s}.\n\ | |
1982 @end deftypefn") | |
1983 { | |
1984 octave_value retval; | |
1985 | |
1986 int nargin = args.length (); | |
1987 | |
1988 if (nargin == 1 && args(0).is_map ()) | |
1989 { | |
1990 retval = static_cast<double> (args(0).nfields ()); | |
1991 } | |
1992 else | |
1993 print_usage (); | |
1994 | |
1995 return retval; | |
1996 } | |
1997 | |
1998 /* | |
1999 ## test isfield | |
2000 %!test | |
2001 %! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; | |
2002 %! assert (isfield (x, "b")); | |
2003 %!assert (isfield (struct ("a", "1"), "a")) | |
2004 %!assert (isfield ({1}, "c"), false) | |
2005 %!assert (isfield (struct ("a", "1"), 10), false) | |
2006 %!assert (isfield (struct ("a", "b"), "a "), false) | |
2007 %!assert (isfield (struct ("a", 1, "b", 2), {"a", "c"}), [true, false]) | |
2008 */ | |
2009 | |
2010 DEFUN (cell2struct, args, , | |
2011 "-*- texinfo -*-\n\ | |
2012 @deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\ | |
2013 Convert @var{cell} to a structure. The number of fields in @var{fields}\n\ | |
2014 must match the number of elements in @var{cell} along dimension @var{dim},\n\ | |
2015 that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\ | |
2016 If @var{dim} is omitted, a value of 1 is assumed.\n\ | |
2017 \n\ | |
2018 @example\n\ | |
2019 @group\n\ | |
2020 A = cell2struct (@{\"Peter\", \"Hannah\", \"Robert\";\n\ | |
2021 185, 170, 168@},\n\ | |
2022 @{\"Name\",\"Height\"@}, 1);\n\ | |
2023 A(1)\n\ | |
2024 @result{}\n\ | |
2025 @{\n\ | |
2026 Name = Peter\n\ | |
2027 Height = 185\n\ | |
2028 @}\n\ | |
2029 \n\ | |
2030 @end group\n\ | |
2031 @end example\n\ | |
2032 @end deftypefn") | |
2033 { | |
2034 octave_value retval; | |
2035 | |
2036 int nargin = args.length (); | |
2037 | |
2038 if (nargin == 2 || nargin == 3) | |
2039 { | |
2040 if (! args(0).is_cell ()) | |
2041 { | |
2042 error ("cell2struct: argument CELL must be of type cell"); | |
2043 return retval; | |
2044 } | |
2045 | |
2046 if (! (args(1).is_cellstr () || args(1).is_char_matrix ())) | |
2047 { | |
2048 error ("cell2struct: FIELDS must be a cell array of strings or a character matrix"); | |
2049 return retval; | |
2050 } | |
2051 | |
2052 const Cell vals = args(0).cell_value (); | |
2053 const Array<std::string> fields = args(1).cellstr_value (); | |
2054 | |
2055 octave_idx_type ext = 0; | |
2056 | |
2057 int dim = 0; | |
2058 | |
2059 if (nargin == 3) | |
2060 { | |
2061 if (args(2).is_real_scalar ()) | |
2062 { | |
2063 dim = nargin == 2 ? 0 : args(2).int_value () - 1; | |
2064 | |
2065 if (error_state) | |
2066 return retval; | |
2067 } | |
2068 else | |
2069 { | |
2070 error ("cell2struct: DIM must be a real scalar"); | |
2071 return retval; | |
2072 } | |
2073 } | |
2074 | |
2075 if (dim < 0) | |
2076 { | |
2077 error ("cell2struct: DIM must be a valid dimension"); | |
2078 return retval; | |
2079 } | |
2080 | |
2081 ext = vals.ndims () > dim ? vals.dims ()(dim) : 1; | |
2082 | |
2083 if (ext != fields.numel ()) | |
2084 { | |
2085 error ("cell2struct: number of FIELDS does not match dimension"); | |
2086 return retval; | |
2087 } | |
2088 | |
2089 int nd = std::max (dim+1, vals.ndims ()); | |
2090 // result dimensions. | |
2091 dim_vector rdv = vals.dims ().redim (nd); | |
2092 | |
2093 assert (ext == rdv(dim)); | |
2094 if (nd == 2) | |
2095 { | |
2096 rdv(0) = rdv(1-dim); | |
2097 rdv(1) = 1; | |
2098 } | |
2099 else | |
2100 { | |
2101 for (int i = dim + 1; i < nd; i++) | |
2102 rdv(i-1) = rdv(i); | |
2103 | |
2104 rdv.resize (nd-1); | |
2105 } | |
2106 | |
2107 octave_map map (rdv); | |
2108 Array<idx_vector> ia (dim_vector (nd, 1), idx_vector::colon); | |
2109 | |
2110 for (octave_idx_type i = 0; i < ext; i++) | |
2111 { | |
2112 ia(dim) = i; | |
2113 map.setfield (fields(i), vals.index (ia).reshape (rdv)); | |
2114 } | |
2115 | |
2116 retval = map; | |
2117 } | |
2118 else | |
2119 print_usage (); | |
2120 | |
2121 return retval; | |
2122 } | |
2123 | |
2124 /* | |
2125 ## test cell2struct versus struct2cell | |
2126 %!test | |
2127 %! keys = cellstr (char (floor (rand (100,10)*24+65)))'; | |
2128 %! vals = mat2cell (rand (100,1), ones (100,1), 1)'; | |
2129 %! s = struct ([keys; vals]{:}); | |
2130 %! t = cell2struct (vals, keys, 2); | |
2131 %! assert (s, t); | |
2132 %! assert (struct2cell (s), vals'); | |
2133 %! assert (fieldnames (s), keys'); | |
2134 | |
2135 %!assert (cell2struct ({1; 2}, {"a"; "b"}), struct ("a", 1, "b", 2)); | |
2136 | |
2137 %!assert (cell2struct ({}, {"f"}, 3), struct ("f", {})); | |
2138 */ | |
2139 | |
2140 | |
2141 // So we can call Fcellstr directly. | |
2142 extern octave_value_list Fcellstr (const octave_value_list& args, int); | |
2143 | |
2144 DEFUN (rmfield, args, , | |
2145 "-*- texinfo -*-\n\ | |
2146 @deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\ | |
2147 Return a copy of the structure (array) @var{s} with the field @var{f}\n\ | |
2148 removed. If @var{f} is a cell array of strings or a character array, remove\n\ | |
2149 the named fields.\n\ | |
2150 @seealso{cellstr, iscellstr, setfield}\n\ | |
2151 @end deftypefn") | |
2152 { | |
2153 octave_value retval; | |
2154 | |
2155 int nargin = args.length (); | |
2156 | |
2157 if (nargin == 2) | |
2158 { | |
2159 octave_map m = args(0).map_value (); | |
2160 | |
2161 octave_value_list fval = Fcellstr (args(1), 1); | |
2162 | |
2163 if (! error_state) | |
2164 { | |
2165 Cell fcell = fval(0).cell_value (); | |
2166 | |
2167 for (int i = 0; i < fcell.numel (); i++) | |
2168 { | |
2169 std::string key = fcell(i).string_value (); | |
2170 | |
2171 if (m.isfield (key)) | |
2172 m.rmfield (key); | |
2173 else | |
2174 { | |
2175 error ("rmfield: structure does not contain field %s", | |
2176 key.c_str ()); | |
2177 | |
2178 break; | |
2179 } | |
2180 } | |
2181 | |
2182 if (! error_state) | |
2183 retval = m; | |
2184 } | |
2185 } | |
2186 else | |
2187 print_usage (); | |
2188 | |
2189 return retval; | |
2190 } | |
2191 | |
2192 /* | |
2193 ## test rmfield | |
2194 %!test | |
2195 %! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; x(6).f="abc123"; | |
2196 %! y = rmfield (x, {"a", "f"}); | |
2197 %! assert (fieldnames (y), {"d"; "b"; "c"}); | |
2198 %! assert (size (y), [1, 6]); | |
2199 */ | |
2200 | |
2201 DEFUN (struct_levels_to_print, args, nargout, | |
2202 "-*- texinfo -*-\n\ | |
2203 @deftypefn {Built-in Function} {@var{val} =} struct_levels_to_print ()\n\ | |
2204 @deftypefnx {Built-in Function} {@var{old_val} =} struct_levels_to_print (@var{new_val})\n\ | |
2205 @deftypefnx {Built-in Function} {} struct_levels_to_print (@var{new_val}, \"local\")\n\ | |
2206 Query or set the internal variable that specifies the number of\n\ | |
2207 structure levels to display.\n\ | |
2208 \n\ | |
2209 When called from inside a function with the \"local\" option, the variable is\n\ | |
2210 changed locally for the function and any subroutines it calls. The original\n\ | |
2211 variable value is restored when exiting the function.\n\ | |
2212 @end deftypefn") | |
2213 { | |
2214 return SET_INTERNAL_VARIABLE_WITH_LIMITS (struct_levels_to_print, | |
2215 -1, INT_MAX); | |
2216 } | |
2217 | |
2218 DEFUN (print_struct_array_contents, args, nargout, | |
2219 "-*- texinfo -*-\n\ | |
2220 @deftypefn {Built-in Function} {@var{val} =} print_struct_array_contents ()\n\ | |
2221 @deftypefnx {Built-in Function} {@var{old_val} =} print_struct_array_contents (@var{new_val})\n\ | |
2222 @deftypefnx {Built-in Function} {} print_struct_array_contents (@var{new_val}, \"local\")\n\ | |
2223 Query or set the internal variable that specifies whether to print struct\n\ | |
2224 array contents. If true, values of struct array elements are printed.\n\ | |
2225 This variable does not affect scalar structures. Their elements\n\ | |
2226 are always printed. In both cases, however, printing will be limited to\n\ | |
2227 the number of levels specified by @var{struct_levels_to_print}.\n\ | |
2228 \n\ | |
2229 When called from inside a function with the \"local\" option, the variable is\n\ | |
2230 changed locally for the function and any subroutines it calls. The original\n\ | |
2231 variable value is restored when exiting the function.\n\ | |
2232 @end deftypefn") | |
2233 { | |
2234 return SET_INTERNAL_VARIABLE (print_struct_array_contents); | |
2235 } |