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