3Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2006,
4 2007, 2008, 2009 John W. Eaton
6This file is part of Octave.
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.
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
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/>.
34#include "oct-lvalue.h"
36#include "unwind-prot.h"
40#include "Array-util.h"
41#include "oct-locbuf.h"
44#include "ls-oct-ascii.h"
45#include "ls-oct-binary.h"
50DEFINE_OCTAVE_ALLOCATOR(octave_struct);
52DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct");
55octave_struct::dotref (const octave_value_list& idx, bool auto_add)
59 assert (idx.length () == 1);
61 std::string nm = idx(0).string_value ();
63 Octave_map::const_iterator p = map.seek (nm);
66 retval = map.contents (p);
68 retval = (numel () == 0) ? Cell (dim_vector (1)) : Cell (dims ());
70 error ("structure has no member `%s'", nm.c_str ());
77gripe_invalid_index (void)
79 error ("invalid index for structure array");
84gripe_invalid_index_for_assignment (void)
86 error ("invalid index for structure array assignment");
90gripe_invalid_index_type (const std::string& nm, char t)
92 error ("%s cannot be indexed with %c", nm.c_str (), t);
96gripe_failed_assignment (void)
98 error ("assignment to structure element failed");
102octave_struct::subsref (const std::string& type,
103 const std::list<octave_value_list>& idx,
106 octave_value_list retval;
114 if (type.length () > 1 && type[1] == '.')
116 std::list<octave_value_list>::const_iterator p = idx.begin ();
117 octave_value_list key_idx = *++p;
119 const Cell tmp = dotref (key_idx);
123 const Cell t = tmp.index (idx.front ());
125 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
127 // We handled two index elements, so tell
128 // next_subsref to skip both of them.
134 retval(0) = map.index (idx.front ());
142 const Cell t = dotref (idx.front ());
144 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
150 gripe_invalid_index_type (type_name (), type[0]);
157 // FIXME -- perhaps there should be an
158 // octave_value_list::next_subsref member function? See also
159 // octave_user_function::subsref.
162 retval = retval(0).next_subsref (nargout, type, idx, skip);
168octave_struct::subsref (const std::string& type,
169 const std::list<octave_value_list>& idx,
180 if (type.length () > 1 && type[1] == '.')
182 std::list<octave_value_list>::const_iterator p = idx.begin ();
183 octave_value_list key_idx = *++p;
185 const Cell tmp = dotref (key_idx, auto_add);
189 const Cell t = tmp.index (idx.front (), auto_add);
191 retval = (t.length () == 1) ? t(0) : octave_value (t, true);
193 // We handled two index elements, so tell
194 // next_subsref to skip both of them.
200 retval = map.index (idx.front (), auto_add);
208 const Cell t = dotref (idx.front (), auto_add);
210 retval = (t.length () == 1) ? t(0) : octave_value (t, true);
216 gripe_invalid_index_type (type_name (), type[0]);
223 // FIXME -- perhaps there should be an
224 // octave_value_list::next_subsref member function? See also
225 // octave_user_function::subsref.
228 retval = retval.next_subsref (auto_add, type, idx, skip);
235%! x(1).a.a = 1; x(2).a.a = 2;
236%! assert (size (x), [1, 2]);
237%! assert (x(1).a.a, 1);
238%! assert (x(2).a.a, 2);
242octave_struct::numeric_conv (const octave_value& val,
243 const std::string& type)
247 if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
248 retval = Octave_map ();
256octave_struct::subsasgn (const std::string& type,
257 const std::list<octave_value_list>& idx,
258 const octave_value& rhs)
262 int n = type.length ();
264 octave_value t_rhs = rhs;
266 if (idx.front ().empty ())
268 error ("missing index in indexed assignment");
272 if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
278 if (type.length () > 1 && type[1] == '.')
280 std::list<octave_value_list>::const_iterator p = idx.begin ();
281 octave_value_list t_idx = *p;
283 octave_value_list key_idx = *++p;
285 assert (key_idx.length () == 1);
287 std::string key = key_idx(0).string_value ();
289 std::list<octave_value_list> next_idx (idx);
291 // We handled two index elements, so subsasgn to
292 // needs to skip both of them.
294 next_idx.erase (next_idx.begin ());
295 next_idx.erase (next_idx.begin ());
297 std::string next_type = type.substr (2);
300 Octave_map::iterator pkey = map.seek (key);
301 if (pkey != map.end ())
303 pkey->second.make_unique ();
304 tmpc = pkey->second.index (idx.front (), true);
307 // FIXME: better code reuse? cf. octave_cell::subsasgn and the case below.
310 if (tmpc.numel () == 1)
312 octave_value& tmp = tmpc(0);
314 if (! tmp.is_defined () || tmp.is_zero_by_zero ())
316 tmp = octave_value::empty_conv (next_type, rhs);
317 tmp.make_unique (); // probably a no-op.
320 // optimization: ignore the copy still stored inside our map.
324 t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
327 gripe_indexed_cs_list ();
331 gripe_invalid_index_for_assignment ();
337 octave_value_list key_idx = idx.front ();
339 assert (key_idx.length () == 1);
341 std::string key = key_idx(0).string_value ();
343 std::list<octave_value_list> next_idx (idx);
345 next_idx.erase (next_idx.begin ());
347 std::string next_type = type.substr (1);
350 Octave_map::iterator pkey = map.seek (key);
351 if (pkey != map.end ())
353 pkey->second.make_unique ();
357 // FIXME: better code reuse?
360 if (tmpc.numel () == 1)
362 octave_value& tmp = tmpc(0);
364 if (! tmp.is_defined () || tmp.is_zero_by_zero ())
366 tmp = octave_value::empty_conv (next_type, rhs);
367 tmp.make_unique (); // probably a no-op.
370 // optimization: ignore the copy still stored inside our map.
374 t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
377 gripe_indexed_cs_list ();
383 gripe_invalid_index_type (type_name (), type[0]);
397 if (n > 1 && type[1] == '.')
399 std::list<octave_value_list>::const_iterator p = idx.begin ();
400 octave_value_list key_idx = *++p;
401 octave_value_list idxf = idx.front ();
403 assert (key_idx.length () == 1);
405 std::string key = key_idx(0).string_value ();
409 if (t_rhs.is_cs_list ())
411 Cell tmp_cell = Cell (t_rhs.list_value ());
413 // Inquire the proper shape of the RHS.
415 dim_vector didx = dims ().redim (idxf.length ());
416 for (octave_idx_type k = 0; k < idxf.length (); k++)
417 if (! idxf(k).is_magic_colon ()) didx(k) = idxf(k).numel ();
419 if (didx.numel () == tmp_cell.numel ())
420 tmp_cell = tmp_cell.reshape (didx);
423 map.assign (idxf, key, tmp_cell);
428 retval = octave_value (this);
431 gripe_failed_assignment ();
435 const Octave_map& cmap = const_cast<const Octave_map &> (map);
436 // cast map to const reference to avoid forced key insertion.
437 if (idxf.all_scalars ()
438 || cmap.contents (key).index (idxf, true).numel () == 1)
440 map.assign (idxf, key, t_rhs.storable_value ());
444 retval = octave_value (this);
447 gripe_failed_assignment ();
449 else if (! error_state)
450 gripe_nonbraced_cs_list_assignment ();
454 gripe_failed_assignment ();
460 Octave_map rhs_map = t_rhs.map_value ();
464 map.assign (idx.front (), rhs_map);
469 retval = octave_value (this);
472 gripe_failed_assignment ();
475 error ("invalid structure assignment");
479 if (t_rhs.is_null_value())
481 map.maybe_delete_elements (idx.front());
486 retval = octave_value (this);
489 gripe_failed_assignment ();
492 error ("invalid structure assignment");
500 octave_value_list key_idx = idx.front ();
502 assert (key_idx.length () == 1);
504 std::string key = key_idx(0).string_value ();
506 if (t_rhs.is_cs_list ())
508 Cell tmp_cell = Cell (t_rhs.list_value ());
510 // The shape of the RHS is irrelevant, we just want
511 // the number of elements to agree and to preserve the
512 // shape of the left hand side of the assignment.
514 if (numel () == tmp_cell.numel ())
515 tmp_cell = tmp_cell.reshape (dims ());
517 map.assign (key, tmp_cell);
520 // Regularize a null matrix if stored into a struct component.
521 map.assign (key, t_rhs.storable_value ());
526 retval = octave_value (this);
529 gripe_failed_assignment ();
534 gripe_invalid_index_type (type_name (), type[0]);
542 gripe_failed_assignment ();
548octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
550 // Octave_map handles indexing itself.
551 return map.index (idx, resize_ok);
555octave_struct::byte_size (void) const
557 // Neglect the size of the fieldnames.
561 for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++)
563 std::string key = map.key (p);
565 octave_value val = octave_value (map.contents (p));
567 retval += val.byte_size ();
574octave_struct::print (std::ostream& os, bool) const
580octave_struct::print_raw (std::ostream& os, bool) const
582 unwind_protect frame;
584 frame.protect_var (Vstruct_levels_to_print);
586 if (Vstruct_levels_to_print >= 0)
588 bool print_keys_only = Vstruct_levels_to_print-- == 0;
594 increment_indent_level ();
596 octave_idx_type n = map.numel ();
598 if (n != 1 || print_keys_only)
601 dim_vector dv = dims ();
602 os << dv.str () << " struct array containing the fields:";
606 increment_indent_level ();
609 string_vector key_list = map.keys ();
611 for (octave_idx_type i = 0; i < key_list.length (); i++)
613 std::string key = key_list[i];
615 Cell val = map.contents (key);
617 octave_value tmp = (n == 1) ? val(0) : octave_value (val, true);
619 if (n != 1 || print_keys_only)
625 dim_vector dv = tmp.dims ();
626 os << ": " << dv.str () << " " << tmp.type_name ();
631 tmp.print_with_name (os, key);
634 if (n != 1 || print_keys_only)
635 decrement_indent_level ();
637 decrement_indent_level ();
652octave_struct::print_name_tag (std::ostream& os, const std::string& name) const
658 if (Vstruct_levels_to_print < 0)
671scalar (const dim_vector& dims)
673 return dims.length () == 2 && dims (0) == 1 && dims (1) == 1;
678%! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
679%!assert(struct('a',1,'b',3),x(1))
680%!assert(isempty(x([])))
681%!assert(isempty(struct('a',{},'b',{})))
682%!assert(struct('a',{1,2},'b',{3,3}),x)
683%!assert(struct('a',{1,2},'b',3),x)
684%!assert(struct('a',{1,2},'b',{3}),x)
685%!assert(struct('b',3,'a',{1,2}),x)
686%!assert(struct('b',{3},'a',{1,2}),x)
688%!assert(size(x),[0,0]);
689%!assert(isstruct(x));
690%!assert(isempty(fieldnames(x)));
691%!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4")
692%!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs");
693%!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs");
696DEFUN (struct, args, ,
698@deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\
700Create a structure and initialize its value.\n\
702If the values are cell arrays, create a structure array and initialize\n\
703its values. The dimensions of each cell array of values must match.\n\
704Singleton cells and non-cell values are repeated so that they fill\n\
705the entire array. If the cells are empty, create an empty structure\n\
706array with the specified field names.\n\
708If the argument is an object, return the underlying struct.\n\
713 int nargin = args.length ();
715 // struct ([]) returns an empty struct.
717 // struct (empty_matrix) returns an empty struct with the same
718 // dimensions as the empty matrix.
720 // Note that struct () creates a 1x1 struct with no fields for
721 // compatibility with Matlab.
723 if (nargin == 1 && args(0).is_object ())
725 Octave_map m = args(0).map_value ();
726 retval = octave_value (new octave_struct (m));
731 if ((nargin == 1 || nargin == 2)
732 && args(0).is_empty () && args(0).is_real_matrix ())
738 if (args(1).is_cellstr ())
739 retval = Octave_map (args(0).dims (), args(1).cell_value ());
741 error ("struct: expecting cell array of field names as second argument");
744 retval = Octave_map (args(0).dims ());
749 // Check for "field", VALUE pairs.
751 for (int i = 0; i < nargin; i += 2)
753 if (! args(i).is_string () || i + 1 >= nargin)
755 error ("struct expects alternating \"field\", VALUE pairs");
760 // Check that the dimensions of the values correspond.
762 dim_vector dims (1, 1);
764 int first_dimensioned_value = 0;
766 for (int i = 1; i < nargin; i += 2)
768 if (args(i).is_cell ())
770 dim_vector argdims (args(i).dims ());
772 if (! scalar (argdims))
774 if (! first_dimensioned_value)
777 first_dimensioned_value = i + 1;
779 else if (dims != argdims)
781 error ("struct: dimensions of parameter %d do not match those of parameter %d",
782 first_dimensioned_value, i+1);
789 // Create the return value.
791 Octave_map map (dims);
793 for (int i = 0; i < nargin; i+= 2)
797 std::string key (args(i).string_value ());
802 if (! valid_identifier (key))
804 error ("struct: invalid structure field name `%s'", key.c_str ());
808 // Value may be v, { v }, or { v1, v2, ... }
809 // In the first two cases, we need to create a cell array of
810 // the appropriate dimensions filled with v. In the last case,
811 // the cell array has already been determined to be of the
812 // correct dimensions.
814 if (args(i+1).is_cell ())
816 const Cell c (args(i+1).cell_value ());
821 if (scalar (c.dims ()))
822 map.assign (key, Cell (dims, c(0)));
827 map.assign (key, Cell (dims, args(i+1)));
833 return octave_value (map);
836DEFUN (isstruct, args, ,
838@deftypefn {Built-in Function} {} isstruct (@var{expr})\n\
839Return 1 if the value of the expression @var{expr} is a structure\n\
840(or a structure array).\n\
845 if (args.length () == 1)
846 retval = args(0).is_map ();
853DEFUN (fieldnames, args, ,
855@deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\
856Return a cell array of strings naming the elements of the structure\n\
857@var{struct}. It is an error to call @code{fieldnames} with an\n\
858argument that is not a structure.\n\
863 int nargin = args.length ();
867 octave_value arg = args(0);
869 if (arg.is_map () || arg.is_object ())
871 Octave_map m = arg.map_value ();
873 string_vector keys = m.keys ();
875 if (keys.length () == 0)
876 retval = Cell (0, 1);
878 retval = Cell (m.keys ());
881 gripe_wrong_type_arg ("fieldnames", args(0));
890%!# test preservation of fieldname order
892%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
893%! assert(fieldnames(x), {"d"; "a"; "b"; "c"});
896DEFUN (isfield, args, ,
898@deftypefn {Built-in Function} {} isfield (@var{expr}, @var{name})\n\
899Return true if the expression @var{expr} is a structure and it includes an\n\
900element named @var{name}. The first argument must be a structure and\n\
901the second must be a string.\n\
906 int nargin = args.length ();
912 // FIXME -- should this work for all types that can do
913 // structure reference operations?
915 if (args(0).is_map () && args(1).is_string ())
917 std::string key = args(1).string_value ();
919 Octave_map m = args(0).map_value ();
921 retval = m.contains (key) != 0;
930DEFUN (nfields, args, ,
932@deftypefn {Built-in Function} {} nfields (@var{s})\n\
933Return the number of fields of the structure @var{s}.\n\
938 int nargin = args.length ();
940 if (nargin == 1 && args(0).is_map ())
942 retval = static_cast<double> (args(0).nfields ());
953%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
954%! assert (isfield (x, "b"));
955%!assert( isfield( struct("a", "1"), "a"));
956%!assert( isfield( {1}, "c"), logical (0));
957%!assert( isfield( struct("a", "1"), 10), logical (0));
958%!assert( isfield( struct("a", "b"), "a "), logical (0));
962// Check that the dimensions of the input arguments are correct.
965cell2struct_check_args (const dim_vector& c_dv, const dim_vector& f_dv,
966 bool is_cell, int dim)
970 if (dim >= 0 && dim < c_dv.length ())
974 if (f_dv.numel () != c_dv(dim))
976 error ("cell2struct: numel (FIELD) != size (CELL, DIM)");
983 if (f_dv.length () > 2)
985 error ("cell2struct: field array must be a 2-d matrix");
989 else if (f_dv(0) != c_dv(dim))
991 error ("cell2struct: size (FIELD, 1) != length (C, DIM)");
999 error ("cell2struct: DIM out of range");
1008cell2struct_construct_idx (Array<octave_idx_type>& ra_idx1,
1009 const Array<octave_idx_type>& ra_idx2,
1010 octave_idx_type dim, octave_idx_type fill_value)
1012 octave_idx_type iidx = 0;
1014 for (octave_idx_type idx = 0; idx < ra_idx1.length (); idx++)
1017 ra_idx1.elem (idx) = fill_value;
1019 ra_idx1.elem (idx) = ra_idx2(iidx++);
1023DEFUN (cell2struct, args, ,
1025@deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\
1026Convert @var{cell} to a structure. The number of fields in @var{fields}\n\
1027must match the number of elements in @var{cell} along dimension @var{dim},\n\
1028that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\
1032A = cell2struct (@{'Peter', 'Hannah', 'Robert';\n\
1034 @{'Name','Height'@}, 1);\n\
1046 octave_value retval;
1048 if (args.length () == 3)
1050 Cell c = args(0).cell_value ();
1054 octave_value field = args(1);
1056 // Field is either cell or character matrix.
1058 // FIXME -- this could be simplified if we had
1059 // cellstr and iscellstr functions available.
1061 bool field_is_cell = field.is_cell ();
1064 charMatrix field_char;
1067 field_cell = field.cell_value ();
1069 field_char = field.char_matrix_value ();
1073 // Retrieve the dimension value.
1075 // FIXME -- int_value () should print out the
1076 // conversions it does to be Matlab compatible.
1078 octave_idx_type dim = args(2).int_value () - 1;
1082 dim_vector c_dv = c.dims ();
1083 dim_vector field_dv = field.dims ();
1085 if (cell2struct_check_args (c_dv, field_dv, field_is_cell,
1088 octave_idx_type c_dv_length = c_dv.length ();
1090 // Dimension vector for the Cell arrays to be
1091 // put into the structure.
1093 dim_vector value_dv;
1095 // Initialize c_value_dv.
1097 if (c_dv_length == 2)
1098 value_dv = dim_vector (1, 1);
1100 value_dv.resize (c_dv_length - 1);
1102 octave_idx_type idx_tmp = 0;
1104 for (octave_idx_type i = 0; i < c_dv_length; i++)
1107 value_dv.elem (idx_tmp++) = c_dv.elem (i);
1110 // All initializing is done, we can start moving
1115 // If field is a cell array then we use all
1116 // elements in array, on the other hand when
1117 // field is a character array the number of
1118 // elements is equals the number of rows.
1120 octave_idx_type field_numel
1121 = field_is_cell ? field_dv.numel (): field_dv(0);
1123 // For matlab compatibility.
1125 if (field_numel == 0)
1126 map.reshape (dim_vector (0, 1));
1128 for (octave_idx_type i = 0; i < field_numel; i++)
1130 // Construct cell array which goes into the
1131 // structure together with the appropriate
1134 Cell c_value (value_dv);
1136 Array<octave_idx_type> value_idx (value_dv.length (), 0);
1137 Array<octave_idx_type> c_idx (c_dv_length, 0);
1139 for (octave_idx_type j = 0; j < value_dv.numel (); j++)
1141 // Need to do this to construct the
1142 // appropriate idx for getting elements
1143 // from the original cell array.
1145 cell2struct_construct_idx (c_idx, value_idx,
1148 c_value.elem (value_idx) = c.elem (c_idx);
1150 increment_index (value_idx, value_dv);
1153 std::string field_str;
1157 // Matlab retrieves the field values
1158 // column by column.
1160 octave_value field_tmp = field_cell.elem (i);
1162 field_str = field_tmp.string_value ();
1166 error ("cell2struct: fields have to be of type string");
1172 field_str = field_char.row_as_string (i);
1178 if (! valid_identifier (field_str))
1180 error ("cell2struct: invalid field name `%s'",
1181 field_str.c_str ());
1185 map.reshape (value_dv);
1187 map.assign (field_str, c_value);
1195 error ("cell2struct: expecting third argument to be an integer");
1198 error ("cell2struct: expecting second argument to be a cell or character array");
1201 error ("cell2struct: expecting first argument to be a cell array");
1210%!# test cell2struct versus struct2cell
1212%! keys = cellstr (char (floor (rand (100,10)*24+65)))';
1213%! vals = mat2cell(rand (100,1), ones (100,1), 1)';
1214%! s = struct ([keys; vals]{:});
1215%! t = cell2struct (vals, keys, 2);
1217%! assert (struct2cell (s), vals');
1218%! assert (fieldnames (s), keys');
1222// So we can call Fcellstr directly.
1223extern octave_value_list Fcellstr (const octave_value_list& args, int);
1225DEFUN (rmfield, args, ,
1227@deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\
1228Return a copy of the structure (array) @var{s} with the field @var{f} removed.\n\
1229If @var{f} is a cell array of strings or a character array, remove the\n\
1231@seealso{cellstr, iscellstr, setfield}\n\
1234 octave_value retval;
1236 int nargin = args.length ();
1240 Octave_map m = args(0).map_value ();
1242 octave_value_list fval = Fcellstr (args(1), 1);
1246 Cell fcell = fval(0).cell_value ();
1248 for (int i = 0; i < fcell.numel (); i++)
1250 std::string key = fcell(i).string_value ();
1252 if (m.contains (key))
1256 error ("rmfield: structure does not contain field %s",
1276%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; x(6).f="abc123";
1277%! y = rmfield (x, {"a", "f"});
1278%! assert (fieldnames (y), {"d"; "b"; "c"});
1279%! assert (size (y), [1, 6]);
1283octave_struct::save_ascii (std::ostream& os)
1285 Octave_map m = map_value ();
1287 octave_idx_type nf = m.nfields ();
1289 const dim_vector dv = dims ();
1291 os << "# ndims: " << dv.length () << "\n";
1293 for (int i = 0; i < dv.length (); i++)
1294 os << " " << dv (i);
1297 os << "# length: " << nf << "\n";
1299 // Iterating over the list of keys will preserve the order of the
1301 string_vector keys = m.keys ();
1303 for (octave_idx_type i = 0; i < nf; i++)
1305 std::string key = keys(i);
1307 octave_value val = map.contents (key);
1309 bool b = save_ascii_data (os, val, key, false, 0);
1319octave_struct::load_ascii (std::istream& is)
1321 octave_idx_type len = 0;
1322 dim_vector dv (1, 1);
1323 bool success = true;
1325 // KLUGE: earlier Octave versions did not save extra dimensions with struct,
1326 // and as a result did not preserve dimensions for empty structs.
1327 // The default dimensions were 1x1, which we want to preserve.
1328 string_vector keywords(2);
1330 keywords[0] = "ndims";
1331 keywords[1] = "length";
1335 if (extract_keyword (is, keywords, kw, len, true))
1337 if (kw == keywords[0])
1339 int mdims = std::max (static_cast<int> (len), 2);
1341 for (int i = 0; i < mdims; i++)
1344 success = extract_keyword (is, keywords[1], len);
1350 if (success && len >= 0)
1356 for (octave_idx_type j = 0; j < len; j++)
1361 // recurse to read cell elements
1363 = read_ascii_data (is, std::string (), dummy, t2, j);
1368 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1372 error ("load: internal error loading struct elements");
1376 m.assign (nm, tcell);
1383 error ("load: failed to load structure");
1388 map = Octave_map (dv);
1390 panic_impossible ();
1393 error ("load: failed to extract number of elements in structure");
1401octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
1403 Octave_map m = map_value ();
1405 octave_idx_type nf = m.nfields ();
1407 dim_vector d = dims ();
1408 if (d.length () < 1)
1411 // Use negative value for ndims
1412 int32_t di = - d.length();
1413 os.write (reinterpret_cast<char *> (&di), 4);
1414 for (int i = 0; i < d.length (); i++)
1417 os.write (reinterpret_cast<char *> (&di), 4);
1421 os.write (reinterpret_cast<char *> (&len), 4);
1423 // Iterating over the list of keys will preserve the order of the
1425 string_vector keys = m.keys ();
1427 for (octave_idx_type i = 0; i < nf; i++)
1429 std::string key = keys(i);
1431 octave_value val = map.contents (key);
1433 bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
1443octave_struct::load_binary (std::istream& is, bool swap,
1444 oct_mach_info::float_format fmt)
1446 bool success = true;
1448 if (! is.read (reinterpret_cast<char *> (&len), 4))
1451 swap_bytes<4> (&len);
1453 dim_vector dv (1, 1);
1457 // We have explicit dimensions.
1463 for (int i = 0; i < mdims; i++)
1465 if (! is.read (reinterpret_cast<char *> (&di), 4))
1468 swap_bytes<4> (&di);
1472 if (! is.read (reinterpret_cast<char *> (&len), 4))
1475 swap_bytes<4> (&len);
1482 for (octave_idx_type j = 0; j < len; j++)
1488 // recurse to read cell elements
1489 std::string nm = read_binary_data (is, swap, fmt, std::string (),
1495 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1499 error ("load: internal error loading struct elements");
1503 m.assign (nm, tcell);
1510 error ("load: failed to load structure");
1515 map = Octave_map (dv);
1522#if defined (HAVE_HDF5)
1525octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
1527 hid_t data_hid = -1;
1530 data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1532 data_hid = H5Gcreate (loc_id, name, 0);
1534 if (data_hid < 0) return false;
1536 // recursively add each element of the structure to this group
1537 Octave_map m = map_value ();
1539 octave_idx_type nf = m.nfields ();
1541 // Iterating over the list of keys will preserve the order of the
1543 string_vector keys = m.keys ();
1545 for (octave_idx_type i = 0; i < nf; i++)
1547 std::string key = keys(i);
1549 octave_value val = map.contents (key);
1551 bool retval2 = add_hdf5_data (data_hid, val, key, "", false,
1558 H5Gclose (data_hid);
1564octave_struct::load_hdf5 (hid_t loc_id, const char *name)
1566 bool retval = false;
1568 hdf5_callback_data dsub;
1571 Octave_map m (dim_vector (1, 1));
1572 int current_item = 0;
1573 hsize_t num_obj = 0;
1575 hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
1577 hid_t group_id = H5Gopen (loc_id, name);
1579 H5Gget_num_objs (group_id, &num_obj);
1580 H5Gclose (group_id);
1582 // FIXME -- fields appear to be sorted alphabetically on loading.
1583 // Why is that happening?
1585 while (current_item < static_cast<int> (num_obj)
1586 && (retval2 = H5Giterate (loc_id, name, ¤t_item,
1587 hdf5_read_next_data, &dsub)) > 0)
1589 octave_value t2 = dsub.tc;
1591 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1595 error ("load: internal error loading struct elements");
1599 m.assign (dsub.name, tcell);
1615octave_struct::as_mxArray (void) const
1617 int nf = nfields ();
1618 string_vector kv = map_keys ();
1620 OCTAVE_LOCAL_BUFFER (const char *, f, nf);
1622 for (int i = 0; i < nf; i++)
1623 f[i] = kv[i].c_str ();
1625 mxArray *retval = new mxArray (dims (), nf, f);
1627 mxArray **elts = static_cast<mxArray **> (retval->get_data ());
1629 mwSize nel = numel ();
1631 mwSize ntot = nf * nel;
1633 for (int i = 0; i < nf; i++)
1635 Cell c = map.contents (kv[i]);
1637 const octave_value *p = c.data ();
1640 for (mwIndex j = i; j < ntot; j += nf)
1641 elts[j] = new mxArray (p[k++]);