3
Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2006,
6
This file is part of Octave.
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.
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
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/>.
34
#include "oct-lvalue.h"
36
#include "ov-struct.h"
37
#include "unwind-prot.h"
39
#include "variables.h"
41
#include "Array-util.h"
43
#include "byte-swap.h"
44
#include "ls-oct-ascii.h"
45
#include "ls-oct-binary.h"
48
#include "pr-output.h"
50
DEFINE_OCTAVE_ALLOCATOR(octave_struct);
52
DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct");
55
octave_struct::dotref (const octave_value_list& idx)
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
error ("structure has no member `%s'", nm.c_str ());
75
gripe_invalid_index (void)
77
error ("invalid index for structure array");
82
gripe_invalid_index_for_assignment (void)
84
error ("invalid index for structure array assignment");
88
gripe_invalid_index_type (const std::string& nm, char t)
90
error ("%s cannot be indexed with %c", nm.c_str (), t);
94
gripe_failed_assignment (void)
96
error ("assignment to structure element failed");
100
octave_struct::subsref (const std::string& type,
101
const std::list<octave_value_list>& idx,
104
octave_value_list retval;
112
if (type.length () > 1 && type[1] == '.')
114
std::list<octave_value_list>::const_iterator p = idx.begin ();
115
octave_value_list key_idx = *++p;
117
Cell tmp = dotref (key_idx);
121
Cell t = tmp.index (idx.front ());
123
retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
125
// We handled two index elements, so tell
126
// next_subsref to skip both of them.
132
retval(0) = map.index (idx.front ());
140
Cell t = dotref (idx.front ());
142
retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
148
gripe_invalid_index_type (type_name (), type[0]);
155
// FIXME -- perhaps there should be an
156
// octave_value_list::next_subsref member function? See also
157
// octave_user_function::subsref.
160
retval = retval(0).next_subsref (nargout, type, idx, skip);
166
octave_struct::numeric_conv (const Cell& val,
167
const std::string& type)
171
if (val.length () == 1)
175
if (type.length () > 0 && type[0] == '.' && ! retval.is_map ())
176
retval = Octave_map ();
179
gripe_invalid_index_for_assignment ();
185
octave_struct::subsasgn (const std::string& type,
186
const std::list<octave_value_list>& idx,
187
const octave_value& rhs)
191
int n = type.length ();
193
octave_value t_rhs = rhs;
195
if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
201
if (type.length () > 1 && type[1] == '.')
203
std::list<octave_value_list>::const_iterator p = idx.begin ();
204
octave_value_list t_idx = *p;
206
octave_value_list key_idx = *++p;
208
assert (key_idx.length () == 1);
210
std::string key = key_idx(0).string_value ();
214
if (! map.contains (key))
215
u = octave_value::empty_conv (type.substr (2), rhs);
218
Cell map_val = map.contents (key);
220
Cell map_elt = map_val.index (idx.front (), true);
222
u = numeric_conv (map_elt, type.substr (2));
227
std::list<octave_value_list> next_idx (idx);
229
// We handled two index elements, so subsasgn to
230
// needs to skip both of them.
232
next_idx.erase (next_idx.begin ());
233
next_idx.erase (next_idx.begin ());
237
t_rhs = u.subsasgn (type.substr (2), next_idx, rhs);
241
gripe_invalid_index_for_assignment ();
247
octave_value_list key_idx = idx.front ();
249
assert (key_idx.length () == 1);
251
std::string key = key_idx(0).string_value ();
255
if (! map.contains (key))
256
u = octave_value::empty_conv (type.substr (1), rhs);
259
Cell map_val = map.contents (key);
261
u = numeric_conv (map_val, type.substr (1));
266
std::list<octave_value_list> next_idx (idx);
268
next_idx.erase (next_idx.begin ());
272
t_rhs = u.subsasgn (type.substr (1), next_idx, rhs);
278
gripe_invalid_index_type (type_name (), type[0]);
292
if (n > 1 && type[1] == '.')
294
std::list<octave_value_list>::const_iterator p = idx.begin ();
295
octave_value_list key_idx = *++p;
297
assert (key_idx.length () == 1);
299
std::string key = key_idx(0).string_value ();
303
map.assign (idx.front (), key, t_rhs);
308
retval = octave_value (this);
311
gripe_failed_assignment ();
314
gripe_failed_assignment ();
320
Octave_map rhs_map = t_rhs.map_value ();
324
map.assign (idx.front (), rhs_map);
329
retval = octave_value (this);
332
gripe_failed_assignment ();
335
error ("invalid structure assignment");
339
if (t_rhs.is_empty())
341
map.maybe_delete_elements (idx.front());
346
retval = octave_value (this);
349
gripe_failed_assignment ();
352
error ("invalid structure assignment");
360
octave_value_list key_idx = idx.front ();
362
assert (key_idx.length () == 1);
364
std::string key = key_idx(0).string_value ();
366
if (t_rhs.is_cs_list ())
368
Cell tmp_cell = Cell (t_rhs.list_value ());
370
// The shape of the RHS is irrelevant, we just want
371
// the number of elements to agree and to preserve the
372
// shape of the left hand side of the assignment.
374
if (numel () == tmp_cell.numel ())
375
tmp_cell = tmp_cell.reshape (dims ());
377
map.assign (key, tmp_cell);
380
map.assign (key, t_rhs);
385
retval = octave_value (this);
388
gripe_failed_assignment ();
393
gripe_invalid_index_type (type_name (), type[0]);
401
gripe_failed_assignment ();
407
octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
411
octave_idx_type n_idx = idx.length ();
413
int nd = map.ndims ();
423
idx_vector i = idx (0).index_vector ();
426
retval = map.index (i, resize_ok, Cell::resize_fill_value ());
432
if (n_idx == 2 && nd == 2)
434
idx_vector i = idx (0).index_vector ();
438
idx_vector j = idx (1).index_vector ();
441
retval = map.index (i, j, resize_ok,
442
Cell::resize_fill_value ());
447
Array<idx_vector> idx_vec (n_idx);
449
for (octave_idx_type i = 0; i < n_idx; i++)
451
idx_vec(i) = idx(i).index_vector ();
458
retval = map.index (idx_vec, resize_ok,
459
Cell::resize_fill_value ());
469
octave_struct::byte_size (void) const
471
// Neglect the size of the fieldnames.
475
for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++)
477
std::string key = map.key (p);
479
octave_value val = octave_value (map.contents (p));
481
retval += val.byte_size ();
488
octave_struct::print (std::ostream& os, bool) const
494
octave_struct::print_raw (std::ostream& os, bool) const
496
unwind_protect::begin_frame ("octave_struct_print");
498
unwind_protect_int (Vstruct_levels_to_print);
500
if (Vstruct_levels_to_print >= 0)
502
bool print_keys_only = (Vstruct_levels_to_print == 0
503
|| map.numel () == 0);
505
Vstruct_levels_to_print--;
511
increment_indent_level ();
513
octave_idx_type n = map.numel ();
515
if (n == 0 || (n > 1 && print_keys_only))
518
dim_vector dv = dims ();
519
os << dv.str () << " struct array containing the fields:";
523
increment_indent_level ();
526
string_vector key_list = map.keys ();
528
for (octave_idx_type i = 0; i < key_list.length (); i++)
530
std::string key = key_list[i];
532
Cell val = map.contents (key);
534
octave_value tmp = (n == 1) ? val(0) : octave_value (val, true);
542
dim_vector dv = tmp.dims ();
543
os << ": " << dv.str () << " " << tmp.type_name ();
548
tmp.print_with_name (os, key);
551
if (n == 0 || (n > 1 && print_keys_only))
552
decrement_indent_level ();
554
decrement_indent_level ();
567
unwind_protect::run_frame ("octave_struct_print");
571
octave_struct::print_name_tag (std::ostream& os, const std::string& name) const
577
if (Vstruct_levels_to_print < 0)
590
scalar (const dim_vector& dims)
592
return dims.length () == 2 && dims (0) == 1 && dims (1) == 1;
597
%! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
598
%!assert(struct('a',1,'b',3),x(1))
599
%!assert(isempty(x([])))
600
%!assert(isempty(struct('a',{},'b',{})))
601
%!assert(struct('a',{1,2},'b',{3,3}),x)
602
%!assert(struct('a',{1,2},'b',3),x)
603
%!assert(struct('a',{1,2},'b',{3}),x)
604
%!assert(struct('b',3,'a',{1,2}),x)
605
%!assert(struct('b',{3},'a',{1,2}),x)
607
%!assert(size(x),[0,0]);
608
%!assert(isstruct(x));
609
%!assert(isempty(fieldnames(x)));
610
%!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4")
611
%!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs");
612
%!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs");
615
DEFUN (struct, args, ,
617
@deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\
619
Create a structure and initialize its value.\n\
621
If the values are cell arrays, create a structure array and initialize\n\
622
its values. The dimensions of each cell array of values must match.\n\
623
Singleton cells and non-cell values are repeated so that they fill\n\
624
the entire array. If the cells are empty, create an empty structure\n\
625
array with the specified field names.\n\
630
int nargin = args.length ();
632
// struct ([]) returns an empty struct.
634
// struct (empty_matrix) returns an empty struct with the same
635
// dimensions as the empty matrix.
637
// Note that struct () creates a 1x1 struct with no fields for
638
// compatibility with Matlab.
640
if ((nargin == 1 || nargin == 2)
641
&& args(0).is_empty () && args(0).is_real_matrix ())
647
if (args(1).is_cellstr ())
648
retval = Octave_map (args(0).dims (), args(1).cell_value ());
650
error ("struct: expecting cell array of field names as second argument");
653
retval = Octave_map (args(0).dims ());
658
// Check for "field", VALUE pairs.
660
for (int i = 0; i < nargin; i += 2)
662
if (! args(i).is_string () || i + 1 >= nargin)
664
error ("struct expects alternating \"field\", VALUE pairs");
669
// Check that the dimensions of the values correspond.
671
dim_vector dims (1, 1);
673
int first_dimensioned_value = 0;
675
for (int i = 1; i < nargin; i += 2)
677
if (args(i).is_cell ())
679
dim_vector argdims (args(i).dims ());
681
if (! scalar (argdims))
683
if (! first_dimensioned_value)
686
first_dimensioned_value = i + 1;
688
else if (dims != argdims)
690
error ("struct: dimensions of parameter %d do not match those of parameter %d",
691
first_dimensioned_value, i+1);
698
// Create the return value.
700
Octave_map map (dims);
702
for (int i = 0; i < nargin; i+= 2)
706
std::string key (args(i).string_value ());
711
if (! valid_identifier (key))
713
error ("struct: invalid structure field name `%s'", key.c_str ());
717
// Value may be v, { v }, or { v1, v2, ... }
718
// In the first two cases, we need to create a cell array of
719
// the appropriate dimensions filled with v. In the last case,
720
// the cell array has already been determined to be of the
721
// correct dimensions.
723
if (args(i+1).is_cell ())
725
const Cell c (args(i+1).cell_value ());
730
if (scalar (c.dims ()))
731
map.assign (key, Cell (dims, c(0)));
736
map.assign (key, Cell (dims, args(i+1)));
742
return octave_value (map);
745
DEFUN (isstruct, args, ,
747
@deftypefn {Built-in Function} {} isstruct (@var{expr})\n\
748
Return 1 if the value of the expression @var{expr} is a structure.\n\
753
if (args.length () == 1)
754
retval = args(0).is_map ();
761
DEFUN (fieldnames, args, ,
763
@deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\
764
Return a cell array of strings naming the elements of the structure\n\
765
@var{struct}. It is an error to call @code{fieldnames} with an\n\
766
argument that is not a structure.\n\
771
int nargin = args.length ();
775
if (args(0).is_map ())
777
Octave_map m = args(0).map_value ();
778
string_vector keys = m.keys ();
779
if (keys.length () == 0)
780
retval = Cell (0, 1);
782
retval = Cell (m.keys ());
785
gripe_wrong_type_arg ("fieldnames", args(0));
793
DEFUN (isfield, args, ,
795
@deftypefn {Built-in Function} {} isfield (@var{expr}, @var{name})\n\
796
Return true if the expression @var{expr} is a structure and it includes an\n\
797
element named @var{name}. The first argument must be a structure and\n\
798
the second must be a string.\n\
803
int nargin = args.length ();
809
// FIXME -- should this work for all types that can do
810
// structure reference operations?
812
if (args(0).is_map () && args(1).is_string ())
814
std::string key = args(1).string_value ();
816
Octave_map m = args(0).map_value ();
818
retval = m.contains (key) != 0;
827
// Check that the dimensions of the input arguments are correct.
830
cell2struct_check_args (const dim_vector& c_dv, const dim_vector& f_dv,
831
bool is_cell, int dim)
835
if (dim >= 0 && dim < c_dv.length ())
839
if (f_dv.numel () != c_dv(dim))
841
error ("cell2struct: numel (FIELD) != size (CELL, DIM)");
848
if (f_dv.length () > 2)
850
error ("cell2struct: field array must be a 2-d matrix");
854
else if (f_dv(0) != c_dv(dim))
856
error ("cell2struct: size (FIELD, 1) != length (C, DIM)");
864
error ("cell2struct: DIM out of range");
873
cell2struct_construct_idx (Array<octave_idx_type>& ra_idx1,
874
const Array<octave_idx_type>& ra_idx2,
875
octave_idx_type dim, octave_idx_type fill_value)
877
octave_idx_type iidx = 0;
879
for (octave_idx_type idx = 0; idx < ra_idx1.length (); idx++)
882
ra_idx1.elem (idx) = fill_value;
884
ra_idx1.elem (idx) = ra_idx2(iidx++);
888
DEFUN (cell2struct, args, ,
890
@deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\
891
Convert @var{cell} to a structure. The number of fields in @var{fields}\n\
892
must match the number of elements in @var{cell} along dimension @var{dim},\n\
893
that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\
897
A = cell2struct (@{'Peter', 'Hannah', 'Robert';\n\
899
@{'Name','Height'@}, 1);\n\
913
if (args.length () == 3)
915
Cell c = args(0).cell_value ();
919
octave_value field = args(1);
921
// Field is either cell or character matrix.
923
// FIXME -- this could be simplified if we had
924
// cellstr and iscellstr functions available.
926
bool field_is_cell = field.is_cell ();
929
charMatrix field_char;
932
field_cell = field.cell_value ();
934
field_char = field.char_matrix_value ();
938
// Retrieve the dimension value.
940
// FIXME -- int_value () should print out the
941
// conversions it does to be Matlab compatible.
943
octave_idx_type dim = args(2).int_value () - 1;
947
dim_vector c_dv = c.dims ();
948
dim_vector field_dv = field.dims ();
950
if (cell2struct_check_args (c_dv, field_dv, field_is_cell,
953
octave_idx_type c_dv_length = c_dv.length ();
955
// Dimension vector for the Cell arrays to be
956
// put into the structure.
960
// Initialize c_value_dv.
962
if (c_dv_length == 2)
963
value_dv = dim_vector (1, 1);
965
value_dv.resize (c_dv_length - 1);
967
octave_idx_type idx_tmp = 0;
969
for (octave_idx_type i = 0; i < c_dv_length; i++)
972
value_dv.elem (idx_tmp++) = c_dv.elem (i);
975
// All initializing is done, we can start moving
980
// If field is a cell array then we use all
981
// elements in array, on the other hand when
982
// field is a character array the number of
983
// elements is equals the number of rows.
985
octave_idx_type field_numel
986
= field_is_cell ? field_dv.numel (): field_dv(0);
988
// For matlab compatibility.
990
if (field_numel == 0)
991
map.reshape (dim_vector (0, 1));
993
for (octave_idx_type i = 0; i < field_numel; i++)
995
// Construct cell array which goes into the
996
// structure together with the appropriate
999
Cell c_value (value_dv);
1001
Array<octave_idx_type> value_idx (value_dv.length (), 0);
1002
Array<octave_idx_type> c_idx (c_dv_length, 0);
1004
for (octave_idx_type j = 0; j < value_dv.numel (); j++)
1006
// Need to do this to construct the
1007
// appropriate idx for getting elements
1008
// from the original cell array.
1010
cell2struct_construct_idx (c_idx, value_idx,
1013
c_value.elem (value_idx) = c.elem (c_idx);
1015
increment_index (value_idx, value_dv);
1018
std::string field_str;
1022
// Matlab retrieves the field values
1023
// column by column.
1025
octave_value field_tmp = field_cell.elem (i);
1027
field_str = field_tmp.string_value ();
1031
error ("cell2struct: fields have to be of type string");
1037
field_str = field_char.row_as_string (i);
1043
if (! valid_identifier (field_str))
1045
error ("cell2struct: invalid field name `%s'",
1046
field_str.c_str ());
1050
map.reshape (value_dv);
1052
map.assign (field_str, c_value);
1060
error ("cell2struct: expecting third argument to be an integer");
1063
error ("cell2struct: expecting second argument to be a cell or character array");
1066
error ("cell2struct: expecting first argument to be a cell array");
1074
// So we can call Fcellstr directly.
1075
extern octave_value_list Fcellstr (const octave_value_list& args, int);
1077
DEFUN (rmfield, args, ,
1079
@deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\
1080
Remove field @var{f} from the structure @var{s}. If @var{f} is a\n\
1081
cell array of character strings or a character array, remove the\n\
1083
@seealso{cellstr, iscellstr, setfield}\n\
1086
octave_value retval;
1088
int nargin = args.length ();
1092
Octave_map m = args(0).map_value ();
1094
octave_value_list fval = Fcellstr (args(1), 1);
1098
Cell fcell = fval(0).cell_value ();
1100
for (int i = 0; i < fcell.numel (); i++)
1102
std::string key = fcell(i).string_value ();
1104
if (m.contains (key))
1108
error ("rmfield: structure does not contain field %s",
1126
octave_struct::save_ascii (std::ostream& os)
1128
Octave_map m = map_value ();
1129
os << "# length: " << m.nfields () << "\n";
1131
Octave_map::iterator i = m.begin ();
1132
while (i != m.end ())
1134
octave_value val = map.contents (i);
1136
bool b = save_ascii_data (os, val, m.key (i), false, 0);
1148
octave_struct::load_ascii (std::istream& is)
1150
octave_idx_type len = 0;
1151
bool success = true;
1153
if (extract_keyword (is, "length", len) && len >= 0)
1159
for (octave_idx_type j = 0; j < len; j++)
1164
// recurse to read cell elements
1166
= read_ascii_data (is, std::string (), dummy, t2, j);
1171
Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1175
error ("load: internal error loading struct elements");
1179
m.assign (nm, tcell);
1186
error ("load: failed to load structure");
1191
map = Octave_map (dim_vector (1, 1));
1193
panic_impossible ();
1196
error ("load: failed to extract number of elements in structure");
1204
octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
1206
Octave_map m = map_value ();
1208
int32_t len = m.nfields ();
1209
os.write (reinterpret_cast<char *> (&len), 4);
1211
Octave_map::iterator i = m.begin ();
1212
while (i != m.end ())
1214
octave_value val = map.contents (i);
1216
bool b = save_binary_data (os, val, m.key (i), "", 0, save_as_floats);
1228
octave_struct::load_binary (std::istream& is, bool swap,
1229
oct_mach_info::float_format fmt)
1231
bool success = true;
1233
if (! is.read (reinterpret_cast<char *> (&len), 4))
1236
swap_bytes<4> (&len);
1242
for (octave_idx_type j = 0; j < len; j++)
1248
// recurse to read cell elements
1249
std::string nm = read_binary_data (is, swap, fmt, std::string (),
1255
Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1259
error ("load: internal error loading struct elements");
1263
m.assign (nm, tcell);
1270
error ("load: failed to load structure");
1275
map = Octave_map (dim_vector (1, 1));
1277
panic_impossible ();
1282
#if defined (HAVE_HDF5)
1285
octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
1287
hid_t data_hid = -1;
1289
data_hid = H5Gcreate (loc_id, name, 0);
1290
if (data_hid < 0) return false;
1292
// recursively add each element of the structure to this group
1293
Octave_map m = map_value ();
1294
Octave_map::iterator i = m.begin ();
1295
while (i != m.end ())
1297
octave_value val = map.contents (i);
1299
bool retval2 = add_hdf5_data (data_hid, val, m.key (i), "", false,
1308
H5Gclose (data_hid);
1314
octave_struct::load_hdf5 (hid_t loc_id, const char *name,
1315
bool have_h5giterate_bug)
1317
bool retval = false;
1319
hdf5_callback_data dsub;
1322
Octave_map m (dim_vector (1, 1));
1323
int current_item = 0;
1324
#ifdef HAVE_H5GGET_NUM_OBJS
1325
hsize_t num_obj = 0;
1326
hid_t group_id = H5Gopen (loc_id, name);
1327
H5Gget_num_objs (group_id, &num_obj);
1328
H5Gclose (group_id);
1330
while (current_item < static_cast<int> (num_obj)
1331
&& (retval2 = H5Giterate (loc_id, name, ¤t_item,
1332
hdf5_read_next_data, &dsub)) > 0)
1334
while ((retval2 = H5Giterate (loc_id, name, ¤t_item,
1335
hdf5_read_next_data, &dsub)) > 0)
1338
octave_value t2 = dsub.tc;
1340
Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1344
error ("load: internal error loading struct elements");
1348
m.assign (dsub.name, tcell);
1350
if (have_h5giterate_bug)
1351
current_item++; // H5Giterate returned the last index processed
1366
octave_struct::as_mxArray (void) const
1368
int nf = nfields ();
1369
string_vector kv = map_keys ();
1371
OCTAVE_LOCAL_BUFFER (const char *, f, nf);
1373
for (int i = 0; i < nf; i++)
1374
f[i] = kv[i].c_str ();
1376
mxArray *retval = new mxArray (dims (), nf, f);
1378
mxArray **elts = static_cast<mxArray **> (retval->get_data ());
1380
mwSize nel = numel ();
1382
mwSize ntot = nf * nel;
1384
for (int i = 0; i < nf; i++)
1386
Cell c = map.contents (kv[i]);
1388
const octave_value *p = c.data ();
1391
for (mwIndex j = i; j < ntot; j += nf)
1392
elts[j] = new mxArray (p[k++]);
1399
;;; Local Variables: ***