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