GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
ov-struct.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <iostream>
28 
29 #include "Cell.h"
30 #include "defun.h"
31 #include "error.h"
32 #include "gripes.h"
33 #include "mxarray.h"
34 #include "oct-lvalue.h"
35 #include "ov-struct.h"
36 #include "unwind-prot.h"
37 #include "utils.h"
38 #include "variables.h"
39 
40 #include "Array-util.h"
41 #include "oct-locbuf.h"
42 
43 #include "byte-swap.h"
44 #include "ls-oct-ascii.h"
45 #include "ls-oct-binary.h"
46 #include "ls-hdf5.h"
47 #include "ls-utils.h"
48 #include "pr-output.h"
49 
51 
53 
54 // How many levels of structure elements should we print?
55 static int Vstruct_levels_to_print = 2;
56 
57 // TRUE means print struct array contents, up to the number of levels
58 // specified by struct_levels_to_print.
59 static bool Vprint_struct_array_contents = false;
60 
63 {
64  octave_base_value *retval = 0;
65 
66  if (numel () == 1)
67  retval = new octave_scalar_struct (map.checkelem (0));
68 
69  return retval;
70 }
71 
72 Cell
73 octave_struct::dotref (const octave_value_list& idx, bool auto_add)
74 {
75  Cell retval;
76 
77  assert (idx.length () == 1);
78 
79  std::string nm = idx(0).string_value ();
80 
82 
83  if (p != map.end ())
84  retval = map.contents (p);
85  else if (auto_add)
86  retval = (numel () == 0) ? Cell (dim_vector (1, 1)) : Cell (dims ());
87  else
88  error_with_id ("Octave:invalid-indexing",
89  "structure has no member '%s'", nm.c_str ());
90 
91  return retval;
92 }
93 
94 #if 0
95 static void
97 {
98  error ("invalid index for structure array");
99 }
100 #endif
101 
102 static void
104 {
105  error ("invalid index for structure array assignment");
106 }
107 
108 static void
109 gripe_invalid_index_type (const std::string& nm, char t)
110 {
111  error ("%s cannot be indexed with %c", nm.c_str (), t);
112 }
113 
114 static void
116 {
117  error ("assignment to structure element failed");
118 }
119 
120 static void
121 maybe_warn_invalid_field_name (const std::string& key, const char *who)
122 {
123  if (! valid_identifier (key))
124  {
125  if (who)
126  warning_with_id ("Octave:matlab-incompatible",
127  "%s: invalid structure field name '%s'",
128  who, key.c_str ());
129  else
130  warning_with_id ("Octave:matlab-incompatible",
131  "invalid structure field name '%s'",
132  key.c_str ());
133  }
134 }
135 
137 octave_struct::subsref (const std::string& type,
138  const std::list<octave_value_list>& idx,
139  int nargout)
140 {
141  octave_value_list retval;
142 
143  int skip = 1;
144 
145  switch (type[0])
146  {
147  case '(':
148  {
149  if (type.length () > 1 && type[1] == '.')
150  {
151  std::list<octave_value_list>::const_iterator p = idx.begin ();
152  octave_value_list key_idx = *++p;
153 
154  const Cell tmp = dotref (key_idx);
155 
156  if (! error_state)
157  {
158  const Cell t = tmp.index (idx.front ());
159 
160  retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
161 
162  // We handled two index elements, so tell
163  // next_subsref to skip both of them.
164 
165  skip++;
166  }
167  }
168  else
169  retval(0) = do_index_op (idx.front ());
170  }
171  break;
172 
173  case '.':
174  {
175  if (map.numel () > 0)
176  {
177  const Cell t = dotref (idx.front ());
178 
179  retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
180  }
181  }
182  break;
183 
184  case '{':
185  gripe_invalid_index_type (type_name (), type[0]);
186  break;
187 
188  default:
189  panic_impossible ();
190  }
191 
192  // FIXME: perhaps there should be an
193  // octave_value_list::next_subsref member function? See also
194  // octave_user_function::subsref.
195 
196  if (idx.size () > 1)
197  retval = retval(0).next_subsref (nargout, type, idx, skip);
198 
199  return retval;
200 }
201 
203 octave_struct::subsref (const std::string& type,
204  const std::list<octave_value_list>& idx,
205  bool auto_add)
206 {
207  octave_value retval;
208 
209  int skip = 1;
210 
211  switch (type[0])
212  {
213  case '(':
214  {
215  if (type.length () > 1 && type[1] == '.')
216  {
217  std::list<octave_value_list>::const_iterator p = idx.begin ();
218  octave_value_list key_idx = *++p;
219 
220  const Cell tmp = dotref (key_idx, auto_add);
221 
222  if (! error_state)
223  {
224  const Cell t = tmp.index (idx.front (), auto_add);
225 
226  retval = (t.length () == 1) ? t(0) : octave_value (t, true);
227 
228  // We handled two index elements, so tell
229  // next_subsref to skip both of them.
230 
231  skip++;
232  }
233  }
234  else
235  retval = do_index_op (idx.front (), auto_add);
236  }
237  break;
238 
239  case '.':
240  {
241  if (map.numel () > 0)
242  {
243  const Cell t = dotref (idx.front (), auto_add);
244 
245  retval = (t.length () == 1) ? t(0) : octave_value (t, true);
246  }
247  }
248  break;
249 
250  case '{':
251  gripe_invalid_index_type (type_name (), type[0]);
252  break;
253 
254  default:
255  panic_impossible ();
256  }
257 
258  // FIXME: perhaps there should be an
259  // octave_value_list::next_subsref member function? See also
260  // octave_user_function::subsref.
261 
262  if (idx.size () > 1)
263  retval = retval.next_subsref (auto_add, type, idx, skip);
264 
265  return retval;
266 }
267 
268 /*
269 %!test
270 %! x(1).a.a = 1;
271 %! x(2).a.a = 2;
272 %! assert (size (x), [1, 2]);
273 %! assert (x(1).a.a, 1);
274 %! assert (x(2).a.a, 2);
275 */
276 
279  const std::string& type)
280 {
281  octave_value retval;
282 
283  if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
284  retval = octave_map ();
285  else
286  retval = val;
287 
288  return retval;
289 }
290 
292 octave_struct::subsasgn (const std::string& type,
293  const std::list<octave_value_list>& idx,
294  const octave_value& rhs)
295 {
296  octave_value retval;
297 
298  int n = type.length ();
299 
300  octave_value t_rhs = rhs;
301 
302  if (idx.front ().empty ())
303  {
304  error ("missing index in indexed assignment");
305  return retval;
306  }
307 
308  if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
309  {
310  switch (type[0])
311  {
312  case '(':
313  {
314  if (type.length () > 1 && type[1] == '.')
315  {
316  std::list<octave_value_list>::const_iterator p = idx.begin ();
317  octave_value_list t_idx = *p;
318 
319  octave_value_list key_idx = *++p;
320 
321  assert (key_idx.length () == 1);
322 
323  std::string key = key_idx(0).string_value ();
324 
325  maybe_warn_invalid_field_name (key, "subsasgn");
326 
327  if (error_state)
328  return retval;
329 
330  std::list<octave_value_list> next_idx (idx);
331 
332  // We handled two index elements, so subsasgn to
333  // needs to skip both of them.
334 
335  next_idx.erase (next_idx.begin ());
336  next_idx.erase (next_idx.begin ());
337 
338  std::string next_type = type.substr (2);
339 
340  Cell tmpc (1, 1);
341  octave_map::iterator pkey = map.seek (key);
342  if (pkey != map.end ())
343  {
344  map.contents (pkey).make_unique ();
345  tmpc = map.contents (pkey).index (idx.front (), true);
346  }
347 
348  // FIXME: better code reuse?
349  // cf. octave_cell::subsasgn and the case below.
350  if (! error_state)
351  {
352  if (tmpc.numel () == 1)
353  {
354  octave_value& tmp = tmpc(0);
355 
356  bool orig_undefined = tmp.is_undefined ();
357 
358  if (orig_undefined || tmp.is_zero_by_zero ())
359  {
360  tmp = octave_value::empty_conv (next_type, rhs);
361  tmp.make_unique (); // probably a no-op.
362  }
363  else
364  // optimization: ignore the copy
365  // still stored inside our map.
366  tmp.make_unique (1);
367 
368  if (! error_state)
369  t_rhs =
370  (orig_undefined
371  ? tmp.undef_subsasgn (next_type, next_idx, rhs)
372  : tmp.subsasgn (next_type, next_idx, rhs));
373  }
374  else
376  }
377  }
378  else
380  }
381  break;
382 
383  case '.':
384  {
385  octave_value_list key_idx = idx.front ();
386 
387  assert (key_idx.length () == 1);
388 
389  std::string key = key_idx(0).string_value ();
390 
391  maybe_warn_invalid_field_name (key, "subsasgn");
392 
393  if (error_state)
394  return retval;
395 
396  std::list<octave_value_list> next_idx (idx);
397 
398  next_idx.erase (next_idx.begin ());
399 
400  std::string next_type = type.substr (1);
401 
402  Cell tmpc (1, 1);
403  octave_map::iterator pkey = map.seek (key);
404  if (pkey != map.end ())
405  {
406  map.contents (pkey).make_unique ();
407  tmpc = map.contents (pkey);
408  }
409 
410  // FIXME: better code reuse?
411  if (! error_state)
412  {
413  if (tmpc.numel () == 1)
414  {
415  octave_value& tmp = tmpc(0);
416 
417  bool orig_undefined = tmp.is_undefined ();
418 
419  if (orig_undefined || tmp.is_zero_by_zero ())
420  {
421  tmp = octave_value::empty_conv (next_type, rhs);
422  tmp.make_unique (); // probably a no-op.
423  }
424  else
425  // optimization: ignore the copy
426  // still stored inside our map.
427  tmp.make_unique (1);
428 
429  if (! error_state)
430  t_rhs = (orig_undefined
431  ? tmp.undef_subsasgn (next_type, next_idx, rhs)
432  : tmp.subsasgn (next_type, next_idx, rhs));
433  }
434  else
436  }
437  }
438  break;
439 
440  case '{':
441  gripe_invalid_index_type (type_name (), type[0]);
442  break;
443 
444  default:
445  panic_impossible ();
446  }
447  }
448 
449  if (! error_state)
450  {
451  switch (type[0])
452  {
453  case '(':
454  {
455  if (n > 1 && type[1] == '.')
456  {
457  std::list<octave_value_list>::const_iterator p = idx.begin ();
458  octave_value_list key_idx = *++p;
459  octave_value_list idxf = idx.front ();
460 
461  assert (key_idx.length () == 1);
462 
463  std::string key = key_idx(0).string_value ();
464 
465  maybe_warn_invalid_field_name (key, "subsasgn");
466 
467  if (error_state)
468  return retval;
469 
470  if (! error_state)
471  {
472  if (t_rhs.is_cs_list ())
473  {
474  Cell tmp_cell = Cell (t_rhs.list_value ());
475 
476  // Inquire the proper shape of the RHS.
477 
478  dim_vector didx = dims ().redim (idxf.length ());
479  for (octave_idx_type k = 0; k < idxf.length (); k++)
480  if (! idxf(k).is_magic_colon ())
481  didx(k) = idxf(k).numel ();
482 
483  if (didx.numel () == tmp_cell.numel ())
484  tmp_cell = tmp_cell.reshape (didx);
485 
486 
487  map.assign (idxf, key, tmp_cell);
488 
489  if (! error_state)
490  {
491  count++;
492  retval = octave_value (this);
493  }
494  else
496  }
497  else
498  {
499  const octave_map& cmap =
500  const_cast<const octave_map &> (map);
501  // cast to const reference, avoid forced key insertion.
502  if (idxf.all_scalars ()
503  || cmap.contents (key).index (idxf, true).numel ()
504  == 1)
505  {
506  map.assign (idxf,
507  key, Cell (t_rhs.storable_value ()));
508  if (! error_state)
509  {
510  count++;
511  retval = octave_value (this);
512  }
513  else
515  }
516  else if (! error_state)
518  }
519  }
520  else
522  }
523  else
524  {
525  if (t_rhs.is_map () || t_rhs.is_object ())
526  {
527  octave_map rhs_map = t_rhs.map_value ();
528 
529  if (! error_state)
530  {
531  map.assign (idx.front (), rhs_map);
532 
533  if (! error_state)
534  {
535  count++;
536  retval = octave_value (this);
537  }
538  else
540  }
541  else
542  error ("invalid structure assignment");
543  }
544  else
545  {
546  if (t_rhs.is_null_value ())
547  {
548  map.delete_elements (idx.front ());
549 
550  if (! error_state)
551  {
552  count++;
553  retval = octave_value (this);
554  }
555  else
557  }
558  else
559  error ("invalid structure assignment");
560  }
561  }
562  }
563  break;
564 
565  case '.':
566  {
567  octave_value_list key_idx = idx.front ();
568 
569  assert (key_idx.length () == 1);
570 
571  std::string key = key_idx(0).string_value ();
572 
573  maybe_warn_invalid_field_name (key, "subsasgn");
574 
575  if (error_state)
576  return retval;
577 
578  if (t_rhs.is_cs_list ())
579  {
580  Cell tmp_cell = Cell (t_rhs.list_value ());
581 
582  // The shape of the RHS is irrelevant, we just want
583  // the number of elements to agree and to preserve the
584  // shape of the left hand side of the assignment.
585 
586  if (numel () == tmp_cell.numel ())
587  tmp_cell = tmp_cell.reshape (dims ());
588 
589  map.setfield (key, tmp_cell);
590  }
591  else
592  {
593  Cell tmp_cell(1, 1);
594  tmp_cell(0) = t_rhs.storable_value ();
595  map.setfield (key, tmp_cell);
596  }
597 
598  if (! error_state)
599  {
600  count++;
601  retval = octave_value (this);
602  }
603  else
605  }
606  break;
607 
608  case '{':
609  gripe_invalid_index_type (type_name (), type[0]);
610  break;
611 
612  default:
613  panic_impossible ();
614  }
615  }
616  else
618 
619  retval.maybe_mutate ();
620 
621  return retval;
622 }
623 
625 octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
626 {
627  // octave_map handles indexing itself.
628  return map.index (idx, resize_ok);
629 }
630 
631 size_t
633 {
634  // Neglect the size of the fieldnames.
635 
636  size_t retval = 0;
637 
638  for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
639  {
640  std::string key = map.key (p);
641 
643 
644  retval += val.byte_size ();
645  }
646 
647  return retval;
648 }
649 
650 void
651 octave_struct::print (std::ostream& os, bool) const
652 {
653  print_raw (os);
654 }
655 
656 void
657 octave_struct::print_raw (std::ostream& os, bool) const
658 {
659  unwind_protect frame;
660 
661  frame.protect_var (Vstruct_levels_to_print);
662 
663  if (Vstruct_levels_to_print >= 0)
664  {
665  bool max_depth_reached = Vstruct_levels_to_print-- == 0;
666 
667  bool print_fieldnames_only
668  = (max_depth_reached || ! Vprint_struct_array_contents);
669 
671 
672  newline (os);
673  indent (os);
674  dim_vector dv = dims ();
675  os << dv.str () << " struct array containing the fields:";
676  newline (os);
677 
679 
680  string_vector key_list = map.fieldnames ();
681 
682  for (octave_idx_type i = 0; i < key_list.length (); i++)
683  {
684  std::string key = key_list[i];
685 
686  Cell val = map.contents (key);
687 
688  newline (os);
689 
690  if (print_fieldnames_only)
691  {
692  indent (os);
693  os << key;
694  }
695  else
696  {
697  octave_value tmp (val);
698  tmp.print_with_name (os, key);
699  }
700  }
701 
702  if (print_fieldnames_only)
703  newline (os);
704 
707  }
708  else
709  {
710  indent (os);
711  os << "<structure>";
712  newline (os);
713  }
714 }
715 
716 bool
717 octave_struct::print_name_tag (std::ostream& os, const std::string& name) const
718 {
719  bool retval = false;
720 
721  indent (os);
722 
723  if (Vstruct_levels_to_print < 0)
724  os << name << " = ";
725  else
726  {
727  os << name << " =";
728  newline (os);
729  retval = true;
730  }
731 
732  return retval;
733 }
734 
735 static bool
736 scalar (const dim_vector& dims)
737 {
738  return dims.length () == 2 && dims (0) == 1 && dims (1) == 1;
739 }
740 
741 
742 bool
743 octave_struct::save_ascii (std::ostream& os)
744 {
745  octave_map m = map_value ();
746 
747  octave_idx_type nf = m.nfields ();
748 
749  const dim_vector dv = dims ();
750 
751  os << "# ndims: " << dv.length () << "\n";
752 
753  for (int i = 0; i < dv.length (); i++)
754  os << " " << dv (i);
755  os << "\n";
756 
757  os << "# length: " << nf << "\n";
758 
759  // Iterating over the list of keys will preserve the order of the
760  // fields.
761  string_vector keys = m.fieldnames ();
762 
763  for (octave_idx_type i = 0; i < nf; i++)
764  {
765  std::string key = keys(i);
766 
767  octave_value val = map.contents (key);
768 
769  bool b = save_ascii_data (os, val, key, false, 0);
770 
771  if (! b)
772  return os;
773  }
774 
775  return true;
776 }
777 
778 bool
779 octave_struct::load_ascii (std::istream& is)
780 {
781  octave_idx_type len = 0;
782  dim_vector dv (1, 1);
783  bool success = true;
784 
785  // KLUGE: earlier Octave versions did not save extra dimensions with struct,
786  // and as a result did not preserve dimensions for empty structs.
787  // The default dimensions were 1x1, which we want to preserve.
789 
790  keywords[0] = "ndims";
791  keywords[1] = "length";
792 
793  std::string kw;
794 
795  if (extract_keyword (is, keywords, kw, len, true))
796  {
797  if (kw == keywords[0])
798  {
799  int mdims = std::max (static_cast<int> (len), 2);
800  dv.resize (mdims);
801  for (int i = 0; i < mdims; i++)
802  is >> dv(i);
803 
804  success = extract_keyword (is, keywords[1], len);
805  }
806  }
807  else
808  success = false;
809 
810  if (success && len >= 0)
811  {
812  if (len > 0)
813  {
814  octave_map m (dv);
815 
816  for (octave_idx_type j = 0; j < len; j++)
817  {
818  octave_value t2;
819  bool dummy;
820 
821  // recurse to read cell elements
822  std::string nm
823  = read_ascii_data (is, std::string (), dummy, t2, j);
824 
825  if (!is)
826  break;
827 
828  Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
829 
830  if (error_state)
831  {
832  error ("load: internal error loading struct elements");
833  return false;
834  }
835 
836  m.setfield (nm, tcell);
837  }
838 
839  if (is)
840  map = m;
841  else
842  {
843  error ("load: failed to load structure");
844  success = false;
845  }
846  }
847  else if (len == 0 )
848  map = octave_map (dv);
849  else
850  panic_impossible ();
851  }
852  else
853  {
854  error ("load: failed to extract number of elements in structure");
855  success = false;
856  }
857 
858  return success;
859 }
860 
861 bool
862 octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
863 {
864  octave_map m = map_value ();
865 
866  octave_idx_type nf = m.nfields ();
867 
868  dim_vector d = dims ();
869  if (d.length () < 1)
870  return false;
871 
872  // Use negative value for ndims
873  int32_t di = - d.length ();
874  os.write (reinterpret_cast<char *> (&di), 4);
875  for (int i = 0; i < d.length (); i++)
876  {
877  di = d(i);
878  os.write (reinterpret_cast<char *> (&di), 4);
879  }
880 
881  int32_t len = nf;
882  os.write (reinterpret_cast<char *> (&len), 4);
883 
884  // Iterating over the list of keys will preserve the order of the
885  // fields.
886  string_vector keys = m.fieldnames ();
887 
888  for (octave_idx_type i = 0; i < nf; i++)
889  {
890  std::string key = keys(i);
891 
892  octave_value val = map.contents (key);
893 
894  bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
895 
896  if (! b)
897  return os;
898  }
899 
900  return true;
901 }
902 
903 bool
904 octave_struct::load_binary (std::istream& is, bool swap,
906 {
907  bool success = true;
908  int32_t len;
909  if (! is.read (reinterpret_cast<char *> (&len), 4))
910  return false;
911  if (swap)
912  swap_bytes<4> (&len);
913 
914  dim_vector dv (1, 1);
915 
916  if (len < 0)
917  {
918  // We have explicit dimensions.
919  int mdims = -len;
920 
921  int32_t di;
922  dv.resize (mdims);
923 
924  for (int i = 0; i < mdims; i++)
925  {
926  if (! is.read (reinterpret_cast<char *> (&di), 4))
927  return false;
928  if (swap)
929  swap_bytes<4> (&di);
930  dv(i) = di;
931  }
932 
933  if (! is.read (reinterpret_cast<char *> (&len), 4))
934  return false;
935  if (swap)
936  swap_bytes<4> (&len);
937  }
938 
939  if (len > 0)
940  {
941  octave_map m (dv);
942 
943  for (octave_idx_type j = 0; j < len; j++)
944  {
945  octave_value t2;
946  bool dummy;
947  std::string doc;
948 
949  // recurse to read cell elements
950  std::string nm = read_binary_data (is, swap, fmt, std::string (),
951  dummy, t2, doc);
952 
953  if (!is)
954  break;
955 
956  Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
957 
958  if (error_state)
959  {
960  error ("load: internal error loading struct elements");
961  return false;
962  }
963 
964  m.setfield (nm, tcell);
965  }
966 
967  if (is)
968  map = m;
969  else
970  {
971  error ("load: failed to load structure");
972  success = false;
973  }
974  }
975  else if (len == 0)
976  map = octave_map (dv);
977  else
978  success = false;
979 
980  return success;
981 }
982 
983 #if defined (HAVE_HDF5)
984 
985 bool
986 octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
987 {
988  hid_t data_hid = -1;
989 
990 #if HAVE_HDF5_18
991  data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
992 #else
993  data_hid = H5Gcreate (loc_id, name, 0);
994 #endif
995  if (data_hid < 0) return false;
996 
997  // recursively add each element of the structure to this group
998  octave_map m = map_value ();
999 
1000  octave_idx_type nf = m.nfields ();
1001 
1002  // Iterating over the list of keys will preserve the order of the
1003  // fields.
1004  string_vector keys = m.fieldnames ();
1005 
1006  for (octave_idx_type i = 0; i < nf; i++)
1007  {
1008  std::string key = keys(i);
1009 
1010  octave_value val = map.contents (key);
1011 
1012  bool retval2 = add_hdf5_data (data_hid, val, key, "", false,
1013  save_as_floats);
1014 
1015  if (! retval2)
1016  break;
1017  }
1018 
1019  H5Gclose (data_hid);
1020 
1021  return true;
1022 }
1023 
1024 bool
1025 octave_struct::load_hdf5 (hid_t loc_id, const char *name)
1026 {
1027  bool retval = false;
1028 
1029  hdf5_callback_data dsub;
1030 
1031  herr_t retval2 = 0;
1032  octave_map m (dim_vector (1, 1));
1033  int current_item = 0;
1034  hsize_t num_obj = 0;
1035 #if HAVE_HDF5_18
1036  hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
1037 #else
1038  hid_t group_id = H5Gopen (loc_id, name);
1039 #endif
1040  H5Gget_num_objs (group_id, &num_obj);
1041  H5Gclose (group_id);
1042 
1043  // FIXME: fields appear to be sorted alphabetically on loading.
1044  // Why is that happening?
1045 
1046  while (current_item < static_cast<int> (num_obj)
1047  && (retval2 = H5Giterate (loc_id, name, &current_item,
1048  hdf5_read_next_data, &dsub)) > 0)
1049  {
1050  octave_value t2 = dsub.tc;
1051 
1052  Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1053 
1054  if (error_state)
1055  {
1056  error ("load: internal error loading struct elements");
1057  return false;
1058  }
1059 
1060  m.setfield (dsub.name, tcell);
1061 
1062  }
1063 
1064  if (retval2 >= 0)
1065  {
1066  map = m;
1067  retval = true;
1068  }
1069 
1070  return retval;
1071 }
1072 
1073 #endif
1074 
1075 mxArray *
1077 {
1078  int nf = nfields ();
1079  string_vector kv = map_keys ();
1080 
1081  OCTAVE_LOCAL_BUFFER (const char *, f, nf);
1082 
1083  for (int i = 0; i < nf; i++)
1084  f[i] = kv[i].c_str ();
1085 
1086  mxArray *retval = new mxArray (dims (), nf, f);
1087 
1088  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
1089 
1090  mwSize nel = numel ();
1091 
1092  mwSize ntot = nf * nel;
1093 
1094  for (int i = 0; i < nf; i++)
1095  {
1096  Cell c = map.contents (kv[i]);
1097 
1098  const octave_value *p = c.data ();
1099 
1100  mwIndex k = 0;
1101  for (mwIndex j = i; j < ntot; j += nf)
1102  elts[j] = new mxArray (p[k++]);
1103  }
1104 
1105  return retval;
1106 }
1107 
1110 {
1111  if (n < map.numel ())
1112  return map.checkelem (n);
1113  else
1114  return octave_value ();
1115 }
1116 
1117 bool
1119  const octave_value& x)
1120 {
1121  bool retval = false;
1122 
1123  if (n < map.numel ())
1124  {
1125  // To avoid copying the scalar struct, it just stores a pointer to
1126  // itself.
1127  const octave_scalar_map *sm_ptr;
1128  void *here = reinterpret_cast<void *>(&sm_ptr);
1129  return (x.get_rep ().fast_elem_insert_self (here, btyp_struct)
1130  && map.fast_elem_insert (n, *sm_ptr));
1131  }
1132 
1133  return retval;
1134 }
1136 
1138  "struct");
1139 
1142 {
1143  octave_value retval;
1144 
1145  assert (idx.length () == 1);
1146 
1147  std::string nm = idx(0).string_value ();
1148 
1149  maybe_warn_invalid_field_name (nm, "subsref");
1150 
1151  if (error_state)
1152  return retval;
1153 
1154  retval = map.getfield (nm);
1155 
1156  if (! auto_add && retval.is_undefined ())
1157  error_with_id ("Octave:invalid-indexing",
1158  "structure has no member '%s'", nm.c_str ());
1159 
1160  return retval;
1161 }
1162 
1164 octave_scalar_struct::subsref (const std::string& type,
1165  const std::list<octave_value_list>& idx)
1166 {
1167  octave_value retval;
1168 
1169  if (type[0] == '.')
1170  {
1171  int skip = 1;
1172 
1173  retval = dotref (idx.front ());
1174 
1175  if (idx.size () > 1)
1176  retval = retval.next_subsref (type, idx, skip);
1177  }
1178  else
1179  retval = to_array ().subsref (type, idx);
1180 
1181  return retval;
1182 }
1183 
1185 octave_scalar_struct::subsref (const std::string& type,
1186  const std::list<octave_value_list>& idx,
1187  int nargout)
1188 {
1189  octave_value_list retval;
1190 
1191  if (type[0] == '.')
1192  {
1193  int skip = 1;
1194 
1195  retval(0) = dotref (idx.front ());
1196 
1197  if (idx.size () > 1)
1198  retval = retval(0).next_subsref (nargout, type, idx, skip);
1199  }
1200  else
1201  retval = to_array ().subsref (type, idx, nargout);
1202 
1203  return retval;
1204 }
1205 
1207 octave_scalar_struct::subsref (const std::string& type,
1208  const std::list<octave_value_list>& idx,
1209  bool auto_add)
1210 {
1211  octave_value retval;
1212 
1213  if (type[0] == '.')
1214  {
1215  int skip = 1;
1216 
1217  retval = dotref (idx.front (), auto_add);
1218 
1219  if (idx.size () > 1)
1220  retval = retval.next_subsref (auto_add, type, idx, skip);
1221  }
1222  else
1223  retval = to_array ().subsref (type, idx, auto_add);
1224 
1225  return retval;
1226 }
1227 
1228 /*
1229 %!test
1230 %! x(1).a.a = 1;
1231 %! x(2).a.a = 2;
1232 %! assert (size (x), [1, 2]);
1233 %! assert (x(1).a.a, 1);
1234 %! assert (x(2).a.a, 2);
1235 */
1236 
1239  const std::string& type)
1240 {
1241  octave_value retval;
1242 
1243  if (type.length () > 0 && type[0] == '.' && ! val.is_map ())
1244  retval = octave_map ();
1245  else
1246  retval = val;
1247 
1248  return retval;
1249 }
1250 
1252 octave_scalar_struct::subsasgn (const std::string& type,
1253  const std::list<octave_value_list>& idx,
1254  const octave_value& rhs)
1255 {
1256  octave_value retval;
1257 
1258  if (idx.front ().empty ())
1259  {
1260  error ("missing index in indexed assignment");
1261  return retval;
1262  }
1263 
1264  if (type[0] == '.')
1265  {
1266  int n = type.length ();
1267 
1268  octave_value t_rhs = rhs;
1269 
1270  octave_value_list key_idx = idx.front ();
1271 
1272  assert (key_idx.length () == 1);
1273 
1274  std::string key = key_idx(0).string_value ();
1275 
1276  maybe_warn_invalid_field_name (key, "subsasgn");
1277 
1278  if (error_state)
1279  return retval;
1280 
1281  if (n > 1)
1282  {
1283  std::list<octave_value_list> next_idx (idx);
1284 
1285  next_idx.erase (next_idx.begin ());
1286 
1287  std::string next_type = type.substr (1);
1288 
1289  octave_value tmp;
1290  octave_map::iterator pkey = map.seek (key);
1291  if (pkey != map.end ())
1292  {
1293  map.contents (pkey).make_unique ();
1294  tmp = map.contents (pkey);
1295  }
1296 
1297  if (! error_state)
1298  {
1299  bool orig_undefined = tmp.is_undefined ();
1300 
1301  if (orig_undefined || tmp.is_zero_by_zero ())
1302  {
1303  tmp = octave_value::empty_conv (next_type, rhs);
1304  tmp.make_unique (); // probably a no-op.
1305  }
1306  else
1307  // optimization: ignore the copy still stored inside our map.
1308  tmp.make_unique (1);
1309 
1310  if (! error_state)
1311  t_rhs = (orig_undefined
1312  ? tmp.undef_subsasgn (next_type, next_idx, rhs)
1313  : tmp.subsasgn (next_type, next_idx, rhs));
1314  }
1315  }
1316 
1317  if (! error_state)
1318  map.setfield (key, t_rhs.storable_value ());
1319  else
1321 
1322  count++;
1323  retval = this;
1324  }
1325  else
1326  {
1327  // Forward this case to octave_struct.
1328  octave_value tmp (new octave_struct (octave_map (map)));
1329  retval = tmp.subsasgn (type, idx, rhs);
1330  }
1331 
1332  return retval;
1333 }
1334 
1337 {
1338  // octave_map handles indexing itself.
1339  return octave_map (map).index (idx, resize_ok);
1340 }
1341 
1342 size_t
1344 {
1345  // Neglect the size of the fieldnames.
1346 
1347  size_t retval = 0;
1348 
1349  for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
1350  {
1351  std::string key = map.key (p);
1352 
1353  octave_value val = octave_value (map.contents (p));
1354 
1355  retval += val.byte_size ();
1356  }
1357 
1358  return retval;
1359 }
1360 
1361 void
1362 octave_scalar_struct::print (std::ostream& os, bool) const
1363 {
1364  print_raw (os);
1365 }
1366 
1367 void
1368 octave_scalar_struct::print_raw (std::ostream& os, bool) const
1369 {
1370  unwind_protect frame;
1371 
1372  frame.protect_var (Vstruct_levels_to_print);
1373 
1374  if (Vstruct_levels_to_print >= 0)
1375  {
1376  bool max_depth_reached = Vstruct_levels_to_print-- == 0;
1377 
1378  bool print_fieldnames_only = max_depth_reached;
1379 
1381 
1382  if (! Vcompact_format)
1383  newline (os);
1384 
1385  indent (os);
1386  os << "scalar structure containing the fields:";
1387  newline (os);
1388  if (! Vcompact_format)
1389  newline (os);
1390 
1392 
1393  string_vector key_list = map.fieldnames ();
1394 
1395  for (octave_idx_type i = 0; i < key_list.length (); i++)
1396  {
1397  std::string key = key_list[i];
1398 
1399  octave_value val = map.contents (key);
1400 
1401  if (print_fieldnames_only)
1402  {
1403  indent (os);
1404  os << key;
1405  dim_vector dv = val.dims ();
1406  os << ": " << dv.str () << " " << val.type_name ();
1407  newline (os);
1408  }
1409  else
1410  val.print_with_name (os, key);
1411  }
1412 
1415  }
1416  else
1417  {
1418  indent (os);
1419  os << "<structure>";
1420  newline (os);
1421  }
1422 }
1423 
1424 bool
1426  const std::string& name) const
1427 {
1428  bool retval = false;
1429 
1430  indent (os);
1431 
1432  if (Vstruct_levels_to_print < 0)
1433  os << name << " = ";
1434  else
1435  {
1436  os << name << " =";
1437  newline (os);
1438  retval = true;
1439  }
1440 
1441  return retval;
1442 }
1443 
1444 bool
1446 {
1447  octave_map m = map_value ();
1448 
1449  octave_idx_type nf = m.nfields ();
1450 
1451  const dim_vector dv = dims ();
1452 
1453  os << "# ndims: " << dv.length () << "\n";
1454 
1455  for (int i = 0; i < dv.length (); i++)
1456  os << " " << dv (i);
1457  os << "\n";
1458 
1459  os << "# length: " << nf << "\n";
1460 
1461  // Iterating over the list of keys will preserve the order of the
1462  // fields.
1463  string_vector keys = m.fieldnames ();
1464 
1465  for (octave_idx_type i = 0; i < nf; i++)
1466  {
1467  std::string key = keys(i);
1468 
1469  octave_value val = map.contents (key);
1470 
1471  bool b = save_ascii_data (os, val, key, false, 0);
1472 
1473  if (! b)
1474  return os;
1475  }
1476 
1477  return true;
1478 }
1479 
1480 bool
1482 {
1483  bool success = true;
1484  octave_idx_type len = 0;
1485 
1486  if (extract_keyword (is, "length", len) && len >= 0)
1487  {
1488  if (len > 0)
1489  {
1491 
1492  for (octave_idx_type j = 0; j < len; j++)
1493  {
1494  octave_value t2;
1495  bool dummy;
1496 
1497  // recurse to read cell elements
1498  std::string nm
1499  = read_ascii_data (is, std::string (), dummy, t2, j);
1500 
1501  if (!is)
1502  break;
1503 
1504  if (error_state)
1505  {
1506  error ("load: internal error loading struct elements");
1507  return false;
1508  }
1509 
1510  m.setfield (nm, t2);
1511  }
1512 
1513  if (is)
1514  map = m;
1515  else
1516  {
1517  error ("load: failed to load structure");
1518  success = false;
1519  }
1520  }
1521  else if (len == 0)
1522  map = octave_scalar_map ();
1523  else
1524  panic_impossible ();
1525  }
1526  else
1527  {
1528  error ("load: failed to extract number of elements in structure");
1529  success = false;
1530  }
1531 
1532  return success;
1533 }
1534 
1535 bool
1536 octave_scalar_struct::save_binary (std::ostream& os, bool& save_as_floats)
1537 {
1538  octave_map m = map_value ();
1539 
1540  octave_idx_type nf = m.nfields ();
1541 
1542  int32_t len = nf;
1543  os.write (reinterpret_cast<char *> (&len), 4);
1544 
1545  // Iterating over the list of keys will preserve the order of the
1546  // fields.
1547  string_vector keys = m.fieldnames ();
1548 
1549  for (octave_idx_type i = 0; i < nf; i++)
1550  {
1551  std::string key = keys(i);
1552 
1553  octave_value val = map.contents (key);
1554 
1555  bool b = save_binary_data (os, val, key, "", 0, save_as_floats);
1556 
1557  if (! b)
1558  return os;
1559  }
1560 
1561  return true;
1562 }
1563 
1564 bool
1565 octave_scalar_struct::load_binary (std::istream& is, bool swap,
1567 {
1568  bool success = true;
1569  int32_t len;
1570  if (! is.read (reinterpret_cast<char *> (&len), 4))
1571  return false;
1572  if (swap)
1573  swap_bytes<4> (&len);
1574 
1575  dim_vector dv (1, 1);
1576 
1577  if (len > 0)
1578  {
1580 
1581  for (octave_idx_type j = 0; j < len; j++)
1582  {
1583  octave_value t2;
1584  bool dummy;
1585  std::string doc;
1586 
1587  // recurse to read cell elements
1588  std::string nm = read_binary_data (is, swap, fmt, std::string (),
1589  dummy, t2, doc);
1590 
1591  if (!is)
1592  break;
1593 
1594  if (error_state)
1595  {
1596  error ("load: internal error loading struct elements");
1597  return false;
1598  }
1599 
1600  m.setfield (nm, t2);
1601  }
1602 
1603  if (is)
1604  map = m;
1605  else
1606  {
1607  error ("load: failed to load structure");
1608  success = false;
1609  }
1610  }
1611  else if (len == 0)
1612  map = octave_scalar_map ();
1613  else
1614  success = false;
1615 
1616  return success;
1617 }
1618 
1619 #if defined (HAVE_HDF5)
1620 
1621 bool
1622 octave_scalar_struct::save_hdf5 (hid_t loc_id, const char *name,
1623  bool save_as_floats)
1624 {
1625  hid_t data_hid = -1;
1626 
1627 #if HAVE_HDF5_18
1628  data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1629 #else
1630  data_hid = H5Gcreate (loc_id, name, 0);
1631 #endif
1632  if (data_hid < 0) return false;
1633 
1634  // recursively add each element of the structure to this group
1636 
1637  octave_idx_type nf = m.nfields ();
1638 
1639  // Iterating over the list of keys will preserve the order of the
1640  // fields.
1641  string_vector keys = m.fieldnames ();
1642 
1643  for (octave_idx_type i = 0; i < nf; i++)
1644  {
1645  std::string key = keys(i);
1646 
1647  octave_value val = map.contents (key);
1648 
1649  bool retval2 = add_hdf5_data (data_hid, val, key, "", false,
1650  save_as_floats);
1651 
1652  if (! retval2)
1653  break;
1654  }
1655 
1656  H5Gclose (data_hid);
1657 
1658  return true;
1659 }
1660 
1661 bool
1662 octave_scalar_struct::load_hdf5 (hid_t loc_id, const char *name)
1663 {
1664  bool retval = false;
1665 
1666  hdf5_callback_data dsub;
1667 
1668  herr_t retval2 = 0;
1670  int current_item = 0;
1671  hsize_t num_obj = 0;
1672 #if HAVE_HDF5_18
1673  hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT);
1674 #else
1675  hid_t group_id = H5Gopen (loc_id, name);
1676 #endif
1677  H5Gget_num_objs (group_id, &num_obj);
1678  H5Gclose (group_id);
1679 
1680  // FIXME: fields appear to be sorted alphabetically on loading.
1681  // Why is that happening?
1682 
1683  while (current_item < static_cast<int> (num_obj)
1684  && (retval2 = H5Giterate (loc_id, name, &current_item,
1685  hdf5_read_next_data, &dsub)) > 0)
1686  {
1687  octave_value t2 = dsub.tc;
1688 
1689  if (error_state)
1690  {
1691  error ("load: internal error loading struct elements");
1692  return false;
1693  }
1694 
1695  m.setfield (dsub.name, t2);
1696 
1697  }
1698 
1699  if (retval2 >= 0)
1700  {
1701  map = m;
1702  retval = true;
1703  }
1704 
1705  return retval;
1706 }
1707 
1708 #endif
1709 
1710 mxArray *
1712 {
1713  int nf = nfields ();
1714  string_vector kv = map_keys ();
1715 
1716  OCTAVE_LOCAL_BUFFER (const char *, f, nf);
1717 
1718  for (int i = 0; i < nf; i++)
1719  f[i] = kv[i].c_str ();
1720 
1721  mxArray *retval = new mxArray (dims (), nf, f);
1722 
1723  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
1724 
1725  mwSize nel = numel ();
1726 
1727  mwSize ntot = nf * nel;
1728 
1729  for (int i = 0; i < nf; i++)
1730  {
1731  Cell c = map.contents (kv[i]);
1732 
1733  const octave_value *p = c.data ();
1734 
1735  mwIndex k = 0;
1736  for (mwIndex j = i; j < ntot; j += nf)
1737  elts[j] = new mxArray (p[k++]);
1738  }
1739 
1740  return retval;
1741 }
1742 
1743 
1746 {
1747  return new octave_struct (octave_map (map));
1748 }
1749 
1750 bool
1752  builtin_type_t btyp) const
1753 {
1754 
1755  if (btyp == btyp_struct)
1756  {
1757  *(reinterpret_cast<const octave_scalar_map **>(where)) = &map;
1758  return true;
1759  }
1760  else
1761  return false;
1762 }
1763 
1764 DEFUN (struct, args, ,
1765  "-*- texinfo -*-\n\
1766 @deftypefn {Built-in Function} {} struct (@var{field1}, @var{value1}, @var{field2}, @var{value2}, @dots{})\n\
1767 \n\
1768 Create a scalar or array structure and initialize its values. The\n\
1769 @var{field1}, @var{field2}, @dots{} variables are strings giving the\n\
1770 names of the fields and the @var{value1}, @var{value2}, @dots{}\n\
1771 variables can be any type.\n\
1772 \n\
1773 If the values are cell arrays, create a structure array and initialize\n\
1774 its values. The dimensions of each cell array of values must match.\n\
1775 Singleton cells and non-cell values are repeated so that they fill\n\
1776 the entire array. If the cells are empty, create an empty structure\n\
1777 array with the specified field names.\n\
1778 \n\
1779 If the argument is an object, return the underlying struct.\n\
1780 \n\
1781 Observe that the syntax is optimized for struct @strong{arrays}. Consider\n\
1782 the following examples:\n\
1783 \n\
1784 @example\n\
1785 @group\n\
1786 struct (\"foo\", 1)\n\
1787  @result{} scalar structure containing the fields:\n\
1788  foo = 1\n\
1789 \n\
1790 struct (\"foo\", @{@})\n\
1791  @result{} 0x0 struct array containing the fields:\n\
1792  foo\n\
1793 \n\
1794 struct (\"foo\", @{ @{@} @})\n\
1795  @result{} scalar structure containing the fields:\n\
1796  foo = @{@}(0x0)\n\
1797 \n\
1798 struct (\"foo\", @{1, 2, 3@})\n\
1799  @result{} 1x3 struct array containing the fields:\n\
1800  foo\n\
1801 \n\
1802 @end group\n\
1803 @end example\n\
1804 \n\
1805 @noindent\n\
1806 The first case is an ordinary scalar struct, one field, one value. The\n\
1807 second produces an empty struct array with one field and no values, since\n\
1808 s being passed an empty cell array of struct array values. When the value is\n\
1809 a cell array containing a single entry, this becomes a scalar struct with\n\
1810 that single entry as the value of the field. That single entry happens\n\
1811 to be an empty cell array.\n\
1812 \n\
1813 Finally, if the value is a non-scalar cell array, then @code{struct}\n\
1814 produces a struct @strong{array}.\n\
1815 @end deftypefn")
1816 {
1817  octave_value retval;
1818 
1819  int nargin = args.length ();
1820 
1821  // struct ([]) returns an empty struct.
1822 
1823  // struct (empty_matrix) returns an empty struct with the same
1824  // dimensions as the empty matrix.
1825 
1826  // Note that struct () creates a 1x1 struct with no fields for
1827  // compatibility with Matlab.
1828 
1829  if (nargin == 1 && args(0).is_map ())
1830  return args(0);
1831 
1832  if (nargin == 1 && args(0).is_object ())
1833  {
1834  retval = args(0).map_value ();
1835 
1836  return retval;
1837  }
1838 
1839  if ((nargin == 1 || nargin == 2)
1840  && args(0).is_empty () && args(0).is_real_matrix ())
1841  {
1842  Cell fields;
1843 
1844  if (nargin == 2)
1845  {
1846  if (args(1).is_cellstr ())
1847  retval = octave_map (args(0).dims (), args(1).cellstr_value ());
1848  else
1849  error ("struct: expecting cell array of field names as second argument");
1850  }
1851  else
1852  retval = octave_map (args(0).dims ());
1853 
1854  return retval;
1855  }
1856 
1857  // Check for "field", VALUE pairs.
1858 
1859  for (int i = 0; i < nargin; i += 2)
1860  {
1861  if (! args(i).is_string () || i + 1 >= nargin)
1862  {
1863  error ("struct: expecting alternating \"field\", VALUE pairs");
1864  return retval;
1865  }
1866  }
1867 
1868  // Check that the dimensions of the values correspond.
1869 
1870  dim_vector dims (1, 1);
1871 
1872  int first_dimensioned_value = 0;
1873 
1874  for (int i = 1; i < nargin; i += 2)
1875  {
1876  if (args(i).is_cell ())
1877  {
1878  dim_vector argdims (args(i).dims ());
1879 
1880  if (! scalar (argdims))
1881  {
1882  if (! first_dimensioned_value)
1883  {
1884  dims = argdims;
1885  first_dimensioned_value = i + 1;
1886  }
1887  else if (dims != argdims)
1888  {
1889  error ("struct: dimensions of parameter %d do not match those of parameter %d",
1890  first_dimensioned_value, i+1);
1891  return retval;
1892  }
1893  }
1894  }
1895  }
1896 
1897  // Create the return value.
1898 
1899  octave_map map (dims);
1900 
1901  for (int i = 0; i < nargin; i+= 2)
1902  {
1903  // Get key.
1904 
1905  std::string key (args(i).string_value ());
1906 
1907  if (error_state)
1908  return retval;
1909 
1910  maybe_warn_invalid_field_name (key, "struct");
1911 
1912  if (error_state)
1913  return retval;
1914 
1915  // Value may be v, { v }, or { v1, v2, ... }
1916  // In the first two cases, we need to create a cell array of
1917  // the appropriate dimensions filled with v. In the last case,
1918  // the cell array has already been determined to be of the
1919  // correct dimensions.
1920 
1921  if (args(i+1).is_cell ())
1922  {
1923  const Cell c (args(i+1).cell_value ());
1924 
1925  if (error_state)
1926  return retval;
1927 
1928  if (scalar (c.dims ()))
1929  map.setfield (key, Cell (dims, c(0)));
1930  else
1931  map.setfield (key, c);
1932  }
1933  else
1934  map.setfield (key, Cell (dims, args(i+1)));
1935 
1936  if (error_state)
1937  return retval;
1938  }
1939 
1940  return octave_value (map);
1941 }
1942 
1943 /*
1944 %!shared x
1945 %! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
1946 %!assert (struct ("a",1, "b",3), x(1))
1947 %!assert (isempty (x([])))
1948 %!assert (isempty (struct ("a",{}, "b",{})))
1949 %!assert (struct ("a",{1,2}, "b",{3,3}), x)
1950 %!assert (struct ("a",{1,2}, "b",3), x)
1951 %!assert (struct ("a",{1,2}, "b",{3}), x)
1952 %!assert (struct ("b",3, "a",{1,2}), x)
1953 %!assert (struct ("b",{3}, "a",{1,2}), x)
1954 %!test x = struct ([]);
1955 %!assert (size (x), [0,0])
1956 %!assert (isstruct (x))
1957 %!assert (isempty (fieldnames (x)))
1958 %!fail ('struct ("a",{1,2},"b",{1,2,3})', 'dimensions of parameter 2 do not match those of parameter 4')
1959 %!fail ('struct (1,2,3,4)', 'struct: expecting alternating "field", VALUE pairs')
1960 %!fail ('struct ("1",2,"3")', 'struct: expecting alternating "field", VALUE pairs')
1961 */
1962 
1963 DEFUN (isstruct, args, ,
1964  "-*- texinfo -*-\n\
1965 @deftypefn {Built-in Function} {} isstruct (@var{x})\n\
1966 Return true if @var{x} is a structure or a structure array.\n\
1967 @seealso{ismatrix, iscell, isa}\n\
1968 @end deftypefn")
1969 {
1970  octave_value retval;
1971 
1972  if (args.length () == 1)
1973  retval = args(0).is_map ();
1974  else
1975  print_usage ();
1976 
1977  return retval;
1978 }
1979 
1980 DEFUN (__fieldnames__, args, ,
1981  "-*- texinfo -*-\n\
1982 @deftypefn {Built-in Function} {} __fieldnames__ (@var{struct})\n\
1983 @deftypefnx {Built-in Function} {} __fieldnames__ (@var{obj})\n\
1984 Internal function.\n\
1985 \n\
1986 Implements @code{fieldnames()} for structures and Octave objects.\n\
1987 @seealso{fieldnames}\n\
1988 @end deftypefn")
1989 {
1990  octave_value retval;
1991 
1992  // Input validation has already been done in fieldnames.m.
1993  octave_value arg = args(0);
1994 
1995  octave_map m = arg.map_value ();
1996 
1997  string_vector keys = m.fieldnames ();
1998 
1999  if (keys.length () == 0)
2000  retval = Cell (0, 1);
2001  else
2002  retval = Cell (keys);
2003 
2004  return retval;
2005 }
2006 
2007 DEFUN (isfield, args, ,
2008  "-*- texinfo -*-\n\
2009 @deftypefn {Built-in Function} {} isfield (@var{x}, @var{name})\n\
2010 Return true if the @var{x} is a structure and it\n\
2011 includes an element named @var{name}. If @var{name} is a cell\n\
2012 array of strings then a logical array of equal dimension is returned.\n\
2013 @end deftypefn")
2014 {
2015  octave_value retval;
2016 
2017  int nargin = args.length ();
2018 
2019  if (nargin == 2)
2020  {
2021  retval = false;
2022 
2023  if (args(0).is_map ())
2024  {
2025  octave_map m = args(0).map_value ();
2026 
2027  // FIXME: should this work for all types that can do
2028  // structure reference operations?
2029 
2030  if (args(1).is_string ())
2031  {
2032  std::string key = args(1).string_value ();
2033 
2034  retval = m.isfield (key);
2035  }
2036  else if (args(1).is_cell ())
2037  {
2038  Cell c = args(1).cell_value ();
2039  boolNDArray bm (c.dims ());
2040  octave_idx_type n = bm.numel ();
2041 
2042  for (octave_idx_type i = 0; i < n; i++)
2043  {
2044  if (c(i).is_string ())
2045  {
2046  std::string key = c(i).string_value ();
2047 
2048  bm(i) = m.isfield (key);
2049  }
2050  else
2051  bm(i) = false;
2052  }
2053 
2054  retval = bm;
2055  }
2056  }
2057  }
2058  else
2059  print_usage ();
2060 
2061  return retval;
2062 }
2063 
2064 DEFUN (nfields, args, ,
2065  "-*- texinfo -*-\n\
2066 @deftypefn {Built-in Function} {} nfields (@var{s})\n\
2067 Return the number of fields of the structure @var{s}.\n\
2068 @end deftypefn")
2069 {
2070  octave_value retval;
2071 
2072  int nargin = args.length ();
2073 
2074  if (nargin == 1 && args(0).is_map ())
2075  {
2076  retval = static_cast<double> (args(0).nfields ());
2077  }
2078  else
2079  print_usage ();
2080 
2081  return retval;
2082 }
2083 
2084 /*
2085 ## test isfield
2086 %!test
2087 %! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3;
2088 %! assert (isfield (x, "b"));
2089 %!assert (isfield (struct ("a", "1"), "a"))
2090 %!assert (isfield ({1}, "c"), false)
2091 %!assert (isfield (struct ("a", "1"), 10), false)
2092 %!assert (isfield (struct ("a", "b"), "a "), false)
2093 %!assert (isfield (struct ("a", 1, "b", 2), {"a", "c"}), [true, false])
2094 */
2095 
2096 DEFUN (cell2struct, args, ,
2097  "-*- texinfo -*-\n\
2098 @deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\
2099 Convert @var{cell} to a structure. The number of fields in @var{fields}\n\
2100 must match the number of elements in @var{cell} along dimension @var{dim},\n\
2101 that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\
2102 If @var{dim} is omitted, a value of 1 is assumed.\n\
2103 \n\
2104 @example\n\
2105 @group\n\
2106 A = cell2struct (@{\"Peter\", \"Hannah\", \"Robert\";\n\
2107  185, 170, 168@},\n\
2108  @{\"Name\",\"Height\"@}, 1);\n\
2109 A(1)\n\
2110  @result{}\n\
2111  @{\n\
2112  Name = Peter\n\
2113  Height = 185\n\
2114  @}\n\
2115 \n\
2116 @end group\n\
2117 @end example\n\
2118 @end deftypefn")
2119 {
2120  octave_value retval;
2121 
2122  int nargin = args.length ();
2123 
2124  if (nargin == 2 || nargin == 3)
2125  {
2126  if (! args(0).is_cell ())
2127  {
2128  error ("cell2struct: argument CELL must be of type cell");
2129  return retval;
2130  }
2131 
2132  if (! (args(1).is_cellstr () || args(1).is_char_matrix ()))
2133  {
2134  error ("cell2struct: FIELDS must be a cell array of strings or a character matrix");
2135  return retval;
2136  }
2137 
2138  const Cell vals = args(0).cell_value ();
2139  const Array<std::string> fields = args(1).cellstr_value ();
2140 
2141  octave_idx_type ext = 0;
2142 
2143  int dim = 0;
2144 
2145  if (nargin == 3)
2146  {
2147  if (args(2).is_real_scalar ())
2148  {
2149  dim = nargin == 2 ? 0 : args(2).int_value () - 1;
2150 
2151  if (error_state)
2152  return retval;
2153  }
2154  else
2155  {
2156  error ("cell2struct: DIM must be a real scalar");
2157  return retval;
2158  }
2159  }
2160 
2161  if (dim < 0)
2162  {
2163  error ("cell2struct: DIM must be a valid dimension");
2164  return retval;
2165  }
2166 
2167  ext = vals.ndims () > dim ? vals.dims ()(dim) : 1;
2168 
2169  if (ext != fields.numel ())
2170  {
2171  error ("cell2struct: number of FIELDS does not match dimension");
2172  return retval;
2173  }
2174 
2175  int nd = std::max (dim+1, vals.ndims ());
2176  // result dimensions.
2177  dim_vector rdv = vals.dims ().redim (nd);
2178 
2179  assert (ext == rdv(dim));
2180  if (nd == 2)
2181  {
2182  rdv(0) = rdv(1-dim);
2183  rdv(1) = 1;
2184  }
2185  else
2186  {
2187  for (int i = dim + 1; i < nd; i++)
2188  rdv(i-1) = rdv(i);
2189 
2190  rdv.resize (nd-1);
2191  }
2192 
2193  octave_map map (rdv);
2195 
2196  for (octave_idx_type i = 0; i < ext; i++)
2197  {
2198  ia(dim) = i;
2199  map.setfield (fields(i), vals.index (ia).reshape (rdv));
2200  }
2201 
2202  retval = map;
2203  }
2204  else
2205  print_usage ();
2206 
2207  return retval;
2208 }
2209 
2210 /*
2211 ## test cell2struct versus struct2cell
2212 %!test
2213 %! keys = cellstr (char (floor (rand (100,10)*24+65)))';
2214 %! vals = mat2cell (rand (100,1), ones (100,1), 1)';
2215 %! s = struct ([keys; vals]{:});
2216 %! t = cell2struct (vals, keys, 2);
2217 %! assert (s, t);
2218 %! assert (struct2cell (s), vals');
2219 %! assert (fieldnames (s), keys');
2220 
2221 %!assert (cell2struct ({1; 2}, {"a"; "b"}), struct ("a", 1, "b", 2));
2222 
2223 %!assert (cell2struct ({}, {"f"}, 3), struct ("f", {}));
2224 */
2225 
2226 
2227 // So we can call Fcellstr directly.
2228 extern octave_value_list Fcellstr (const octave_value_list& args, int);
2229 
2230 DEFUN (rmfield, args, ,
2231  "-*- texinfo -*-\n\
2232 @deftypefn {Built-in Function} {@var{s} =} rmfield (@var{s}, \"@var{f}\")\n\
2233 @deftypefnx {Built-in Function} {@var{s} =} rmfield (@var{s}, @var{f})\n\
2234 Return a copy of the structure (array) @var{s} with the field @var{f}\n\
2235 removed. If @var{f} is a cell array of strings or a character array, remove\n\
2236 each of the named fields.\n\
2237 @seealso{cellstr, iscellstr, setfield}\n\
2238 @end deftypefn")
2239 {
2240  octave_value retval;
2241 
2242  int nargin = args.length ();
2243 
2244  if (nargin == 2)
2245  {
2246  octave_map m = args(0).map_value ();
2247 
2248  octave_value_list fval = Fcellstr (args(1), 1);
2249 
2250  if (! error_state)
2251  {
2252  Cell fcell = fval(0).cell_value ();
2253 
2254  for (int i = 0; i < fcell.numel (); i++)
2255  {
2256  std::string key = fcell(i).string_value ();
2257 
2258  if (m.isfield (key))
2259  m.rmfield (key);
2260  else
2261  {
2262  error ("rmfield: structure does not contain field %s",
2263  key.c_str ());
2264 
2265  break;
2266  }
2267  }
2268 
2269  if (! error_state)
2270  retval = m;
2271  }
2272  }
2273  else
2274  print_usage ();
2275 
2276  return retval;
2277 }
2278 
2279 /*
2280 ## test rmfield
2281 %!shared x
2282 %! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; x(6).f="abc123";
2283 %!
2284 %!test
2285 %! y = rmfield (x, "c");
2286 %! assert (fieldnames (y), {"d"; "a"; "b"; "f"});
2287 %! assert (size (y), [1, 6]);
2288 %!test
2289 %! y = rmfield (x, {"a", "f"});
2290 %! assert (fieldnames (y), {"d"; "b"; "c"});
2291 %! assert (size (y), [1, 6]);
2292 */
2293 
2294 DEFUN (struct_levels_to_print, args, nargout,
2295  "-*- texinfo -*-\n\
2296 @deftypefn {Built-in Function} {@var{val} =} struct_levels_to_print ()\n\
2297 @deftypefnx {Built-in Function} {@var{old_val} =} struct_levels_to_print (@var{new_val})\n\
2298 @deftypefnx {Built-in Function} {} struct_levels_to_print (@var{new_val}, \"local\")\n\
2299 Query or set the internal variable that specifies the number of\n\
2300 structure levels to display.\n\
2301 \n\
2302 When called from inside a function with the @qcode{\"local\"} option, the\n\
2303 variable is changed locally for the function and any subroutines it calls. \n\
2304 The original variable value is restored when exiting the function.\n\
2305 @end deftypefn")
2306 {
2307  return SET_INTERNAL_VARIABLE_WITH_LIMITS (struct_levels_to_print, -1,
2309 }
2310 
2311 DEFUN (print_struct_array_contents, args, nargout,
2312  "-*- texinfo -*-\n\
2313 @deftypefn {Built-in Function} {@var{val} =} print_struct_array_contents ()\n\
2314 @deftypefnx {Built-in Function} {@var{old_val} =} print_struct_array_contents (@var{new_val})\n\
2315 @deftypefnx {Built-in Function} {} print_struct_array_contents (@var{new_val}, \"local\")\n\
2316 Query or set the internal variable that specifies whether to print struct\n\
2317 array contents. If true, values of struct array elements are printed.\n\
2318 This variable does not affect scalar structures. Their elements\n\
2319 are always printed. In both cases, however, printing will be limited to\n\
2320 the number of levels specified by @var{struct_levels_to_print}.\n\
2321 \n\
2322 When called from inside a function with the @qcode{\"local\"} option, the\n\
2323 variable is changed locally for the function and any subroutines it calls. \n\
2324 The original variable value is restored when exiting the function.\n\
2325 @end deftypefn")
2326 {
2327  return SET_INTERNAL_VARIABLE (print_struct_array_contents);
2328 }