comparison src/octave-value/ov-cell.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-cell.cc@f7afecdd87ef
children 62a35ae7d6a2
comparison
equal deleted inserted replaced
15056:bc32288f4a42 15057:46b19589b593
1 /*
2
3 Copyright (C) 1999-2012 John W. Eaton
4 Copyright (C) 2009-2010 VZLU Prague
5
6 This file is part of Octave.
7
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <iomanip>
29 #include <iostream>
30 #include <sstream>
31 #include <vector>
32 #include <queue>
33
34 #include "Array-util.h"
35 #include "byte-swap.h"
36 #include "lo-utils.h"
37 #include "quit.h"
38 #include "oct-locbuf.h"
39
40 #include "defun.h"
41 #include "error.h"
42 #include "ov-cell.h"
43 #include "oct-obj.h"
44 #include "unwind-prot.h"
45 #include "utils.h"
46 #include "ov-base-mat.h"
47 #include "ov-base-mat.cc"
48 #include "ov-re-mat.h"
49 #include "ov-scalar.h"
50 #include "pr-output.h"
51 #include "ov-scalar.h"
52 #include "gripes.h"
53
54 #include "ls-oct-ascii.h"
55 #include "ls-oct-binary.h"
56 #include "ls-hdf5.h"
57 #include "ls-utils.h"
58
59 // Cell is able to handle octave_value indexing by itself, so just forward
60 // everything.
61
62 template <>
63 octave_value
64 octave_base_matrix<Cell>::do_index_op (const octave_value_list& idx,
65 bool resize_ok)
66 {
67 return matrix.index (idx, resize_ok);
68 }
69
70 template <>
71 void
72 octave_base_matrix<Cell>::assign (const octave_value_list& idx, const Cell& rhs)
73 {
74 matrix.assign (idx, rhs);
75 }
76
77 template <>
78 void
79 octave_base_matrix<Cell>::assign (const octave_value_list& idx, octave_value rhs)
80 {
81 // FIXME: Really?
82 if (rhs.is_cell ())
83 matrix.assign (idx, rhs.cell_value ());
84 else
85 matrix.assign (idx, Cell (rhs));
86 }
87
88 template <>
89 void
90 octave_base_matrix<Cell>::delete_elements (const octave_value_list& idx)
91 {
92 matrix.delete_elements (idx);
93 }
94
95 // FIXME: this list of specializations is becoming so long that we should really ask
96 // whether octave_cell should inherit from octave_base_matrix at all.
97
98 template <>
99 octave_value
100 octave_base_matrix<Cell>::fast_elem_extract (octave_idx_type n) const
101 {
102 if (n < matrix.numel ())
103 return Cell (matrix(n));
104 else
105 return octave_value ();
106 }
107
108 template <>
109 bool
110 octave_base_matrix<Cell>::fast_elem_insert (octave_idx_type n,
111 const octave_value& x)
112 {
113 const octave_cell *xrep =
114 dynamic_cast<const octave_cell *> (&x.get_rep ());
115
116 bool retval = xrep && xrep->matrix.numel () == 1 && n < matrix.numel ();
117 if (retval)
118 matrix(n) = xrep->matrix(0);
119
120 return retval;
121 }
122
123 template class octave_base_matrix<Cell>;
124
125 DEFINE_OCTAVE_ALLOCATOR (octave_cell);
126
127 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_cell, "cell", "cell");
128
129 static void
130 gripe_failed_assignment (void)
131 {
132 error ("assignment to cell array failed");
133 }
134
135 octave_value_list
136 octave_cell::subsref (const std::string& type,
137 const std::list<octave_value_list>& idx,
138 int nargout)
139 {
140 octave_value_list retval;
141
142 switch (type[0])
143 {
144 case '(':
145 retval(0) = do_index_op (idx.front ());
146 break;
147
148 case '{':
149 {
150 octave_value tmp = do_index_op (idx.front ());
151
152 if (! error_state)
153 {
154 Cell tcell = tmp.cell_value ();
155
156 if (tcell.length () == 1)
157 retval(0) = tcell(0,0);
158 else
159 retval = octave_value (octave_value_list (tcell), true);
160 }
161 }
162 break;
163
164 case '.':
165 {
166 std::string nm = type_name ();
167 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
168 }
169 break;
170
171 default:
172 panic_impossible ();
173 }
174
175 // FIXME -- perhaps there should be an
176 // octave_value_list::next_subsref member function? See also
177 // octave_user_function::subsref.
178
179 if (idx.size () > 1)
180 retval = retval(0).next_subsref (nargout, type, idx);
181
182 return retval;
183 }
184
185 octave_value
186 octave_cell::subsref (const std::string& type,
187 const std::list<octave_value_list>& idx,
188 bool auto_add)
189 {
190 octave_value retval;
191
192 switch (type[0])
193 {
194 case '(':
195 retval = do_index_op (idx.front (), auto_add);
196 break;
197
198 case '{':
199 {
200 octave_value tmp = do_index_op (idx.front (), auto_add);
201
202 if (! error_state)
203 {
204 const Cell tcell = tmp.cell_value ();
205
206 if (tcell.length () == 1)
207 retval = tcell(0,0);
208 else
209 retval = octave_value (octave_value_list (tcell), true);
210 }
211 }
212 break;
213
214 case '.':
215 {
216 std::string nm = type_name ();
217 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
218 }
219 break;
220
221 default:
222 panic_impossible ();
223 }
224
225 // FIXME -- perhaps there should be an
226 // octave_value_list::next_subsref member function? See also
227 // octave_user_function::subsref.
228
229 if (idx.size () > 1)
230 retval = retval.next_subsref (auto_add, type, idx);
231
232 return retval;
233 }
234
235 octave_value
236 octave_cell::subsasgn (const std::string& type,
237 const std::list<octave_value_list>& idx,
238 const octave_value& rhs)
239 {
240 octave_value retval;
241
242 int n = type.length ();
243
244 octave_value t_rhs = rhs;
245
246 clear_cellstr_cache ();
247
248 if (idx.front ().empty ())
249 {
250 error ("missing index in indexed assignment");
251 return retval;
252 }
253
254 if (n > 1)
255 {
256 switch (type[0])
257 {
258 case '(':
259 {
260 if (is_empty () && type[1] == '.')
261 {
262 // Allow conversion of empty cell array to some other
263 // type in cases like
264 //
265 // x = {}; x(i).f = rhs
266
267 octave_value tmp = octave_value::empty_conv (type, rhs);
268
269 return tmp.subsasgn (type, idx, rhs);
270 }
271 else
272 {
273 octave_value tmp = do_index_op (idx.front (), true);
274
275 if (! tmp.is_defined ())
276 tmp = octave_value::empty_conv (type.substr (1), rhs);
277
278 if (! error_state)
279 {
280 std::list<octave_value_list> next_idx (idx);
281
282 next_idx.erase (next_idx.begin ());
283
284 tmp.make_unique ();
285
286 t_rhs = tmp.subsasgn (type.substr (1), next_idx, rhs);
287 }
288 }
289 }
290 break;
291
292 case '{':
293 {
294 matrix.make_unique ();
295 Cell tmpc = matrix.index (idx.front (), true);
296
297 if (! error_state)
298 {
299 std::list<octave_value_list> next_idx (idx);
300
301 next_idx.erase (next_idx.begin ());
302
303 std::string next_type = type.substr (1);
304
305 if (tmpc.numel () == 1)
306 {
307 octave_value tmp = tmpc(0);
308 tmpc = Cell ();
309
310 if (! tmp.is_defined () || tmp.is_zero_by_zero ())
311 {
312 tmp = octave_value::empty_conv (type.substr (1), rhs);
313 tmp.make_unique (); // probably a no-op.
314 }
315 else
316 // optimization: ignore the copy still stored inside our array.
317 tmp.make_unique (1);
318
319 if (! error_state)
320 t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
321 }
322 else
323 gripe_indexed_cs_list ();
324 }
325 }
326 break;
327
328 case '.':
329 {
330 if (is_empty ())
331 {
332 // Do nothing; the next branch will handle it.
333 }
334 else
335 {
336 std::string nm = type_name ();
337 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
338 }
339 }
340 break;
341
342 default:
343 panic_impossible ();
344 }
345 }
346
347 if (! error_state)
348 {
349 switch (type[0])
350 {
351 case '(':
352 {
353 octave_value_list i = idx.front ();
354
355 if (t_rhs.is_cell ())
356 octave_base_matrix<Cell>::assign (i, t_rhs.cell_value ());
357 else
358 if (t_rhs.is_null_value ())
359 octave_base_matrix<Cell>::delete_elements (i);
360 else
361 octave_base_matrix<Cell>::assign (i, Cell (t_rhs));
362
363 if (! error_state)
364 {
365 count++;
366 retval = octave_value (this);
367 }
368 else
369 gripe_failed_assignment ();
370 }
371 break;
372
373 case '{':
374 {
375 octave_value_list idxf = idx.front ();
376
377 if (t_rhs.is_cs_list ())
378 {
379 Cell tmp_cell = Cell (t_rhs.list_value ());
380
381 // Inquire the proper shape of the RHS.
382
383 dim_vector didx = dims ().redim (idxf.length ());
384 for (octave_idx_type k = 0; k < idxf.length (); k++)
385 if (! idxf(k).is_magic_colon ()) didx(k) = idxf(k).numel ();
386
387 if (didx.numel () == tmp_cell.numel ())
388 tmp_cell = tmp_cell.reshape (didx);
389
390
391 octave_base_matrix<Cell>::assign (idxf, tmp_cell);
392 }
393 else if (idxf.all_scalars () || do_index_op (idxf, true).numel () == 1)
394 // Regularize a null matrix if stored into a cell.
395 octave_base_matrix<Cell>::assign (idxf, Cell (t_rhs.storable_value ()));
396 else if (! error_state)
397 gripe_nonbraced_cs_list_assignment ();
398
399 if (! error_state)
400 {
401 count++;
402 retval = octave_value (this);
403 }
404 else
405 gripe_failed_assignment ();
406 }
407 break;
408
409 case '.':
410 {
411 if (is_empty ())
412 {
413 // Allow conversion of empty cell array to some other
414 // type in cases like
415 //
416 // x = {}; x.f = rhs
417
418 octave_value tmp = octave_value::empty_conv (type, rhs);
419
420 return tmp.subsasgn (type, idx, rhs);
421 }
422 else
423 {
424 std::string nm = type_name ();
425 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
426 }
427 }
428 break;
429
430 default:
431 panic_impossible ();
432 }
433 }
434
435 return retval;
436 }
437
438 bool
439 octave_cell::is_cellstr (void) const
440 {
441 bool retval;
442 if (cellstr_cache.get ())
443 retval = true;
444 else
445 {
446 retval = matrix.is_cellstr ();
447 // Allocate empty cache to mark that this is indeed a cellstr.
448 if (retval)
449 cellstr_cache.reset (new Array<std::string> ());
450 }
451
452 return retval;
453 }
454
455 void
456 octave_cell::assign (const octave_value_list& idx, const Cell& rhs)
457 {
458 clear_cellstr_cache ();
459 octave_base_matrix<Cell>::assign (idx, rhs);
460 }
461
462 void
463 octave_cell::assign (const octave_value_list& idx, const octave_value& rhs)
464 {
465 clear_cellstr_cache ();
466 octave_base_matrix<Cell>::assign (idx, rhs);
467 }
468
469
470 void
471 octave_cell::delete_elements (const octave_value_list& idx)
472 {
473 clear_cellstr_cache ();
474 octave_base_matrix<Cell>::delete_elements (idx);
475 }
476
477 size_t
478 octave_cell::byte_size (void) const
479 {
480 size_t retval = 0;
481
482 for (octave_idx_type i = 0; i < numel (); i++)
483 retval += matrix(i).byte_size ();
484
485 return retval;
486 }
487
488 octave_value
489 octave_cell::sort (octave_idx_type dim, sortmode mode) const
490 {
491 octave_value retval;
492
493 if (is_cellstr ())
494 {
495 Array<std::string> tmp = cellstr_value ();
496
497 tmp = tmp.sort (dim, mode);
498
499 // We already have the cache.
500 retval = new octave_cell (tmp);
501 }
502 else
503 error ("sort: only cell arrays of character strings may be sorted");
504
505 return retval;
506 }
507
508 octave_value
509 octave_cell::sort (Array<octave_idx_type> &sidx, octave_idx_type dim,
510 sortmode mode) const
511 {
512 octave_value retval;
513
514 if (is_cellstr ())
515 {
516 Array<std::string> tmp = cellstr_value ();
517
518 tmp = tmp.sort (sidx, dim, mode);
519
520 // We already have the cache.
521 retval = new octave_cell (tmp);
522 }
523 else
524 error ("sort: only cell arrays of character strings may be sorted");
525
526 return retval;
527 }
528
529 sortmode
530 octave_cell::is_sorted (sortmode mode) const
531 {
532 sortmode retval = UNSORTED;
533
534 if (is_cellstr ())
535 {
536 Array<std::string> tmp = cellstr_value ();
537
538 retval = tmp.is_sorted (mode);
539 }
540 else
541 error ("issorted: A is not a cell array of strings");
542
543 return retval;
544 }
545
546
547 Array<octave_idx_type>
548 octave_cell::sort_rows_idx (sortmode mode) const
549 {
550 Array<octave_idx_type> retval;
551
552 if (is_cellstr ())
553 {
554 Array<std::string> tmp = cellstr_value ();
555
556 retval = tmp.sort_rows_idx (mode);
557 }
558 else
559 error ("sortrows: only cell arrays of character strings may be sorted");
560
561 return retval;
562 }
563
564 sortmode
565 octave_cell::is_sorted_rows (sortmode mode) const
566 {
567 sortmode retval = UNSORTED;
568
569 if (is_cellstr ())
570 {
571 Array<std::string> tmp = cellstr_value ();
572
573 retval = tmp.is_sorted_rows (mode);
574 }
575 else
576 error ("issorted: A is not a cell array of strings");
577
578 return retval;
579 }
580
581 bool
582 octave_cell::is_true (void) const
583 {
584 error ("invalid conversion from cell array to logical value");
585 return false;
586 }
587
588 octave_value_list
589 octave_cell::list_value (void) const
590 {
591 return octave_value_list (matrix);
592 }
593
594 string_vector
595 octave_cell::all_strings (bool pad) const
596 {
597 string_vector retval;
598
599 octave_idx_type nel = numel ();
600
601 int n_elts = 0;
602
603 octave_idx_type max_len = 0;
604
605 std::queue<string_vector> strvec_queue;
606
607 for (octave_idx_type i = 0; i < nel; i++)
608 {
609 string_vector s = matrix(i).all_strings ();
610
611 if (error_state)
612 return retval;
613
614 octave_idx_type s_len = s.length ();
615
616 n_elts += s_len ? s_len : 1;
617
618 octave_idx_type s_max_len = s.max_length ();
619
620 if (s_max_len > max_len)
621 max_len = s_max_len;
622
623 strvec_queue.push (s);
624 }
625
626 retval = string_vector (n_elts);
627
628 octave_idx_type k = 0;
629
630 for (octave_idx_type i = 0; i < nel; i++)
631 {
632 const string_vector s = strvec_queue.front ();
633 strvec_queue.pop ();
634
635 octave_idx_type s_len = s.length ();
636
637 if (s_len)
638 {
639 for (octave_idx_type j = 0; j < s_len; j++)
640 {
641 std::string t = s[j];
642 int t_len = t.length ();
643
644 if (pad && max_len > t_len)
645 t += std::string (max_len - t_len, ' ');
646
647 retval[k++] = t;
648 }
649 }
650 else if (pad)
651 retval[k++] = std::string (max_len, ' ');
652 else
653 retval[k++] = std::string ();
654 }
655
656 return retval;
657 }
658
659 Array<std::string>
660 octave_cell::cellstr_value (void) const
661 {
662 Array<std::string> retval;
663
664 if (is_cellstr ())
665 {
666 if (cellstr_cache->is_empty ())
667 *cellstr_cache = matrix.cellstr_value ();
668
669 return *cellstr_cache;
670 }
671 else
672 error ("invalid conversion from cell array to array of strings");
673
674 return retval;
675 }
676
677 bool
678 octave_cell::print_as_scalar (void) const
679 {
680 return true;
681 }
682
683 void
684 octave_cell::print (std::ostream& os, bool) const
685 {
686 print_raw (os);
687 }
688
689 void
690 octave_cell::print_raw (std::ostream& os, bool) const
691 {
692 int nd = matrix.ndims ();
693
694 if (nd == 2)
695 {
696 octave_idx_type nr = rows ();
697 octave_idx_type nc = columns ();
698
699 if (nr > 0 && nc > 0)
700 {
701 newline (os);
702 indent (os);
703 os << "{";
704 newline (os);
705
706 increment_indent_level ();
707
708 for (octave_idx_type j = 0; j < nc; j++)
709 {
710 for (octave_idx_type i = 0; i < nr; i++)
711 {
712 octave_quit ();
713
714 std::ostringstream buf;
715 buf << "[" << i+1 << "," << j+1 << "]";
716
717 octave_value val = matrix(i,j);
718
719 val.print_with_name (os, buf.str ());
720 }
721 }
722
723 decrement_indent_level ();
724
725 indent (os);
726 os << "}";
727 newline (os);
728 }
729 else
730 {
731 indent (os);
732 os << "{}";
733 if (Vprint_empty_dimensions)
734 os << "(" << nr << "x" << nc << ")";
735 newline (os);
736 }
737 }
738 else
739 {
740 indent (os);
741 dim_vector dv = matrix.dims ();
742 os << "{" << dv.str () << " Cell Array}";
743 newline (os);
744 }
745 }
746
747 #define CELL_ELT_TAG "<cell-element>"
748
749 bool
750 octave_cell::save_ascii (std::ostream& os)
751 {
752 dim_vector d = dims ();
753 if (d.length () > 2)
754 {
755 os << "# ndims: " << d.length () << "\n";
756
757 for (int i = 0; i < d.length (); i++)
758 os << " " << d (i);
759 os << "\n";
760
761 Cell tmp = cell_value ();
762
763 for (octave_idx_type i = 0; i < d.numel (); i++)
764 {
765 octave_value o_val = tmp.elem (i);
766
767 // Recurse to print sub-value.
768 bool b = save_ascii_data (os, o_val, CELL_ELT_TAG, false, 0);
769
770 if (! b)
771 return os;
772 }
773 }
774 else
775 {
776 // Keep this case, rather than use generic code above for backward
777 // compatiability. Makes load_ascii much more complex!!
778 os << "# rows: " << rows () << "\n"
779 << "# columns: " << columns () << "\n";
780
781 Cell tmp = cell_value ();
782
783 for (octave_idx_type j = 0; j < tmp.cols (); j++)
784 {
785 for (octave_idx_type i = 0; i < tmp.rows (); i++)
786 {
787 octave_value o_val = tmp.elem (i, j);
788
789 // Recurse to print sub-value.
790 bool b = save_ascii_data (os, o_val, CELL_ELT_TAG, false, 0);
791
792 if (! b)
793 return os;
794 }
795
796 os << "\n";
797 }
798 }
799
800 return true;
801 }
802
803 bool
804 octave_cell::load_ascii (std::istream& is)
805 {
806 bool success = true;
807
808 clear_cellstr_cache ();
809
810 string_vector keywords(2);
811
812 keywords[0] = "ndims";
813 keywords[1] = "rows";
814
815 std::string kw;
816 octave_idx_type val = 0;
817
818 if (extract_keyword (is, keywords, kw, val, true))
819 {
820 if (kw == "ndims")
821 {
822 int mdims = static_cast<int> (val);
823
824 if (mdims >= 0)
825 {
826 dim_vector dv;
827 dv.resize (mdims);
828
829 for (int i = 0; i < mdims; i++)
830 is >> dv(i);
831
832 Cell tmp(dv);
833
834 for (octave_idx_type i = 0; i < dv.numel (); i++)
835 {
836 octave_value t2;
837 bool dummy;
838
839 // recurse to read cell elements
840 std::string nm = read_ascii_data (is, std::string (),
841 dummy, t2, i);
842
843 if (nm == CELL_ELT_TAG)
844 {
845 if (is)
846 tmp.elem (i) = t2;
847 }
848 else
849 {
850 error ("load: cell array element had unexpected name");
851 success = false;
852 break;
853 }
854 }
855
856 if (is)
857 matrix = tmp;
858 else
859 {
860 error ("load: failed to load matrix constant");
861 success = false;
862 }
863 }
864 else
865 {
866 error ("load: failed to extract number of rows and columns");
867 success = false;
868 }
869 }
870 else if (kw == "rows")
871 {
872 octave_idx_type nr = val;
873 octave_idx_type nc = 0;
874
875 if (nr >= 0 && extract_keyword (is, "columns", nc) && nc >= 0)
876 {
877 if (nr > 0 && nc > 0)
878 {
879 Cell tmp (nr, nc);
880
881 for (octave_idx_type j = 0; j < nc; j++)
882 {
883 for (octave_idx_type i = 0; i < nr; i++)
884 {
885 octave_value t2;
886 bool dummy;
887
888 // recurse to read cell elements
889 std::string nm = read_ascii_data (is, std::string (),
890 dummy, t2, i);
891
892 if (nm == CELL_ELT_TAG)
893 {
894 if (is)
895 tmp.elem (i, j) = t2;
896 }
897 else
898 {
899 error ("load: cell array element had unexpected name");
900 success = false;
901 goto cell_read_error;
902 }
903 }
904 }
905
906 cell_read_error:
907
908 if (is)
909 matrix = tmp;
910 else
911 {
912 error ("load: failed to load cell element");
913 success = false;
914 }
915 }
916 else if (nr == 0 || nc == 0)
917 matrix = Cell (nr, nc);
918 else
919 panic_impossible ();
920 }
921 else
922 {
923 error ("load: failed to extract number of rows and columns for cell array");
924 success = false;
925 }
926 }
927 else
928 panic_impossible ();
929 }
930 else
931 {
932 error ("load: failed to extract number of rows and columns");
933 success = false;
934 }
935
936 return success;
937 }
938
939 bool
940 octave_cell::save_binary (std::ostream& os, bool& save_as_floats)
941 {
942 dim_vector d = dims ();
943 if (d.length () < 1)
944 return false;
945
946 // Use negative value for ndims
947 int32_t di = - d.length ();
948 os.write (reinterpret_cast<char *> (&di), 4);
949 for (int i = 0; i < d.length (); i++)
950 {
951 di = d(i);
952 os.write (reinterpret_cast<char *> (&di), 4);
953 }
954
955 Cell tmp = cell_value ();
956
957 for (octave_idx_type i = 0; i < d.numel (); i++)
958 {
959 octave_value o_val = tmp.elem (i);
960
961 // Recurse to print sub-value.
962 bool b = save_binary_data (os, o_val, CELL_ELT_TAG, "", 0,
963 save_as_floats);
964
965 if (! b)
966 return false;
967 }
968
969 return true;
970 }
971
972 bool
973 octave_cell::load_binary (std::istream& is, bool swap,
974 oct_mach_info::float_format fmt)
975 {
976 clear_cellstr_cache ();
977
978 bool success = true;
979 int32_t mdims;
980 if (! is.read (reinterpret_cast<char *> (&mdims), 4))
981 return false;
982 if (swap)
983 swap_bytes<4> (&mdims);
984 if (mdims >= 0)
985 return false;
986
987 mdims = -mdims;
988 int32_t di;
989 dim_vector dv;
990 dv.resize (mdims);
991
992 for (int i = 0; i < mdims; i++)
993 {
994 if (! is.read (reinterpret_cast<char *> (&di), 4))
995 return false;
996 if (swap)
997 swap_bytes<4> (&di);
998 dv(i) = di;
999 }
1000
1001 // Convert an array with a single dimension to be a row vector.
1002 // Octave should never write files like this, other software
1003 // might.
1004
1005 if (mdims == 1)
1006 {
1007 mdims = 2;
1008 dv.resize (mdims);
1009 dv(1) = dv(0);
1010 dv(0) = 1;
1011 }
1012
1013 octave_idx_type nel = dv.numel ();
1014 Cell tmp(dv);
1015
1016 for (octave_idx_type i = 0; i < nel; i++)
1017 {
1018 octave_value t2;
1019 bool dummy;
1020 std::string doc;
1021
1022 // recurse to read cell elements
1023 std::string nm = read_binary_data (is, swap, fmt, std::string (),
1024 dummy, t2, doc);
1025
1026 if (nm == CELL_ELT_TAG)
1027 {
1028 if (is)
1029 tmp.elem (i) = t2;
1030 }
1031 else
1032 {
1033 error ("load: cell array element had unexpected name");
1034 success = false;
1035 break;
1036 }
1037 }
1038
1039 if (is)
1040 matrix = tmp;
1041 else
1042 {
1043 error ("load: failed to load matrix constant");
1044 success = false;
1045 }
1046
1047 return success;
1048 }
1049
1050 void *
1051 octave_cell::mex_get_data (void) const
1052 {
1053 clear_cellstr_cache ();
1054 return matrix.mex_get_data ();
1055 }
1056
1057 #if defined (HAVE_HDF5)
1058
1059 bool
1060 octave_cell::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
1061 {
1062 dim_vector dv = dims ();
1063 int empty = save_hdf5_empty (loc_id, name, dv);
1064 if (empty)
1065 return (empty > 0);
1066
1067 hsize_t rank = dv.length ();
1068 hid_t space_hid = -1, data_hid = -1, size_hid = -1;
1069
1070 #if HAVE_HDF5_18
1071 data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1072 #else
1073 data_hid = H5Gcreate (loc_id, name, 0);
1074 #endif
1075
1076 if (data_hid < 0)
1077 return false;
1078
1079 // Have to save cell array shape, since can't have a
1080 // dataset of groups....
1081
1082 space_hid = H5Screate_simple (1, &rank, 0);
1083
1084 if (space_hid < 0)
1085 {
1086 H5Gclose (data_hid);
1087 return false;
1088 }
1089
1090 OCTAVE_LOCAL_BUFFER (octave_idx_type, hdims, rank);
1091
1092 // Octave uses column-major, while HDF5 uses row-major ordering
1093 for (hsize_t i = 0; i < rank; i++)
1094 hdims[i] = dv(rank-i-1);
1095
1096 #if HAVE_HDF5_18
1097 size_hid = H5Dcreate (data_hid, "dims", H5T_NATIVE_IDX, space_hid,
1098 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1099 #else
1100 size_hid = H5Dcreate (data_hid, "dims", H5T_NATIVE_IDX, space_hid,
1101 H5P_DEFAULT);
1102 #endif
1103 if (size_hid < 0)
1104 {
1105 H5Sclose (space_hid);
1106 H5Gclose (data_hid);
1107 return false;
1108 }
1109
1110 if (H5Dwrite (size_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL,
1111 H5P_DEFAULT, hdims) < 0)
1112 {
1113 H5Dclose (size_hid);
1114 H5Sclose (space_hid);
1115 H5Gclose (data_hid);
1116 return false;
1117 }
1118
1119 H5Dclose (size_hid);
1120 H5Sclose (space_hid);
1121
1122 // Recursively add each element of the cell to this group.
1123
1124 Cell tmp = cell_value ();
1125
1126 octave_idx_type nel = dv.numel ();
1127
1128 for (octave_idx_type i = 0; i < nel; i++)
1129 {
1130 std::ostringstream buf;
1131 int digits = static_cast<int> (gnulib::floor (::log10 (static_cast<double> (nel)) + 1.0));
1132 buf << "_" << std::setw (digits) << std::setfill ('0') << i;
1133 std::string s = buf.str ();
1134
1135 if (! add_hdf5_data (data_hid, tmp.elem (i), s.c_str (), "", false,
1136 save_as_floats))
1137 {
1138 H5Gclose (data_hid);
1139 return false;
1140 }
1141 }
1142
1143 H5Gclose (data_hid);
1144
1145 return true;
1146 }
1147
1148 bool
1149 octave_cell::load_hdf5 (hid_t loc_id, const char *name)
1150 {
1151 clear_cellstr_cache ();
1152
1153 bool retval = false;
1154
1155 dim_vector dv;
1156 int empty = load_hdf5_empty (loc_id, name, dv);
1157 if (empty > 0)
1158 matrix.resize (dv);
1159 if (empty)
1160 return (empty > 0);
1161
1162 #if HAVE_HDF5_18
1163 hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
1164 #else
1165 hid_t group_id = H5Gopen (loc_id, name);
1166 #endif
1167
1168 if (group_id < 0)
1169 return false;
1170
1171 #if HAVE_HDF5_18
1172 hid_t data_hid = H5Dopen (group_id, "dims", H5P_DEFAULT);
1173 #else
1174 hid_t data_hid = H5Dopen (group_id, "dims");
1175 #endif
1176 hid_t space_hid = H5Dget_space (data_hid);
1177 hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
1178 if (rank != 1)
1179 {
1180 H5Dclose (data_hid);
1181 H5Gclose (group_id);
1182 return false;
1183 }
1184
1185 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
1186 OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
1187
1188 H5Sget_simple_extent_dims (space_hid, hdims, maxdims);
1189
1190 // Octave uses column-major, while HDF5 uses row-major ordering.
1191
1192 dv.resize (hdims[0]);
1193
1194 OCTAVE_LOCAL_BUFFER (octave_idx_type, tmp, hdims[0]);
1195
1196 if (H5Dread (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL,
1197 H5P_DEFAULT, tmp) < 0)
1198 {
1199 H5Dclose (data_hid);
1200 H5Gclose (group_id);
1201 return false;
1202 }
1203
1204 H5Dclose (data_hid);
1205 H5Gclose (group_id);
1206
1207 for (hsize_t i = 0, j = hdims[0] - 1; i < hdims[0]; i++, j--)
1208 dv(j) = tmp[i];
1209
1210 hdf5_callback_data dsub;
1211
1212 herr_t retval2 = -1;
1213
1214 Cell m (dv);
1215
1216 int current_item = 0;
1217
1218 hsize_t num_obj = 0;
1219 #if HAVE_HDF5_18
1220 group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
1221 #else
1222 group_id = H5Gopen (loc_id, name);
1223 #endif
1224 H5Gget_num_objs (group_id, &num_obj);
1225 H5Gclose (group_id);
1226
1227 for (octave_idx_type i = 0; i < dv.numel (); i++)
1228 {
1229
1230 if (current_item >= static_cast<int> (num_obj))
1231 retval2 = -1;
1232 else
1233 retval2 = H5Giterate (loc_id, name, &current_item,
1234 hdf5_read_next_data, &dsub);
1235
1236 if (retval2 <= 0)
1237 break;
1238
1239 octave_value ov = dsub.tc;
1240 m.elem (i) = ov;
1241
1242 }
1243
1244 if (retval2 >= 0)
1245 {
1246 matrix = m;
1247 retval = true;
1248 }
1249
1250 return retval;
1251 }
1252
1253 #endif
1254
1255 DEFUN (iscell, args, ,
1256 "-*- texinfo -*-\n\
1257 @deftypefn {Built-in Function} {} iscell (@var{x})\n\
1258 Return true if @var{x} is a cell array object.\n\
1259 @seealso{ismatrix, isstruct, iscellstr, isa}\n\
1260 @end deftypefn")
1261 {
1262 octave_value retval;
1263
1264 if (args.length () == 1)
1265 retval = args(0).is_cell ();
1266 else
1267 print_usage ();
1268
1269 return retval;
1270 }
1271
1272 DEFUN (cell, args, ,
1273 "-*- texinfo -*-\n\
1274 @deftypefn {Built-in Function} {} cell (@var{n})\n\
1275 @deftypefnx {Built-in Function} {} cell (@var{m}, @var{n})\n\
1276 @deftypefnx {Built-in Function} {} cell (@var{m}, @var{n}, @var{k}, @dots{})\n\
1277 @deftypefnx {Built-in Function} {} cell ([@var{m} @var{n} @dots{}])\n\
1278 Create a new cell array object.\n\
1279 If invoked with a single scalar integer argument, return a square\n\
1280 @nospell{NxN} cell array. If invoked with two or more scalar\n\
1281 integer arguments, or a vector of integer values, return an array with\n\
1282 the given dimensions.\n\
1283 @end deftypefn")
1284 {
1285 octave_value retval;
1286
1287 int nargin = args.length ();
1288
1289 dim_vector dims;
1290
1291 switch (nargin)
1292 {
1293 case 0:
1294 dims = dim_vector (0, 0);
1295 break;
1296
1297 case 1:
1298 get_dimensions (args(0), "cell", dims);
1299 break;
1300
1301 default:
1302 {
1303 dims.resize (nargin);
1304
1305 for (int i = 0; i < nargin; i++)
1306 {
1307 dims(i) = args(i).is_empty () ? 0 : args(i).nint_value ();
1308
1309 if (error_state)
1310 {
1311 error ("cell: expecting scalar arguments");
1312 break;
1313 }
1314 }
1315 }
1316 break;
1317 }
1318
1319 if (! error_state)
1320 {
1321 dims.chop_trailing_singletons ();
1322
1323 check_dimensions (dims, "cell");
1324
1325 if (! error_state)
1326 retval = Cell (dims, Matrix ());
1327 }
1328
1329 return retval;
1330 }
1331
1332 DEFUN (iscellstr, args, ,
1333 "-*- texinfo -*-\n\
1334 @deftypefn {Built-in Function} {} iscellstr (@var{cell})\n\
1335 Return true if every element of the cell array @var{cell} is a\n\
1336 character string.\n\
1337 @seealso{ischar}\n\
1338 @end deftypefn")
1339 {
1340 octave_value retval;
1341
1342 if (args.length () == 1)
1343 retval = args(0).is_cellstr ();
1344 else
1345 print_usage ();
1346
1347 return retval;
1348 }
1349
1350 // Note that since Fcellstr calls Fiscellstr, we need to have
1351 // Fiscellstr defined first (to provide a declaration) and also we
1352 // should keep it in the same file (so we don't have to provide a
1353 // declaration) and so we don't have to use feval to call it.
1354
1355 DEFUN (cellstr, args, ,
1356 "-*- texinfo -*-\n\
1357 @deftypefn {Built-in Function} {} cellstr (@var{string})\n\
1358 Create a new cell array object from the elements of the string\n\
1359 array @var{string}.\n\
1360 @end deftypefn")
1361 {
1362 octave_value retval;
1363
1364 if (args.length () == 1)
1365 {
1366 octave_value_list tmp = Fiscellstr (args, 1);
1367
1368 if (tmp(0).is_true ())
1369 retval = args(0);
1370 else
1371 {
1372 string_vector s = args(0).all_strings ();
1373
1374 if (! error_state)
1375 retval = (s.is_empty ()
1376 ? Cell (octave_value (std::string ()))
1377 : Cell (s, true));
1378 else
1379 error ("cellstr: argument STRING must be a 2-D character array");
1380 }
1381 }
1382 else
1383 print_usage ();
1384
1385 return retval;
1386 }
1387
1388 DEFUN (struct2cell, args, ,
1389 "-*- texinfo -*-\n\
1390 @deftypefn {Built-in Function} {} struct2cell (@var{S})\n\
1391 Create a new cell array from the objects stored in the struct object.\n\
1392 If @var{f} is the number of fields in the structure, the resulting\n\
1393 cell array will have a dimension vector corresponding to\n\
1394 @code{[@var{F} size(@var{S})]}. For example:\n\
1395 \n\
1396 @example\n\
1397 @group\n\
1398 s = struct (\"name\", @{\"Peter\", \"Hannah\", \"Robert\"@},\n\
1399 \"age\", @{23, 16, 3@});\n\
1400 c = struct2cell (s)\n\
1401 @result{} c = @{1x1x3 Cell Array@}\n\
1402 c(1,1,:)(:)\n\
1403 @result{}\n\
1404 @{\n\
1405 [1,1] = Peter\n\
1406 [2,1] = Hannah\n\
1407 [3,1] = Robert\n\
1408 @}\n\
1409 c(2,1,:)(:)\n\
1410 @result{}\n\
1411 @{\n\
1412 [1,1] = 23\n\
1413 [2,1] = 16\n\
1414 [3,1] = 3\n\
1415 @}\n\
1416 @end group\n\
1417 @end example\n\
1418 \n\
1419 @seealso{cell2struct, fieldnames}\n\
1420 @end deftypefn")
1421 {
1422 octave_value retval;
1423
1424 int nargin = args.length ();
1425
1426 if (nargin == 1)
1427 {
1428 const octave_map m = args(0).map_value ();
1429
1430 if (! error_state)
1431 {
1432 const dim_vector m_dv = m.dims ();
1433
1434 octave_idx_type num_fields = m.nfields ();
1435
1436 // The resulting dim_vector should have dimensions:
1437 // [numel(fields) size(struct)]
1438 // except if the struct is a column vector.
1439
1440 dim_vector result_dv;
1441 if (m_dv (m_dv.length () - 1) == 1)
1442 result_dv.resize (m_dv.length ());
1443 else
1444 result_dv.resize (m_dv.length () + 1); // Add 1 for the fields.
1445
1446 result_dv(0) = num_fields;
1447
1448 for (int i = 1; i < result_dv.length (); i++)
1449 result_dv(i) = m_dv(i-1);
1450
1451 NoAlias<Cell> c (result_dv);
1452
1453 octave_idx_type n_elts = m.numel ();
1454
1455 // Fill c in one sweep. Note that thanks to octave_map structure,
1456 // we don't need a key lookup at all.
1457 for (octave_idx_type j = 0; j < n_elts; j++)
1458 for (octave_idx_type i = 0; i < num_fields; i++)
1459 c(i,j) = m.contents(i)(j);
1460
1461 retval = c;
1462 }
1463 else
1464 error ("struct2cell: argument S must be a structure");
1465 }
1466 else
1467 print_usage ();
1468
1469 return retval;
1470 }
1471
1472 /*
1473 %!test
1474 %! keys = cellstr (char (floor (rand (11,10)*24+65)))';
1475 %! vals = cellfun (@(x) mat2cell (rand (19,1), ones (19,1), 1), ...
1476 %! mat2cell ([1:11]', ones (11,1), 1), "uniformoutput", false)';
1477 %! s = struct ([keys; vals]{:});
1478 %! t = cell2struct ([vals{:}], keys, 2);
1479 %! assert (s, t);
1480 %! assert (struct2cell (s), [vals{:}]');
1481 %! assert (fieldnames (s), keys');
1482 */
1483
1484 mxArray *
1485 octave_cell::as_mxArray (void) const
1486 {
1487 mxArray *retval = new mxArray (dims ());
1488
1489 mxArray **elts = static_cast<mxArray **> (retval->get_data ());
1490
1491 mwSize nel = numel ();
1492
1493 const octave_value *p = matrix.data ();
1494
1495 for (mwIndex i = 0; i < nel; i++)
1496 elts[i] = new mxArray (p[i]);
1497
1498 return retval;
1499 }
1500
1501 octave_value
1502 octave_cell::map (unary_mapper_t umap) const
1503 {
1504 switch (umap)
1505 {
1506 #define FORWARD_MAPPER(UMAP) \
1507 case umap_ ## UMAP: \
1508 return matrix.UMAP ()
1509 FORWARD_MAPPER (xisalnum);
1510 FORWARD_MAPPER (xisalpha);
1511 FORWARD_MAPPER (xisascii);
1512 FORWARD_MAPPER (xiscntrl);
1513 FORWARD_MAPPER (xisdigit);
1514 FORWARD_MAPPER (xisgraph);
1515 FORWARD_MAPPER (xislower);
1516 FORWARD_MAPPER (xisprint);
1517 FORWARD_MAPPER (xispunct);
1518 FORWARD_MAPPER (xisspace);
1519 FORWARD_MAPPER (xisupper);
1520 FORWARD_MAPPER (xisxdigit);
1521 FORWARD_MAPPER (xtoascii);
1522 FORWARD_MAPPER (xtolower);
1523 FORWARD_MAPPER (xtoupper);
1524
1525 default:
1526 return octave_base_value::map (umap);
1527 }
1528 }