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, &current_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, &current_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)) = &map;
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 }