changelog shortlog tags changeset files revisions annotate raw

src/ov-struct.cc

changeset 9846: 1d90fc211872
parent:8e5009334661
author: John W. Eaton <jwe@octave.org>
date: Sat Nov 21 21:44:51 2009 -0500 (33 hours ago)
permissions: -rw-r--r--
description: configure.ac: report freetype, fontconfig, and fltk cflags and libs info
1/*
2
3Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2006,
4 2007, 2008, 2009 John W. Eaton
5
6This file is part of Octave.
7
8Octave is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by the
10Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13Octave is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along 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 <iostream>
29
30#include "Cell.h"
31#include "defun.h"
32#include "error.h"
33#include "gripes.h"
34#include "oct-lvalue.h"
35#include "ov-list.h"
36#include "ov-struct.h"
37#include "unwind-prot.h"
38#include "utils.h"
39#include "variables.h"
40
41#include "Array-util.h"
42#include "oct-locbuf.h"
43
44#include "byte-swap.h"
45#include "ls-oct-ascii.h"
46#include "ls-oct-binary.h"
47#include "ls-hdf5.h"
48#include "ls-utils.h"
49#include "pr-output.h"
50
51DEFINE_OCTAVE_ALLOCATOR(octave_struct);
52
53DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct");
54
55Cell
56octave_struct::dotref (const octave_value_list& idx, bool auto_add)
57{
58 Cell retval;
59
60 assert (idx.length () == 1);
61
62 std::string nm = idx(0).string_value ();
63
64 Octave_map::const_iterator p = map.seek (nm);
65
66 if (p != map.end ())
67 retval = map.contents (p);
68 else if (auto_add)
69 retval = (numel () == 0) ? Cell (dim_vector (1)) : Cell (dims ());
70 else
71 error ("structure has no member `%s'", nm.c_str ());
72
73 return retval;
74}
75
76#if 0
77static void
78gripe_invalid_index (void)
79{
80 error ("invalid index for structure array");
81}
82#endif
83
84static void
85gripe_invalid_index_for_assignment (void)
86{
87 error ("invalid index for structure array assignment");
88}
89
90static void
91gripe_invalid_index_type (const std::string& nm, char t)
92{
93 error ("%s cannot be indexed with %c", nm.c_str (), t);
94}
95
96static void
97gripe_failed_assignment (void)
98{
99 error ("assignment to structure element failed");
100}
101
102octave_value_list
103octave_struct::subsref (const std::string& type,
104 const std::list<octave_value_list>& idx,
105 int nargout)
106{
107 octave_value_list retval;
108
109 int skip = 1;
110
111 switch (type[0])
112 {
113 case '(':
114 {
115 if (type.length () > 1 && type[1] == '.')
116 {
117 std::list<octave_value_list>::const_iterator p = idx.begin ();
118 octave_value_list key_idx = *++p;
119
120 const Cell tmp = dotref (key_idx);
121
122 if (! error_state)
123 {
124 const Cell t = tmp.index (idx.front ());
125
126 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
127
128 // We handled two index elements, so tell
129 // next_subsref to skip both of them.
130
131 skip++;
132 }
133 }
134 else
135 retval(0) = map.index (idx.front ());
136 }
137 break;
138
139 case '.':
140 {
141 if (map.numel() > 0)
142 {
143 const Cell t = dotref (idx.front ());
144
145 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
146 }
147 }
148 break;
149
150 case '{':
151 gripe_invalid_index_type (type_name (), type[0]);
152 break;
153
154 default:
155 panic_impossible ();
156 }
157
158 // FIXME -- perhaps there should be an
159 // octave_value_list::next_subsref member function? See also
160 // octave_user_function::subsref.
161
162 if (idx.size () > 1)
163 retval = retval(0).next_subsref (nargout, type, idx, skip);
164
165 return retval;
166}
167
168octave_value
169octave_struct::subsref (const std::string& type,
170 const std::list<octave_value_list>& idx,
171 bool auto_add)
172{
173 octave_value retval;
174
175 int skip = 1;
176
177 switch (type[0])
178 {
179 case '(':
180 {
181 if (type.length () > 1 && type[1] == '.')
182 {
183 std::list<octave_value_list>::const_iterator p = idx.begin ();
184 octave_value_list key_idx = *++p;
185
186 const Cell tmp = dotref (key_idx, auto_add);
187
188 if (! error_state)
189 {
190 const Cell t = tmp.index (idx.front (), auto_add);
191
192 retval = (t.length () == 1) ? t(0) : octave_value (t, true);
193
194 // We handled two index elements, so tell
195 // next_subsref to skip both of them.
196
197 skip++;
198 }
199 }
200 else
201 retval = map.index (idx.front (), auto_add);
202 }
203 break;
204
205 case '.':
206 {
207 if (map.numel() > 0)
208 {
209 const Cell t = dotref (idx.front (), auto_add);
210
211 retval = (t.length () == 1) ? t(0) : octave_value (t, true);
212 }
213 }
214 break;
215
216 case '{':
217 gripe_invalid_index_type (type_name (), type[0]);
218 break;
219
220 default:
221 panic_impossible ();
222 }
223
224 // FIXME -- perhaps there should be an
225 // octave_value_list::next_subsref member function? See also
226 // octave_user_function::subsref.
227
228 if (idx.size () > 1)
229 retval = retval.next_subsref (auto_add, type, idx, skip);
230
231 return retval;
232}
233
234/*
235%!test
236%! x(1).a.a = 1; x(2).a.a = 2;
237%! assert (size (x), [1, 2]);
238%! assert (x(1).a.a, 1);
239%! assert (x(2).a.a, 2);
240*/
241
242octave_value
243octave_struct::numeric_conv (const octave_value& val,
244 const std::string& type)
245{
246 octave_value retval;
247
248 if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
249 retval = Octave_map ();
250 else
251 retval = val;
252
253 return retval;
254}
255
256octave_value
257octave_struct::subsasgn (const std::string& type,
258 const std::list<octave_value_list>& idx,
259 const octave_value& rhs)
260{
261 octave_value retval;
262
263 int n = type.length ();
264
265 octave_value t_rhs = rhs;
266
267 if (idx.front ().empty ())
268 {
269 error ("missing index in indexed assignment");
270 return retval;
271 }
272
273 if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
274 {
275 switch (type[0])
276 {
277 case '(':
278 {
279 if (type.length () > 1 && type[1] == '.')
280 {
281 std::list<octave_value_list>::const_iterator p = idx.begin ();
282 octave_value_list t_idx = *p;
283
284 octave_value_list key_idx = *++p;
285
286 assert (key_idx.length () == 1);
287
288 std::string key = key_idx(0).string_value ();
289
290 std::list<octave_value_list> next_idx (idx);
291
292 // We handled two index elements, so subsasgn to
293 // needs to skip both of them.
294
295 next_idx.erase (next_idx.begin ());
296 next_idx.erase (next_idx.begin ());
297
298 std::string next_type = type.substr (2);
299
300 Cell tmpc (1, 1);
301 Octave_map::iterator pkey = map.seek (key);
302 if (pkey != map.end ())
303 {
304 pkey->second.make_unique ();
305 tmpc = pkey->second.index (idx.front (), true);
306 }
307
308 // FIXME: better code reuse? cf. octave_cell::subsasgn and the case below.
309 if (! error_state)
310 {
311 if (tmpc.numel () == 1)
312 {
313 octave_value& tmp = tmpc(0);
314
315 if (! tmp.is_defined () || tmp.is_zero_by_zero ())
316 {
317 tmp = octave_value::empty_conv (next_type, rhs);
318 tmp.make_unique (); // probably a no-op.
319 }
320 else
321 // optimization: ignore the copy still stored inside our map.
322 tmp.make_unique (1);
323
324 if (! error_state)
325 t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
326 }
327 else
328 gripe_indexed_cs_list ();
329 }
330 }
331 else
332 gripe_invalid_index_for_assignment ();
333 }
334 break;
335
336 case '.':
337 {
338 octave_value_list key_idx = idx.front ();
339
340 assert (key_idx.length () == 1);
341
342 std::string key = key_idx(0).string_value ();
343
344 std::list<octave_value_list> next_idx (idx);
345
346 next_idx.erase (next_idx.begin ());
347
348 std::string next_type = type.substr (1);
349
350 Cell tmpc (1, 1);
351 Octave_map::iterator pkey = map.seek (key);
352 if (pkey != map.end ())
353 {
354 pkey->second.make_unique ();
355 tmpc = pkey->second;
356 }
357
358 // FIXME: better code reuse?
359 if (! error_state)
360 {
361 if (tmpc.numel () == 1)
362 {
363 octave_value& tmp = tmpc(0);
364
365 if (! tmp.is_defined () || tmp.is_zero_by_zero ())
366 {
367 tmp = octave_value::empty_conv (next_type, rhs);
368 tmp.make_unique (); // probably a no-op.
369 }
370 else
371 // optimization: ignore the copy still stored inside our map.
372 tmp.make_unique (1);
373
374 if (! error_state)
375 t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
376 }
377 else
378 gripe_indexed_cs_list ();
379 }
380 }
381 break;
382
383 case '{':
384 gripe_invalid_index_type (type_name (), type[0]);
385 break;
386
387 default:
388 panic_impossible ();
389 }
390 }
391
392 if (! error_state)
393 {
394 switch (type[0])
395 {
396 case '(':
397 {
398 if (n > 1 && type[1] == '.')
399 {
400 std::list<octave_value_list>::const_iterator p = idx.begin ();
401 octave_value_list key_idx = *++p;
402 octave_value_list idxf = idx.front ();
403
404 assert (key_idx.length () == 1);
405
406 std::string key = key_idx(0).string_value ();
407
408 if (! error_state)
409 {
410 if (t_rhs.is_cs_list ())
411 {
412 Cell tmp_cell = Cell (t_rhs.list_value ());
413
414 // Inquire the proper shape of the RHS.
415
416 dim_vector didx = dims ().redim (idxf.length ());
417 for (octave_idx_type k = 0; k < idxf.length (); k++)
418 if (! idxf(k).is_magic_colon ()) didx(k) = idxf(k).numel ();
419
420 if (didx.numel () == tmp_cell.numel ())
421 tmp_cell = tmp_cell.reshape (didx);
422
423
424 map.assign (idxf, key, tmp_cell);
425
426 if (! error_state)
427 {
428 count++;
429 retval = octave_value (this);
430 }
431 else
432 gripe_failed_assignment ();
433 }
434 else
435 {
436 const Octave_map& cmap = const_cast<const Octave_map &> (map);
437 // cast map to const reference to avoid forced key insertion.
438 if (idxf.all_scalars ()
439 || cmap.contents (key).index (idxf, true).numel () == 1)
440 {
441 map.assign (idxf, key, t_rhs.storable_value ());
442 if (! error_state)
443 {
444 count++;
445 retval = octave_value (this);
446 }
447 else
448 gripe_failed_assignment ();
449 }
450 else if (! error_state)
451 error ("invalid assignment to cs-list outside multiple assignment.");
452 }
453 }
454 else
455 gripe_failed_assignment ();
456 }
457 else
458 {
459 if (t_rhs.is_map())
460 {
461 Octave_map rhs_map = t_rhs.map_value ();
462
463 if (! error_state)
464 {
465 map.assign (idx.front (), rhs_map);
466
467 if (! error_state)
468 {
469 count++;
470 retval = octave_value (this);
471 }
472 else
473 gripe_failed_assignment ();
474 }
475 else
476 error ("invalid structure assignment");
477 }
478 else
479 {
480 if (t_rhs.is_null_value())
481 {
482 map.maybe_delete_elements (idx.front());
483
484 if (! error_state)
485 {
486 count++;
487 retval = octave_value (this);
488 }
489 else
490 gripe_failed_assignment ();
491 }
492 else
493 error ("invalid structure assignment");
494 }
495 }
496 }
497 break;
498
499 case '.':
500 {
501 octave_value_list key_idx = idx.front ();
502
503 assert (key_idx.length () == 1);
504
505 std::string key = key_idx(0).string_value ();
506
507 if (t_rhs.is_cs_list ())
508 {
509 Cell tmp_cell = Cell (t_rhs.list_value ());
510
511 // The shape of the RHS is irrelevant, we just want
512 // the number of elements to agree and to preserve the
513 // shape of the left hand side of the assignment.
514
515 if (numel () == tmp_cell.numel ())
516 tmp_cell = tmp_cell.reshape (dims ());
517
518 map.assign (key, tmp_cell);
519 }
520 else
521 // Regularize a null matrix if stored into a struct component.
522 map.assign (key, t_rhs.storable_value ());
523
524 if (! error_state)
525 {
526 count++;
527 retval = octave_value (this);
528 }
529 else
530 gripe_failed_assignment ();
531 }
532 break;
533
534 case '{':
535 gripe_invalid_index_type (type_name (), type[0]);
536 break;
537
538 default:
539 panic_impossible ();
540 }
541 }
542 else
543 gripe_failed_assignment ();
544
545 return retval;
546}
547
548octave_value
549octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
550{
551 // Octave_map handles indexing itself.
552 return map.index (idx, resize_ok);
553}
554
555size_t
556octave_struct::byte_size (void) const
557{
558 // Neglect the size of the fieldnames.
559
560 size_t retval = 0;
561
562 for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++)
563 {
564 std::string key = map.key (p);
565
566 octave_value val = octave_value (map.contents (p));
567
568 retval += val.byte_size ();
569 }
570
571 return retval;
572}
573
574void
575octave_struct::print (std::ostream& os, bool) const
576{
577 print_raw (os);
578}
579
580void
581octave_struct::print_raw (std::ostream& os, bool) const
582{
583 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame ();
584
585 unwind_protect::protect_var (Vstruct_levels_to_print);
586
587 if (Vstruct_levels_to_print >= 0)
588 {
589 bool print_keys_only = Vstruct_levels_to_print-- == 0;
590
591 indent (os);
592 os << "{";
593 newline (os);
594
595 increment_indent_level ();
596
597 octave_idx_type n = map.numel ();
598
599 if (n != 1 || print_keys_only)
600 {
601 indent (os);
602 dim_vector dv = dims ();
603 os << dv.str () << " struct array containing the fields:";
604 newline (os);
605 newline (os);
606
607 increment_indent_level ();
608 }
609
610 string_vector key_list = map.keys ();
611
612 for (octave_idx_type i = 0; i < key_list.length (); i++)
613 {
614 std::string key = key_list[i];
615
616 Cell val = map.contents (key);
617
618 octave_value tmp = (n == 1) ? val(0) : octave_value (val, true);
619
620 if (n != 1 || print_keys_only)
621 {
622 indent (os);
623 os << key;
624 if (n == 1)
625 {
626 dim_vector dv = tmp.dims ();
627 os << ": " << dv.str () << " " << tmp.type_name ();
628 }
629 newline (os);
630 }
631 else
632 tmp.print_with_name (os, key);
633 }
634
635 if (n != 1 || print_keys_only)
636 decrement_indent_level ();
637
638 decrement_indent_level ();
639
640 indent (os);
641 os << "}";
642 newline (os);
643 }
644 else
645 {
646 indent (os);
647 os << "<structure>";
648 newline (os);
649 }
650
651 unwind_protect::run_frame (uwp_frame);
652}
653
654bool
655octave_struct::print_name_tag (std::ostream& os, const std::string& name) const
656{
657 bool retval = false;
658
659 indent (os);
660
661 if (Vstruct_levels_to_print < 0)
662 os << name << " = ";
663 else
664 {
665 os << name << " =";
666 newline (os);
667 retval = true;
668 }
669
670 return retval;
671}
672
673static bool
674scalar (const dim_vector& dims)
675{
676 return dims.length () == 2 && dims (0) == 1 && dims (1) == 1;
677}
678
679/*
680%!shared x
681%! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
682%!assert(struct('a',1,'b',3),x(1))
683%!assert(isempty(x([])))
684%!assert(isempty(struct('a',{},'b',{})))
685%!assert(struct('a',{1,2},'b',{3,3}),x)
686%!assert(struct('a',{1,2},'b',3),x)
687%!assert(struct('a',{1,2},'b',{3}),x)
688%!assert(struct('b',3,'a',{1,2}),x)
689%!assert(struct('b',{3},'a',{1,2}),x)
690%!test x=struct([]);
691%!assert(size(x),[0,0]);
692%!assert(isstruct(x));
693%!assert(isempty(fieldnames(x)));
694%!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4")
695%!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs");
696%!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs");
697*/
698
699DEFUN (struct, args, ,
700 "-*- texinfo -*-\n\
701@deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\
702\n\
703Create a structure and initialize its value.\n\
704\n\
705If the values are cell arrays, create a structure array and initialize\n\
706its values. The dimensions of each cell array of values must match.\n\
707Singleton cells and non-cell values are repeated so that they fill\n\
708the entire array. If the cells are empty, create an empty structure\n\
709array with the specified field names.\n\
710\n\
711If the argument is an object, return the underlying struct.\n\
712@end deftypefn")
713{
714 octave_value retval;
715
716 int nargin = args.length ();
717
718 // struct ([]) returns an empty struct.
719
720 // struct (empty_matrix) returns an empty struct with the same
721 // dimensions as the empty matrix.
722
723 // Note that struct () creates a 1x1 struct with no fields for
724 // compatibility with Matlab.
725
726 if (nargin == 1 && args(0).is_object ())
727 {
728 Octave_map m = args(0).map_value ();
729 retval = octave_value (new octave_struct (m));
730
731 return retval;
732 }
733
734 if ((nargin == 1 || nargin == 2)
735 && args(0).is_empty () && args(0).is_real_matrix ())
736 {
737 Cell fields;
738
739 if (nargin == 2)
740 {
741 if (args(1).is_cellstr ())
742 retval = Octave_map (args(0).dims (), args(1).cell_value ());
743 else
744 error ("struct: expecting cell array of field names as second argument");
745 }
746 else
747 retval = Octave_map (args(0).dims ());
748
749 return retval;
750 }
751
752 // Check for "field", VALUE pairs.
753
754 for (int i = 0; i < nargin; i += 2)
755 {
756 if (! args(i).is_string () || i + 1 >= nargin)
757 {
758 error ("struct expects alternating \"field\", VALUE pairs");
759 return retval;
760 }
761 }
762
763 // Check that the dimensions of the values correspond.
764
765 dim_vector dims (1, 1);
766
767 int first_dimensioned_value = 0;
768
769 for (int i = 1; i < nargin; i += 2)
770 {
771 if (args(i).is_cell ())
772 {
773 dim_vector argdims (args(i).dims ());
774
775 if (! scalar (argdims))
776 {
777 if (! first_dimensioned_value)
778 {
779 dims = argdims;
780 first_dimensioned_value = i + 1;
781 }
782 else if (dims != argdims)
783 {
784 error ("struct: dimensions of parameter %d do not match those of parameter %d",
785 first_dimensioned_value, i+1);
786 return retval;
787 }
788 }
789 }
790 }
791
792 // Create the return value.
793
794 Octave_map map (dims);
795
796 for (int i = 0; i < nargin; i+= 2)
797 {
798 // Get key.
799
800 std::string key (args(i).string_value ());
801
802 if (error_state)
803 return retval;
804
805 if (! valid_identifier (key))
806 {
807 error ("struct: invalid structure field name `%s'", key.c_str ());
808 return retval;
809 }
810
811 // Value may be v, { v }, or { v1, v2, ... }
812 // In the first two cases, we need to create a cell array of
813 // the appropriate dimensions filled with v. In the last case,
814 // the cell array has already been determined to be of the
815 // correct dimensions.
816
817 if (args(i+1).is_cell ())
818 {
819 const Cell c (args(i+1).cell_value ());
820
821 if (error_state)
822 return retval;
823
824 if (scalar (c.dims ()))
825 map.assign (key, Cell (dims, c(0)));
826 else
827 map.assign (key, c);
828 }
829 else
830 map.assign (key, Cell (dims, args(i+1)));
831
832 if (error_state)
833 return retval;
834 }
835
836 return octave_value (map);
837}
838
839DEFUN (isstruct, args, ,
840 "-*- texinfo -*-\n\
841@deftypefn {Built-in Function} {} isstruct (@var{expr})\n\
842Return 1 if the value of the expression @var{expr} is a structure.\n\
843@end deftypefn")
844{
845 octave_value retval;
846
847 if (args.length () == 1)
848 retval = args(0).is_map ();
849 else
850 print_usage ();
851
852 return retval;
853}
854
855DEFUN (fieldnames, args, ,
856 "-*- texinfo -*-\n\
857@deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\
858Return a cell array of strings naming the elements of the structure\n\
859@var{struct}. It is an error to call @code{fieldnames} with an\n\
860argument that is not a structure.\n\
861@end deftypefn")
862{
863 octave_value retval;
864
865 int nargin = args.length ();
866
867 if (nargin == 1)
868 {
869 octave_value arg = args(0);
870
871 if (arg.is_map () || arg.is_object ())
872 {
873 Octave_map m = arg.map_value ();
874
875 string_vector keys = m.keys ();
876
877 if (keys.length () == 0)
878 retval = Cell (0, 1);
879 else
880 retval = Cell (m.keys ());
881 }
882 else
883 gripe_wrong_type_arg ("fieldnames", args(0));
884 }
885 else
886 print_usage ();
887
888 return retval;
889}
890
891DEFUN (isfield, args, ,
892 "-*- texinfo -*-\n\
893@deftypefn {Built-in Function} {} isfield (@var{expr}, @var{name})\n\
894Return true if the expression @var{expr} is a structure and it includes an\n\
895element named @var{name}. The first argument must be a structure and\n\
896the second must be a string.\n\
897@end deftypefn")
898{
899 octave_value retval;
900
901 int nargin = args.length ();
902
903 if (nargin == 2)
904 {
905 retval = false;
906
907 // FIXME -- should this work for all types that can do
908 // structure reference operations?
909
910 if (args(0).is_map () && args(1).is_string ())
911 {
912 std::string key = args(1).string_value ();
913
914 Octave_map m = args(0).map_value ();
915
916 retval = m.contains (key) != 0;
917 }
918 }
919 else
920 print_usage ();
921
922 return retval;
923}
924
925DEFUN (nfields, args, ,
926 "-*- texinfo -*-\n\
927@deftypefn {Built-in Function} {} nfields (@var{s})\n\
928Return the number of fields of the structure @var{s}.\n\
929@end deftypefn")
930{
931 octave_value retval;
932
933 int nargin = args.length ();
934
935 if (nargin == 1 && args(0).is_map ())
936 {
937 retval = static_cast<double> (args(0).nfields ());
938 }
939 else
940 print_usage ();
941
942 return retval;
943}
944
945// Check that the dimensions of the input arguments are correct.
946
947static bool
948cell2struct_check_args (const dim_vector& c_dv, const dim_vector& f_dv,
949 bool is_cell, int dim)
950{
951 bool retval = true;
952
953 if (dim >= 0 && dim < c_dv.length ())
954 {
955 if (is_cell)
956 {
957 if (f_dv.numel () != c_dv(dim))
958 {
959 error ("cell2struct: numel (FIELD) != size (CELL, DIM)");
960
961 retval = false;
962 }
963 }
964 else
965 {
966 if (f_dv.length () > 2)
967 {
968 error ("cell2struct: field array must be a 2-d matrix");
969
970 retval = false;
971 }
972 else if (f_dv(0) != c_dv(dim))
973 {
974 error ("cell2struct: size (FIELD, 1) != length (C, DIM)");
975
976 retval = false;
977 }
978 }
979 }
980 else
981 {
982 error ("cell2struct: DIM out of range");
983
984 retval = false;
985 }
986
987 return retval;
988}
989
990static void
991cell2struct_construct_idx (Array<octave_idx_type>& ra_idx1,
992 const Array<octave_idx_type>& ra_idx2,
993 octave_idx_type dim, octave_idx_type fill_value)
994{
995 octave_idx_type iidx = 0;
996
997 for (octave_idx_type idx = 0; idx < ra_idx1.length (); idx++)
998 {
999 if (idx == dim)
1000 ra_idx1.elem (idx) = fill_value;
1001 else
1002 ra_idx1.elem (idx) = ra_idx2(iidx++);
1003 }
1004}
1005
1006DEFUN (cell2struct, args, ,
1007 "-*- texinfo -*-\n\
1008@deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\
1009Convert @var{cell} to a structure. The number of fields in @var{fields}\n\
1010must match the number of elements in @var{cell} along dimension @var{dim},\n\
1011that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\
1012\n\
1013@example\n\
1014@group\n\
1015A = cell2struct (@{'Peter', 'Hannah', 'Robert';\n\
1016 185, 170, 168@},\n\
1017 @{'Name','Height'@}, 1);\n\
1018A(1)\n\
1019@result{} ans =\n\
1020 @{\n\
1021 Height = 185\n\
1022 Name = Peter\n\
1023 @}\n\
1024\n\
1025@end group\n\
1026@end example\n\
1027@end deftypefn")
1028{
1029 octave_value retval;
1030
1031 if (args.length () == 3)
1032 {
1033 Cell c = args(0).cell_value ();
1034
1035 if (! error_state)
1036 {
1037 octave_value field = args(1);
1038
1039 // Field is either cell or character matrix.
1040
1041 // FIXME -- this could be simplified if we had
1042 // cellstr and iscellstr functions available.
1043
1044 bool field_is_cell = field.is_cell ();
1045
1046 Cell field_cell;
1047 charMatrix field_char;
1048
1049 if (field_is_cell)
1050 field_cell = field.cell_value ();
1051 else
1052 field_char = field.char_matrix_value ();
1053
1054 if (! error_state)
1055 {
1056 // Retrieve the dimension value.
1057
1058 // FIXME -- int_value () should print out the
1059 // conversions it does to be Matlab compatible.
1060
1061 octave_idx_type dim = args(2).int_value () - 1;
1062
1063 if (! error_state)
1064 {
1065 dim_vector c_dv = c.dims ();
1066 dim_vector field_dv = field.dims ();
1067
1068 if (cell2struct_check_args (c_dv, field_dv, field_is_cell,
1069 dim))
1070 {
1071 octave_idx_type c_dv_length = c_dv.length ();
1072
1073 // Dimension vector for the Cell arrays to be
1074 // put into the structure.
1075
1076 dim_vector value_dv;
1077
1078 // Initialize c_value_dv.
1079
1080 if (c_dv_length == 2)
1081 value_dv = dim_vector (1, 1);
1082 else
1083 value_dv.resize (c_dv_length - 1);
1084
1085 octave_idx_type idx_tmp = 0;
1086
1087 for (octave_idx_type i = 0; i < c_dv_length; i++)
1088 {
1089 if (i != dim)
1090 value_dv.elem (idx_tmp++) = c_dv.elem (i);
1091 }
1092
1093 // All initializing is done, we can start moving
1094 // values.
1095
1096 Octave_map map;
1097
1098 // If field is a cell array then we use all
1099 // elements in array, on the other hand when
1100 // field is a character array the number of
1101 // elements is equals the number of rows.
1102
1103 octave_idx_type field_numel
1104 = field_is_cell ? field_dv.numel (): field_dv(0);
1105
1106 // For matlab compatibility.
1107
1108 if (field_numel == 0)
1109 map.reshape (dim_vector (0, 1));
1110
1111 for (octave_idx_type i = 0; i < field_numel; i++)
1112 {
1113 // Construct cell array which goes into the
1114 // structure together with the appropriate
1115 // field name.
1116
1117 Cell c_value (value_dv);
1118
1119 Array<octave_idx_type> value_idx (value_dv.length (), 0);
1120 Array<octave_idx_type> c_idx (c_dv_length, 0);
1121
1122 for (octave_idx_type j = 0; j < value_dv.numel (); j++)
1123 {
1124 // Need to do this to construct the
1125 // appropriate idx for getting elements
1126 // from the original cell array.
1127
1128 cell2struct_construct_idx (c_idx, value_idx,
1129 dim, i);
1130
1131 c_value.elem (value_idx) = c.elem (c_idx);
1132
1133 increment_index (value_idx, value_dv);
1134 }
1135
1136 std::string field_str;
1137
1138 if (field_is_cell)
1139 {
1140 // Matlab retrieves the field values
1141 // column by column.
1142
1143 octave_value field_tmp = field_cell.elem (i);
1144
1145 field_str = field_tmp.string_value ();
1146
1147 if (error_state)
1148 {
1149 error ("cell2struct: fields have to be of type string");
1150 break;
1151 }
1152 }
1153 else
1154 {
1155 field_str = field_char.row_as_string (i);
1156
1157 if (error_state)
1158 return retval;
1159 }
1160
1161 if (! valid_identifier (field_str))
1162 {
1163 error ("cell2struct: invalid field name `%s'",
1164 field_str.c_str ());
1165 break;
1166 }
1167
1168 map.reshape (value_dv);
1169
1170 map.assign (field_str, c_value);
1171 }
1172
1173 if (! error_state)
1174 retval = map;
1175 }
1176 }
1177 else
1178 error ("cell2struct: expecting third argument to be an integer");
1179 }
1180 else
1181 error ("cell2struct: expecting second argument to be a cell or character array");
1182 }
1183 else
1184 error ("cell2struct: expecting first argument to be a cell array");
1185 }
1186 else
1187 print_usage ();
1188
1189 return retval;
1190}
1191
1192// So we can call Fcellstr directly.
1193extern octave_value_list Fcellstr (const octave_value_list& args, int);
1194
1195DEFUN (rmfield, args, ,
1196 "-*- texinfo -*-\n\
1197@deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\
1198Remove field @var{f} from the structure @var{s}. If @var{f} is a\n\
1199cell array of character strings or a character array, remove the\n\
1200named fields.\n\
1201@seealso{cellstr, iscellstr, setfield}\n\
1202@end deftypefn")
1203{
1204 octave_value retval;
1205
1206 int nargin = args.length ();
1207
1208 if (nargin == 2)
1209 {
1210 Octave_map m = args(0).map_value ();
1211
1212 octave_value_list fval = Fcellstr (args(1), 1);
1213
1214 if (! error_state)
1215 {
1216 Cell fcell = fval(0).cell_value ();
1217
1218 for (int i = 0; i < fcell.numel (); i++)
1219 {
1220 std::string key = fcell(i).string_value ();
1221
1222 if (m.contains (key))
1223 m.del (key);
1224 else
1225 {
1226 error ("rmfield: structure does not contain field %s",
1227 key.c_str ());
1228
1229 break;
1230 }
1231 }
1232
1233 if (! error_state)
1234 retval = m;
1235 }
1236 }
1237 else
1238 print_usage ();
1239
1240 return retval;
1241}
1242
1243bool
1244octave_struct::save_ascii (std::ostream& os)
1245{
1246 Octave_map m = map_value ();
1247
1248 octave_idx_type nf = m.nfields ();
1249
1250 os << "# length: " << nf << "\n";
1251
1252 // Iterating over the list of keys will preserve the order of the
1253 // fields.
1254 string_vector keys = m.keys ();
1255
1256 for (octave_idx_type i = 0; i < nf; i++)
1257 {
1258 std::string key = keys(i);
1259
1260 octave_value val = map.contents (key);
1261
1262 bool b = save_ascii_data (os, val, key, false, 0);
1263
1264 if (! b)
1265 return os;
1266 }
1267
1268 return true;
1269}
1270
1271bool
1272octave_struct::load_ascii (std::istream& is)
1273{
1274 octave_idx_type len = 0;
1275 bool success = true;
1276
1277 if (extract_keyword (is, "length", len) && len >= 0)
1278 {
1279 if (len > 0)
1280 {
1281 Octave_map m (map);
1282
1283 for (octave_idx_type j = 0; j < len; j++)
1284 {
1285 octave_value t2;
1286 bool dummy;
1287
1288 // recurse to read cell elements
1289 std::string nm
1290 = read_ascii_data (is, std::string (), dummy, t2, j);
1291
1292 if (!is)
1293 break;
1294
1295 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1296
1297 if (error_state)
1298 {
1299 error ("load: internal error loading struct elements");
1300 return false;
1301 }
1302
1303 m.assign (nm, tcell);
1304 }
1305
1306 if (is)
1307 map = m;
1308 else
1309 {
1310 error ("load: failed to load structure");
1311 success = false;
1312 }
1313 }
1314 else if (len == 0 )
1315 map = Octave_map (dim_vector (1, 1));
1316 else
1317 panic_impossible ();
1318 }
1319 else {
1320 error ("load: failed to extract number of elements in structure");
1321 success = false;
1322 }
1323
1324 return success;
1325}
1326
1327bool
1328octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
1329{
1330 Octave_map m = map_value ();
1331
1332 octave_idx_type nf = m.nfields ();
1333
1334 int32_t len = nf;
1335 os.write (reinterpret_cast<char *> (&len), 4);
1336
1337 // Iterating over the list of keys will preserve the order of the
1338 // fields.
1339 string_vector keys = m.keys ();
1340
1341 for (octave_idx_type i = 0; i < nf; i++)
1342 {
1343 std::string key = keys(i);
1344
1345 octave_value val = map.contents (key);
1346
1347 bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
1348
1349 if (! b)
1350 return os;
1351 }
1352
1353 return true;
1354}
1355
1356bool
1357octave_struct::load_binary (std::istream& is, bool swap,
1358 oct_mach_info::float_format fmt)
1359{
1360 bool success = true;
1361 int32_t len;
1362 if (! is.read (reinterpret_cast<char *> (&len), 4))
1363 return false;
1364 if (swap)
1365 swap_bytes<4> (&len);
1366
1367 if (len > 0)
1368 {
1369 Octave_map m (map);
1370
1371 for (octave_idx_type j = 0; j < len; j++)
1372 {
1373 octave_value t2;
1374 bool dummy;
1375 std::string doc;
1376
1377 // recurse to read cell elements
1378 std::string nm = read_binary_data (is, swap, fmt, std::string (),
1379 dummy, t2, doc);
1380
1381 if (!is)
1382 break;
1383
1384 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1385
1386 if (error_state)
1387 {
1388 error ("load: internal error loading struct elements");
1389 return false;
1390 }
1391
1392 m.assign (nm, tcell);
1393 }
1394
1395 if (is)
1396 map = m;
1397 else
1398 {
1399 error ("load: failed to load structure");
1400 success = false;
1401 }
1402 }
1403 else if (len == 0 )
1404 map = Octave_map (dim_vector (1, 1));
1405 else
1406 panic_impossible ();
1407
1408 return success;
1409}
1410
1411#if defined (HAVE_HDF5)
1412
1413bool
1414octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
1415{
1416 hid_t data_hid = -1;
1417
1418 data_hid = H5Gcreate (loc_id, name, 0);
1419 if (data_hid < 0) return false;
1420
1421 // recursively add each element of the structure to this group
1422 Octave_map m = map_value ();
1423
1424 octave_idx_type nf = m.nfields ();
1425
1426 // Iterating over the list of keys will preserve the order of the
1427 // fields.
1428 string_vector keys = m.keys ();
1429
1430 for (octave_idx_type i = 0; i < nf; i++)
1431 {
1432 std::string key = keys(i);
1433
1434 octave_value val = map.contents (key);
1435
1436 bool retval2 = add_hdf5_data (data_hid, val, key, "", false,
1437 save_as_floats);
1438
1439 if (! retval2)
1440 break;
1441 }
1442
1443 H5Gclose (data_hid);
1444
1445 return true;
1446}
1447
1448bool
1449octave_struct::load_hdf5 (hid_t loc_id, const char *name,
1450 bool have_h5giterate_bug)
1451{
1452 bool retval = false;
1453
1454 hdf5_callback_data dsub;
1455
1456 herr_t retval2 = 0;
1457 Octave_map m (dim_vector (1, 1));
1458 int current_item = 0;
1459#ifdef HAVE_H5GGET_NUM_OBJS
1460 hsize_t num_obj = 0;
1461 hid_t group_id = H5Gopen (loc_id, name);
1462 H5Gget_num_objs (group_id, &num_obj);
1463 H5Gclose (group_id);
1464
1465 // FIXME -- fields appear to be sorted alphabetically on loading.
1466 // Why is that happening?
1467
1468 while (current_item < static_cast<int> (num_obj)
1469 && (retval2 = H5Giterate (loc_id, name, &current_item,
1470 hdf5_read_next_data, &dsub)) > 0)
1471#else
1472 while ((retval2 = H5Giterate (loc_id, name, &current_item,
1473 hdf5_read_next_data, &dsub)) > 0)
1474#endif
1475 {
1476 octave_value t2 = dsub.tc;
1477
1478 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1479
1480 if (error_state)
1481 {
1482 error ("load: internal error loading struct elements");
1483 return false;
1484 }
1485
1486 m.assign (dsub.name, tcell);
1487
1488 if (have_h5giterate_bug)
1489 current_item++; // H5Giterate returned the last index processed
1490 }
1491
1492 if (retval2 >= 0)
1493 {
1494 map = m;
1495 retval = true;
1496 }
1497
1498 return retval;
1499}
1500
1501#endif
1502
1503mxArray *
1504octave_struct::as_mxArray (void) const
1505{
1506 int nf = nfields ();
1507 string_vector kv = map_keys ();
1508
1509 OCTAVE_LOCAL_BUFFER (const char *, f, nf);
1510
1511 for (int i = 0; i < nf; i++)
1512 f[i] = kv[i].c_str ();
1513
1514 mxArray *retval = new mxArray (dims (), nf, f);
1515
1516 mxArray **elts = static_cast<mxArray **> (retval->get_data ());
1517
1518 mwSize nel = numel ();
1519
1520 mwSize ntot = nf * nel;
1521
1522 for (int i = 0; i < nf; i++)
1523 {
1524 Cell c = map.contents (kv[i]);
1525
1526 const octave_value *p = c.data ();
1527
1528 mwIndex k = 0;
1529 for (mwIndex j = i; j < ntot; j += nf)
1530 elts[j] = new mxArray (p[k++]);
1531 }
1532
1533 return retval;
1534}
1535
1536/*
1537;;; Local Variables: ***
1538;;; mode: C++ ***
1539;;; End: ***
1540*/